CMake中的target_link_libraries命令用于指定链接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的使用要求将被传播(propagated)。目标依赖项的使用要求会影响其自身源代码的编译。其格式如下:
- target_link_libraries(
... - ... ...) # general form
- target_link_libraries(
-
- ...
- [
- ...]...) # Libraries for a Target and/or its Dependents
- target_link_libraries(
- ...) # Libraries for both a Target and its Dependents
- target_link_libraries(
-
... - [
...]...) # Libraries for a Target and/or its Dependents (Legacy) - target_link_libraries(
LINK_INTERFACE_LIBRARIES - ...) # Libraries for Dependents Only (Legacy)
1.general form: 命名的
每个
(1).A library target name:生成的链接行(link line)将具有与target关联的可链接库文件的完整路径。如果库文件发生更改,构建系统将具有重新链接
命名的target必须由项目中的add_library命令创建或作为IMPORTED库创建。如果它是在项目中创建的,则会在构建系统中自动添加一个排序依赖项,以确保指定的库目标在
如果导入的库设置了IMPORTED_NO_SONAME目标属性,CMake可能会要求链接器搜索库而不是使用完整路径(例如/usr/lib/libfoo.so变为-lfoo)。
目标工件(target's artifact)的完整路径将自动为shell加引号/转义(quoted/escaped).
(2).A full path to a library file:生成的链接行通常会保留文件的完整路径。如果库文件更改,构建系统将具有重新链接
在某些情况下,CMake可能会询问链接器搜索的库(例如/usr/lib/libfoo.so变为-lfoo),例如,当检测到共享库没有SONAME字段时。
如果库文件在macOS框架(framework)中,框架的Headers目录也会作为使用需求处理。
在VS2010及更高版本的Visual Studio Generators上,以.targets结尾的库文件将被视为MSBuild目标文件并导入到生成的项目文件中。
库文件的完整路径将自动为shell加引号/转义(quoted/escaped).
(3).A plain library name:生成的链接行将要求链接器搜索库(例如,foo变为-lfoo或foo.lib).
库名称/标志被视为命令行字符串片段,将在没有额外引号或转义的情况下使用。
(4).A link flag:以-开头但不是-l或-framework的项目名称被视为链接器标志。
链接标志被视为命令行字符串片段,将在没有额外引号或转义的情况下使用。
(5).A generator expression:$<...>生成器表达式可以评估上述任何items或以分号分割的列表。如果...包含任何;字符,则必须使用显式引用的参数"$<...>",以便此命令将其作为单个
此外,生成器表达式可以用作上述任何items的片段,例如foo$<1:_d>
注意:生成器表达式将不会用于策略CMP0003或策略CMP0004的OLD处理中。
(6).A debug, optimized, or general keyword immediately followed by another
包含::的项目,如Foo::Bar,被假定为IMPORTED或ALIAS库目标名称,如果不存在这样的目标,将导致错误。
- cmake_policy(GET CMP0079 var) # 3.22
- message("var: ${var}") # var: NEW
-
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
- add_library(add_shared SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp) # 将会在build目录下生成libadd_shared.so
-
- add_executable(sample_add ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp)
- target_link_libraries(sample_add add_shared) # 若注释掉此句,则会报 error: sample_add.cpp:(.text+0x25): undefined reference to 'add(int, int)'
2.Libraries for a Target and/or its Dependents:PUBLIC, PRIVATE和INTERFACE关键字可用于在一个命令中指定link dependencies and the link interface。
PUBLIC之后的库和目标链接到链接接口,并成为链接接口的一部分。PRIVATE之后的库和目标被链接到,但不是链接接口的一部分。INTERFACE之后的库被附加到链接接口,不用于链接
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
- add_library(add_shared SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp) # 将会在build目录下生成libadd_shared.so
-
- add_executable(sample_add ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp)
- target_link_libraries(sample_add PRIVATE add_shared) # 也可以为PUBLIC;但不能为INTERFACE,若为INTERFACE,则会报error: sample_add.cpp:(.text+0x25): undefined reference to `add(int, int)'
3.Libraries for both a Target and its Dependents:默认情况下,库依赖使用此签名是可传递(transitive)的。当这个target链接到另一个target时,链接到该target的库也将出现在另一个target的链接行上。这个可传递的"链接接口"存储在INTERFACE_LINK_LIBRARIES target属性中,可以通过直接设置该属性来覆盖。当CMP0022未设置为NEW时,传递链接是内置的,但可能会被LINK_INTERFACE_LIBRARIES属性覆盖。
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
- add_library(add_shared SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp) # 将会在build目录下生成libadd_shared.so
- add_library(subtraction_shared SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/subtraction.cpp)
-
- target_link_libraries(subtraction_shared INTERFACE add_shared) # 也可以为PUBLIC;但不可以为PRIVATE,若为PRIVATE,则会报error:sample_add.cpp:(.text+0x25): undefined reference to `add(int, int)'
-
- add_executable(sample_add ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp)
- target_link_libraries(sample_add subtraction_shared) # 注意:此处sample_add链接的是subtraction_shared而不是add_shared
- # 可查看build/CMakeFiles/sample_add.dir/link.txt文件
4.Libraries for a Target and/or its Dependents (Legacy):该签名仅用于兼容性,请改用PUBLIC或PRIVATE关键字。
5.Libraries for Dependents Only (Legacy):该签名仅用于兼容性,请改用INTERFACE模式。
6.Linking Object Libraries:Object Libraries可用作target_link_libraries的
OBJECT library类型定义了编译给定源文件所产生的目标文件的非归档集合(The OBJECT library type defines a non-archival collection of object files resulting from compiling the given source files).通过使用语法$
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
- add_library(Add SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp)
- # target_compile_definitions(Add PUBLIC Add) # 有无此句好像都能执行
-
- # compiles subtraction.cpp(obj.cpp) with -DAdd -DOBJ
- add_library(Obj OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/source/subtraction.cpp)
- # target_compile_definitions(Obj PUBLIC Obj)
- target_link_libraries(Obj PUBLIC Add)
-
- # compiles multipy.cpp with -DAdd -DOBJ
- add_library(Multipy SHARED ${CMAKE_CURRENT_SOURCE_DIR}/source/multipy.cpp)
- target_link_libraries(Multipy PUBLIC Obj)
-
- # compiles sample_add.cpp with -DAdd -DObj and links executable main to Multipy and Add
- add_executable(main ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp)
- target_link_libraries(main Multipy)
7.Linking Object Libraries via $
这也可以通过静态库传递(transitively)。
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
- add_library(Obj OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/source/subtraction.cpp)
- # target_compile_definitions(Obj PUBLIC Obj) # 有无此句好像都能执行
-
- add_executable(main ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_subtraction.cpp)
- # links executable main with object files from sample_subtraction.cpp and subtraction.cpp followed by the pthread and dl libraries
- target_link_libraries(main PRIVATE pthread $
dl) -
- add_library(iface_obj INTERFACE)
- target_link_libraries(iface_obj INTERFACE Obj $
) -
- # compiles sample_subtraction.cpp with -DObj and links executable main2 with object files from sample_subtraction.cpp and subtraction.cpp
- add_executable(main2 ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_subtraction.cpp)
- target_link_libraries(main2 PRIVATE iface_obj)
-
- # this also works transitively through a static library.
- add_library(add STATIC ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp)
- target_link_libraries(add PRIVATE iface_obj)
-
- add_executable(main3 ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_subtraction.cpp)
- target_link_libraries(main3 PRIVATE add)
8.Cyclic Dependencies of Static Libraries(静态库的循环依赖):库依赖图通常是非循环的(DAG),但在相互依赖的STATIC库的情况下,CMake允许该图包含循环(强连接组件)。当另一个target链接到其中一个库时,CMake会重复整个连接的组件。
虽然一次重复通常就足够了,但病理对象文件和符号排列(pathological object file and symbol arrangements)可能需要更多。可以通过使用LINK_INTERFACE_MULTIPLICITY target属性或在上次target_link_libraries调用中手动重复该组件来处理此类情况。然而,如果两个存档(archives)真的如此相互依赖,那么应该使用Object Libraries将它们组合成一个单一的存档。
- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
-
- add_library(add STATIC ${CMAKE_CURRENT_SOURCE_DIR}/source/add.cpp)
- add_library(subtraction STATIC ${CMAKE_CURRENT_SOURCE_DIR}/source/subtraction.cpp)
- target_link_libraries(add subtraction)
- target_link_libraries(subtraction add)
-
- # links main to add subtraction add subtraction
- add_executable(main ${CMAKE_CURRENT_SOURCE_DIR}/samples/sample_add.cpp)
- target_link_libraries(main subtraction)
执行测试代码需要多个文件:
build.sh内容如下:
- #! /bin/bash
-
- # supported input parameters(cmake commands)
- params=(function macro cmake_parse_arguments \
- find_library find_path find_file find_program find_package \
- cmake_policy cmake_minimum_required project include \
- string list set foreach message option if while return \
- math file configure_file \
- include_directories add_executable add_library target_link_libraries install)
-
- usage()
- {
- echo "Error: $0 needs to have an input parameter"
-
- echo "supported input parameters:"
- for param in ${params[@]}; do
- echo " $0 ${param}"
- done
-
- exit -1
- }
-
- if [ $# != 1 ]; then
- usage
- fi
-
- flag=0
- for param in ${params[@]}; do
- if [ $1 == ${param} ]; then
- flag=1
- break
- fi
- done
-
- if [ ${flag} == 0 ]; then
- echo "Error: parameter \"$1\" is not supported"
- usage
- exit -1
- fi
-
- if [[ ! -d "build" ]]; then
- mkdir build
- cd build
- else
- cd build
- fi
-
- echo "==== test $1 ===="
-
- # test_set.cmake: cmake -DTEST_CMAKE_FEATURE=$1 --log-level=verbose ..
- # test_option.cmake: cmake -DTEST_CMAKE_FEATURE=$1 -DBUILD_PYTORCH=ON ..
- cmake -DTEST_CMAKE_FEATURE=$1 ..
- # It can be executed directly on the terminal, no need to execute build.sh, for example: cmake -P test_set.cmake
- make
- # make install # only used in cmake files with install command
CMakeLists.txt内容如下:
- cmake_minimum_required(VERSION 3.22)
- project(cmake_feature_usage)
-
- message("#### current cmake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}")
- include(test_${TEST_CMAKE_FEATURE}.cmake)
- message("==== test finish ====")
test_target_link_libraries.cmake内容为上面的所有测试代码段。
另外还包括三个目录:include,source,samples,它们都是非常简单的实现,仅用于测试,如下:

可能的执行结果如下图所示:
