【问题标题】:How can I make `target_link_libraries` dependencies transitive from OBJECT libraries in cmake?如何从 cmake 中的 OBJECT 库中传递“target_link_libraries”依赖项?
【发布时间】:2020-03-30 06:06:21
【问题描述】:

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

小例子:

main 依赖于objB,后者依赖于objAobjAobjB 都是 CMake 中的 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)

注意:https://github.com/scraimer/cmake-transitive-object-library-link-issue 上提供了一组工作文件

如果我将objA 更改为非OBJECT 库,则可以通过摆脱OBJECT 库依赖关系链来消除问题。也就是说,换行

add_library(objA OBJECT a.c)

成为:

add_library(objA a.c)

所以这是OBJECT 库特有的东西。我应该如何指定使mainobjA 链接的依赖项? (无需在每个使用objB 的可执行目标中指定objA

【问题讨论】:

  • objAobjA 都是 CMake 中的 OBJECT 库。你的意思是objAobjB都是CMake中的OBJECT库。
  • @ManthanTilva 已修复。谢谢。

标签: cmake


【解决方案1】:

Object library 目标不是真正的库,它们只是对象的集合,但在用于构建真正的目标(如可执行文件或共享/静态库)之前,它们并没有真正链接在一起。引用链接文档:

add_library(<name> OBJECT <src>...)

创建一个对象库。对象库会编译源文件,但不会将其对象文件归档或链接到库中。

尽管如此,you can apply 一个 target_link_library() 对对象库的命令,但只是为了指定它们的源对其他库的依赖关系。链接的文档解释了您的问题:

对象库的使用要求被传递[...],但它的对象文件不是。

对象库可以“链接”到其他对象库以获得使用要求,但由于它们没有链接步骤,因此不会对其对象文件进行任何操作。

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

【讨论】:

  • 我原以为target_link_library 也是“对象库的使用要求”,因此会“传递传递”。
  • 我同意,至少可以说很尴尬。鉴于此 CMake 对象库功能似乎取代了 libtool 便利库,它也应该提供这种便利。
【解决方案2】:

这源于OBJECT 库的另一个问题:目标代码重复。作为布拉德·金explains

我们需要小心重复使用 [example item's] 目标文件

如果传递传播是默认设置,您可能会意外地导致链接器尝试链接相同代码的多个副本,从而注定您的项目无法被 CMake 编译。

这是不允许OBJECT 库传递依赖的充分理由。这很棘手,所以最好避免。以至于它在他的优秀著作“Professional CMake: A Practical Guide”中被称为良好实践:

如果目标使用库中的某些内容,它应该始终直接链接到该库。即使 库已经是目标链接到的其他东西的链接依赖,不要依赖间接 目标直接使用的东西的链接依赖关系。

他还加了in another issue

对象库的传递性与常规库不同。 build-system手动的话是这样的:

那些其他目标的链接(或归档)步骤将使用直接链接的目标库中的目标文件。

其中的关键部分是“直接链接”。在您的示例中,mainb 获取对象,因为它直接链接到b,但因为它不直接链接到a,所以即使@987654333,它也不会获取a 的对象@链接到a。 其原因与深度传递性可能导致对象文件被多次添加的问题有关,这将导致错误。这个特定方面在问题跟踪器中出现了几次,但我手头没有问题编号(您可能可以搜索它们并跟踪各种讨论)。

所以解决方案似乎是避免依赖target_link_library 来获取OBJECT 库。有两种方法:首先是根本不使用OBJECT 库。其次是明确指定要在层次结构中链接的对象,如 Hiroshi Miura 的proposed

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

这是明确的,但甚至不能解决我遇到的问题!我怀疑这也可能由于菱形图案而遇到重复问题,但我还没有测试过。

也许在接下来的几个月里,我会根据objA 的 LINK_LIBRARIES 属性使用生成器表达式找出更好的解决方案。不过不知道该怎么做。

【讨论】:

    【解决方案3】:

    一种解决方案是为每个 OBJECT 库定义一个 INTERFACE 库。接口库的依赖是可传递的。

    # Defines an object library named ${T}_obj,
    # interface library named ${T} linked to it,
    # and sets ${varname} to ${T}_obj.
    macro(add_object varname T)
      add_library(${T}_obj OBJECT ${ARGN})
      add_library(${T} INTERFACE)
      target_link_libraries(${T} INTERFACE ${T}_obj $<TARGET_OBJECTS:${T}_obj>)
      set(${varname} ${T}_obj)
    endmacro(add_object)
    

    用法

    add_object(T a a.c) 
    
    add_object(T b b.c) # sets T to b_obj
    target_link_libraries(${T} a)
    

    【讨论】:

      猜你喜欢
      • 2014-11-20
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2020-12-03
      • 2013-11-28
      • 1970-01-01
      • 2013-04-27
      • 1970-01-01
      相关资源
      最近更新 更多