如何使 `target_link_libraries` 依赖项从 cmake 中的 OBJECT 库传递?

Sha*_*mer 9 cmake

OBJECT如果我在 CMake 中指定库的依赖关系链,则target_link_libraries目标可执行文件中仅使用最后一个库的依赖关系。

最小示例:

main取决于objB,取决于objA。和objA都是CMake 中objBOBJECT库。

我希望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图书馆特有的东西。我应该如何指定要链接的依赖mainobjA?(无需objA在每个使用的可执行目标中指定objB

For*_*tor 6

对象库目标不是真正的库,它们只是对象的集合,但直到它们被用来构建真正的目标(如可执行文件或共享/静态库)时,它们才真正链接在一起。引用链接文档:

\n
add_library(<name> OBJECT <src>...)\n
Run 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

因此,传递传播仅影响编译其他真实库的定义和依赖项,而不影响对象本身。

\n

  • 我本来期望 `target_link_library` 也是一个“对象库的使用要求”,因此是“传递传播”。 (3认同)
  • 我同意,至少可以说这很尴尬。鉴于此 CMake 对象库功能似乎取代了 libtool 便利库,它也应该提供这种便利。 (2认同)

Sha*_*mer 2

这源于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. 但不知道该怎么做。