首页 > 其他分享 >Cmake中“目标层级“的概念(target_include_directories和include_directories的区别)

Cmake中“目标层级“的概念(target_include_directories和include_directories的区别)

时间:2024-10-23 12:49:22浏览次数:3  
标签:Cmake CoreLib directories 目标 add link FeatureLib MyApp include

CMake 中,“目标层级”(Target-Level)是一个核心概念,涉及到项目中构建的具体实体,如可执行文件、库等。理解目标层级对于有效地使用现代 CMake 功能、管理依赖关系以及配置构建过程至关重要。以下将详细解释什么是目标层级、其重要性以及如何在 CMake 中应用相关命令。

什么是“目标”?

**目标(Target)**是 CMake 中的一个基本构建单元,代表了最终要生成的文件或构建过程中的中间产物。主要包括:

  1. 可执行文件(Executable):通过 add_executable() 定义。
  2. 静态库(Static Library):通过 add_library() 定义,类型为 STATIC
  3. 动态库(Shared Library):通过 add_library() 定义,类型为 SHARED
  4. 模块库(Module Library):通过 add_library() 定义,类型为 MODULE

示例

# 定义一个静态库目标
add_library(MyStaticLib STATIC src/mylib.cpp)

# 定义一个动态库目标
add_library(MySharedLib SHARED src/mylib.cpp)

# 定义一个可执行文件目标
add_executable(MyApp src/main.cpp)

在上述示例中,MyStaticLibMySharedLibMyApp 都是不同的目标。

目标层级的重要性

使用目标层级的主要优点包括:

  1. 封装性:每个目标的属性(如编译选项、链接库等)都是独立管理的,避免了全局设置带来的副作用。
  2. 依赖管理:CMake 可以自动处理目标之间的依赖关系,确保正确的构建顺序。
  3. 可维护性:通过将配置与特定目标绑定,项目的配置更加清晰和模块化,易于维护和扩展。
  4. 现代化功能:现代 CMake 强调面向目标的配置,支持更高级的功能,如接口库(Interface Libraries)和生成位置自适应的构建规则。

全局命令 vs. 目标层级命令

在之前的回答中提到的 link_directories()link_libraries()全局命令,它们影响整个 CMake 项目中后续定义的所有目标。而 target_link_directories()target_link_libraries()目标层级命令,它们只影响特定的目标。

全局命令

  • link_directories():为所有目标指定链接库的搜索路径。
  • link_libraries():为所有目标指定要链接的库。

缺点

  • 可能导致意外的库链接,难以追踪问题。
  • 全局设置可能影响到不需要这些库的目标,导致不必要的依赖。

目标层级命令

  • target_link_directories():为特定目标指定链接库的搜索路径。
  • target_link_libraries():为特定目标指定要链接的库。

优点

  • 只影响指定的目标,避免全局副作用。
  • 更加明确和可维护,易于理解每个目标的依赖关系。

详细解释目标层级

1. 定义目标

在 CMake 中,每个目标通过诸如 add_executable()add_library() 等命令定义。这些目标可以是最终的可执行文件、静态库、动态库,甚至是一些中间的构建单元。

# 定义一个静态库目标
add_library(MyLib STATIC src/mylib.cpp)

# 定义一个可执行文件目标
add_executable(MyApp src/main.cpp)

2. 为目标设置属性

一旦定义了目标,就可以为其设置各种属性,如包含目录、编译选项、链接库等。这些属性通过目标层级的命令进行设置。

示例:为特定目标添加包含目录和链接库
# 为 MyLib 添加包含目录
target_include_directories(MyLib PUBLIC include/)

# 为 MyApp 链接 MyLib
target_link_libraries(MyApp PRIVATE MyLib)

在这个示例中:

  • MyLib 添加了一个包含目录 include/,并且通过 PUBLIC 关键字,这个包含目录对链接到 MyLib 的其他目标也可见。
  • MyApp 链接了 MyLib,并且通过 PRIVATE 关键字,表示 MyApp 使用 MyLib,但这个依赖不会传递给依赖 MyApp 的其他目标。

3. 目标之间的依赖关系

目标层级命令允许你清晰地定义目标之间的依赖关系,CMake 会自动处理这些依赖,确保正确的构建顺序。

示例:定义依赖关系
# 定义库目标
add_library(Utils STATIC src/utils.cpp)

# 定义可执行文件并链接库
add_executable(MyApp src/main.cpp)
target_link_libraries(MyApp PRIVATE Utils)

