如何使“target\u link\u libraries”依赖项从cmake中的对象库传递?
如果在CMake中指定如何使“target\u link\u libraries”依赖项从cmake中的对象库传递?,cmake,Cmake,如果在CMake中指定对象库的依赖关系链,则在目标可执行文件中仅使用最后一个库的目标链接库依赖关系 最简单的例子: main取决于objB,后者取决于objA。 objA和objB都是CMake中的OBJECT库 我希望main与这两个对象文件链接。没有 cmake_minimum_required(VERSION 3.13) project(transitive-object-library-link-issue VERSION 1.0.0 LANGUAGES C) add_library(
对象
库的依赖关系链,则在目标可执行文件中仅使用最后一个库的目标链接库
依赖关系
最简单的例子:
main
取决于objB
,后者取决于objA
。
objA
和objB
都是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)
注意:一组工作文件可在
如果我将objA
更改为非对象
库,则通过消除对象
库依赖项链,可以消除该问题。换言之,更改行
add_library(objA OBJECT a.c)
将是:
add_library(objA a.c)
因此,它是特定于对象
库的。我应该如何指定使main
链接到objA
?(无需在每个使用objB
的可执行目标中指定objA
)目标不是真正的库,它们只是对象的集合,但在用于构建真正的目标(如可执行库或共享/静态库)之前,它们不会真正链接在一起。引用链接文件:
add_library(<name> OBJECT <src>...)
add_库(对象…)
创建一个对象库。对象库编译源文件,但不将其对象文件归档或链接到库中
尽管如此,还是使用target\u link\u library()
命令将其链接到对象库,但只指定其源对其他库的依赖关系。链接文档解释了您的问题:
对象库的使用要求以传递方式传播[…],但其对象文件不是
对象库可以“链接”到其他对象库以获得使用要求,但由于它们没有链接步骤,因此无法对其对象文件执行任何操作
因此,传递传播只影响编译其他真实库的定义和依赖项,而不影响对象本身。这源于
对象
库的另一个问题:对象代码的复制。作为布拉德·金:
我们需要小心地消除[示例项的]对象文件的重复使用
如果默认为传递传播,则可能会意外导致链接器尝试链接同一代码的多个副本,从而使您的项目不可由CMake编译
这是一个不允许对象
库的可传递依赖项的充分理由。这很棘手,所以最好避免。如此之多,以至于在他的优秀著作“”中提到这是一个良好的实践:
如果目标使用某个库中的内容,它应该始终直接链接到该库。即使
库已经是一个链接依赖于其他目标链接,不要依赖于间接链接
目标直接使用的内容的链接依赖关系
他还补充说:
对象库的可传递性与常规库不同。手册上的文字是这样的:
这些其他目标的链接(或归档)步骤将使用直接链接的对象库中的对象文件
其中的关键部分是“直接链接”。在您的示例中,main
从b
获取对象,因为它直接链接到b
,但因为它不直接链接到a
,所以它不会获取a
的对象,即使b
链接到a
。
其原因与深瞬变性可能导致多次添加对象文件的问题有关,这将导致错误。这一特定方面在问题跟踪程序中出现过几次,但我手头没有问题编号(您可能可以搜索它们并跟踪各种讨论)
因此,解决方案似乎是避免依赖对象
库的目标链接库
。有两种方法:第一种是不使用对象
库。第二个是明确指定要在层次结构中链接的对象,如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>)
add_库(对象a.c)
添加库(b对象b.c)
目标资源(b公共美元)
添加可执行文件(main.c)
目标资源(主要私有$)
这是明确的,但甚至不能解决我的问题!我怀疑由于菱形图案,这也可能会遇到重复问题,但我还没有测试过
也许在接下来的几个月里,我会根据
objA
的LINK\u LIBRARIES属性,使用生成器表达式找到一个更好的解决方案。但是,不确定如何做到这一点。一个解决方案是为每个对象库定义一个接口库。接口库的依赖关系是可传递的
# 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)
objA
和objA
都是CMake中的对象库。你是说objA
和objB
都是CMake中的对象库吗。@ManthanTilva修复了。谢谢。我本以为target\u link\u library
也是一个“对象库的使用要求”,因此是“可传递的传播”。我同意,至少说起来很尴尬。鉴于此CMake对象库功能似乎取代了libtool便利库,它也应该提供这种便利。
add_object(T a a.c)
add_object(T b b.c) # sets T to b_obj
target_link_libraries(${T} a)