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?
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=c99")
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")
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- ..
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.
System wide C++ change on Ubuntu:
sudo apt-get install clang
sudo update-alternatives --config c++
Will print something like this:
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/g++ 20 auto mode
1 /usr/bin/clang++ 10 manual mode
2 /usr/bin/g++ 20 manual mode
Then just select clang++.
There is only one alternative in link group cc (providing /usr/bin/cc): /usr/bin/gcc
You can use the toolchain file mechanism of cmake for this purpose, see e.g. here. You write a toolchain file for each compiler containing the corresponding definitions. At config time, you run e.g
cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/clang-toolchain.cmake ..
and all the compiler information will be set during the project() call from the toolchain file. Though in the documentation is mentionend only in the context of cross-compiling, it works as well for different compilers on the same system.
You can use the option command:
option(USE_CLANG "build application with clang" OFF) # OFF is the default
and then wrap the clang-compiler settings in if()s:
if(USE_CLANG)
SET (...)
....
endif(USE_CLANG)
This way it is displayed as an cmake option in the gui-configuration tools.
To make it systemwide you can of course use an environment variable as the default value or stay with Ferruccio's answer.
cmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmake
.
System wide C change on Ubuntu:
sudo update-alternatives --config cc
System wide C++ change on Ubuntu:
sudo update-alternatives --config c++
For each of the above, press Selection number (1) and Enter to select Clang:
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/gcc 20 auto mode
1 /usr/bin/clang 10 manual mode
2 /usr/bin/gcc 20 manual mode
Press enter to keep the current choice[*], or type selection number:
/opt/clang-llvm-3.5/
then first install a new alternative: sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
If the default compiler chosen by cmake
is gcc
and you have installed clang
, you can use the easy way to compile your project with clang
:
$ mkdir build && cd build
$ CXX=clang++ CC=clang cmake ..
$ make -j2
or specify the compiler for cmake:
$ cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang ..
You definitely don't need to use the various different llvm-ar etc programs:
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")
These are made to work on the llvm internal format and as such aren't useful to the build of your application.
As a note -O4 will invoke LTO on your program which you may not want (it will increase compile time greatly) and clang defaults to c99 mode so that flag isn't necessarily needed either.
According to the help of cmake
:
-C <initial-cache>
Pre-load a script to populate the cache.
When cmake is first run in an empty build tree, it creates a CMakeCache.txt file and populates it with customizable settings for the project. This option may be used to specify a file from
which to load cache entries before the first pass through the project's cmake listfiles. The loaded entries take priority over the project's default values. The given file should be a CMake
script containing SET commands that use the CACHE option, not a cache-format file.
You make be able to create files like gcc_compiler.txt
and clang_compiler.txt
to includes all relative configuration in CMake syntax.
Clang Example (clang_compiler.txt):
set(CMAKE_C_COMPILER "/usr/bin/clang" CACHE string "clang compiler" FORCE)
Then run it as
GCC:
cmake -C gcc_compiler.txt XXXXXXXX
Clang:
cmake -C clang_compiler.txt XXXXXXXX
You can use the syntax: $ENV{environment-variable}
in your CMakeLists.txt
to access environment variables. You could create scripts which initialize a set of environment variables appropriately and just have references to those variables in your CMakeLists.txt
files.
-DCMAKE_C_COMPILER ...
etc?
CMakeLists.txt
of every project and have it query the new variables. I was hoping there'd be a convenient way of doing it system-wide, without having to modify any project files. Similar to passing a CMAKE_TOOLCHAIN_FILE
.
Simply add this at the end of your ~/.bashrc
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
Relaunch the terminal and from now on, cmake would use clang to build every projects. Edit the ~/.bashrc to switch back to gcc.
It is best not to specify a compiler in CMakelists.txt.
Just add the following command
-D CMAKE_CXX_COMPILER="xx" -D CMAKE_C_COMPILER="xx"
Example:
cmake -D CMAKE_CXX_COMPILER="/bin/clang++-xx" -D CMAKE_C_COMPILER="/bin/clang-xx"
Success story sharing
CMAKE_USER_MAKE_RULES_OVERRIDE
works. It seems the file is being ignored (i.e. despiteCMAKE_C_FLAGS_RELEASE
being set to-O4
in the overrides file, it's showing the default value of-O3 -DNDEBUG
in cmake).src/build-clang
directory the overrides are being ignored.CC
andCXX
variables, it may be because you need to delete all files from the build directory first.rm CMakeCache.txt
may not be sifficient.