【问题标题】:How can I group target dependencies in CMake?如何在 CMake 中对目标依赖项进行分组?
【发布时间】:2020-02-13 21:06:58
【问题描述】:

我有一个非常复杂的基于make 的项目,我正在尝试迁移到现代 CMake 用法。在Makefile 中,我有几个类似的共享库目标,它们共享大部分相同的编译标志。所以,它看起来像这样:

add_library(lib1 SHARED src1.cpp src2.cpp)
target_compile_options(lib1 PUBLIC -public-flag1 -public-flag2 -unique-flag3 PRIVATE -private-flag)

add_library(lib2 SHARED src3.cpp src4.cpp) 
target_compile_options(lib2 PUBLIC -public-flag -public-flag2 PRIVATE -private-flag)

有什么方法可以抽象出常见的依赖关系,这样我就不必在每个目标下重复它们了?似乎Interface Library 将是执行此操作的方法,例如:

add_library(common_options INTERFACE)
target_compile_options(common_options 
    PUBLIC -public-flag1 -public-flag2
    PRIVATE -private-flag
)
add_library(lib1 SHARED src1.cpp src2.cpp)
target_compile_options(lib1 PUBLIC -unique-flag3)
target_link_libraries(lib1 common_options)

add_library(lib2 SHARED src3.cpp src4.cpp) 
target_link_libraries(lib1 common_options)

在我看来,这将是可维护性的净赢。但是,CMake 会抛出一个错误,抱怨接口目标只能携带 INTERFACE 选项(我无法向其添加 PRIVATE 选项)。是否有其他方法可以让我封装目标之间共享的 PUBLICPRIVATE 标志?

【问题讨论】:

  • 你不能将变量设置为你想要的任何东西并在调用target_compile_options时扩展它
  • 或者您可以编写一个函数/宏来创建一个库并设置公共属性。

标签: c++ cmake


【解决方案1】:

你在正确的轨道上。考虑一下:

add_library(public  INTERFACE)
add_library(private INTERFACE)
target_compile_options(public  INTERFACE -Werror)
target_compile_options(private INTERFACE -Wall)

target_link_libraries(lib1
    PUBLIC  # <-- public's flags will be applied to lib1 and any targets linking to lib1
        public
    PRIVATE # <-- private's flags will only be applied to lib1
        private
)

简而言之,您忘记在对target_link_libraries 的调用中添加范围。

更新

所以我认为我的问题的直接答案是我不能完全按照我的意愿去做,这会将私有和公共编译选项依赖项包含在一个实体中。相反,我只需要制作一个公共的和一个私人的。没有我希望的那么干净,但可以管理。

并非如此,您将始终必须指定 PUBLICPRIVATE 范围,但如果您愿意使用 target_compile_options 而不是接口库来实现这一点,那么这也可以:

set(COMMON_FLAGS
    PUBLIC
        -Werror
        -ffast-math
    PRIVATE
        -Wall
)

target_compile_options(lib1 ${COMMON_FLAGS})
target_compile_options(lib2
    ${COMMON_FLAGS}
    PUBLIC # <-- you can still set scoped flags
        -fno-fast-math
)

然而,在我看来,使用接口库并处理必须使用PUBLICPRIVATE 的事实从长远来看既更简洁,也更易于维护。

顺便说一句,如果你想将COMMON_FLAGS 压缩成一行:set(COMMON_FLAGS "PUBLIC;-Werror;-ffast-math;PRIVATE;-Wall")

【讨论】:

  • 谢谢。所以我认为我的问题的直接答案是我不能完全按照我的意愿去做,这会将私有和公共编译选项依赖项包含在一个实体中。相反,我只需要制作一个公共的和一个私人的。不像我希望的那样干净,但可以管理。
  • @JasonR 更新了我的答案。如果您将变量视为单个实体,这是可能的。我不知道有任何其他方法可以实现您想要的。
猜你喜欢
  • 2014-01-13
  • 2011-12-25
  • 2020-03-07
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
相关资源
最近更新 更多