在这个例子中,MyApp 依赖于 Utils。CMake 会确保在构建 MyApp 之前先构建 Utils

4. 可见性关键字

在目标层级命令中,可以使用 PRIVATEPUBLICINTERFACE 关键字来控制属性的可见性和传递性。

  • PRIVATE:属性仅对当前目标可见。
  • PUBLIC:属性对当前目标及依赖它的其他目标可见。
  • INTERFACE:属性仅对依赖该目标的其他目标可见,不影响当前目标。
示例:使用可见性关键字
# 定义库目标
add_library(CoreLib STATIC src/core.cpp)

# 定义公共包含目录
target_include_directories(CoreLib PUBLIC include/core)

# 定义另一个库,依赖于 CoreLib
add_library(FeatureLib STATIC src/feature.cpp)
target_link_libraries(FeatureLib PRIVATE CoreLib)

# 定义可执行文件,依赖于 FeatureLib
add_executable(MyApp src/main.cpp)
target_link_libraries(MyApp PRIVATE FeatureLib)

在这个例子中:

  • CoreLib 的包含目录 include/corePUBLIC,因此任何链接 CoreLib 的目标(如 FeatureLib)也会继承这个包含目录。
  • FeatureLib 通过 PRIVATE 链接 CoreLib,意味着 MyApp 不会自动继承 CoreLib 的属性,除非显式指定。

为什么使用目标层级而不是全局命令?

  1. 模块化和可维护性:目标层级的配置使得每个目标的依赖关系和属性独立,便于维护和理解。
  2. 避免全局副作用:全局命令可能导致不可预期的行为,特别是在大型项目中,目标层级命令则提供了更高的隔离性。
  3. 自动依赖管理:CMake 能够根据目标之间的依赖关系自动处理构建顺序和链接顺序,减少手动配置的复杂性。
  4. 现代 CMake 最佳实践:现代 CMake 强调面向目标的配置方法,这种方法更灵活、强大且易于扩展。

进一步的示例

假设你有一个项目,包含一个核心库、一个功能库以及一个可执行文件。核心库依赖于一个外部库 mylib,功能库依赖于核心库,而可执行文件依赖于功能库。

CMakeLists.txt 示例

cmake_minimum_required(VERSION 3.13)
project(MyProject)

# 定义核心库
add_library(CoreLib STATIC src/core.cpp)

# 指定 CoreLib 的包含目录
target_include_directories(CoreLib PUBLIC include/core)

# 指定 CoreLib 的链接目录(假设 mylib 位于 /usr/local/lib)
target_link_directories(CoreLib PRIVATE /usr/local/lib)

# 链接 CoreLib 所需的外部库 mylib
target_link_libraries(CoreLib PRIVATE mylib)

# 定义功能库
add_library(FeatureLib STATIC src/feature.cpp)

# 链接 FeatureLib 依赖的 CoreLib
target_link_libraries(FeatureLib PUBLIC CoreLib)

# 定义可执行文件
add_executable(MyApp src/main.cpp)

# 链接 MyApp 依赖的 FeatureLib
target_link_libraries(MyApp PRIVATE FeatureLib)

解释

  1. CoreLib

    • 包含目录 include/core 对任何链接 CoreLib 的目标可见(PUBLIC)。
    • 链接目录 /usr/local/lib 仅对 CoreLib 本身有效(PRIVATE)。
    • 链接外部库 mylib 仅对 CoreLib 本身有效(PRIVATE)。
  2. FeatureLib

    • 通过 PUBLIC 关键字链接 CoreLib,这意味着任何链接 FeatureLib 的目标(如 MyApp)也会自动链接 CoreLib 并继承其 PUBLIC 属性(如包含目录)。
  3. MyApp

    • 通过 PRIVATE 关键字链接 FeatureLib,这意味着 MyApp 使用 FeatureLib,但不会将 FeatureLib 的依赖传递给其他目标(如果有的话)。

构建流程

  1. 构建顺序:CMake 自动识别 MyApp 依赖于 FeatureLib,而 FeatureLib 又依赖于 CoreLib,因此会按顺序构建 CoreLibFeatureLibMyApp
  2. 链接设置MyApp 会链接到 FeatureLib,而由于 FeatureLib 公共链接了 CoreLibMyApp 也会自动链接到 CoreLibPUBLIC 属性,如包含目录。

总结

