首页 > 其他分享 >cmake中link_directories()与link_libraried()全局性的理解

cmake中link_directories()与link_libraried()全局性的理解

时间:2024-10-23 12:49:09浏览次数:8  
标签:cmake libraried libB libA 目标 link 全局 链接

在 CMake 中,link_directories()link_libraries() 是全局命令,这意味着它们的设置会影响 之后CMakeLists.txt 文件中定义的 所有目标(targets)。要深入理解这一点,下面将详细解释全局命令的作用范围、它们如何影响项目中的多个目标、以及为什么在现代 CMake 中更推荐使用目标级别的命令。

全局命令的定义与作用

1. link_directories()

作用:指定链接器在编译时搜索库文件的目录。

语法

link_directories(directory1 directory2 ...)

影响范围:全局,影响调用该命令之后定义的所有目标。

2. link_libraries()

作用:为所有后续定义的目标指定要链接的库。

语法

link_libraries(library1 library2 ...)

影响范围:全局,影响调用该命令之后定义的所有目标。

如何理解“全局命令影响整个 CMake 项目中后续定义的所有目标”

示例项目结构

假设我们有一个简单的项目结构如下:

MyProject/
├── CMakeLists.txt
├── libA/
│   ├── CMakeLists.txt
│   └── libA.cpp
├── libB/
│   ├── CMakeLists.txt
│   └── libB.cpp
└── app/
    ├── CMakeLists.txt
    └── main.cpp

使用全局命令的 CMakeLists.txt

# MyProject/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 全局链接目录
link_directories(/usr/local/lib/custom)

# 全局链接库
link_libraries(mylib_global)

add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(app)
# MyProject/libA/CMakeLists.txt
add_library(libA STATIC libA.cpp)
# 不需要额外指定链接库,因 link_libraries 已全局设置
# MyProject/libB/CMakeLists.txt
add_library(libB STATIC libB.cpp)
# 不需要额外指定链接库,因 link_libraries 已全局设置
# MyProject/app/CMakeLists.txt
add_executable(MyApp main.cpp)
# 不需要额外指定链接库,因 link_libraries 已全局设置

解析

  1. link_directories(/usr/local/lib/custom)

    • 这个命令告诉链接器在 /usr/local/lib/custom 目录下搜索库文件。
    • 由于这是全局命令,libAlibBMyApp 在链接时都会在这个目录中查找库文件。
  2. link_libraries(mylib_global)

    • 这个命令指定所有后续定义的目标都要链接 mylib_global 库。
    • 因此,libAlibBMyApp 在链接时都会自动链接 mylib_global

结果与潜在问题

  • 预期效果

    • 所有目标(libAlibBMyApp)都链接了位于 /usr/local/lib/custommylib_global 库。
  • 潜在问题

    1. 不必要的依赖

      • 如果某些目标不需要 mylib_global,它们仍然会被链接到该库,增加了不必要的依赖和最终的可执行文件大小。
    2. 名称冲突

      • 如果不同的目标需要链接不同版本或不同名称的库,使用全局命令可能导致链接到错误的库,导致难以排查的错误。
    3. 维护复杂性

      • 随着项目规模的扩大,全局命令可能导致依赖关系变得难以管理和理解,特别是在多个子目录和模块中。

对比使用目标级别命令

为了避免上述问题,现代 CMake 推荐使用目标级别的命令 target_link_directories()target_link_libraries(),它们只影响特定的目标,而不是全局作用。

改进后的 CMakeLists.txt
# MyProject/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(libA)
add_subdirectory(libB)
add_subdirectory(app)
# MyProject/libA/CMakeLists.txt
add_library(libA STATIC libA.cpp)
target_link_directories(libA PRIVATE /usr/local/lib/custom)
target_link_libraries(libA PRIVATE mylib_libA)
# MyProject/libB/CMakeLists.txt
add_library(libB STATIC libB.cpp)
target_link_directories(libB PRIVATE /opt/another_lib)
target_link_libraries(libB PRIVATE mylib_libB)
# MyProject/app/CMakeLists.txt
add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE libA libB)
解析
  1. libA

    • libA 在链接时搜索 /usr/local/lib/custom 目录。
    • libA 链接到 mylib_libA 库。
  2. libB

    • libB 在链接时搜索 /opt/another_lib 目录。
    • libB 链接到 mylib_libB 库。
  3. MyApp

    • 仅链接到 libAlibB,而不会自动链接到 mylib_libAmylib_libB,除非这些库通过 libAlibBPUBLICINTERFACE 属性传递。
优势
  1. 精确控制

    • 每个目标的链接设置都是独立的,避免了全局影响。
  2. 避免不必要的依赖

    • 只有需要的目标才会链接到特定的库,减少了不必要的依赖和潜在的冲突。
  3. 提高可维护性

    • 随着项目的增长,依赖关系变得更加清晰和易于管理。
  4. 支持传递性

    • 使用 PUBLICINTERFACE 关键字,可以更好地管理库的依赖传递。例如,如果 libA 的公共接口依赖于某个库,那么链接到 libA 的目标也会自动链接到该库。

实际应用中的注意事项

1. 避免混用全局和目标级别命令

在同一个项目中混用全局命令和目标级别命令可能导致混乱和难以预测的行为。最好选择一种方式,并在整个项目中保持一致。

2. 逐步迁移到目标级别命令

