Building with CMake, Ninja and Clang on Windows

I was running into similar problems when trying to use clang cmake and msvc 2017 together. At least for a very simple test project, I was able to get everything running, but I'm quite new to that stuff, so maybe my solution won't solve your probles.

Anyway. As far as I know, you should use clang-cl.exe rather than clang.exe with VS. However, building still failed for me in x86 configurations due to some linker problems regarding x86 vs x64 library incompatibilities.

So here's my solution to get both, x64 and x86 configurations, building in VS 2017.

  1. Download and install BOTH windows clang/llvm installers from http://releases.llvm.org/download.html. You don't have to add them to the path, as we'll explicitly specify the path later.
  2. Create a folder with a CMakeLists.txt, and open that in VS via the Open Folder dialog.
  3. In the CMake menu, select Change CMake Settings > CMakeLists.txt. This will generate a CMakeSettings.json containing settings for all build configs.
  4. Specify the paths of the x64/x86 cmake compilers in the cmakeCommandArgs for all configurations. Mine looks like this:

    {    // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
    
    "configurations": [
        {
            "name": "x86-Debug",
            "generator": "Ninja",
            "configurationType": "Debug",
            "inheritEnvironments": [ "msvc_x86" ],
            "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
            "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
            "cmakeCommandArgs": "-D CMAKE_CXX_COMPILER=D:/windows/LLVM5_x86/bin/clang-cl.exe",
            "buildCommandArgs": "-v",
            "ctestCommandArgs": ""
        },
        {
            "name": "x86-Release",
            "generator": "Ninja",
            "configurationType": "RelWithDebInfo",
            "inheritEnvironments": [ "msvc_x86" ],
            "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
            "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
            "cmakeCommandArgs": "-D CMAKE_CXX_COMPILER=D:/windows/LLVM5_x86/bin/clang-cl.exe",
            "buildCommandArgs": "-v",
            "ctestCommandArgs": ""
        },
        {
            "name": "x64-Debug",
            "generator": "Ninja",
            "configurationType": "Debug",
            "inheritEnvironments": [ "msvc_x64" ],
            "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
            "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
            "cmakeCommandArgs": "-D CMAKE_CXX_COMPILER=D:/windows/LLVM5/bin/clang-cl.exe",
            "buildCommandArgs": "-v",
            "ctestCommandArgs": ""
        },
        {
            "name": "x64-Release",
            "generator": "Ninja",
            "configurationType": "RelWithDebInfo",
            "inheritEnvironments": [ "msvc_x64" ],
            "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
            "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
            "cmakeCommandArgs": "-D CMAKE_CXX_COMPILER=D:/windows/LLVM5/bin/clang-cl.exe",
            "buildCommandArgs": "-v",
            "ctestCommandArgs": ""
        }
    ]
    

    }

Now you should be able to build both x64 and x86 configurations without errors.


Inspired by the "Ways to Compile with Clang on Windows" blog post from @Unspongeful and after some extended testing, the following command line worked for me (and yes, it's one big command I just splitted into several lines for better readability):

> cmake -E env LDFLAGS="-fuse-ld=lld-link" PATH="<path\to\ninja>" 
      cmake -H. -G Ninja -Bbuild 
         -DCMAKE_C_COMPILER:PATH="%ProgramFiles(x86)%\LLVM\bin\clang.exe" 
         -DCMAKE_CXX_COMPILER:PATH="%ProgramFiles(x86)%\LLVM\bin\clang.exe" 
         -DCMAKE_C_COMPILER_ID="Clang" 
         -DCMAKE_CXX_COMPILER_ID="Clang" 
         -DCMAKE_SYSTEM_NAME="Generic"

Here is some background information:

  • I injected your linker flags with the LDFLAGS environment variable

    See Passing compiler options cmake

  • I reduced the PATH environment variable to just point to where ninja is located, because CMake was picking my MinGW toolchain (which I didn't want included in the build process)

    Related to Environment variable used by CMake to detect Visual C++ compiler tools for Ninja

  • Defining the compiler ids "bypasses the check for working compiler and basic compiler information tests"

    See obsolete, but sometimes useful CMakeForceCompiler module

  • And I set CMAKE_SYSTEM_NAME to Generic to avoid having any additional platform specific compiler/linker flags added by CMake

    See How to partially disabling cmake C/C++ custom compiler checking

It seems at the moment you have to bypass a lot of CMake's automatic checks to get it working. So probably check with the CMake team or raise an issue to get this scenario officially supported.

And the last part with a Generic system is probably not the best choice, because it will skip Windows specific settings like the .exe suffix.

But it was the only constellation that actually worked:

-- The C compiler identification is Clang
-- The CXX compiler identification is Clang
-- Check for working C compiler: C:/Program Files (x86)/LLVM/bin/clang.exe
-- Check for working C compiler: C:/Program Files (x86)/LLVM/bin/clang.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/LLVM/bin/clang.exe
-- Check for working CXX compiler: C:/Program Files (x86)/LLVM/bin/clang.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: build

I finally found a way to use my favoured tools in a way that pleases me. It's not perfect, but it works better than Florians approach with setting the system name to Generic (which I've been using for some time now)

I first set up VS Code to use the VS developers terminal as its standard terminal. I did this by adding the following line to the VS Code preferences

"terminal.integrated.shell.windows": "C:\\MeineProgramme\\Visual_Studio\\2017\\BuildTools\\Common7\\Tools\\LaunchDevCmd.bat"

After starting the terminal within VS Code I need to call the respective batch file which sets the required environment variables (in my case vcvars64.bat). These can be found in

C:\MeineProgramme\Visual_Studio\2017\BuildTools\VC\Auxiliary\Build

After navigating to my build directory I run CMake with the following options

cmake .. -G Ninja -DCMAKE_CXX_COMPILER:PATH="C:\MeineProgramme\LLVM\bin\clang-cl.exe" -DCMAKE_LINKER:PATH="C:\MeineProgramme\LLVM\bin\lld-link.exe"

this encourages CMake to use all my installed LLVM tools. Not only clang and lld (make sure to use lld-link which supports the options led by a /), but also llvm-ar and llvm-ranlib. The only MS build tool used is the resource compiler which I don't use at the moment.

So far success I think.

Don't hesitate to contact me or comment below if you got further questions.