【问题标题】:target_compile_definitions for multiple CMake targets?多个 CMake 目标的 target_compile_definitions?
【发布时间】:2017-12-02 18:49:00
【问题描述】:

我已经 been told 直接在 CMake 中设置 CFLAGS 是不好的做法,相反,我应该使用 target_compile_definitions() 命令。

好的,但是 - 如果我想对多个(独立)目标使用相似/相同的定义怎么办?我不想一遍又一遍地重复自己。

【问题讨论】:

  • 链接失效(至少现在)。 bad practice to do things like seting CFLAGS directly in CMake - 如果你谈论设置变量CMAKE_CXX_FLAGS,那么这取决于你想要设置什么样的选项。无需完全避免设置变量。
  • @Tsyvarev:添加了视频链接。
  • @einpoklum 用于我们的内部构建系统,我们公司的每个人都使用我们的所有构建系统,我们直接设置CMAKE_CXX_FLAGS,因此它们对于所有目标都是相同的。在我们的例子中,这是有道理的。如果您想开源您的项目,并让其他人通过 ExternalProject 使用您的 CMakeLists,那么这样做将被视为不好的做法,因为您将构建标志强加给用户。这取决于你的情况
  • @SteveLorimer - ... have others consume your CMakeLists via ExternalProject, then doing so would be considered bad practice - ExternalProject 不会影响项目的 CMAKE_CXX_FLAGS。你的意思是add_subdirectory 吗?
  • @SteveLorimer:实际上,在第二个问题上,请注意,其他人是通过 ExternalProject 使用您的 CMakeLists 还是只是用户构建它并不重要——这仍然是不好的做法,因为如果用户有不同的 C/C++ 编译器具有不同的标志语法,那么你可能会被搞砸。

标签: cmake dry idioms compiler-options


【解决方案1】:

我看到了三种可能的方式:

  1. 使用target_compile_definitions(... INTERFACE/PUBLIC ...) 的首选,它将通过target_link_libraries() 命令将编译器定义自行传播到目标。

  2. 使用set_property(TARGET target1 target2 ... APPEND PROPERTY COMPILE_DEFINITIONS ...) 为多个目标设置相同的定义。

  3. 您仍然可以使用add_definitions()remove_definitions() 的“旧命令”来修改COMPILE_DEFINITIONS 目录属性(这将预先设置此目录范围内的所有COMPILE_DEFINITIONS 目标属性)。

参考文献

【讨论】:

  • 编辑了我的问题以排除选项 1 - 这不是我的意思。我会尝试选项 2... 并且它有效。谢谢。
  • 请注意,如果所有目标都创建在与 set_property 调用相同的目录中,选项 2. 可能只是一个好主意。现代 CMake 依赖于您将设置保持本地化并接近目标的定义。我个人认为对目标属性进行“远程”操作是不好的风格。
【解决方案2】:

tl;dr:您可以循环迭代目标。

如果您有一堆具有一些共同/相似功能的目标,您可能希望简单地在一个循环中操作它们!请记住 - CMake 不像 GNU Make,它是一种成熟的脚本语言(嗯,有点)。所以你可以写:

set(my_targets
    foo
    bar
    baz)

foreach(TARGET ${my_targets})
    add_executable(${TARGET} "${TARGET}.cu")
    target_compile_options(${TARGET} PRIVATE "--some_option=some_value")
    target_link_libraries(${TARGET} PRIVATE some_lib)
    # and so on
    set_target_properties(
        ${TARGET}
        PROPERTIES
        C_STANDARD 99
        C_STANDARD_REQUIRED YES
        C_EXTENSIONS NO )
endforeach(TARGET)

您还可以初始化一个空的目标列表,然后到处添加,最后集中应用您的常用选项和设置。

注意:在此示例中,我添加了 PRIVATE 编译选项,但如果您需要将其中的一些传递到目标使用您的目标,您可以将它们设为 PUBLIC)。

【讨论】:

    【解决方案3】:

    另一个巧妙的解决方案是定义一个具有所有必需属性和编译器定义的接口库目标(一个不生成任何二进制文件的假目标),然后将其他现有目标链接到它

    示例:

    add_library(myfakelib INTERFACE)
    target_compile_definitions(myfakelib INTERFACE MY_NEEDED_DEFINITION)
    
    add_executable(actualtarget1 main1.cpp)
    add_executable(actualtarget2 main2.cpp)
    
    set_property(
        TARGET actualtarget1 actualtarget2
        APPEND PROPERTY LINK_LIBRARIES myfakelib
    )
    

    参考:

    https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries

    【讨论】:

    • 必须是接口库目标吗?不能是某种通用的人工目标吗?此外,库目标是否会传播 C 语言属性?
    • 任何库目标都会传播属性,“INTERFACE”类型实际上是一种“人工”类型,不会产生任何二进制文件,正如我所提到的
    猜你喜欢
    • 2014-11-08
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    相关资源
    最近更新 更多