当前位置: 首页 > news >正文

CMake目标依赖关系解析

直接回答:是的,当你执行 cmake --build build -t prebuilt 时,CMake 会去执行 ${prebuilt_target}


详细解释:为什么它会执行?

原因就在于你代码中的最后一行:add_dependencies(prebuilt ${prebuilt_target})

这行代码建立了一个明确的依赖关系。我们来分解一下:

  1. prebuilt 是什么?
    你提到“我并没有指定prebuilt这个变量作为一个target”,这通常是误解的关键。在你的CMakeLists.txt文件中,肯定在某处有一个地方通过 add_custom_targetadd_executableadd_library 创建了一个名为 prebuilt 的目标。
    例如,很可能有这样一行代码:

    add_custom_target(prebuilt ...)
    

    这个 prebuilt 目标是一个“顶级”目标,它的唯一目的可能就是聚合其他像 ${prebuilt_target} 这样的子任务。

  2. add_dependencies 的作用
    add_dependencies(target-name depends-target1 depends-target2 ...) 这条命令的作用是告诉CMake:

    在开始构建 target-name 之前,必须确保 depends-target1, depends-target2 等所有依赖项都已经成功构建。

    这意味着,prebuilt 目标依赖于 ${prebuilt_target} 目标。

  3. 构建时的逻辑链
    当你运行 cmake --build build -t prebuilt-t--target 的缩写)时,你是在命令CMake:“请构建名为 prebuilt 的目标”。

    CMake的构建系统会这样处理:

    • “用户要构建 prebuilt。”
    • “检查一下,prebuilt 依赖于 ${prebuilt_target}。”
    • “好的,那我首先必须确保 ${prebuilt_target} 是最新的并且已经执行。”
    • 执行 ${prebuilt_target} 目标定义的命令(即你的 cp -f 复制操作)。
    • 一旦 ${prebuilt_target} 执行完成,prebuilt 目标本身的构建(可能没有任何实际操作)就被认为完成了。

总结一下: 你不是通过“变量”来指定,而是通过 add_dependencies 命令,将 ${prebuilt_target} 添加为 prebuilt 这个已存在目标的依赖项。因此,构建 prebuilt 必然会先触发其所有依赖项的构建。


一个简单的类比

这就像是一个Makefile中的规则:

all: prebuiltprebuilt: copy_task@echo "All prebuilts are done."copy_task:cp file_a.txt /destination/

当你运行 make prebuilt 时,make 会首先去执行 copy_task,因为它是一个依赖项。CMake中的 add_dependencies 就实现了类似 prebuilt: copy_task 的依赖关系。


额外建议和改进

你的代码虽然功能正确,但可以写得更现代、更清晰一些:

  1. 使用 cmake -E copy 代替 bash -c/cp: 这使得命令与平台无关(在Windows上也能工作,无需bash)。
  2. 使用 DEPENDS 参数add_custom_targetadd_custom_commandDEPENDS 参数是更精确地指定文件级依赖关系的方式。
  3. 避免重复查找: 如果 ${lib} 是一个明确的文件名,find 可能会在构建目录中意外找到多个同名文件。最好在配置阶段就确定库的完整路径。

改进后的版本可能类似于:

# 假设你已经在某个地方通过 find_library 或 get_target_property 获取了库的完整路径
# 并保存在一个变量里,比如 ${FULL_LIB_PATH}add_custom_target(${prebuilt_target} ALLCOMMAND${CMAKE_COMMAND} -E copy_if_different${FULL_LIB_PATH}${PREBUILT_LIB_PATH}/COMMENT "Copying ${lib} to prebuilt path: ${PREBUILT_LIB_PATH}"VERBATIM
)# 如果 prebuilt 目标存在,仍然添加依赖关系
if(TARGET prebuilt)add_dependencies(prebuilt ${prebuilt_target})
endif()

你可以直接使用 cmake --build <build_dir> -t <specific_target> 来只构建 prebuilt_target 集合中的某一个特定目标(比如一个通过 add_library 添加的库)。

这是一个非常常见且高效的开发工作流。

原理是什么?

这个功能的原理在于CMake构建系统的模块化目标化设计:

  1. 每个目标都是独立的实体
    每当你在CMake中使用 add_library(my_lib ...)add_executable(my_exe ...)add_custom_target(my_custom_target ...) 时,你都是在定义一个独立的、命名的构建目标

  2. 生成的构建系统文件
    CMake会根据你的 CMakeLists.txt 生成底层构建系统(如 Makefile 或 Ninja.build)的文件。在这个生成的系统中,每个CMake目标都会对应一个构建规则或目标

    • 如果你使用 Makefile 生成器,会生成一个名为 my_libmake 目标。
    • 如果你使用 Ninja 生成器,会生成一个名为 my_libninja 构建目标。
  3. --target (-t) 参数的作用
    cmake --build 命令是一个跨平台的通用命令,它是对底层构建工具(如 make, ninja, msbuild 等)的封装。--target 参数的作用就是将这个参数直接传递给底层的构建工具

    所以,当你运行:

    cmake --build build -t my_lib
    

    它实际上等价于:

    • 在Makefile生成器上cd build && make my_lib
    • 在Ninja生成器上cd build && ninja my_lib
  4. 依赖关系的自动处理
    底层构建工具(make/ninja)的核心功能就是处理依赖关系图。当你要求构建 my_lib 时,构建工具会:

    • 查看它的依赖项(例如,由 target_link_libraries(my_lib PRIVATE some_dependency)add_dependencies(my_lib some_dependency) 定义的)。
    • 自动地、按正确的顺序先去构建所有它依赖的、并且尚未构建或已过期的目标。
    • 最后再构建 my_lib 本身。

