CMake execute_process用法详解

news2025/4/22 17:01:52

execute_process 是 CMake 中的一个命令,用于在 CMake 配置阶段(即运行 cmake 命令时)执行外部进程。它与 add_custom_commandadd_custom_target 不同,后者是在构建阶段(如 makeninja)执行命令。execute_process 通常用于获取系统信息、生成代码或处理依赖项。


基本语法

execute_process(
    COMMAND <cmd1> [<args1>]
    [COMMAND <cmd2> [<args2>] ...]
    [WORKING_DIRECTORY <dir>]
    [TIMEOUT <seconds>]
    [RESULT_VARIABLE <var>]
    [OUTPUT_VARIABLE <var>]
    [ERROR_VARIABLE <var>]
    [INPUT_FILE <file>]
    [OUTPUT_FILE <file>]
    [ERROR_FILE <file>]
    [OUTPUT_QUIET]
    [ERROR_QUIET]
    [COMMAND_ECHO <where>]
    [ENCODING <encoding>]
    [ECHO_OUTPUT_VARIABLE]
    [ECHO_ERROR_VARIABLE]
    [OUTPUT_STRIP_TRAILING_WHITESPACE]
    [ERROR_STRIP_TRAILING_WHITESPACE]
)

参数详解

1. COMMAND (必需)

指定要执行的命令及其参数。可以链式调用多个命令,按顺序执行(类似 Shell 的管道 |)。

execute_process(
  COMMAND echo "Hello"
  COMMAND sed "s/Hello/Hi/"
)
# 输出 "Hi"
2. WORKING_DIRECTORY

设置命令执行的工作目录。

execute_process(
  COMMAND pwd
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/subdir
)
3. TIMEOUT

设置超时时间(秒),超时后终止进程。

execute_process(
  COMMAND sleep 10
  TIMEOUT 5  # 5 秒后终止
)
4. RESULT_VARIABLE

保存命令执行的返回值(退出码)。通常 0 表示成功,非 0 表示错误。

execute_process(
  COMMAND git rev-parse --verify HEAD
  RESULT_VARIABLE git_result
)
if(NOT git_result EQUAL 0)
  message(FATAL_ERROR "Git failed!")
endif()
5. OUTPUT_VARIABLEERROR_VARIABLE

捕获命令的标准输出(stdout)和标准错误(stderr)。

execute_process(
  COMMAND ls non_existent_file
  OUTPUT_VARIABLE out
  ERROR_VARIABLE err
)
message("Output: ${out}")  # 空
message("Error: ${err}")   # 显示错误信息
6. OUTPUT_STRIP_TRAILING_WHITESPACE

删除输出末尾的空白字符(如换行符)。

