【问题标题】:Switching between GCC and Clang/LLVM using CMake使用 CMake 在 GCC 和 Clang/LLVM 之间切换
【发布时间】:2011-10-25 06:12:30
【问题描述】:

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

【问题讨论】:

    标签: cmake llvm clang


    【解决方案1】:

    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

    另请参阅此 CMake FAQ 关于 make 覆盖文件。

    【讨论】:

    • 我已经按照您的回答进行了操作,除了 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 可能不够。
    【解决方案2】:

    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
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      可以使用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 这样的命令。
      • 现在我明白你想要完成什么了。我不知道该行为是否由 cmake 提供,但您可以尝试在开始运行 CMakeLists.txt 之前似乎加载脚本的 -C 选项。不过没试过。
      【解决方案5】:

      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
      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        您绝对不需要使用各种不同的 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")
        SET (CMAKE_RANLIB  "/usr/bin/llvm-ranlib")
        

        这些用于 llvm 内部格式,因此对构建您的应用程序没有用处。

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

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

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

            【讨论】:

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

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

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

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

            【讨论】:

              【解决方案11】:

              最好不要在 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"
              

              【讨论】:

                猜你喜欢
                • 2017-09-25
                • 2016-07-07
                • 2016-10-27
                • 1970-01-01
                • 2012-05-04
                • 2015-06-01
                • 2014-04-20
                • 2010-12-05
                • 1970-01-01
                相关资源
                最近更新 更多