考虑一下这个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 )
我们假设来自modules/b/inc
的标头包含来自modules/a/inc
的标头,因此B
库的任何消费者也必须将modules/a/inc
添加到其包含路径中,并且添加USING_A=1
预处理器定义。
让我们使用Ninja
生成器(但任何生成器都会出现问题,包括Makefile
,Xcode
和Visual Studio
):
cmake -GNinja ../path/to/source
让我们构建C
库:
ninja libC.a
所有内容都正确构建,但是构建libA.a
只需要花费大量时间来构建libB.a
和libC.a
。
如果我将C's
的{{1}}依赖关系更改为B
,则不会构建INTERFACE
和libA.a
,而是编译libB.a
失败,因为包含应该从modules/c/src/src1.cpp
继承的目录和编译定义,并且它的依赖关系不会被继承。
有没有办法告诉CMake特定目标不应该编译 - 取决于B
列表中指定的特定目标(链接依赖应该保留)?我知道有时需要这些依赖项(例如,如果target_link_libraries
依赖于某些自定义命令为它依赖项生成标题),但这不是这里的情况。我正在寻找一个解决方案,为每个静态库目标指定它是否应该编译 - 依赖于另一个静态库目标,同时仍保持链接依赖性并从其依赖项中获取所有正确的编译标志。
答案 0 :(得分:1)
目前,我不知道问题target_link_libraries
没有完整的目标级依赖关系。而且不确定事情会在不久的将来发生变化。 CMake开发人员的post from the bugreport:
关于相关问题的使用target_link_libraries总是足以获得排序依赖性,许多项目依赖于此。我们无法为任何目标类型更改它。
在不改变语义的情况下可以做的是Ninja生成器检测依赖项的传递闭包何时没有任何自定义命令,并且在这种情况下从编译规则和自定义命令中删除对它的依赖性。只需要链接步骤对依赖项库文件的完全依赖性。在开发人员邮件列表中可以更好地讨论这方面的工作。
That answer建议在STATIC库之间拒绝target_link_libraries
,这会删除一些不需要的依赖项。我已根据您的目的调整了该方案:
使用 INTERFACE 库表达“编译时依赖关系”。真实库仅用于链接可执行文件或 SHARED 库。
# 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)
选择可执行或非 STATIC 库target_link_libraries
使用真实 STATIC 库,这些 STATIC 甚至在此类可执行/ SHARED库的目标文件之前构建库。
答案 1 :(得分:1)
几年来,我们一直在使用以下函数将静态库彼此链接,而不会导致它们之间的构建顺序依赖性。虽然并不完美,但总体上我们还是很满意。
O(n)
已知的缺点:
对于上述任何方面的改进或修正,将不胜感激。