举例说明

假设你的CMakeLists.txt如下:

cmake_minimum_required(VERSION 3.10)
project(MyProject)# 添加两个库目标
add_library(network_lib network.cpp)
add_library(math_lib math.cpp)# 添加一个可执行文件,依赖这两个库
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE network_lib math_lib)# 添加一个自定义的“集合”目标,方便一键构建所有库
add_custom_target(prebuilt_libsDEPENDS network_lib math_lib # 这个custom target依赖于两个库目标COMMENT "All prebuilt libraries are up to date."
)

在这个项目中,你有多个可以独立构建的目标

  • network_lib
  • math_lib
  • my_app
  • prebuilt_libs

你可以这样使用:

  1. 只构建 math_lib 及其依赖

    cmake --build build -t math_lib
    

    这会只编译 math.cpp 并生成 libmath_lib.a(或在Windows上是 math_lib.lib)。它不会碰 network.cppmain.cpp

  2. 只构建 network_lib

    cmake --build build -t network_lib
    
  3. 构建整个应用程序 my_app

    cmake --build build -t my_app
    

    这会自动先检查并构建 network_libmath_lib(如果它们需要更新),然后再链接生成 my_app 可执行文件。

  4. 构建你定义的“集合”目标 prebuilt_libs

    cmake --build build -t prebuilt_libs
    

    这会触发构建 network_libmath_lib,因为它们被列为 DEPENDS

总结

  • 可以:直接使用 -t <target_name> 构建任何一个在CMake中明确定义的目标(库、可执行文件、自定义目标),无论它是否是另一个更大目标的依赖项。
  • 原理:CMake为每个目标在底层构建系统中生成了对应的规则。--build -t 命令直接将目标名称传递给底层工具(make/ninja),由后者负责解析依赖图并执行最小范围的必要构建操作。

这是一种非常推荐的做法,特别是在大型项目中,可以极大地节省开发时的构建时间。你不需要每次都构建整个项目,只需构建你正在修改的那个模块即可。


文章转载自:

http://kM2hIGwv.cwyfs.cn
http://42LdGDpJ.cwyfs.cn
http://AXOBR3bm.cwyfs.cn
http://F0GYtZ9h.cwyfs.cn
http://HvifYuZB.cwyfs.cn
http://hFMPzTVk.cwyfs.cn
http://yB9fdOPU.cwyfs.cn
http://zsTRSaYx.cwyfs.cn
http://TJyuiXZS.cwyfs.cn
http://6fthQ7GX.cwyfs.cn
http://TF1qh9Zc.cwyfs.cn
http://OFtuHMkV.cwyfs.cn
http://wPbRSCd7.cwyfs.cn
http://wzRByTcG.cwyfs.cn
http://zKoVLH7L.cwyfs.cn
http://nIjdnKdc.cwyfs.cn
http://G0bVBbxo.cwyfs.cn
http://qRdservo.cwyfs.cn
http://qntH3eWM.cwyfs.cn
http://MlFH2XhZ.cwyfs.cn
http://SJVB2BRM.cwyfs.cn
http://XXotFpWT.cwyfs.cn
http://l4PlFxSK.cwyfs.cn
http://4ZceSkln.cwyfs.cn
http://698L8QJj.cwyfs.cn
http://9JMaEzFA.cwyfs.cn
http://gyp9AI3n.cwyfs.cn
http://szjz86TG.cwyfs.cn
http://TPooFTG0.cwyfs.cn
http://bvVCJVKj.cwyfs.cn
http://www.dtcms.com/a/377367.html

相关文章:

  • 小型企业常用的元数据管理工具
  • 论文AI写作哪个软件好?实测对比5款热门AI写作工具
  • PostgreSQL 内机器学习的关键智能算法研究
  • 12公里无人机图传模组:从模糊到超高清的飞跃,抗干扰能力全面升级
  • GitHub Actions中steps下面的Setup environment设置的环境变量不能在后面步骤使用问题处理
  • YOLOv5实战-GPU版本的pytorch虚拟环境配置
  • 苍穹外卖项目实战(day7-2)-购物车操作功能完善-记录实战教程、问题的解决方法以及完整代码
  • 【VsCode】离线状态下安装插件
  • 浏览器开发CEFSharp (十七)网页自定义下载—仙盟创梦IDE
  • Nodejs读取目录下面的文件
  • docker 重命名镜像
  • 「CTF」青少年CTF·雏形系统
  • 光子计算芯片实战:Lightmatter Passage互连架构性能评测
  • 实时多模态电力交易决策系统:设计与实现
  • 条码控件Aspose.BarCode教程:使用 C# 构建 Code11 条形码生成器
  • 分布式专题——7 Redis Stack扩展功能
  • QuestionPicture:一键批量改图,支持压缩图片
  • Prompt提示词(保姆级教程)
  • SSM病房管理信息系统o45h4(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • SpreadJS:让多源数据筛选排序如 Excel 般便捷高效
  • ARM内存映射与启动地址重映射机制解析
  • 如何使用 QuickAPI 快速连接 MySQL 数据库并发布 RESTful API
  • PAT 1104 Sum of Number Segments
  • LeetCode 热题 3.无重复字符的最长子串
  • 抓虫:unshared后执行命令dump
  • 自定义类型:结构体、枚举、联合
  • SnowPro Core Certification
  • Java 大视界 -- Java 大数据机器学习模型在金融市场情绪分析与投资决策辅助中的应用
  • C++ 学习与 CLion 使用:(十三)分别提供了 CLion 中使用 cout 和 cin 中文乱码的问题
  • 容器编排工具Docker Copmose