目标层级在 CMake 中指的是围绕具体构建目标(如可执行文件、库)进行的配置和管理。与全局命令相比,目标层级命令提供了更高的封装性、可维护性和灵活性。通过将依赖关系和属性与特定目标绑定,CMake 能够更有效地管理复杂项目的构建过程。

关键点

  • 目标(Target):项目中构建的具体实体,如可执行文件、静态库、动态库等。
  • 目标层级命令:仅影响特定目标的命令,如 target_link_libraries()target_link_directories()
  • 可见性关键字PRIVATEPUBLICINTERFACE,用于控制属性的传播范围。
  • 现代 CMake 最佳实践:优先使用目标层级命令,避免全局命令,以实现更模块化和可维护的构建配置。

标签:Cmake,CoreLib,directories,目标,add,link,FeatureLib,MyApp,include
From: https://blog.csdn.net/qq_45993770/article/details/143158133

相关文章

  • cmake中link_directories()与link_libraried()全局性的理解
    在CMake中,link_directories()和link_libraries()是全局命令,这意味着它们的设置会影响之后在CMakeLists.txt文件中定义的所有目标(targets)。要深入理解这一点,下面将详细解释全局命令的作用范围、它们如何影响项目中的多个目标、以及为什么在现代CMake中更推荐使用......
  • cmake学习笔记
    最近在学cmake的用法,参考了cmake使用详细教程(日常使用这一篇就足够了)这篇文章,这篇文章讲的很仔细,下面记录自己的学习过程。1、系统以及开发工具一开始想通过虚拟机安装Ubuntu和vscode,后面想到了之前本机Windows安装过wsl,wsl的就是Ubuntu,在wsl+本地vscode的开发下,很快就把文章......
  • ubuntu更新Cmake
    CMake先验知识创建软链接如何删除符号链接如何找出失效链接并将其删除PATH优先级查看当前CMake命令的位置高版本CMake安装参考先验知识创建软链接ln-s<pathtothefile/foldertobelinked><thepathofthelinktobecreated>ln是链接命令,-s指定此......
  • cmake使用方法
    CMake是一个跨平台的构建系统生成器,广泛用于C++项目。它允许开发者编写平台无关的构建脚本(称为`CMakeLists.txt`),然后在不同的平台上生成对应的构建文件(如Makefile、VisualStudio项目文件等)。以下是使用CMake的基本步骤和一些常见的用法。 ###安装CMake首先,你需......
  • windows下基于cmake配置opencv并使用visual studio编译
     在Windows上下载并编译OpenCV,然后配置系统环境变量的步骤如下:1.下载OpenCV打开OpenCV官方下载页面。找到最新的Windows版本,点击下载,例如:opencv-4.x.x-vc14_vc15.exe,这将是一个自解压文件。下载完成后,双击opencv-4.x.x-vc14_vc15.exe文件,选择一个目录将其解压,......
  • 简单的cmake使用
    使用CMakeLists.txt生成可执行文件编写一个最简单的CMakeLists以生成可执行文件,仅需要以下三步指明最小支持的cmake版本cmake_minimum_required指明项目的代号或者说名称project使用add_executable来生成可执行文件其中add_executable参数为可执行文件名称,后面跟着源文......
  • cmake使用笔记
    cmake_cxx_flags常用值在CMake中,CMAKE_CXX_FLAGS是一个用于指定C++编译器选项的变量。你可以将不同的编译选项添加到这个变量中,以影响编译过程的行为。以下是一些常用的CMAKE_CXX_FLAGS值及其说明:1.优化选项1.-O0:禁用优化(默认选项)。2.-O1:启用一级优化。3.-O2:启用二......
  • cmakelist 源码生成so 文件 orthanc mysql
    cmakelist.txt#Orthanc-ALightweight,RESTfulDICOMStore#Copyright(C)2012-2016SebastienJodogne,MedicalPhysics#Department,UniversityHospitalofLiege,Belgium#Copyright(C)2017-2023OsimisS.A.,Belgium#Copyright(C)2024-2024Orthanc......
  • CMake 属性之目录属性
    【写在前面】CMake的目录属性是指在特定目录(及其子目录)范围内有效的设置。这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。通过目录属性,你可以指定编译器选项、包含路径、预处理定义等,而无需在每个目标或文件中重......
  • CMake 属性之目录属性
     【写在前面】        CMake的目录属性是指在特定目录(及其子目录)范围内有效的设置。        这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。        通过目录属性,你可以指定编译器......