如何使cmake中的OBJECT库具有对target_link_libraries的依赖关系?

时间:2019-12-05 10:19:59

标签: cmake

如果我在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链接? (不必在每个使用objA的可执行目标中指定objB

3 个答案:

答案 0 :(得分:2)

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

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

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

尽管如此,对对象库使用you can apply target_link_library()命令,但仅用于指定其源对其他库的依赖关系。链接的文档解释了您的问题:

  

对象库的使用要求会通过传递方式传播,但对象文件却不会。

     

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

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

答案 1 :(得分:1)

一种解决方案是为每个 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)

答案 2 :(得分:0)

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

  

我们需要注意避免重复使用[示例项的]对象文件

如果默认设置为传递传播,则可能会意外使链接程序尝试链接同一代码的多个副本,从而使您的项目无法被CMake编译。

这是一个足够好的理由,不允许OBJECT库的传递依赖。这很棘手,因此最好避免。如此之多,以至于在他的出色著作“ Professional CMake: A Practical Guide”中提到了“良好做法”:

  

如果目标使用库中的内容,则应始终直接链接到该库。即使   库已经是目标链接到的其他对象的链接依赖项,而不依赖于间接链接   目标直接使用的东西的链接依赖性。

他还添加了in another issue

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

     
    

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

  
     

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

因此解决方案似乎是避免依赖a库的target_link_library库。有两种方法:第一种是根本不使用OBJECT库。其次是像三浦宏(Hiroshi Miura)所说的proposed那样,明确指定要在层次结构中链接的对象:

OBJECT

这是明确的,但甚至不能解决我遇到的问题!我怀疑由于菱形图案的原因,这也可能会导致重复问题,但我尚未对此进行测试。

也许在接下来的几个月中,我将基于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>) 的LINK_LIBRARIES属性,使用生成器表达式找到一个更好的解决方案。不过,不知道该怎么做。