target_link_libraries¶
指定在链接给定目标和/或其依赖项时要使用的库或标志。来自已链接库目标的 使用要求 (Usage requirements) 将被传播。目标依赖项的使用要求会影响其自身源代码的编译。
概述¶
此命令有几种签名方式,详见下文。它们都具有以下通用形式:
target_link_libraries(<target> ... <item>... ...)
指定的 <target> 必须是由 add_executable() 或 add_library() 等命令创建的,并且不能是 别名目标 (ALIAS target)。如果策略 CMP0079 未设置为 NEW,则该目标必须在当前目录中创建。针对同一 <target> 的重复调用将按调用顺序追加项。
3.13 版本新增: <target> 不一定非要在调用 target_link_libraries 的同一目录中定义。
每个 <item> 可以是:
库目标名称:生成的链接行将包含指向与该目标关联的可链接库文件的完整路径。如果库文件发生更改,构建系统将产生重新链接
<target>的依赖关系。该目标名称必须由项目内的
add_library()创建,或者是 导入的库 (IMPORTED library)。如果它是在项目内创建的,则会在构建系统中自动添加排序依赖项,以确保在<target>链接之前,指定的库目标是最新的。如果导入的库设置了
IMPORTED_NO_SONAME目标属性,CMake 可能会要求链接器搜索该库,而不是使用完整路径(例如,/usr/lib/libfoo.so变为-lfoo)。目标工件的完整路径将自动为 shell 进行引用/转义。
库文件的完整路径:生成的链接行通常会保留文件的完整路径。如果库文件发生更改,构建系统将产生重新链接
<target>的依赖关系。在某些情况下,CMake 可能会要求链接器搜索该库(例如,
/usr/lib/libfoo.so变为-lfoo),例如当检测到共享库没有SONAME字段时。在 4.0 之前的 CMake 版本中,请参阅策略CMP0060以讨论另一种情况。如果库文件位于 macOS 框架中,该框架的
Headers目录也将被作为 使用要求 进行处理。这与将框架目录作为包含目录传递具有相同的效果。3.28 版本新增: 库文件可以指向 Apple 平台上的
.xcframework文件夹。如果是这种情况,目标将获得所选库的Headers目录作为使用要求。3.8 版本新增: 对于 VS 2010 及更高版本的 Visual Studio 生成器,以
.targets结尾的库文件将被视为 MSBuild 目标文件并导入生成的项目文件中。其他生成器不支持此功能。库文件的完整路径将自动为 shell 进行引用/转义。
纯库名称:生成的链接行将要求链接器搜索该库(例如,
foo变为-lfoo或foo.lib)。库名称/标志被视为命令行字符串片段,并将按原样使用,无需额外引用或转义。
链接标志:以
-开头(但不是-l或-framework)的项名称被视为链接器标志。注意,对于传递依赖项,此类标志将像任何其他库链接项一样处理,因此通常仅将它们指定为不会传播到依赖项的私有 (private) 链接项是安全的。此处指定的链接标志将被插入到链接命令中与链接库相同的位置。根据链接器的不同,这可能不正确。请使用
LINK_OPTIONS目标属性或target_link_options()命令来显式添加链接标志。标志随后将被放置在链接命令中工具链定义的标志位置。3.13 版本新增:
LINK_OPTIONS目标属性和target_link_options()命令。对于较早版本的 CMake,请改用LINK_FLAGS属性。链接标志被视为命令行字符串片段,并将按原样使用,无需额外引用或转义。
生成器表达式:
$<...>生成器表达式可以求值为上述任何项,或求值为它们的 分号分隔列表。如果...包含任何;字符(例如在求值${list}变量后),请务必使用显式引用的参数"$<...>",以便此命令将其接收为单个<item>。此外,生成器表达式可以用作上述任何项的片段,例如
foo$<1:_d>。debug、optimized或general关键字后紧跟另一个<item>。在此类关键字之后的项将仅用于相应的构建配置。debug关键字对应于Debug配置(或如果已设置,则对应于DEBUG_CONFIGURATIONS全局属性中命名的配置)。optimized关键字对应于所有其他配置。general关键字对应于所有配置,且完全可选。这些关键字由该命令直接解释,因此当由生成器表达式产生时,它们没有特殊含义。或者,像
$<CONFIG>这样的生成器表达式提供了更精细的按配置链接<item>的功能。对于更结构化的方法,可以通过创建并链接到设置了IMPORTED_CONFIGURATIONS属性的 导入的库目标 (IMPORTED library targets) 来实现更高的粒度,尤其是在查找模块中。
包含 :: 的项(如 Foo::Bar)被假定为 IMPORT 或 ALIAS 库目标名称,如果不存在此类目标,则会导致错误。请参阅策略 CMP0028。
有关 CMake 如何在链接器命令行上对直接链接依赖项进行排序的详细信息,请参阅 CMAKE_LINK_LIBRARIES_STRATEGY 变量和相应的 LINK_LIBRARIES_STRATEGY 目标属性。
有关定义构建系统属性的更多信息,请参阅 cmake-buildsystem(7) 手册。
处理编译器驱动程序差异¶
4.0 版本新增。
为了将选项传递给链接器工具,每个编译器驱动程序都有其自己的语法。LINKER: 前缀和 , 分隔符可用于以可移植的方式指定要传递给链接器工具的选项。LINKER: 将被替换为适当的驱动程序选项,, 将被替换为适当的驱动程序分隔符。驱动程序前缀和分隔符由 CMAKE_<LANG>_LINKER_WRAPPER_FLAG 和 CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP 变量的值给定。
例如,对于 Clang,"LINKER:-z,defs" 会变成 -Xlinker -z -Xlinker defs;对于 GNU GCC,则会变成 -Wl,-z,defs。
LINKER: 前缀支持使用 SHELL: 前缀和空格作为分隔符来指定参数,作为一种替代语法。前面的示例将变为 "LINKER:SHELL:-z defs"。
注意
不支持在 LINKER: 前缀的开头以外的任何位置指定 SHELL: 前缀。
为目标和/或其依赖项指定库¶
target_link_libraries(<target>
{INTERFACE|PUBLIC|PRIVATE} <item>...
[{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
PUBLIC、PRIVATE 和 INTERFACE 作用域 (scope) 关键字可用于在单个命令中指定链接依赖项和链接接口。
PUBLIC 后面的库和目标既会被链接,也会成为链接接口的一部分。PRIVATE 后面的库和目标会被链接,但不会成为链接接口的一部分。INTERFACE 后面的库会被附加到链接接口中,且不会用于链接 <target>。
为目标及其依赖项指定库¶
target_link_libraries(<target> <item>...)
在此签名中,库依赖项默认是传递的。当此目标被链接到另一个目标时,链接到此目标的库也会出现在另一个目标的链接行上。此传递性的“链接接口”存储在 INTERFACE_LINK_LIBRARIES 目标属性中,并可以通过直接设置该属性来覆盖。
在 4.0 之前的 CMake 版本中,如果 CMP0022 未设置为 NEW,则传递链接是内置的,但可以通过 LINK_INTERFACE_LIBRARIES 属性覆盖。对该命令其他签名的调用可能会设置该属性,使得仅通过此签名链接的任何库变为私有的。
为目标和/或其依赖项指定库(旧版)¶
此签名仅用于兼容性。建议优先使用 PUBLIC 或 PRIVATE 关键字。
target_link_libraries(<target>
<LINK_PRIVATE|LINK_PUBLIC> <lib>...
[<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...)
LINK_PUBLIC 和 LINK_PRIVATE 模式可用于在单个命令中指定链接依赖项和链接接口。
LINK_PUBLIC 后面的库和目标既会被链接,也会成为 INTERFACE_LINK_LIBRARIES 的一部分。
在 4.0 之前的 CMake 版本中,如果策略 CMP0022 不是 NEW,它们也会成为 LINK_INTERFACE_LIBRARIES 的一部分。LINK_PRIVATE 后面的库和目标会被链接,但不会成为 INTERFACE_LINK_LIBRARIES(或 LINK_INTERFACE_LIBRARIES)的一部分。
仅为依赖项指定库(旧版)¶
此签名仅用于兼容性。建议优先使用 INTERFACE 模式。
target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...)
LINK_INTERFACE_LIBRARIES 模式将库附加到 INTERFACE_LINK_LIBRARIES 目标属性,而不是将它们用于链接。
在 4.0 之前的 CMake 版本中,如果策略 CMP0022 不是 NEW,则此模式也会将库附加到 LINK_INTERFACE_LIBRARIES 及其按配置等效项。
链接对象库¶
3.12 版本新增。
对象库 (Object Libraries) 可以用作 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 链接到 A。此外,代码
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 属性中时,它们将被视为 接口库 (Interface 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 的链接依赖项会传播,包括对 $<TARGET_OBJECTS:obj3> 的 iface_obj3 引用。use_static3 可执行文件是使用来自 use_static3.c 和 obj3.c 的目标文件创建的,并链接到库 libstatic3.a。
使用此方法时,项目有责任避免将多个依赖的二进制文件链接到 iface_obj3,因为它们都将在各自的链接行上获得 obj3 的目标文件。
注意
在 3.21 之前的某些 CMake 版本中,在 target_link_libraries 调用中引用 $<TARGET_OBJECTS> 是可以工作的,但并不完全受支持:
它没有将目标文件放在链接行上库的前面。
它没有在对象库上添加排序依赖项。
它在具有多个架构的 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_LINK_LIBRARIES 中填充依赖项的绝对路径。这会将在创建软件包的机器上找到的依赖项库文件路径硬编码到安装的软件包中。
有关创建可重定位包(relocatable packages)时在指定使用需求时需要注意的额外事项的讨论,请参阅 cmake-packages(7) 手册的 创建可重定位包 部分。