ChatGPT解决这个技术问题 Extra ChatGPT

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

我有许多使用 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 变量之间切换,最好是作为系统范围的更改而不是特定于项目的更改(即不仅仅是将它们添加到项目的 CMakeLists.txt 中)?

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


s
sakra

CMake 在检测到要使用的 C 和 C++ 编译器时尊重环境变量 CCCXX

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

编译器特定标志可以通过将它们放入 make 覆盖文件并将 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_PREFIXCMakeFindBinUtils 模块支持此变量:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

将所有这些放在一起,您可以编写一个 shell 包装器,它设置环境变量 CCCXX,然后使用提到的变量覆盖调用 cmake

另请参阅有关 make 覆盖文件的 CMake FAQ


我已经按照您的回答,除了 CMAKE_USER_MAKE_RULES_OVERRIDE 之外的所有内容都有效。似乎该文件被忽略了(即,尽管在覆盖文件中将 CMAKE_C_FLAGS_RELEASE 设置为 -O4,但它在 cmake 中显示了 -O3 -DNDEBUG 的默认值)。
请注意,大部分信息都缓存在构建树顶层的文件 CMakeCache.txt 中。要在 gcc 和 clang 之间切换,您应该有两个完全独立的构建树,并且只需 cd 来回“切换”编译器。使用给定编译器生成构建树后,您无法切换该构建树的编译器。
@DLRdave 使用两个独立的构建树是一个明智的想法;一个我没有考虑过的。糟糕 :) 但是,即使在新的 src/build-clang 目录中执行此操作,也会忽略覆盖。
@Rezzie ClangOverrides.txt 中的标志必须使用后缀 _INIT 定义。请参阅更新的答案。
读者注意。如果您在 CMake 不支持 CCCXX 变量时遇到问题,可能是因为您需要先从构建目录中删除所有文件。 rm CMakeCache.txt 可能不够。
S
Stéphane

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


谢谢,我不知道这个!虽然我猜这取决于 cmake 在哪里寻找编译器,对吧?
@Ibrahim 此配置将“c++”符号链接设置为您选择的编译器,cmake 默认检查“c++”,而不是“g++”。因此,除非 cmake 配置非常具体,否则这应该可以正常工作(并且对我有用)。
我收到回复说“链接组 c++ 中只有一种选择”。请扩展您的答案以包括如何将 clang 添加到此列表
请谨慎使用此替代方法,因为它可能会对您的系统产生副作用。在安装过程中重新编译某些内核模块并且与 clang 不兼容的软件包(例如 nvidia 驱动程序)已经遇到了问题。
如果您想安装 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
j
j_fu

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

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

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


T
Tobias Schlegel

您可以使用选项命令:

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 这样的命令。
现在我明白你想要完成什么。我不知道该行为是否由 cmake 提供,但您可以尝试在开始运行 CMakeLists.txt 之前似乎加载脚本的 -C 选项。虽然没试过。
V
Victor Lyuboslavsky

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:

如果您手动安装了 clang 并将其放在非标准位置,它可能不会显示 --config。例如,如果它在 /opt/clang-llvm-3.5/ 中,则首先安装一个新的替代方案:sudo update-alternatives --install /usr/bin/c++ c++ /opt/clang-llvm-3.5/bin/clang++ 30
y
yee

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

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

或为 cmake 指定编译器:

$ cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang ..

e
echristo

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

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") 设置 (CMAKE_RANLIB "/usr/bin/llvm-ranlib")

它们适用于 llvm 内部格式,因此对构建应用程序没有用处。

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


E
Enze Chi

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

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

Clang 示例(clang_compiler.txt):

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

然后运行它

海合会:

cmake -C gcc_compiler.txt XXXXXXXX

铛:

cmake -C clang_compiler.txt XXXXXXXX

F
Ferruccio

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


请你能再详细一点吗?你的意思是在启动cmake之前导出环境变量的shell脚本吗?需要设置哪些变量?或者你的意思是一个脚本/别名,它只是用 -DCMAKE_C_COMPILER ... 等调用 cmake?
我的意思是一个只导出适当环境变量的脚本。您将创建自己的环境变量并在 CMakeLists.txt 文件中引用它们。
啊;我明白你的意思了。唯一的事情是这需要遍历每个项目的 CMakeLists.txt 并让它查询新变量。我希望有一种方便的方法可以在系统范围内进行,而无需修改任何项目文件。类似于传递 CMAKE_TOOLCHAIN_FILE
S
SuperNoob

只需在 ~/.bashrc 的末尾添加即可

export CC=/usr/bin/clang
export CXX=/usr/bin/clang++

重新启动终端,从现在开始,cmake 将使用 clang 来构建每个项目。编辑 ~/.bashrc 以切换回 gcc。


b
blackice

最好不要在 CMakelists.txt 中指定编译器。

只需添加以下命令

-D CMAKE_CXX_COMPILER="xx" -D CMAKE_C_COMPILER="xx"

例子:

cmake -D CMAKE_CXX_COMPILER="/bin/clang++-xx" -D CMAKE_C_COMPILER="/bin/clang-xx"

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