使用CMake在GCC和Clang / LLVM之间切换

Switching between GCC and Clang/LLVM using CMake

我有许多使用cmake构建的项目,我希望能够轻松地在使用gcc或clang/llvm编译它们之间切换。我相信(如果我错了请纠正我!)要使用clang,我需要设置以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    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")

在这些变量和默认GCC变量之间是否有一种简单的切换方法,最好是作为系统范围的更改而不是特定于项目的更改(即,不只是将它们添加到项目的cmakelists.txt中)?

另外,在使用clang而不是gcc进行编译时,是否需要使用llvm-*程序而不是系统默认值?有什么区别?


CSEAL在检测C和C++编译器时使用环境变量EDCOX1、3和EDCOX1 4。

1
2
3
4
5
$ export CC=/usr/bin/clang
$ export CXX=/usr/bin/clang++
$ cmake ..
-- The C compiler identification is Clang
-- The CXX compiler identification is Clang

编译器特定的标志可以通过将它们放入系统范围的cmake文件并将cmake-user-make-rules-override变量指向它来重写。创建包含以下内容的文件~/ClangOverrides.txt

1
2
3
4
5
6
7
8
9
10
11
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       "-O4 -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       "-O4 -DNDEBUG")
SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT"-O2 -g")

后缀init将使cmake用给定的值初始化相应的*_FLAGS变量。然后按以下方式调用cmake:

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

最后,为了强制使用llvm binutils,设置内部变量_CMAKE_TOOLCHAIN_PREFIXCMakeFindBinUtils模块支持该变量:

1
$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

综上所述,您可以编写一个shell包装器,它设置环境变量CCCXX,然后使用上述变量覆盖调用cmake。


Ubuntu上的系统级C++更改:

1
2
sudo apt-get install clang
sudo update-alternatives --config c++

将打印如下内容:

1
2
3
4
5
  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

然后选择clang++。


您可以使用选项命令:

1
option(USE_CLANG"build application with clang" OFF) # OFF is the default

然后在if()s中包装clang编译器设置:

1
2
3
4
if(USE_CLANG)
    SET (...)
    ....
endif(USE_CLANG)

这样,它在GUI配置工具中显示为cmake选项。

为了使它在系统范围内,您当然可以使用一个环境变量作为默认值,或者使用ferrocio的答案。


Ubuntu上的系统范围C更改:

sudo update-alternatives --config cc

Ubuntu上的系统级C++更改:

sudo update-alternatives --config c++

对于上述每一项,按选择编号(1)并输入以选择Clang:

1
2
3
4
5
6
  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:


您绝对不需要使用各种不同的llvm ar etc程序:

1
2
3
4
5
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")

这些都是为了在LLVM内部格式上工作,因此对应用程序的构建没有帮助。

注意-O4将在您的程序上调用您可能不需要的LTO(它将大大增加编译时间),clang默认为c99模式,因此也不必使用该标志。


为此,可以使用cmake的工具链文件机制,请参见此处的示例。为每个编译器编写一个包含相应定义的工具链文件。在配置时,您运行例如

1
 cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/clang-toolchain.cmake ..

所有编译器信息都将在从工具链文件调用project()的过程中设置。尽管在文档中只提到交叉编译的上下文,但它也适用于同一系统上的不同编译器。


根据cmake的帮助:

1
2
3
4
5
6
-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.

您可以创建像gcc_compiler.txtclang_compiler.txt这样的文件,以便在cmake语法中包含所有相关配置。

clang示例(clang_compiler.txt):

1
 set(CMAKE_C_COMPILER"/usr/bin/clang" CACHE string"clang compiler" FORCE)

然后运行它作为

海湾合作委员会:

1
cmake -C gcc_compiler.txt XXXXXXXX

Clang:

1
cmake -C clang_compiler.txt XXXXXXXX

您可以在CMakeLists.txt中使用语法:$ENV{environment-variable}来访问环境变量。您可以创建脚本来适当地初始化一组环境变量,并且只在您的CMakeLists.txt文件中引用这些变量。


如果cmake选择的默认编译器是gcc,并且您安装了clang,则可以使用简单的方法使用clang编译项目:

1
2
3
$ mkdir build && cd build
$ CXX=clang++ CC=clang cmake ..
$ make -j2