我有一个非常复杂的基于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)
有没有办法可以抽象出常见的依赖项,这样我就不必在每个目标下重复它们?似乎接口库是执行此操作的方法,如下所示:
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
选项(。有没有其他方法可以让我封装目标之间共享的PUBLIC
和PRIVATE
标志?
你走在正确的轨道上。考虑一下:
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
的调用中添加范围。
更新:
所以我认为对我问题的直接回答是我不能完全做我想做的事,即将私有和公共编译选项依赖项都包含在单个实体中。相反,我只需要做一个公共的和一个私人的。没有我希望的那么干净,但可以管理。
不是真的,您将始终必须指定PUBLIC
和PRIVATE
范围,但是如果您愿意使用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
)
然而,在我看来,使用接口库并只处理你必须使用PUBLIC
的事实,从长远来看,PRIVATE
既干净又更易于维护。
顺便说一句,如果您想将COMMON_FLAGS
压缩到一行:set(COMMON_FLAGS "PUBLIC;-Werror;-ffast-math;PRIVATE;-Wall")