PAYATHON 2026

如何向 CMake 的 execute_process 传递包含分号的参数?

技术老齐

可以。execute_process() 能把含分号的字符串作为一个参数传给目标进程。最简单的写法是在 COMMAND 中给这个参数加双引号。如果需要先组装参数列表,就要在列表中保留 \;,这样展开时才能得到普通分号。这里不需要 execute_process() 专用的转义序列。

直接传递:给单个参数加双引号

假设 foo 是可执行程序,bar 和 with;semicolon 是它的两个参数:

execute_process(
    COMMAND foo bar "with;semicolon"
)

参数来自变量时,也用双引号包住变量:

set(value "with;semicolon")

execute_process(
    COMMAND foo bar "${value}"
)

CMake 会将双引号包住的内容作为一个参数传入命令,并保留其中的分号。目标进程收到的是 with;semicolon,不含外层双引号。参见 CMake 参数语法。

必须使用参数列表时:保留一层分号转义

如果需要继续使用 execute_process(COMMAND ${args}),可以这样构造列表:

set(args
    "foo"
    "bar"
    "with\\;semicolon"
)

execute_process(COMMAND ${args})

CMake 会分两步处理:

  1. 解析 "with\\;semicolon" 时,\\ 生成一个字面反斜杠,所以变量中保存的是 with\;semicolon。
  2. 展开未加引号的 ${args} 时,CMake 按列表拆分参数。遇到 \;,会保留分号,并去掉用于转义的反斜杠。

此时,args 保存的字符串相当于:

foo;bar;with\;semicolon

展开后,foo 是程序名,后面两个参数分别是 bar 和 with;semicolon。具体规则见 CMake 的列表展开规则。

如果含分号的值来自变量,可以先转义,再放入列表:

set(value "with;semicolon")
string(REPLACE ";" "\\;" escaped_value "${value}")

set(args "foo" "bar" "${escaped_value}")
execute_process(COMMAND ${args})

这种写法适用于构造列表后直接展开一次的情况。如果中间还经过函数转发或其他列表操作,需要检查转义是否已被提前消耗。

为什么原来的引号没有作用

下面的写法在 set() 调用中给各个值加了双引号:

set(args "foo" "bar" "with;semicolon")

set() 会用分号连接这些值,保存为:

foo;bar;with;semicolon

变量不会记录源码中哪些内容曾被双引号包围。随后执行:

execute_process(COMMAND ${args})

未加引号的 ${args} 会按分号拆分,with 和 semicolon 就成了两个参数。

在字符串中加入 \" 也不能保护分号。变量展开产生的引号只是普通字符,不会被重新解析为 CMake 的引用语法。

也不要改成:

execute_process(COMMAND "${args}")

这会把整个变量的内容,包括其中的分号,作为一个程序名传入,无法按预期区分程序名和参数。

注意事项

直接使用 "${value}" 时,变量中应保存原始的 with;semicolon。只有通过列表展开来传递参数时,才需要保留列表层面的 \;。

通常,execute_process() 直接通过操作系统接口启动程序,无须手动拼接带 shell 引号的命令行。如果显式调用 shell,或在 Windows 上执行 .bat、.cmd 脚本,还需要考虑命令解释器自身的解析规则。参见 execute_process() 官方说明。

问题示例中的引号和括号没有闭合,\n 还会引入换行。如果目标参数只是 with;semicolon,应去掉这些额外字符。

备注:内容仅供参考。