Search code examples
cmakellvmclang

Switching between GCC and Clang/LLVM using CMake


I have a number of projects built using CMake and I'd like to be able to easily switch between using GCC or Clang/LLVM to compile them. I believe (please correct me if I'm mistaken!) that to use Clang I need to set the following:

    SET (CMAKE_C_COMPILER             "/usr/bin/clang")
    SET (CMAKE_C_FLAGS                "-Wall -std=c99")
    SET (CMAKE_C_FLAGS_DEBUG          "-g")
    SET (CMAKE_C_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELEASE        "-O4 -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")

    SET (CMAKE_CXX_COMPILER             "/usr/bin/clang++")
    SET (CMAKE_CXX_FLAGS                "-Wall")
    SET (CMAKE_CXX_FLAGS_DEBUG          "-g")
    SET (CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELEASE        "-O4 -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")

    SET (CMAKE_AR      "/usr/bin/llvm-ar")
    SET (CMAKE_LINKER  "/usr/bin/llvm-ld")
    SET (CMAKE_NM      "/usr/bin/llvm-nm")
    SET (CMAKE_OBJDUMP "/usr/bin/llvm-objdump")
    SET (CMAKE_RANLIB  "/usr/bin/llvm-ranlib")

Is there an easy way of switching between these and the default GCC variables, preferably as a system-wide change rather than project specific (i.e. not just adding them into a project's CMakeLists.txt)?

Also, is it necessary to use the llvm-* programs rather than the system defaults when compiling using clang instead of gcc? What's the difference?


Solution

  • CMake honors the environment variables CC and CXX upon detecting the C and C++ compiler to use:

    $ export CC=/usr/bin/clang
    $ export CXX=/usr/bin/clang++
    $ cmake ..
    -- The C compiler identification is Clang
    -- The CXX compiler identification is Clang
    

    The compiler specific flags can be overridden by putting them into a make override file and pointing the CMAKE_USER_MAKE_RULES_OVERRIDE variable to it. Create a file ~/ClangOverrides.txt with the following contents:

    SET (CMAKE_C_FLAGS_INIT                "-Wall -std=c11")
    SET (CMAKE_C_FLAGS_DEBUG_INIT          "-g")
    SET (CMAKE_C_FLAGS_MINSIZEREL_INIT     "-Os -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELEASE_INIT        "-O3 -DNDEBUG")
    SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
    
    SET (CMAKE_CXX_FLAGS_INIT                "-Wall -std=c++17")
    SET (CMAKE_CXX_FLAGS_DEBUG_INIT          "-g")
    SET (CMAKE_CXX_FLAGS_MINSIZEREL_INIT     "-Os -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELEASE_INIT        "-O3 -DNDEBUG")
    SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
    

    The suffix *_INIT will make CMake initialize the corresponding *_FLAGS variable with the given value. Then invoke cmake in the following way:

    $ cmake -DCMAKE_USER_MAKE_RULES_OVERRIDE=~/ClangOverrides.txt ..
    

    Finally to force the use of the LLVM binutils, set the internal variable _CMAKE_TOOLCHAIN_PREFIX. This variable is honored by the CMakeFindBinUtils module:

    $ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..
    

    Setting _CMAKE_TOOLCHAIN_LOCATION is no longer necessary for CMake version 3.9 or newer.

    Putting this all together you can write a shell wrapper which sets up the environment variables CC and CXX and then invokes cmake with the mentioned variable overrides.

    Also see this CMake FAQ on make override files.