如果你正在维护一个使用全局命令的旧项目,可以考虑逐步迁移到目标级别命令,以提高构建配置的模块化和可维护性。以下是迁移的步骤建议:

  1. 识别全局命令的使用位置

    • 查找所有 link_directories()link_libraries() 的调用位置。
  2. 为每个目标单独指定链接目录和库

    • 使用 target_link_directories()target_link_libraries() 为每个目标设置所需的链接路径和库。
  3. 删除全局命令

    • 确保所有目标都已正确配置后,移除全局命令的调用。

3. 理解可见性关键字

在使用目标级别命令时,理解 PRIVATEPUBLICINTERFACE 关键字的区别非常重要:

  • PRIVATE

    • 属性仅对当前目标可见,不会传递给依赖该目标的其他目标。
  • PUBLIC

    • 属性对当前目标和依赖该目标的其他目标都可见。
  • INTERFACE

    • 属性仅对依赖该目标的其他目标可见,不影响当前目标。
示例
# libA 需要链接外部库 mylibA,且希望依赖 libA 的目标也链接 mylibA
add_library(libA STATIC libA.cpp)
target_link_libraries(libA PUBLIC mylibA)
# MyApp 依赖 libA
add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE libA)

效果

  • libA 本身链接到 mylibA
  • 由于 libA 使用 PUBLIC 关键字链接 mylibAMyApp 在链接 libA 时也会自动链接到 mylibA

总结

全局命令 (link_directories()link_libraries())

  • 作用范围:全局,影响所有后续定义的目标。
  • 优点
    • 简单,适用于小型项目或所有目标共享相同的链接设置。
  • 缺点
    • 容易导致不必要的依赖和潜在的库冲突。
    • 可维护性差,特别是在大型或模块化项目中。

目标级别命令 (target_link_directories()target_link_libraries())

  • 作用范围:仅影响特定的目标。
  • 优点
    • 精确控制,避免全局副作用。
    • 更高的可维护性和模块化。
    • 支持依赖关系的传递和可见性控制。
  • 缺点
    • 需要为每个目标单独配置,初期可能稍显繁琐。

推荐实践

在现代 CMake 项目中,推荐使用目标级别的命令 来配置链接设置。这不仅提高了项目的灵活性和可维护性,还避免了全局命令可能带来的各种问题。只有在确实需要全局影响时,才考虑使用全局命令,并尽量减少其使用范围。

通过理解全局命令和目标级别命令的区别,以及它们在项目中的影响范围,你可以更有效地管理 CMake 项目的构建配置,确保构建过程的正确性和可维护性。

标签:cmake,libraried,libB,libA,目标,link,全局,链接
From: https://blog.csdn.net/qq_45993770/article/details/143158532

相关文章

  • 【论文复现】输电线路故障判别与测距研究(Matlab代码、Simulink仿真实现)
       ......
  • 【论文复现】输电线路故障判别与测距研究(Matlab代码、Simulink仿真实现)
       ......
  • 【论文复现】输电线路故障判别与测距研究(Matlab代码、Simulink仿真实现)
       ......
  • DAPLINK 源码学习(1)BL 之 main() 函数
    目录bootloader主函数1sdk_init()2gpio_init()3config_init()4board_bootloader_init()5运行IF还是BL?6main_task()7总结bootloader主函数1)我们以stm32f103xb_bl为例,从bootloader项目的main()函数开始:(1)sdk_init():MCU初始化(2)gpio_init():USB相关引脚配......
  • EtherCAT转CC-Link协议转换网关
    一,设备主要功能捷米特JM-ECT-CCLK网关是自主研发的一款CC-Link从站功能的通讯网关。该产品主要功能是将各种CC-Link总线和EtherCAT网络连接起来。本网关连接到EtherCAT总线中做为从站使用,连接到CC-Link总线中做为从站使用。应用广泛:实现不同协议设备的集成:工业现场存在支持Et......
  • 深度了解flink rpc机制(三)-组件以及交互
    FlinkRPC整体架构Flink集群间组件的通信底层是使用的actorsystem通信模型和动态代理来实现的,先简单看下FlinkRPC相关的类UML图通信组件RpcGatewayFlinkRPC远程调用网关,是FlinkRPC定义远程调用的接口协议,对外提供可调用的接口,所有实现RPC的组件,都要实现这个接口......
  • vue3 setup lang=ts实现router-link的动态传参
    一、实现目标 可以通过router-link在url里面配置参数然后传递给markdown页面 二、页面配置主页面,即配置router-link的页面templates:<router-link:to="{path:`/mark/${itemId}`}">fff</router-link>script:constitemId=ref('333'); 接收数据页面,即mark页面......
  • cmake学习笔记
    最近在学cmake的用法,参考了cmake使用详细教程(日常使用这一篇就足够了)这篇文章,这篇文章讲的很仔细,下面记录自己的学习过程。1、系统以及开发工具一开始想通过虚拟机安装Ubuntu和vscode,后面想到了之前本机Windows安装过wsl,wsl的就是Ubuntu,在wsl+本地vscode的开发下,很快就把文章......
  • LinkedList详解
    1概述LinkedList和ArrayList是Java集合框架中的两个重要类,它们分别基于链表和动态数组实现。LinkedList选择链表作为其底层数据结构的原因在于链表在某些操作上具有显著的优势。1.1链表的优势动态大小:链表不需要预先分配固定大小的内存,可以根据需要动态扩展或缩......
  • Leetcode 328. Odd Even Linked List
    我的解法没有什么需要推理的地方,要注意一开始要让cur走的比odd和even快,否则会导致cur的next被odd和even修改,代码里有注释。ListNode*oddEvenList(ListNode*head){if(!head){returnhead;}ListNode*cur=nullptr,*headofOdd=h......