cmake执行命令详解

本文最后更新于:2025年11月19日 下午

本文介绍add_custom_target和add_custom_command和execute_process命令。

cmake构建可粗分为配置、生成阶段和构建阶段。配置、生成阶段。

配置阶段时执行命令

execute_process

原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
execute_process(COMMAND <cmd1> [<arguments>]
[COMMAND <cmd2> [<arguments>]]...
[WORKING_DIRECTORY <directory>] 工作目录
[TIMEOUT <seconds>] 超时时间
[RESULT_VARIABLE <variable>]
[RESULTS_VARIABLE <variable>]
[OUTPUT_VARIABLE <variable>] 标准输出变量
[ERROR_VARIABLE <variable>] 错误输出道变量
[INPUT_FILE <file>]
[OUTPUT_FILE <file>]
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
[COMMAND_ECHO <where>]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>] 输出编码
[ECHO_OUTPUT_VARIABLE]
[ECHO_ERROR_VARIABLE]
[COMMAND_ERROR_IS_FATAL <ANY|LAST>])

注意
(1)当有多个COMMAND时,命令会以管道的形式组合起来
(2)虽然多个命令会以管道连接,但是命令的执行是并性的。例如写三个sleep 3的命令,配置阶段整个只会睡眠3s,而不是9s。
(3)如果要顺序执行多个命令,可多次调用execute_process命令,且每一个命令中仅使用一个COMMAND参数指定一个命令。
(4)如果想要命令既能输出到终端中,又可以存入变量中,那么就需要设置下面这两个参数ECHO_OUTPUT_VARIABLE,ECHO_ERROR_VARIABLE
(5)要删除命令输出结尾处的空白,可以设置OUTPUT_STRIP_TRAILING_WHITESPACE
(6)命令只在配置时运行,构建时不会运行。即修改c源代码,make时不会运行命令。但是修改CMakeLists.txt后,会重新配置,它才会运行。
(7)执行awk,用双引号包裹:

1
COMMAND /bin/bash -c "awk '/^#/{printf \"-Wl,--wrap=%s \", $2}' ${CMAKE_CURRENT_SOURCE_DIR}/impl_list.txt"

举例:将当前日期存入变量

1
2
3
4
# 把程序结果输出到一个变量
execute_process(COMMAND date OUTPUT_VARIABLE cur_data)
# 打印这个变量
message("cur_data: ${cur_data}")

构建阶段执行命令

add_custom_target

[官方文档][https://cmake.org/cmake/help/latest/command/add_custom_target.html#add-custom-target]

add_custom_target用于指定类似makefile里面的伪目标,它不生成文件,而且cmake也认为它一直是过时的,即如果有目标依赖它,它总是会执行。

1
2
3
4
5
6
7
8
9
10
11
add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[JOB_POOL job_pool]
[JOB_SERVER_AWARE <bool>]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])

注意:
(1)默认情况下,没有任何目标依赖于自定义目标,换句话说,它不会被触发执行(除非手动指定构建它:cmake –build . –target yourtarget).
因此它一般与add_dependencies,add_custom_command结合起来使用。
(2)添加ALL参数后,这个目标会添加到all的依赖里面。
(3)只要有人依赖它,命令就总是执行,不管DEPENDS是否更新
(4)指定VERBATIM参数后,CMake会针对不同构建系统将<命令行参数>自动转义,以确保最终调用的命令行参数与该命令参数一致。推荐始终指定VERBATIM参数
(5)所有的命令公用一个工作目录,要不同的命令使用不同的目录,要借助${CMAKE_COMMAND} -E chdir命令来执行

1
2
3
4
add_custom_target(test
COMMAND ${CMAKE_COMMAND} -E chdir /etc pwd
COMMAND ${CMAKE_COMMAND} -E chdir /tmp pwd
)

(6)设置命令执行的环境变量也可通过${CMAKE_COMMAND} -E env AA=aa指定

举例-解压配置代码
有时需要在编译前先下载源码

1
2
3
4
5
6
add_custom_target(pre_build
COMMAND tar -xf yourcode.tar.gz
COMMAND {CMAKE_COMMAND} -E chdir yourcode ./configure
)
add_executable(test main.c)
add_dependencies(test pre_build)

add_custom_command

官方文档

作用1–生成构建所需文件

生成文件需要指定OUTPUT,它的参数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
add_custom_command(OUTPUT output1 [output2 ...] 生成的文件
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]] 依赖
[BYPRODUCTS [files...]]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
[JOB_POOL job_pool]
[JOB_SERVER_AWARE <bool>]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[DEPENDS_EXPLICIT_ONLY])

注意:
(1)该命令仅用于定义如何生成文件,但生成规则对应的命令并不会立即执行,因此文件也不会在命令调用后立即生成。只有当该命令指定的<生成文件>在构建过程中被引用时,这些生成规则对应的命令才会执行,文件才会被生成
(2)BYPRODUCTS用于指定副生成文件,主生成的文件和副生成的文件在执行make clean时都会被删除

举例:生成编译所需的c文件:

1
2
3
4
5
add_custom_command(
OUTPUT out.c
COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt -o out.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt)
add_library(myLib out.c)

out.c由自定义命令生成

举例:生成编译所需的.h文件

1
2
3
4
5
6
7
8
9
10
# 添加生成out.h的命令
add_custom_command(
OUTPUT out.h
COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt -o out.h
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt)
# 添加target
add_custom_target(GenerateHeader DEPENDS out.h)
add_library(myLib out.c)
# 添加依赖
add_dependencies(myLib GenerateHeader)

和.c文件不一样的是,.h文件需要手动指定依赖
注意:为何不直接在add_custom_target内运行命令来生成?这样的话,每次都会重新生成这个文件了。

作用2 - 构建事件发生时,执行命令

在target本身构建之前或者之后运行,如果目标已经构建,那么不会运行。

1
2
3
4
5
6
7
8
9
add_custom_command(TARGET <target>
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM]
[COMMAND_EXPAND_LISTS])

PRE_BUILD对Visual Studio 生成器有独特的语法,其他生成器作用和PRE_LINK一样。
PRE_LINK 表示源代码编译之后,但在二进制目标链接前。
POST_BUILD 表示构建之后运行,不指定时,默认是这个。

举例:编译完成后,运行软件

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.0.0)
project(test)
add_executable(test main.c)
add_custom_command(TARGET test
COMMAND test
)

人生苦短,远离bug Leon, 2024-06-05

cmake执行命令详解
https://leon0625.github.io/2024/06/05/70a19a46ac1b/
作者
leon.liu
发布于
2024年6月5日
许可协议