CMake中target_link_libraries的使用

2023-05-16

      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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake中target_link_libraries的使用 的相关文章

  • libSDL、CMake 和 Mac OS X Lion

    我正在尝试在我的Mac上编译cmake项目 但它取决于SDL框架 我安装了这个框架 在 cmake 之后向我报告找不到 libSDL 我自己设置了以下导出变量 按照 cmake 的建议 export SDL INCLUDE DIR Libr
  • target_link_libraries 和 INCLUDE_DIRECTORIES 属性

    在这个片段中 cmake minimum required VERSION 3 0 project hello LANGUAGES C VERSION 0 0 1 add library a INTERFACE target include
  • 如何在使用cmake完成make后打印消息?

    我正在尝试使用 CMake 完成构建过程后打印消息 我只是想在之后通知用户make命令已完成 没有任何错误 我该怎么做 我试过add custom target 但我无法选择何时跑步 另外 我尝试过add custom command 它再
  • cmake 生成 Xcode 项目 - 发布构建有效,但存档因链接器错误而失败

    使用 Xcode 6 3 1 CMake 3 2 2 我有一个与图书馆链接的项目 该库作为代码包含在 xcode project 中 经过编译 然后与主可执行文件链接 项目是用cmake生成的 CMakeLists txt 的一些摘录 ad
  • 使用 NDK 构建具有适用于 Android 的 cmake 构建文件的 C++ 项目

    我必须构建 2 个独立的 C 项目 它们具有针对不同平台的 Cmake 构建文件设置 我想使用 NDK 为 Android 构建它们 以便我可以将它们用作 Android Studio 中的预构建库 如何使用 NDK 为 Android 构
  • CMake:如何最好地构建多个(可选)子项目?

    想象一个包含多个组件的整体项目 basic io web app a app b app c 现在 假设 web 依赖于 io 而 io 又依赖于 basic 所有这些东西都在一个存储库中 并且有一个 CMakeLists txt 将它们构
  • CMake - 将预构建库链接到 C# 项目

    我正在使用 CMake 构建 C 库 该库依赖于已构建的库 dll 我似乎无法让图书馆链接到我的图书馆 我尝试过使用target link libraries mylib external lib 我也尝试过暴力破解 reference e
  • 如何通过 Cmake 查找 iOS/mac OS X 框架

    Context 我通过此将 Boost C 库打包到一个框架 适用于 iOS 中script https github com davidandreoletti boostoniphone generic 该脚本产生boost框架 当链接到
  • XCode iPhone 项目中目标所有配置的通用预处理器宏

    我的应用程序的每个目标通常有四种配置 调试 发布 分发 临时 有没有办法为所有 4 个添加一个通用宏 同时不破坏我到目前为止设置的宏 您在编辑器中看到 多个值 提前致谢 奥比旺 在前缀头文件中定义宏 将包含在所有源文件中
  • cmake 找不到 Qt4

    由于4 8 0已经发布 我重新安装了Qt 现在我也想使用cmake 为了使 cmake 工作 我记得必须添加 mingw bin 文件夹 QtSDK Desktop Qt 4 7 3 到Qt4 7 3中的PATH 所以我猜测在中会有一个类似
  • 在cmake中设置PKG_CONFIG_PATH

    我已经在本地构建了 opencv 并将其安装到本地目录 不是系统默认目录 opencv pc存在于该本地文件夹中的 pkgconfig 文件夹下 我怎样才能找到这个opencv pc来自 cmake 因为我想从我的程序链接并包含 openc
  • 在 CMake 中,CHECK_INCLUDE_FILE_CXX 如何工作?

    以下代码不打印任何内容 CHECK INCLUDE FILE CXX glog logging h GLOG INCLUDE IF GLOG INCLUDE MESSAGE YY ENDIF GLOG INCLUDE 但我设置了以下环境变量
  • 如何使我的单元测试适应 cmake 和 ctest?

    到目前为止 我已经使用了一个临时的单元测试程序 基本上是由批处理文件自动运行的全部单元测试程序 尽管其中很多都明确地检查了他们的结果 但还有更多的作弊行为 他们将结果转储到版本控制的文本文件中 测试结果中的任何更改都会被颠覆标记 我可以轻松
  • 第三方库应该放在哪里?

    我为一个相当规模的 C 项目 http github com nickgammon mushclient具有许多依赖关系 问题是 该项目包含其所有依赖项的源代码 例如 pcre zlib 等 我想将项目精简为与程序本身相关的内容 是否有一些
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 使用星号更改多个源文件的 CMake 编译器标志

    我正在尝试调试与编译器优化相关的问题 O2 或以下版本没有问题 O3 出现段错误 并且我希望能够切换我的源代码块的编译器标志 以便我可以尝试缩小段错误的来源范围 我可以将全局优化级别设置为 O2 并更改单个文件的属性 如下所示 SET SO
  • 将 dll/lib 链接到 cmake 项目

    我试图将库链接到我的 cmake 项目 但遇到链接器错误 我花了 2 个小时尝试解决这个问题 并创建了一个简单的项目 在其中对所有路径进行了硬编码 CMAKE MINIMUM REQUIRED VERSION 3 0 PROJECT Tes
  • 如何将最新的 Windows SDK 版本传递给 CMake?

    如何将最新的 Windows SDK 版本传递给 CMake 这样我就不需要进入 Visual Studio 并从配置属性 常规中手动放置它 我在互联网上搜索 找到了 CMAKE SYSTEM VERSION 变量 并且尝试使用 set C
  • 使用 CMake 在 iOS 中使用另一个 STATIC 库创建一个 STATIC 库

    我有一个 libfooi a 的集合 libfoo1 a libfoo2 a libfoo3 a 使用工厂 带有静态代码 有一个公共接口来创建 C 对象 使用 CMake 我选择其中之一 并创建一个链接它并添加所有内容的 libfooWra
  • CMake:使用其他平台的生成器。如何?

    如何使用 CMake 在 Linux 上生成 Visual Studio 项目文件 你不能 您必须在 Windows 上运行 CMake 才能为 Visual Studio 生成

随机推荐