Thanks to the MSYS2 project, now there is an easy way to utilize Clang to build C/C++ application on Windows. This works equally well for both 32-bit and 64-bit programs.
MSYS2 is a fantastic (and better) reimagination of Cygwin, it is like taking the best part of a typical modern Unix environment (a familiar shell, a general collection of utilities, a porting layer, a package manager, and so on) while still working on Windows. Bootstrapping into MSYS2 is easy, either install it directly (using the GUI installer) or use Chocolatey: choco install msys2
. Once inside its shell, pacman
is the go-to, ever-so-powerful package manager, with thousands of packages available at your disposal.
This of course, includes the toolchain. Not only the latest GCC is there, but we also have Clang! To illustrate the concept, let us go back to the simple ANSI C/C90 program covered in the previous blog post. Once we clone the repository, open MSYS2 32-bit shell and try the following:
pacman -S msys/make mingw32/mingw-w64-i686-clang
It is a simple step to install both Make and Clang. Wait a bit and after that, do the usual magic:
CC=clang make
A caveat here, Clang for Windows does not append the .exe
suffix for the executable. Thus, a quick rename to the rescue:
ren hello hello.exe
And now you can run, inspect, analyze the executable as usual.
To incorporate it into the continuous integration using Azure Pipelines (again, see the previous blog post), we shall construct a new job. The basic step is as follows.
- job: 'i686_windows_clang'
pool:
vmImage: 'vs2017-win2016'
variables:
PACMAN_PACKAGES: C:\tools\msys64\var\cache\pacman\pkg
CC: clang
First, programmatically install MSYS2:
- script: choco install --no-progress msys2
displayName: 'Install MSYS2'
After that, perform some pacman maintenances:
- script: |
pacman -Sy
pacman --noconfirm -S pacman-mirrors
workingDirectory: C:\tools\msys64\usr\bin\
displayName: 'Check pacman'
And then, we install the required packages. At the time of this writing, Clang version 9.0 (the latest) will be installed.
- script: pacman --noconfirm -S msys/make mingw64/mingw-w64-x86_64-clang
workingDirectory: C:\tools\msys64\usr\bin\
displayName: 'Install requirements'
For the x86 architecture (aka, 32-bit Intel/AMD), install a different package:
- script: pacman --noconfirm -S msys/make mingw32/mingw-w64-i686-clang
workingDirectory: C:\tools\msys64\usr\bin\
displayName: 'Install requirements'
And now, down to the actual build step:
- script: |
set PATH=C:\tools\msys64\usr\bin;C:\tools\msys64\mingw64\bin;%PATH%
make
ren hello hello.exe
displayName: 'make'
As a minor tweak, we can also cache pacman downloaded packages. In the above example, it hardly matters since we only install Make and Clang. But if you have a larger application, e.g. requiring Python, Qt, and so on, it is wide to avoid the CI run redownloading the same packages again and again (saving bandwith, and also being nice to those mirrors). We can achieve this by using the Cache task from Azure Pipelines. Simply insert this after MSYS2 installation step.
- task: Cache@2
inputs:
key: pacman
restoreKeys: pacman
path: $(PACMAN_PACKAGES)
displayName: 'Cache pacman packages'
For the complete illustration of such a job, take a look at the actual azure-pipelines.yml for the hello-c90 project.
Clang everywhere, yay!