execute_process(
  COMMAND echo "Hello World   "
  OUTPUT_VARIABLE out
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("Output: [${out}]")  # 输出 "Hello World"
7. INPUT_FILE, OUTPUT_FILE, ERROR_FILE

将输入、输出、错误重定向到文件。

execute_process(
  COMMAND my_tool
  INPUT_FILE input.txt
  OUTPUT_FILE output.txt
  ERROR_FILE error.log
)

常见用法示例

1. 执行命令并获取输出
execute_process(
  COMMAND uname -s
  OUTPUT_VARIABLE OS_NAME
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
message("OS: ${OS_NAME}")  # 如 "Linux", "Darwin"
2. 检查命令是否成功
execute_process(
  COMMAND which python3
  RESULT_VARIABLE result
  OUTPUT_QUIET
)
if(result EQUAL 0)
  message("Python3 found")
else()
  message(FATAL_ERROR "Python3 not found")
endif()
3. 链式命令(管道)
execute_process(
  COMMAND cat ${CMAKE_SOURCE_DIR}/data.txt
  COMMAND grep "important"
  COMMAND wc -l
  OUTPUT_VARIABLE line_count
)
4. 处理错误输出
execute_process(
  COMMAND gcc --version
  ERROR_VARIABLE gcc_error
  OUTPUT_VARIABLE gcc_output
)
if(gcc_error)
  message("Error: ${gcc_error}")
else()
  message("Output: ${gcc_output}")
endif()

注意事项

  1. 执行时机execute_process 在 CMake 配置阶段立即执行,若命令耗时较长,可能拖慢配置过程。
  2. 跨平台兼容性:命令在不同平台下可能需要调整(如 cmd.exe vs bash)。
  3. 输出处理:若输出内容较大,建议重定向到文件而非变量。
  4. 错误处理:始终检查 RESULT_VARIABLE 以确保命令成功。

add_custom_command 的区别

  • execute_process: 在配置阶段运行,直接影响 CMake 变量和后续流程。
  • add_custom_command: 在构建阶段运行,生成文件或触发其他构建步骤。

根据需求选择合适的命令!


你提到的执行时机问题非常重要,也是很多 CMake 初学者容易混淆的地方。我们通过一个具体的例子和对比来彻底理解 execute_process 的执行时机。


CMake 的两个阶段

CMake 的工作流程分为两个阶段:

  1. 配置阶段 (Configure Time)

    • 运行 cmake 命令时发生(如 cmake -B build
    • 此时会执行所有 execute_process 命令
    • 生成构建系统文件(如 Makefilebuild.ninja
  2. 构建阶段 (Build Time)

    • 运行构建命令时发生(如 makeninja
    • 此时会执行 add_custom_commandadd_custom_target 中定义的命令

例子对比

假设我们有两个 CMake 脚本:

案例 1:使用 execute_process(配置阶段执行)
# CMakeLists.txt
message("=== 配置阶段开始 ===")

execute_process(
  COMMAND echo "正在生成 version.h (配置阶段)"
  COMMAND bash -c "echo '#define VERSION \"1.0.0\"' > version.h"
)

add_executable(my_app main.cpp version.h)
message("=== 配置阶段结束 ===")

运行结果:

$ cmake -B build
=== 配置阶段开始 ===
正在生成 version.h (配置阶段)  # 立即执行!
=== 配置阶段结束 ===
Generating done.

$ ls build/version.h  # 文件已生成
version.h

$ make                # 构建阶段不会重新生成 version.h
[100%] Built target my_app
案例 2:使用 add_custom_command(构建阶段执行)
# CMakeLists.txt
message("=== 配置阶段开始 ===")

add_custom_command(
  OUTPUT version.h
  COMMAND echo "正在生成 version.h (构建阶段)"
  COMMAND bash -c "echo '#define VERSION \"1.0.0\"' > version.h"
)

add_executable(my_app main.cpp version.h)
message("=== 配置阶段结束 ===")

运行结果:

$ cmake -B build
=== 配置阶段开始 ===
=== 配置阶段结束 ===  # 此时没有生成 version.h
Generating done.

$ ls build/version.h  # 文件不存在
ls: cannot access 'build/version.h': No such file or directory

$ make                # 构建阶段生成 version.h
[ 50%] Generating version.h
正在生成 version.h (构建阶段)
[100%] Built target my_app

关键差异总结

特性execute_processadd_custom_command
执行时机配置阶段 (cmake 运行时)构建阶段 (makeninja 运行时)
执行次数每次运行 cmake 时执行一次每次构建时执行(如果输出需要更新)
典型用途获取系统信息、预生成配置文件编译时生成代码、处理构建依赖
能否影响构建规则不能直接定义构建系统的依赖关系可以定义构建依赖关系

什么时候用 execute_process

  1. 需要立即获取信息
    例如:检测编译器特性、查询 Git 提交哈希、检查系统库是否存在。

    # 在配置阶段获取 Git 提交 ID
    execute_process(
      COMMAND git log -1 --format=%h
      OUTPUT_VARIABLE GIT_COMMIT_HASH
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    configure_file(config.h.in config.h)  # 将 GIT_COMMIT_HASH 写入头文件
    
  2. 生成构建所需的初始文件
    例如:生成默认配置文件(如果文件不存在)。

    if(NOT EXISTS "${CMAKE_SOURCE_DIR}/config.json")
      execute_process(
        COMMAND cp "${CMAKE_SOURCE_DIR}/config.default.json" 
                    "${CMAKE_SOURCE_DIR}/config.json"
      )
    endif()
    

什么时候用 add_custom_command

  1. 需要在构建时生成文件
    例如:用 Protobuf 生成代码、在编译前预处理资源文件。

    add_custom_command(
      OUTPUT generated_code.cpp
      COMMAND protoc --cpp_out=. my.proto
      DEPENDS my.proto
    )
    add_executable(app main.cpp generated_code.cpp)
    
  2. 构建时需要动态更新内容
    例如:每次构建时更新版本时间戳。

    add_custom_command(
      OUTPUT timestamp.h
      COMMAND bash -c "date +'#define TIMESTAMP \"%Y-%m-%d %H:%M:%S\"' > timestamp.h"
    )
    add_executable(app main.cpp timestamp.h)
    

易错场景分析

错误:期望 execute_process 在每次构建时运行
# ❌ 错误:这个文件只会在运行 cmake 时生成一次
execute_process(
  COMMAND echo "#define BUILD_COUNT 1" > build_count.h
)

# ✅ 正确:使用 add_custom_command 在每次构建时更新
add_custom_command(
  OUTPUT build_count.h
  COMMAND bash -c "echo '#define BUILD_COUNT $(($(cat build_count.h 2>/dev/null | cut -d' ' -f3) + 1))' > build_count.h"
)
错误:在 execute_process 中生成未跟踪的文件
execute_process(
  COMMAND touch some_file.txt  # 生成的文件不会被 CMake 自动跟踪
)

# ✅ 正确:显式声明生成的文件
add_custom_command(
  OUTPUT some_file.txt
  COMMAND touch some_file.txt
)
add_executable(app main.cpp some_file.txt)  # 建立依赖关系

总结

  • execute_process配置阶段的“一次性操作”,适合做初始化工作。
  • 如果你需要 在构建时动态生成内容定义构建依赖关系,应该使用 add_custom_command
  • 可以通过以下命令直观观察执行时机:
    # 查看配置阶段的输出
    cmake -B build
    
    # 查看构建阶段的输出
    cmake --build build --verbose
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模型加载常见问题

safetensors_rust.SafetensorError: Error while deserializing header: HeaderTooLarge 问题代码&#xff1a; model AutoModelForVision2Seq.from_pretrained( "/data-nvme/yang/Qwen2.5-VL-32B-Instruct", trust_remote_codeTrue, torch_dtypetorc…

PyTorch 深度学习实战(37):分布式训练(DP/DDP/Deepspeed)实战

在上一篇文章中&#xff0c;我们探讨了混合精度训练与梯度缩放技术。本文将深入介绍分布式训练的三种主流方法&#xff1a;Data Parallel (DP)、Distributed Data Parallel (DDP) 和 DeepSpeed&#xff0c;帮助您掌握大规模模型训练的关键技术。我们将使用PyTorch在CIFAR-10分类…

微信小程序通过mqtt控制esp32

目录 1.注册巴法云 2.设备连接mqtt 3.微信小程序 备注 本文esp32用的是MicroPython固件&#xff0c;MQTT服务用的是巴法云。 本文参考巴法云官方教程&#xff1a;https://bemfa.blog.csdn.net/article/details/115282152 1.注册巴法云 注册登陆并新建一个topic&#xff…

1.Vue3 - 创建Vue3工程

目录 一、 基于vue-cli 脚手架二、基于vite 推荐2.1 介绍2.2 创建项目2.3 文件介绍2.3.1 extensions.json2.3.2 脚手架的根目录2.3.3 主要文件 src2.3.3.1 main.js2.3.3.2 App.vue 组件2.3.3.3 conponents 2.3.4 env.d.ts2.3.5 index.html 入口文件2.3.6 package2.3.7 tsconfig…

AI编写的“黑科技风格、自动刷新”的看板页面

以下的 index.html 、 script.js 和 styles.css 文件&#xff0c;实现一个具有黑科技风格、自动刷新的能源管理系统实时监控看板。 html页面 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name&q…

11-DevOps-Jenkins Pipeline流水线作业

前面已经完成了&#xff0c;通过在Jenkins中创建自由风格的工程&#xff0c;在界面上的配置&#xff0c;完成了发布、构建的过程。 这种方式的缺点就是如果要在另一台机器上进行同样的配置&#xff0c;需要一项一项去填写&#xff0c;不方便迁移&#xff0c;操作比较麻烦。 解…

【JavaWeb后端开发03】MySQL入门

文章目录 1. 前言1.1 引言1.2 相关概念 2. MySQL概述2.1 安装2.2 连接2.2.1 介绍2.2.2 企业使用方式(了解) 2.3 数据模型2.3.1 **关系型数据库&#xff08;RDBMS&#xff09;**2.3.2 数据模型 3. SQL语句3.1 DDL语句3.1.1 数据库操作3.1.1.1 查询数据库3.1.1.2 创建数据库3.1.1…

Github 热点项目 Jumpserver开源堡垒机让服务器管理效率翻倍

Jumpserver今日喜提160星&#xff0c;总星飙至2.6万&#xff01;这个开源堡垒机有三大亮点&#xff1a;① 像哆啦A梦的口袋&#xff0c;支持多云服务器一站式管理&#xff1b;② 安全审计功能超硬核&#xff0c;操作记录随时可回放&#xff1b;③ 网页终端无需装插件&#xff0…

第七届传智杯全国IT技能大赛程序设计赛道 国赛(总决赛)—— (B组)题解

1.小苯的木棍切割 【解析】首先我们先对数列排序&#xff0c;找到其中最小的数&#xff0c;那么我们就保证了对于任意一个第i1个的值都会大于第i个的值那么第i2个的值也比第i个大&#xff0c;那么我们第i1次切木棍的时候一定会当第i个的值就变为了0的&#xff0c;第i1减去的应该…

Netty前置基础知识之BIO、NIO以及AIO理论详细解析和实战案例

前言 Netty是什么&#xff1f; Netty 是一个基于 Java 的 ​高性能异步事件驱动网络应用框架&#xff0c;主要用于快速开发可维护的协议服务器和客户端。它简化了网络编程的复杂性&#xff0c;特别适合构建需要处理海量并发连接、低延迟和高吞吐量的分布式系统。 1)Netty 是…

开源身份和访问管理(IAM)解决方案:Keycloak

一、Keycloak介绍 1、什么是 Keycloak&#xff1f; Keycloak 是一个开源的身份和访问管理&#xff08;Identity and Access Management - IAM&#xff09;解决方案。它旨在为现代应用程序和服务提供安全保障&#xff0c;简化身份验证和授权过程。Keycloak 提供了集中式的用户…

深入理解 TCP 协议 | 流量、拥塞及错误控制机制

注&#xff1a;本文为 “TCP 协议” 相关文章合辑。 原文为繁体&#xff0c;注意术语描述差异。 略作重排&#xff0c;如有内容异常&#xff0c;请看原文。 作者在不同的文章中互相引用其不同文章&#xff0c;一并汇总于此。 可从本文右侧目录直达本文主题相关的部分&#xff…

VSCode远程图形化GDB

VSCode远程图形化GDB 摘要一、安装VSCode1、使用.exe安装包安装VSCode2、VSCode 插件安装3、VSCode建立远程连接 二、core dump找bug1、开启core文件2、永久生效的方法3、编写测试程序4、运行结果5、查看core段错误位置6、在程序中开启core dump并二者core文件大小 三、gdbserv…

软件工程师中级考试-上午知识点总结(上)

我总结的这些都是每年的考点&#xff0c;必须要记下来的。 1. 计算机系统基础 1.1 码 符号位0表示正数&#xff0c;符号位1表示负数。补码&#xff1a;简化运算部件的设计&#xff0c;最适合进行数字加减运算。移码&#xff1a;与前几种不同&#xff0c;1表示&#xff0c;0表…

基于FreeRTOS和STM32的微波炉

一、项目简介 使用STM32F103C8T6、舵机、继电器、加热片、蜂鸣器、两个按键、LCD及DHT11传感器等硬件。进一步&#xff0c;结合FreeRTOS和状态机等软件实现了一个微波炉系统&#xff1b;实现的功能包含&#xff1a;人机交互、时间及功率设置、异常情况处理及固件升级等。 二、…

国防科大清华城市空间无人机导航推理!GeoNav:赋予多模态大模型地理空间推理能力,实现语言指令导向的空中目标导航

作者&#xff1a; Haotian Xu 1 ^{1} 1, Yue Hu 1 ^{1} 1, Chen Gao 2 ^{2} 2, Zhengqiu Zhu 1 ^{1} 1, Yong Zhao 1 ^{1} 1, Yong Li 2 ^{2} 2, Quanjun Yin 1 ^{1} 1单位&#xff1a; 1 ^{1} 1国防科技大学系统工程学院&#xff0c; 2 ^{2} 2清华大学论文标题&#xff1a;Geo…

uniapp打ios包

uniapp在windows电脑下申请证书并打包上架 前言 该开发笔记记录了在window系统下&#xff0c;在苹果开发者网站生成不同证书&#xff0c;进行uniapp打包调试和上线发布&#xff0c;对window用户友好 注&#xff1a;苹果打包涉及到两种证书&#xff1a;开发证书 和 分发证书 …

快速搭建 Cpolar 内网穿透(Mac 系统)

1、Cpolar快速入门教程&#xff08;官方&#xff09; 链接地址&#xff1a;Cpolar 快速入门 2、官方教程详解 本地安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"这个是从 git 上拉取的&#x…

动态监控进程

1.介绍: top和ps命令很相似,它们都是用来显示正在执行的进程,top和ps最大的不同之处,在于top在执行中可以更新正在执行的进程. 2.基本语法&#xff1a; top [选项] 选项说明 ⭐️僵死进程&#xff1a;内存没有释放,但是进程已经停止工作了,需要及时清理 交互操作说明 应用案…

HADOOP 3.4.1安装和搭建(尚硅谷版~)

目录 1.配置模版虚拟机 2.克隆虚拟机 3.在hadoop102安装JDK 4.完全分布式运行模式 1.配置模版虚拟机 1.安装模板虚拟机&#xff0c;IP地址192.168.10.100、主机名称hadoop100、内存2G、硬盘20G&#xff08;有需求的可以配置4G内存&#xff0c;50G硬盘&#xff09; 2.hado…