目标链接库¶
指定链接给定目标和/或其依赖项时要使用的库或标志。 使用要求 来自链接库目标将被传播。目标依赖项的使用要求会影响其自身源代码的编译。
概述¶
此命令有几个签名,详见以下小节。它们都有一般形式
target_link_libraries(<target> ... <item>... ...)
命名的 <target>
必须由命令创建,例如 add_executable()
或 add_library()
并且不能是 ALIAS target。如果 policy:policy:CMP0079 未设置为 NEW
则目标必须已在当前目录中创建。重复调用相同的 <target>
按调用的顺序追加项目。
在 3.13 版本加入: <target>
不必在与``target_link_libraries`` 调用相同的目录中定义。
每个 <item>
可能是:
库目标名称:生成的链接行将具有与目标关联的可链接库文件的完整路径。如果库文件发生变化,构建系统将依赖于重新链接
<target>
。命名目标必须由项目中的
add_library()
创建或作为 IMPORTED 库 创建。如果它是在项目中创建的,则会在构建系统中自动添加一个排序依赖项,以确保命名的库目标在<target>
链接之前是最新的。如果导入的库设置了
IMPORTED_NO_SONAME
目标属性,CMake 可能会要求链接器搜索库而不是使用完整路径(例如,/usr/lib/libfoo.so
变为- lfoo
)。目标工件的完整路径将自动为 shell 引用/转义。
库文件的完整路径:生成的链接行通常会保留文件的完整路径。如果库文件发生变化,构建系统将依赖于重新链接
<target>
。在某些情况下,CMake 可能会要求链接器搜索库(例如,
/usr/lib/libfoo.so
变为-lfoo
),例如当检测到共享库没有 ` SONAME` 字段。有关另一个案例的讨论,请参阅政策:policy:CMP0060。如果库文件在 macOS 框架中,框架的
Headers
目录也会被处理为 usage requirement。这与将框架目录作为包含目录传递具有相同的效果。在 3.8 版本加入: 在 VS 2010 及更高版本的 Visual Studio Generators 上,以 .targets 结尾的库文件将被视为 MSBuild 目标文件并导入到生成的项目文件中。其他生成器不支持此功能。
库文件的完整路径将自动为 shell 引用/转义。
普通库名称:生成的链接行将要求链接器搜索库(例如,
foo
变为-lfoo
或foo.lib
)。库名称/标志被视为命令行字符串片段,将在没有额外引号或转义的情况下使用。
链接标志:以“-”开头但不是“-l”或“-framework”的项目名称被视为链接器标志。请注意,出于传递依赖性的目的,此类标志将像任何其他库链接项一样对待,因此通常可以安全地将它们指定为不会传播到依赖项的私有链接项。
此处指定的链接标志被插入到链接命令中与链接库相同的位置。这可能不正确,具体取决于链接器。使用
LINK_OPTIONS
目标属性或target_link_options()
命令显式添加链接标志。然后,这些标志将被放置在链接命令中工具链定义的标志位置。在 3.13 版本加入:
LINK_OPTIONS
目标属性和target_link_options()
命令。对于早期版本的 CMake,请改用LINK_FLAGS
属性。链接标志被视为命令行字符串片段,将在没有额外引号或转义的情况下使用。
生成器表达式:
$<...>
generator expression
可以计算为上述任何项目或 :ref: 以分号分隔的列表 <CMake Language Lists> 其中的。如果...
包含任何;
字符,例如在对${list}
变量求值后,一定要使用显式引用的参数"$<...>"
以便此命令将其作为单个<item>
接收.此外,生成器表达式可以用作上述任何项目的片段,例如``foo$<1:_d>``。
请注意,生成器表达式不会用于政策的旧处理:policy:CMP0003 或政策:policy:CMP0004。
debug
、optimized
或general
关键字紧跟另一个<item>
。这样的关键字后面的项目将仅用于相应的构建配置。debug
关键字对应于Debug
配置(或在DEBUG_CONFIGURATIONS
全局属性中命名的配置,如果已设置)。optimized
关键字对应于所有其他配置。general
关键字对应所有配置,纯属可选。通过创建并链接到 IMPORTED library targets,可以为每个配置规则实现更高的粒度。这些关键字由该命令立即解释,因此在由生成器表达式生成时没有特殊含义。
包含 ::
的项目,例如 Foo::Bar
,被假定为 IMPORTED 或 ALIAS 库目标名称并将如果不存在这样的目标,则会导致错误。请参阅政策:policy:CMP0028。
有关定义构建系统属性的更多信息,请参阅 cmake-buildsystem(7)
手册。
目标和/或其从属的库¶
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
PUBLIC
、PRIVATE
和 INTERFACE
scope 关键字可用于在一个命令中指定链接依赖项和链接接口。
PUBLIC
之后的库和目标被链接到,并成为链接接口的一部分。 PRIVATE
之后的库和目标被链接到,但不是链接接口的一部分。 INTERFACE
之后的库附加到链接接口,不用于链接``<target>``。
目标及其从属的库¶
target_link_libraries(<target> <item>...)
默认情况下,库依赖项使用此签名是可传递的。当这个目标链接到另一个目标时,链接到这个目标的库也会出现在另一个目标的链接行上。这个可传递的“链接接口”存储在 INTERFACE_LINK_LIBRARIES
目标属性中,可以通过直接设置该属性来覆盖。当 CMP0022 未设置为 NEW 时,传递链接是内置的,但可能会被 LINK_INTERFACE_LIBRARIES 属性覆盖。调用此命令的其他签名可能会设置属性,使任何由此签名专门链接的库成为私有的。
目标和/或其依赖项的库(旧版)¶
target_link_libraries(<target>
<LINK_PRIVATE|LINK_PUBLIC> <lib>...
[<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...)
LINK_PUBLIC
和 LINK_PRIVATE
模式可用于在一个命令中指定链接依赖项和链接接口。
此签名仅用于兼容性。更喜欢 PUBLIC
或 PRIVATE
关键字。
LINK_PUBLIC
之后的库和目标链接到 INTERFACE_LINK_LIBRARIES
并成为其一部分。如果策略:policy:CMP0022 不是 NEW
,它们也会成为 LINK_INTERFACE_LIBRARIES
的一部分。 LINK_PRIVATE
之后的库和目标链接到 INTERFACE_LINK_LIBRARIES`(或 :prop_tgt:`LINK_INTERFACE_LIBRARIES
),但不是其一部分。
仅供家属使用的图书馆(旧版)¶
target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...)
LINK_INTERFACE_LIBRARIES
模式将库附加到 INTERFACE_LINK_LIBRARIES
目标属性,而不是使用它们进行链接。如果策略:policy:CMP0022 不是``NEW``,那么此模式还将库附加到:prop_tgt:LINK_INTERFACE_LIBRARIES 及其每个配置的等效项。
此签名仅用于兼容性。更喜欢 INTERFACE
模式。
指定为“调试”的库被包装在生成器表达式中以对应于调试版本。如果策略:policy:CMP0022 不是 NEW
,库也会附加到:prop_tgt:LINK_INTERFACE_LIBRARIES_DEBUG <LINK_INTERFACE_LIBRARIES_<CONFIG>> 属性(或与 :prop_gbl 中列出的配置相对应的属性: DEBUG_CONFIGURATIONS 全局属性(如果已设置)。指定为“优化”的库附加到 INTERFACE_LINK_LIBRARIES
属性。如果策略 CMP0022 不是 NEW,它们也会附加到 LINK_INTERFACE_LIBRARIES 属性。指定为“general”(或没有任何关键字)的库被视为同时指定了“debug”和“optimized”。
链接对象库¶
在 3.12 版本加入.
对象库 可以用作``target_link_libraries`` 的``<target>``(第一个)参数来指定它们的源对其他库的依赖性。例如,代码
add_library(A SHARED a.c)
target_compile_definitions(A PUBLIC A)
add_library(obj OBJECT obj.c)
target_compile_definitions(obj PUBLIC OBJ)
target_link_libraries(obj PUBLIC A)
使用“-DA -DOBJ”编译“obj.c”,并为传播到其依赖项的“obj”建立使用要求。
普通库和可执行文件可以链接到 对象库 以获取它们的对象和使用要求。继续上面的例子,代码
add_library(B SHARED b.c)
target_link_libraries(B PUBLIC obj)
使用“-DA -DOBJ”编译“b.c”,使用来自“b.c”和“obj.c”的目标文件创建共享库“B”,并将“B”链接到``一个``。此外,代码
add_executable(main main.c)
target_link_libraries(main B)
使用“-DA -DOBJ”编译“main.c”并将可执行文件“main”链接到“B”和“A”。对象库的使用要求通过“B”传递传递,但它的对象文件不是。
对象库 可能会“链接”到其他对象库以获得使用要求,但由于它们没有链接步骤,因此不会对它们的对象文件执行任何操作。继续上面的例子,代码:
add_library(obj2 OBJECT obj2.c)
target_link_libraries(obj2 PUBLIC obj)
add_executable(main2 main2.c)
target_link_libraries(main2 obj2)
使用“-DA -DOBJ”编译“obj2.c”,使用“main2.c”和“obj2.c”中的目标文件创建可执行文件“main2”,并链接“main2” `` 到 A
。
换句话说,当 对象库 出现在目标的 INTERFACE_LINK_LIBRARIES
属性中时,它们将被视为 接口库,但当它们出现在目标的 LINK_LIBRARIES
属性中时他们的目标文件也将包含在链接中。
通过``$<TARGET_OBJECTS>``链接对象库¶
在 3.21 版本加入.
与对象库关联的对象文件可以由 $<TARGET_OBJECTS>
生成器表达式引用。这些目标文件放在所有库*之前*的链接行上,不管它们的相对顺序如何。此外,将向构建系统添加一个排序依赖项,以确保对象库在依赖目标链接之前是最新的。例如,代码
add_library(obj3 OBJECT obj3.c)
target_compile_definitions(obj3 PUBLIC OBJ3)
add_executable(main3 main3.c)
target_link_libraries(main3 PRIVATE a3 $<TARGET_OBJECTS:obj3> b3)
将可执行文件“main3”与“main3.c”和“obj3.c”中的目标文件链接起来,然后是“a3”和“b3”库。 main3.c
*未*根据 obj3
的使用要求进行编译,例如 -DOBJ3
。
这种方法可用于实现目标文件在链接行中的传递包含作为使用要求。继续上面的例子,代码
add_library(iface_obj3 INTERFACE)
target_link_libraries(iface_obj3 INTERFACE obj3 $<TARGET_OBJECTS:obj3>)
创建一个接口库 iface_obj3
转发 obj3
使用要求,并将 obj3
对象文件添加到从属链接行。代码
add_executable(use_obj3 use_obj3.c)
target_link_libraries(use_obj3 PRIVATE iface_obj3)
使用“-DOBJ3”编译“use_obj3.c”,并将可执行文件“use_obj3”与“use_obj3.c”和“obj3.c”中的目标文件链接起来。
这也可以通过静态库传递。由于静态库不链接,因此它不会使用以这种方式引用的对象库中的对象文件。相反,目标文件成为静态库的传递链接依赖项。继续上面的例子,代码
add_library(static3 STATIC static3.c)
target_link_libraries(static3 PRIVATE iface_obj3)
add_executable(use_static3 use_static3.c)
target_link_libraries(use_static3 PRIVATE static3)
使用“-DOBJ3”编译“static3.c”并仅使用它自己的目标文件创建“libstatic3.a”。 use_static3.c
编译*没有* -DOBJ3
因为使用要求不能通过 static3
的私有依赖传递。然而,static3
的链接依赖项被传播,包括``iface_obj3`` 对``$<TARGET_OBJECTS:obj3>`` 的引用。 use_static3
可执行文件是使用来自``use_static3.c`` 和``obj3.c`` 的目标文件创建的,并链接到库``libstatic3.a``。
使用这种方法时,项目有责任避免将多个依赖二进制文件链接到“iface_obj3”,因为它们都将在其链接行上获得“obj3”目标文件。
备注
在 target_link_libraries
调用中引用 $<TARGET_OBJECTS>
在某些情况下可以在 3.21 之前的 CMake 版本中工作,但不完全支持:
它没有将目标文件放在链接行上的库之前。
它没有添加对对象库的排序依赖。
它在具有多种架构的 Xcode 中不起作用。
静态库的循环依赖¶
库依赖图通常是非循环的(DAG),但在相互依赖的“STATIC”库的情况下,CMake 允许该图包含循环(强连接组件)。当另一个目标链接到其中一个库时,CMake 会重复整个连接的组件。例如,代码
add_library(A STATIC a.c)
add_library(B STATIC b.c)
target_link_libraries(A B)
target_link_libraries(B A)
add_executable(main main.c)
target_link_libraries(main A)
将 main
链接到 A B A B
。虽然一次重复通常就足够了,但病理对象文件和符号排列可能需要更多。可以通过使用 LINK_INTERFACE_MULTIPLICITY 目标属性或通过在最后一个 target_link_libraries
调用中手动重复组件来处理这种情况。但是,如果两个存档真的如此相互依赖,那么它们应该合并成一个存档,也许可以使用 对象库。
创建可重定位包¶
请注意,不建议填充 |INTERFACE_PROPERTY_LINK|具有依赖项绝对路径的目标。这会将依赖项的库文件路径硬编码到已安装的包中 ** 在制作包的机器上找到 ** 。
请参阅 cmake-packages(7) 手册的 创建可重定位包 部分,讨论在创建用于重新分发的包时指定使用要求时必须注意的额外注意事项。