【问题标题】:How do I propogate compile options to subdirectories in CMake?如何将编译选项传播到 CMake 中的子目录?
【发布时间】:2022-02-01 07:33:42
【问题描述】:

在我的项目中,我有一个根 CMakeLists.txt,它定义了一些可执行文件。我使用target_compile_options 为这些可执行文件配置一些设置,例如警告。我有一些子目录可以编译一些库以与可执行文件链接。如何在不重新定义每个子目录CMakeLists.txt 中的编译选项的情况下将编译选项从根CMakeLists.txt 传播到子目录中的依赖项?

例如,这里是我的根CMakeLists.txt的简化版

cmake_minimum_required(VERSION 3.8)

project(proj)

enable_language(C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

add_subdirectory(src/lib/somelib)

add_executable(my_executable src/app/main.c)
target_compile_options(my_executable PUBLIC -Wpedantic) # as an example
target_link_libraries(my_executable PRIVATE somelib)

src/lib/somelib中的CMakeLists.txt

add_library(somelib somelib.c)
target_include_directories(somelib PUBLIC .)

在此示例中,我希望使用根 CMakeLists.txt 中的任何编译选项来编译 somelib.c

【问题讨论】:

    标签: c++ c cmake


    【解决方案1】:

    警告标志的位置在 CMakePresets.json 或自定义工具链文件中。只有硬使用要求属于 CMakeLists.txt 文件。您的代码是否成功编译与您使用的警告无关。

    此外,您通常应该在整个项目中一致地应用警告标志。不要使用构建系统将问题埋在代码中。如果您的编译器抛出误报,请添加特定于编译器的编译指示(根据需要由必要的 ifdef 保护)以在本地禁用有问题代码周围的警告。

    这是我将如何编写您的顶级 CMakeLists.txt

    cmake_minimum_required(VERSION 3.21)
    project(proj LANGUAGES C ASM)
    
    set(CMAKE_C_STANDARD 11
        CACHE STRING "Version of the C standard to use")
    option(CMAKE_C_STANDARD_REQUIRED "Enable to enforce strict C standard selection" ON)
    option(CMAKE_C_EXTENSIONS "Enable to allow compiler-specific C extensions" OFF)
    
    add_subdirectory(src/lib/somelib)
    
    add_executable(my_executable src/app/main.c)
    target_link_libraries(my_executable PRIVATE somelib)
    

    在 CMakePresets.json 中:

    {
       "version": 3,
       "cmakeMinimumRequired": {
          "major": 3,
          "minor": 21,
          "patch": 0
       },
       "configurePresets": [
          {
             "name": "default",
             "displayName": "Default",
             "description": "Default build options for GCC-compatible compilers",
             "binaryDir": "${sourceDir}/build",
             "cacheVariables": {
                "CMAKE_C_FLAGS": "-Wall -Wextra -pedantic"
             }
          }
       ]
    }
    

    编译

    $ cmake --preset default
    

    我已经在其他地方写过这个理由,所以我会发布这些参考资料的链接。

    1. https://alexreinking.com/blog/how-to-use-cmake-without-the-agonizing-pain-part-2.html
    2. https://stackoverflow.com/a/68094639/2137996

    要点是警告标志的含义取决于编译器供应商、变体和版本,因此将它们放在 CMakeLists.txt 中会对这些东西产生非常脆弱的依赖。它使编译器升级和更改变得不必要地困难,并使您的构建更难分发和重用,即使在公司内部也是如此。


    此外,您应避免在 target_include_directories 中使用相对路径,并且库目标通常应使用 $<BUILD_INTERFACE:...> 保护它们的路径,以便为安装/导出做好准备。

    target_include_directories(
      somelib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
    

    【讨论】:

      【解决方案2】:

      来自cmake manual

      add_compile_options

      向 COMPILE_OPTIONS 目录属性添加选项。从当前目录及以下目录编译目标时使用这些选项。

      所以对于给定的示例,应该能够将其添加到顶级 CMakeLists.txt:

      add_compile_options(-Wpedantic)
      

      【讨论】:

      • 有没有办法在每个可执行文件的基础上做这样的事情?即当前目录和给定可执行文件下的所有目标都使用这些选项编译?
      • 绝对不要在新代码中使用目录命令.
      • @AlexReinking 如果您提供理由,那将是很好的反馈。我们都乐于学习。
      • 我们需要一个规范的问答,因为它需要 forever 一遍又一遍地输入相同的内容。他们是一个巨大的脚枪,行为不一致,非本地方式。例如,标志被应用到甚至在调用add_compile_options 之前在同一目录和子目录中定义的目标,但不是那些在在子目录 中定义的目标。 i>在命令之前。
      • 目录命令通常很难解释为什么标志会出现在任何给定目标的命令行上,并且它们的陷阱只会随着项目的增长而加剧。这就是为什么首先创建接口目标属性以及为什么 CMake 开发人员如此强烈地鼓励使用它们并优先考虑它们的开发的重要部分原因。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 2017-11-01
      • 1970-01-01
      相关资源
      最近更新 更多