Cmake命令之execute_process
本文所使用的相关软件版本:
软件名称 | 软件版本 |
---|---|
Linux操作系统 | Ubuntu 22.04 LTS |
cmake | 3.22.1 |
一、基本介绍
如其名字,该命令通过运行指定的命令来执行一个或多个子进程。命令的签名如下:
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>])
execute_process
可以指定多个命令,并且多个命令是通过管道方式执行,上一个命令的标准输出通过管道传递,作为下一个命令的标准输入。所有的命令都共享单个标准错误管道。
来看几个简单的例子:
- 执行单个命令,本例子以执行
uname -o
获取操作系统名称为例。
# CMakeLists.txt
# 输出操作系统名称
EXECUTE_PROCESS(COMMAND uname -o)
运行结果:
GNU/Linux
- 执行多个命令,前一个命令的输出会作为后一个命令的输入(相当于
Unix/Linux
中管道的概念),本例以ls -al
、grep "cmake"
、awk '{print $9}'
,请注意,实际相当于在命令行中执行ls -al | grep "cmake" | awk "{print $9}"
,即过滤出带匹配cmake
字符串的行后,取该行以空格分割的第9
项(对于ls -al
命令就是过滤出文件名称)。
# CMakeLists.txt
# 列出当前文件目录内容项,通过"cmake"和"awk"过滤出文件名"cmake_install.cmake"
# 相当于执行命令: ls -al | grep "cmake" | awk "{print $9}"
EXECUTE_PROCESS(COMMAND ls -al
COMMAND grep "cmake"
COMMAND awk "{print $9}")
运行结果
cmake_install.cmake
二、参数选项详解
-
COMMAND
:待执行的子命令,可以指定多个。 -
WORKING_DIRECTORY
:将指定的目录作为子命令执行的当前工作目录。
# 指定命令的工作目录,在指定目录下执行pwd命令
EXECUTE_PROCESS(COMMAND pwd
WORKING_DIRECTORY "/home")
运行结果:
/home
-
TIMEOUT
:设置子命令执行的超时时间,单位是秒,可以不是整数。注意,是针对每个子命令而言的超时时间,而不是命令总的执行时间。当超时时间到,所有未完成的子命令会结束,并且RESULT_VARIABLE
指定的变量会被设置为包含timeout
的字符串。因此如果下面例子中的TIMEOUT
值大于5
,子命令执行可以成功。
# 设置子命令的超时时间
# 注意,是针对每个子命令而言的超时时间,而不是命令总的执行时间
EXECUTE_PROCESS(COMMAND sleep 5
COMMAND sleep 5
TIMEOUT 4
RESULT_VARIABLE msg)
MESSAGE("Commands execute result: ${msg}")
运行结果:
Commands execute result: Process terminated due to timeout
-
RESULT_VARIABLE
:包含子命令的执行结果,该变量会被设置为最后一个子命令执行的返回码,或执行出错时候的描述字符串(像上个例子中的超时)。
# 最后一个子命令是删除一个不存在的文件,即使前面的命令执行成功,它也只是包含最后一个子命令的执行结果
EXECUTE_PROCESS(COMMAND rm "notexistfile.ext"
RESULT_VARIABLE msg)
MESSAGE("Command execute result: ${msg}")
运行结果:
rm: 无法删除 'notexistfile.ext': 没有那个文件或目录 Command execute result: 1
-
RESULTS_VARIABLE
:3.10
版本引入。将所有的子命令执行结果存入该变量中,子命令的执行结果以分号连接,存储的顺序按照COMMAND
命令的顺序。
# 存储所有子命令的运行结果
EXECUTE_PROCESS(COMMAND ls -al
COMMAND rm "notexistfile.ext"
RESULTS_VARIABLE msg_all)
MESSAGE("ALL commands execute result: ${msg_all}")
运行结果:
rm: 无法删除 'notexistfile.ext': 没有那个文件或目录 ALL commands execute result: 0;1
-
OUTPUT_VARIABLE
,ERROR_VARIABLE
:将标准输出和标准错误管道内容分别写入OUTPUT_VARIABLE
和ERROR_VARIABLE
指定的变量中,如果指定的是同一个变量,那么会按照执行的顺序合并输出。
EXECUTE_PROCESS(COMMAND echo "start"
COMMAND rm "notexistfile.ext"
COMMAND pwd
COMMAND rm "notexistfile2.ext"
COMMAND pwd
WORKING_DIRECTORY "/home"
RESULTS_VARIABLE msg_result
OUTPUT_VARIABLE msg_out
ERROR_VARIABLE msg_err)
MESSAGE("Commands execute results: ${msg_result}")
MESSAGE("Commands output: ${msg_out}")
MESSAGE("Commands error: ${msg_err}")
运行结果:
值得注意的是,由于命令是按照管道方式执行,OUTPUT_VARIABLE只会存储最后一个命令的运行结果,而ERROR_VARIABLE则是存储所有错误
Commands execute results: 0;1;0;1;0 Commands output: /home
Commands error: rm: 无法删除 'notexistfile.ext': 没有那个文件或目录 rm: 无法删除 'notexistfile2.ext': 没有那个文件或目录
-
INPUT_FILE
:指定文件作为第一个命令的标准输入OUTPUT_FILE
:指定文件作为最后一个命令的标准输出ERROR_FILE
:所有命令运行错误结果存储的文件。
EXECUTE_PROCESS(COMMAND read
COMMAND rm "noexistfile.ext"
COMMAND rm "noexistfile2.ext"
COMMAND echo "write message to output"
INPUT_FILE input
OUTPUT_FILE output
ERROR_FILE error)
output
文件内容:write message to output
error
文件内容:rm: noexistfile.ext: No such file or directory rm: noexistfile2.ext: No such file or directory
-
OUTPUT_QUIET
,ERROR_QUIET
:忽略标准输出或者标准错误。 -
COMMAND_ECHO <where>
:3.15
版本引入。将运行的命令echo
到STDOUT
(标准输出)、STDERR
(标准错误)、NONE
,也可以通过设置变量CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
来控制默认值。本例子中将运行的命令(包括参数)都echo
到标准出错(不包含命令本身执行的输出),并且通过执行cmake . 2> file_stderr
来将标准出错重定位到文件file_stderr
中。
EXECUTE_PROCESS(
COMMAND echo "execute commad"
COMMAND ls "CMakeLists.txt"
COMMAND_ECHO STDERR
)
执行:
cmake . 2> file_stderr
的命令行输出为(最后一个命令ls
的输出仍然在命令行展示):CMakeLists.txt
查看文件
file_stderr
:cat file_stderr
'echo' 'execute commad' 'ls' 'CMakeLists.txt'
-
ENCODING <name>
:指定命令执行的输出用何种方式解码,只在Windows
下生效。有如下取值:
NONE
:默认值,使用CMake
内部默认的编码方式(也就是UTF-8
)对命令输出进行解码。AUTO
:使用当前的控制台编码方式,如果未找到合法的编码方式,则使用ANSI
。ANSI
:使用ANSI
方式解码命令输出。OEM
:使用OEM
方式解码命令输出。UTF8
或UTF-8
:使用UTF-8
方式解码命令输出(3.11
版本引入)。
-
ECHO_OUTPUT_VARIABLE
,ECHO_ERROR_VARIABLE
:将标准输出或标准错误复制一份到指定的变量(例如通过OUTPUT_VARIABLE
指定的变量),而不是重定向。这意味着标准输出或者标准错误仍然会有效。
EXECUTE_PROCESS(
COMMAND echo "hello world"
OUTPUT_VARIABLE var_output
ECHO_OUTPUT_VARIABLE # 如果没有指定这个选项,那么命令行终端不会有"hello world"的打印
)
MESSAGE("output var: ${var_output}")
运行结果:
hello world output var: hello world
-
COMMAND_ERROR_IS_FATAL <ANY|LAST>
:3.19
版本引入。指定当遇到错误时的命令行为。
ANY
:任一子命令执行错误,execute_process
会停止执行并抛出错误LAST
:最后一个子命令执行错误,execute_process
会停止执行抛出错误
EXECUTE_PROCESS(COMMAND pwd
COMMAND rm "noexistfile.ext"
COMMAND echo "hello world"
COMMAND_ERROR_IS_FATAL LAST)
运行结果(最后一个子命令执行成功,
LAST
选项不会导致CMake
抛出错误):rm: noexistfile.ext: No such file or directory hello world
EXECUTE_PROCESS(COMMAND pwd
COMMAND rm "noexistfile.ext"
COMMAND echo "hello world"
COMMAND_ERROR_IS_FATAL ANY)
运行结果(第二个子命令执行失败,
ANY
选项会导致CMake
抛出错误):rm: noexistfile.ext: No such file or directory hello world
CMake Error at CMakeLists.txt:21 (execute_process):
execute_process failed command indexes:
2: "Child return code: 1"