CMake中target_link_libraries的使用
Posted fengbingchun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMake中target_link_libraries的使用相关的知识,希望对你有一定的参考价值。
CMake中的target_link_libraries命令用于指定链接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的使用要求将被传播(propagated)。目标依赖项的使用要求会影响其自身源代码的编译。其格式如下:
target_link_libraries(<target> ... <item>... ...) # general form
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...) # Libraries for a Target and/or its Dependents
target_link_libraries(<target> <item>...) # Libraries for both a Target and its Dependents
target_link_libraries(<target>
<LINK_PRIVATE|LINK_PUBLIC> <lib>...
[<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...) # Libraries for a Target and/or its Dependents (Legacy)
target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...) # Libraries for Dependents Only (Legacy)
1.general form: 命名的<target>必须由诸如add_executable或add_library之类的命令创建,并且不能是ALIAS target。如果策略CMP0079未设置为NEW,则target必须已在当前目录中创建。重复调用相同的<target>会按调用顺序追加项目(Repeated calls for the same <target> append items in the order called)。
<target>不必在与target_link_libraries调用相同的目录中定义。
每个<item>可能是:
(1).A library target name:生成的链接行(link line)将具有与target关联的可链接库文件的完整路径。如果库文件发生更改,构建系统将具有重新链接<target>的依赖性。
命名的target必须由项目中的add_library命令创建或作为IMPORTED库创建。如果它是在项目中创建的,则会在构建系统中自动添加一个排序依赖项,以确保指定的库目标在<target>链接之前是最新的。
如果导入的库设置了IMPORTED_NO_SONAME目标属性,CMake可能会要求链接器搜索库而不是使用完整路径(例如/usr/lib/libfoo.so变为-lfoo)。
目标工件(target's artifact)的完整路径将自动为shell加引号/转义(quoted/escaped).
(2).A full path to a library file:生成的链接行通常会保留文件的完整路径。如果库文件更改,构建系统将具有重新链接<target>的依赖性。
在某些情况下,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或以分号分割的列表。如果...包含任何;字符,则必须使用显式引用的参数"$<...>",以便此命令将其作为单个<item>接收。
此外,生成器表达式可以用作上述任何items的片段,例如foo$<1:_d>
注意:生成器表达式将不会用于策略CMP0003或策略CMP0004的OLD处理中。
(6).A debug, optimized, or general keyword immediately followed by another <item>:这样的关键字后面的item将仅用于相应的构建配置。debug关键字对应于Debug配置。optimized关键字对应于所有其它配置。general关键字对应所有配置,完全是可选的。通过创建和链接到IMPORTED库目标,可以为每个配置规则实现更高的粒度。这些关键字由该命令立即解释,因此在由生成器表达式生成时,它们没有特殊含义。
包含::的项目,如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之后的库被附加到链接接口,不用于链接<target>.
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的<target>的(第一个)参数,以指定其源对其他库的依赖。
OBJECT library类型定义了编译给定源文件所产生的目标文件的非归档集合(The OBJECT library type defines a non-archival collection of object files resulting from compiling the given source files).通过使用语法$<TARGET_OBJECTS:name>,目标文件集合(object files collection)可以用作其它target的源输入。
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 $<TARGET_OBJECTS>:与object library关联的object file可以由$<TARGET_OBJECTS>生成器表达式引用(referenced).这样的object file放在所有库之前的链接行上,不管它们的相对顺序如何。
这也可以通过静态库传递(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 $<TARGET_OBJECTS:Obj> dl)
add_library(iface_obj INTERFACE)
target_link_libraries(iface_obj INTERFACE Obj $<TARGET_OBJECTS: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,它们都是非常简单的实现,仅用于测试,如下:
可能的执行结果如下图所示:
GitHub: https://github.com/fengbingchun/Linux_Code_Test
以上是关于CMake中target_link_libraries的使用的主要内容,如果未能解决你的问题,请参考以下文章
cmake中target_link_libraries()使用问题动态库使用绝对路径没问题,但是使用相对路径就矬了?
添加不存在的目标时强制 CMake target_link_libraries 失败
C++学习(四一零)cmake的target_link_libraries
[cmake][转载]cmake中的link_directories, LINK_LIBRARIES, target_link_libraries的区别
调用 `target_link_libraries(target_name, library_name_without_postfix)` 时,`Cmake` 更喜欢链接到哪个库?