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

时间:2018-03-20 18:41:48

标签: 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 )

我们假设来自modules/b/inc的标头包含来自modules/a/inc的标头,因此B库的任何消费者也必须将modules/a/inc添加到其包含路径中,并且添加USING_A=1预处理器定义。

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

cmake -GNinja ../path/to/source

让我们构建C库:

ninja libC.a

所有内容都正确构建,但是构建libA.a只需要花费大量时间来构建libB.alibC.a

如果我将C's的{​​{1}}依赖关系更改为B,则不会构建INTERFACElibA.a,而是编译libB.a失败,因为包含应该从modules/c/src/src1.cpp继承的目录和编译定义,并且它的依赖关系不会被继承。

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

2 个答案:

答案 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)

已知的缺点:

  • 诸如PIC之类的布尔传递属性不会自动应用。
  • 生成依赖关系图时不显示依赖关系。
  • 当发现依赖项时发生错误时,它通常会发出数百行错误消息,因为从本质上讲,我们将对库是否存在的检查推迟到将其传播到数十个目标之前。

对于上述任何方面的改进或修正,将不胜感激。