如何删除cmake静态库的编译依赖项?

DoD*_*oDo 6 cmake

考虑以下CMake设置:

add_library( A STATIC modules/a/src/src1.cpp modules/a/src/src2.cpp )
target_include_directories( A PUBLIC modules/a/inc )
target_compile_definitions( A PUBLIC USING_A=1 )

add_library( B STATIC modules/b/src/src1.cpp modules/b/src/src2.cpp )
target_include_directories( B PUBLIC modules/b/inc )
target_compile_definitions( B PUBLIC USING_B_WRAPPER=1 )
target_link_libraries( B PUBLIC A )

add_library( C STATIC modules/c/src/src1.cpp )
target_include_directories( C PUBLIC modules/c/inc )
target_link_libraries( C PUBLIC B )
Run Code Online (Sandbox Code Playgroud)

让我们假设from的modules/b/incheader头来自modules/a/inc,因此B库的任何使用者也必须添加modules/a/inc其include路径并添加USING_A=1预处理器定义。

让我们用Ninja生成器(但任何发生器,包括出现问题MakefileXcodeVisual Studio):

cmake -GNinja ../path/to/source
Run Code Online (Sandbox Code Playgroud)

让我们构建C库:

ninja libC.a
Run Code Online (Sandbox Code Playgroud)

一切都可以正确构建,但是浪费大量时间来构建libA.alibB.a仅用于构建libC.a

如果我改变C's依赖于BINTERFACE,然后libA.alibB.a不建,而是编译modules/c/src/src1.cpp失败,因为包含目录,并应被继承编译定义B和它的依赖不继承。

有没有办法告诉CMake特定目标不应该依赖于target_link_libraries列表中指定的特定目标进行编译(应该保留链接依赖性)?我知道有时需要那些依赖项(例如,如果A依赖于某些为其依赖对象生成的自定义命令头),但是这里不是这种情况。我正在寻找一种解决方案,为每个静态库目标指定是否应依赖于另一个静态库目标进行编译,同时仍保持链接依赖关系并从其依赖关系中获取所有正确的编译标志。

Tsy*_*rev 1

target_link_libraries目前,如果没有完整的目标级依赖关系,我不知道如何解决问题。并且不确定事情会在不久的将来发生变化。来自错误报告的CMake 开发人员帖子:

使用 target_link_libraries 始终足以获得排序依赖关系,许多项目都依赖于此。我们无法更改任何目标类型的这一点。

在不改变语义的情况下,Ninja 生成器可以检测依赖项的传递闭包何时没有任何自定义命令,并在这种情况下从编译规则和自定义命令中删除对其的排序依赖项。只需要链接步骤对依赖项的库文件的完全依赖项。这方面的工作可以在开发人员邮件列表上更好地讨论。

相关问题的答案建议拒绝target_link_libraries静态库之间的连接,这消除了一些不需要的依赖关系。我已经根据您的目的调整了该场景:

非自然方式

使用INTERFACE库表达“编译时依赖性” 。真实库将仅用于链接可执行文件或共享库。

# Compile-time dependency.
add_library( A_compile INTERFACE )
target_include_directories( A_compile PUBLIC modules/a/inc )
target_compile_definitions( A_compile PUBLIC USING_A=1 )
# Real library.
add_library( A STATIC modules/a/src/src1.cpp modules/a/src/src2.cpp )
target_link_libraries(A A_compile)

# Compile-time dependency.
add_library( B_compile INTERFACE )
target_include_directories( B_compile PUBLIC modules/b/inc )
target_compile_definitions( B_compile PUBLIC USING_B_WRAPPER=1 )
target_link_libraries( B_compile PUBLIC A_compile )
# Real library
add_library( B STATIC modules/b/src/src1.cpp modules/b/src/src2.cpp )
target_link_libraries(B B_compile)    

# Final STATIC library.
add_library( C STATIC modules/c/src/src1.cpp )
target_include_directories( C PUBLIC modules/c/inc )
target_link_libraries( C PUBLIC B_compile )

# ...
# Creation executable or non-STATIC library, linked with C
add_executable(my_exe ...)
# Need to manually list libraries, "compile-time linked" to C.
target_link_libraries(my_exe C B A)
Run Code Online (Sandbox Code Playgroud)

由于可执行或非静态target_link_libraries使用真正的 静态库,因此这些静态库将在此类可执行/共享库的目标文件之前构建。