OBJECT如果我在 CMake 中指定库的依赖关系链,则target_link_libraries目标可执行文件中仅使用最后一个库的依赖关系。
最小示例:
main取决于objB,取决于objA。和objA都是CMake 中objB的OBJECT库。
我希望main链接两个目标文件。事实并非如此。
cmake_minimum_required(VERSION 3.13)
project(transitive-object-library-link-issue VERSION 1.0.0 LANGUAGES C)
add_library(objA OBJECT a.c)
add_library(objB OBJECT b.c)
target_link_libraries(objB PUBLIC objA)
# Should link with 'a.o', since 'objA' is "linked" by 'objB'
add_executable(main main.c)
target_link_libraries(main objB)
Run Code Online (Sandbox Code Playgroud)
注意:可在https://github.com/scraimer/cmake-transitive-object-library-link-issue获取工作文件集
如果我更改objA为非OBJECT库,则可以通过摆脱OBJECT库依赖链来消除问题。换句话说,改变线路
add_library(objA OBJECT a.c)
Run Code Online (Sandbox Code Playgroud)
成为:
add_library(objA a.c)
Run Code Online (Sandbox Code Playgroud)
所以这是OBJECT图书馆特有的东西。我应该如何指定要链接的依赖main项objA?(无需objA在每个使用的可执行目标中指定objB)
对象库目标不是真正的库,它们只是对象的集合,但直到它们被用来构建真正的目标(如可执行文件或共享/静态库)时,它们才真正链接在一起。引用链接文档:
\nadd_library(<name> OBJECT <src>...)\nRun Code Online (Sandbox Code Playgroud)\n\n\n创建对象库。对象库编译源文件,但不将其对象文件存档或链接到库中。
\n
尽管如此,您可以将命令应用于对象target_link_library()库,但只能指定其源对其他库的依赖关系。链接的文档解释了您的问题:
\n\n对象库\xe2\x80\x99s 使用要求可传递传播[...],但其对象文件则不然。
\n对象库可以 \xe2\x80\x9clink\xe2\x80\x9d 到其他对象库以获得使用要求,但由于它们没有链接步骤,因此不会对其对象文件执行任何操作。
\n
因此,传递传播仅影响编译其他真实库的定义和依赖项,而不影响对象本身。
\n这源于OBJECT库的另一个问题:目标代码的重复。正如布拉德·金所解释的:
我们需要小心消除[示例项目]目标文件的重复使用
如果传递传播是默认设置,您可能会意外地导致链接器尝试链接同一代码的多个副本,从而注定您的项目无法由 CMake 编译。
这是不允许OBJECT库传递依赖的充分理由。这很棘手,所以最好避免。以至于在他的优秀著作《Professional CMake: A Practical Guide》中将其作为良好实践提到:
如果目标使用库中的某些内容,则它应该始终直接链接到该库。即使库已经是目标链接到的其他内容的链接依赖项,也不要依赖目标直接使用的内容的间接链接依赖项。
他还在另一期补充道:
对象库的传递性质与常规库不同。构建系统手册是这样描述的:
这些其他目标的链接(或归档)步骤将使用直接链接的对象库中的对象文件。
其中的关键部分是“直接链接”。在您的示例中,
main从中获取对象,b因为它直接链接到b,但因为它不直接链接到a,所以它不会获取a的对象,即使b链接到a。其原因与深度传递性可能导致目标文件被多次添加的问题有关,这将导致错误。这个特定方面在问题跟踪器中出现了几次,但我手头没有问题编号(您可能可以搜索它们并跟踪各种讨论)。
所以解决方案似乎是避免依赖target_link_libraryforOBJECT库。有两种方法:第一种是干脆不使用OBJECT库。其次是明确指定要在层次结构中链接的对象,如Hiroshi Miura 所建议的:
add_library(a OBJECT a.c)
add_library(b OBJECT b.c)
target_sources(b PUBLIC $<TARGET_OBJECTS:a>)
add_executable(main main.c)
target_sources(main PRIVATE $<TARGET_OBJECTS:b>)
Run Code Online (Sandbox Code Playgroud)
这是明确的,但甚至没有解决我的问题!我怀疑这也可能会由于菱形图案而遇到重复问题,但我还没有测试过。
也许在接下来的几个月里,我会使用基于objA. 但不知道该怎么做。
| 归档时间: |
|
| 查看次数: |
3027 次 |
| 最近记录: |