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


269

我有许多使用CMake构建的项目,我希望能够在使用GCC或Clang / LLVM进行编译之间轻松切换。我相信(如果我弄错了,请纠正我!)要使用Clang,我需要设置以下内容:

    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变量和默认GCC变量之间进行切换,最好是作为系统范围的更改而不是特定于项目的更改(即,不只是将它们添加到项目的CMakeLists.txt中)?

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

Answers:


342

CMake尊重环境变量,CCCXX在检测到C和C ++编译器使用以下变量时:

$ 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具有以下内容的文件:

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")

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

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

最后,要强制使用LLVM binutils,请设置内部变量_CMAKE_TOOLCHAIN_PREFIX。该变量受CMakeFindBinUtils模块支持:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

把所有这些组合起来,你可以写一个shell封装程序设置环境变量CCCXX,然后调用cmake与变量提到覆盖。


1
我一直在听你的回答,除了CMAKE_USER_MAKE_RULES_OVERRIDE工作之外,其他一切都没有。似乎文件已被忽略(即,尽管在覆盖文件中将其CMAKE_C_FLAGS_RELEASE设置为-O4,但它显示的-O3 -DNDEBUG是cmake 的默认值)。
Rezzie 2011年

18
请注意,许多此类信息都缓存在构建树顶层的CMakeCache.txt文件中。要在gcc和clang之间切换,您应该有两个完全独立的构建树,然后简单地cd来回切换到“ switch”编译器。一旦使用给定的编译器生成了构建树,就无法切换该构建树的编译器。
DLRdave 2011年

@DLRdave使用两个单独的构建树是一个明智的主意。我没考虑过的 糟糕:)但是,即使是在新环境中进行操作src/build-clang目录中进行操作,替代也会被忽略。
Rezzie 2011年

1
@Rezzie ClangOverrides.txt中的标志必须使用后缀_INIT定义。查看最新答案。
sakra 2011年

8
给读者的注意。如果您在CMake不遵守CCand CXX变量方面遇到麻烦,可能是因为您需要首先从构建目录中删除所有文件。 rm CMakeCache.txt可能不是足够的。
John Dibling 2014年

128

在Ubuntu上进行系统范围的C ++更改:

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

将打印如下内容:

  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 ++。


3
谢谢,我对此一无所知!尽管我猜这取决于cmake在哪里寻找编译器,对吗?
易卜拉欣2012年

1
@Ibrahim此配置将“ c ++”符号链接设置为您选择的编译器,并且默认情况下cmake检查“ c ++”,而不是“ g ++”。因此,除非cmake配置非常具体,否则它应该可以正常工作(对我而言也是如此)。
Zoomulator

2
我得到的答复是“链接组c ++中只有一种选择”。请扩大您的答案以包括如何在此列表中添加clang
vedant 2013年

3
请谨慎使用此替代方法,因为它可能导致系统副作用。nvidia驱动程序之类的软件包已遇到问题,该软件包在安装过程中会重新编译某些内核模块,并且与clang不兼容。
法尔科

2
如果您想安装clang-3.5,clang-3.6等,请使用它来设置默认的stackoverflow.com/a/30742451/1427533,否则,您将获得There is only one alternative in link group cc (providing /usr/bin/cc): /usr/bin/gcc
miguel.martin

23

您可以使用option命令:

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

然后将clang-compiler设置包装在if()s中:

if(USE_CLANG)
    SET (...)
    ....
endif(USE_CLANG)

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

要使其遍及整个系统,您当然可以使用环境变量作为默认值,也可以使用Ferruccio的答案。


这就是我目前设置的方式,但是显然它需要根据每个项目进行。我希望有这样的命令cmake -DCMAKE_COMPILER_DEFINITIONS=MyLlvmDefinitions.cmake
Rezzie 2011年

1
现在,我了解了您要完成的工作。我不知道cmake是否提供了该行为,但是您可以在开始运行CMakeLists.txt之前尝试使用-C选项来加载脚本。还没有尝试过。
Tobias Schlegel

18

在Ubuntu上进行系统范围的C更改:

sudo update-alternatives --config cc

在Ubuntu上进行系统范围的C ++更改:

sudo update-alternatives --config c++

对于上述每个选项,请按选择编号(1),然后按Enter键以选择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:

7
如果您手动安装了clang并将其放在非标准位置,则可能无法使用--config显示。例如,如果在其中,/opt/clang-llvm-3.5/则首先安装新的替代方法: sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
CodeKid 2014年

16

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

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

并且所有编译器信息都将在从工具链文件进行project()调用期间设置。尽管在文档中仅提及交叉编译的上下文,但是它对于同一系统上的不同编译器也适用。


4
我仍然很惊讶如何只能在SO的线程底部找到正确的答案。
斯拉瓦

10

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

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模式,因此也不一定需要该标志。


7

如果选择的默认编译器cmakegcc并且已安装clang,则可以使用以下简单方法来编译项目clang

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

5

根据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.

您可以创建CMake语法之类的文件,gcc_compiler.txtclang_compiler.txt包括所有相关配置。

lang示例(clang_compiler.txt):

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

然后以

GCC:

cmake -C gcc_compiler.txt XXXXXXXX

铛:

cmake -C clang_compiler.txt XXXXXXXX

3

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


请您进一步说明一下?您是说要在启动cmake之前导出环境变量的shell脚本吗?需要设置哪些变量?或者,您的意思是只用-DCMAKE_C_COMPILER ...etc 调用cmake的脚本/别名?
Rezzie 2011年

我的意思是只导出适当的环境变量的脚本。您将组成自己的环境变量,并在CMakeLists.txt文件中引用它们。
Ferruccio

啊 我明白你的意思了。唯一的事情是需要遍历CMakeLists.txt每个项目并让其查询新变量。我希望有一种在系统范围内进行操作的简便方法,而无需修改任何项目文件。类似于通过CMAKE_TOOLCHAIN_FILE
Rezzie 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.