我有许多使用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-*程序而不是系统默认值?有什么不同?


当前回答

在检测到C和c++编译器使用时,CMake尊重环境变量CC和CXX:

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

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

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

最后,为了强制使用LLVM二进制代码,设置内部变量_CMAKE_TOOLCHAIN_PREFIX。这个变量由CMakeFindBinUtils模块提供:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

在CMake 3.9或更新版本中不再需要设置_CMAKE_TOOLCHAIN_LOCATION。

把这些放在一起,您可以编写一个shell包装器,它设置环境变量CC和CXX,然后使用上述变量重写调用cmake。

也请参阅这个CMake常见问题解答关于重写文件。

其他回答

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

在检测到C和c++编译器使用时,CMake尊重环境变量CC和CXX:

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

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

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

最后,为了强制使用LLVM二进制代码,设置内部变量_CMAKE_TOOLCHAIN_PREFIX。这个变量由CMakeFindBinUtils模块提供:

$ cmake -D_CMAKE_TOOLCHAIN_PREFIX=llvm- ..

在CMake 3.9或更新版本中不再需要设置_CMAKE_TOOLCHAIN_LOCATION。

把这些放在一起,您可以编写一个shell包装器,它设置环境变量CC和CXX,然后使用上述变量重写调用cmake。

也请参阅这个CMake常见问题解答关于重写文件。

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的工具链文件机制来达到这个目的,参见这里的例子。为每个编译器编写包含相应定义的工具链文件。在配置时,运行例如

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

所有编译器信息将在project()调用期间从工具链文件中设置。虽然在文档中仅在交叉编译上下文中提到,但它适用于同一系统上的不同编译器。

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

布景(CMAKE_AR /usr/bin/llvm-ar) 集(CMAKE_LINKER "/usr/bin/llvm-ld") 布景(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模式,所以这个标志也不一定需要。