target_link_libraries¶
指定在链接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的 使用要求 将会被传播。目标依赖项的使用要求会影响其自身源文件的编译。
概述¶
此命令有多个签名,详见以下小节。它们都具有以下通用形式
target_link_libraries(<target> ... <item>... ...)
指定的 <target>
必须已通过诸如 add_executable()
或 add_library()
之类的命令创建,并且不得为 ALIAS 目标。如果策略 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
字段时。在 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
开头的项名称被视为链接器标志。请注意,出于传递依赖关系的目的,此类标志将被视为任何其他库链接项,因此通常仅安全地指定为不会传播到依赖项的私有链接项。此处指定的链接标志将插入到链接命令中,位置与链接库相同。这可能不正确,具体取决于链接器。使用
LINK_OPTIONS
目标属性或target_link_options()
命令显式添加链接标志。然后,这些标志将放置在链接命令中工具链定义的标志位置。3.13 版本新增:
LINK_OPTIONS
目标属性和target_link_options()
命令。对于早期版本的 CMake,请改用LINK_FLAGS
属性。链接标志被视为命令行字符串片段,将在不进行额外引用或转义的情况下使用。
生成器表达式:
$<...>
生成器表达式
可以求值为上述任何项,或求值为它们的 分号分隔列表。如果...
包含任何;
字符,例如在评估${list}
变量之后,请务必使用显式引用的参数"$<...>"
,以便此命令将其接收为单个<item>
。此外,生成器表达式可以用作上述任何项的片段,例如
foo$<1:_d>
。紧跟另一个
<item>
的debug
、optimized
或general
关键字。紧跟在此类关键字后面的项将仅用于相应的构建配置。debug
关键字对应于Debug
配置(或在设置了DEBUG_CONFIGURATIONS
全局属性时,对应于该属性中命名的配置)。optimized
关键字对应于所有其他配置。general
关键字对应于所有配置,并且是纯粹可选的。通过创建并链接到 IMPORTED 库目标,可以实现更精细的按配置规则。这些关键字由此命令立即解释,因此当由生成器表达式生成时,它们没有特殊含义。
包含 ::
的项(例如 Foo::Bar
)被假定为 IMPORTED 或 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
变量的值给出。
例如,"LINKER:-z,defs"
对于 Clang
变为 -Xlinker -z -Xlinker defs
,对于 GNU GCC
变为 -Wl,-z,defs
。
LINKER:
前缀支持使用 SHELL:
前缀和空格作为分隔符来指定参数的替代语法。之前的示例变为 "LINKER:SHELL:-z defs"
。
注意
不支持在 LINKER:
前缀的开头以外的任何位置指定 SHELL:
前缀。
目标和/或其依赖项的库¶
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
PUBLIC
、PRIVATE
和 INTERFACE
作用域 关键字可用于在一个命令中指定链接依赖项和链接接口。
跟随 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
,它们也成为 INTERFACE_LINK_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 版本新增。
对象库 可以用作 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
属性中时,它们将被视为 接口库,但是当它们出现在目标的 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
对象文件。
注意
在 CMake 3.21 之前的版本中,在 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
。 这会将依赖项的库文件路径硬编码到已安装的软件包中,这些路径是在构建软件包的机器上找到的。
请参阅 创建可重定位的软件包 部分的 cmake-packages(7)
手册,其中讨论了在为重新分发创建软件包时,指定使用要求时必须采取的额外注意事项。