如何在自定义 CMake 命令中包含文字双引号?
How do I include a literal double quote in a custom CMake command?
我正在尝试创建一个使用一些环境变量运行的自定义命令,例如 LDFLAGS,如果它的值包含空格,则需要用引号引起来:
LDFLAGS="-Lmydir -Lmyotherdir"
由于 CMake 的转义规则,我找不到在 CMake 自定义命令中包含此参数的方法。到目前为止,这是我尝试过的方法:
COMMAND LDFLAGS="-Ldir -Ldir2" echo blah VERBATIM)
产量"LDFLAGS=\"-Ldir -Ldir2\"" echo blah
COMMAND LDFLAGS=\"-Ldir -Ldir2\" echo blah VERBATIM)
产量LDFLAGS=\"-Ldir -Ldir2\" echo blah
似乎我得到了整个字符串的引号,或者转义引号在用作命令的一部分时无法解析。
我希望能有一种方法来包含文字双引号,或者作为一种更好的方法来为命令设置环境变量。请注意,我仍在使用 CMake 2.8,因此我没有 3.2 中可用的新 "env" 命令。
请注意,这不是 的副本,因为这些引用方法中的 none 适用于这种特殊情况。
好的,我删除了原来的答案,因为@Florian 提出的答案更好。多个引用的 args 需要进行一项额外的调整。考虑这样的环境变量列表:
set(my_env_vars LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")
为了产生所需的扩展,转换为字符串,然后将 ;
替换为 space。
set(my_env_string "${my_env_vars}") #produces LDFLAGS="...";CFLAGS="..."
string(REPLACE ";" " " my_env_string "${my_env_string}")
然后您可以继续@Florian 的精彩回答并添加自定义启动规则。如果您的字符串中需要分号,那么您需要先将它们转换为其他内容。
请注意,在这种情况下,我不需要使用 env
:
启动
set_target_properties(mytarget PROPERTIES RULE_LAUNCH_CUSTOM "${my_env_string}")
这当然取决于你的shell。
再想一想,我的原始答案如下,因为我也有无法访问目标名称的情况。
set(my_env LDFLAGS=\"-Ldir -Ldir2" CFLAGS=\"-Idira -Idirb\")
add_custom_command(COMMAND sh -c "${my_env} grep LDFLAGS" VERBATIM)
此技术仍然需要替换列表->字符串转换中的分号。
最明显的选择——在达到 COMMAND
的边界时通常被推荐,尤其是对于旧版本的 CMake——是使用外部脚本。
我只是想添加一些简单的 COMMAND
变体,这些变体可以正常工作并且不需要 shell,但是 - 我不得不承认 - 仍然部分依赖于平台。
一个例子是只将引用的部分放入变量中:
set(vars_as_string "-Ldir -Ldir2")
add_custom_target(
QuotedEnvVar
COMMAND env LD_FLAGS=${vars_as_string} | grep LD_FLAGS
)
实际上确实转义了 space 而不是引号。
另一个例子是添加转义引号作为 "launcher" 规则:
add_custom_target(
LauncherEnvVar
COMMAND env | grep LD_FLAGS
)
set_target_properties(
LauncherEnvVar
PROPERTIES RULE_LAUNCH_CUSTOM "env LD_FLAGS=\"-Ldir -Ldir2\""
)
编辑:添加了无需转义引号的多个引用参数的示例
另一个示例是在函数中 "hide some of the complexity" 并且 - 如果您想将其添加到所有自定义命令调用 - 使用 global/directory RULE_LAUNCH_CUSTOM
属性:
function(set_env)
get_property(_env GLOBAL PROPERTY RULE_LAUNCH_CUSTOM)
if (NOT _env)
set_property(GLOBAL PROPERTY RULE_LAUNCH_CUSTOM "env")
endif()
foreach(_arg IN LISTS ARGN)
set_property(GLOBAL APPEND_STRING PROPERTY RULE_LAUNCH_CUSTOM " ${_arg}")
endforeach()
endfunction(set_env)
set_env(LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")
add_custom_target(
MultipleEnvVar
COMMAND env | grep -E 'LDFLAGS|CFLAGS'
)
备选方案(对于 CMake >= 3.0)
我想我们在这里真正要找的东西(除了 cmake -E env ...
)被命名为 Bracket Argument 并且允许任何字符而不需要添加反斜杠:
set_property(
GLOBAL PROPERTY
RULE_LAUNCH_CUSTOM [=[env LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb"]=]
)
add_custom_target(
MultipleEnvVarNew
COMMAND env | grep -E 'LDFLAGS|CFLAGS'
)
参考资料
您需要 三个 个反斜杠。我最近需要这个来从 PkgConfig 获取预处理器定义并将其应用于我的 C++ 标志:
pkg_get_variable(SHADERDIR movit shaderdir)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSHADERDIR=\\"${SHADERDIR}\\"")
一些 folks 建议使用 ${CMAKE_COMMAND} 并将您的可执行文件作为参数传递,例如:
COMMAND ${CMAKE_COMMAND} -E env "$(WindowsSdkDir)/bin/x64/makecert.exe" ...
这对我有用。
Florian 的回答在几个方面是错误的:
- 将引用部分放在变量中没有区别。
- 你绝对应该使用
VERBATIM
。它修复了特定于平台的引用错误。
- 你绝对不应该为此使用
RULE_LAUNCH_CUSTOM
。它不适用于此,仅适用于某些生成器。
- 您不应该使用
env
作为命令。它在 Windows. 上不可用
事实证明,OP 代码不起作用的真正原因是 CMake 总是完全引用 COMMAND
之后的第一个单词,因为它应该是可执行文件的名称。你根本不应该把环境变量放在第一位。
例如:
add_custom_command(
OUTPUT q1.txt
COMMAND ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)
add_custom_target(q1 ALL DEPENDS q1.txt)
$ VERBOSE=1 make
...
"ENV_VAR=\"a b\"" echo hello > q1.txt
/bin/sh: ENV_VAR="a b": command not found
那么如何传递带空格的环境变量呢?简单。
add_custom_command(
OUTPUT q1.txt
COMMAND ${CMAKE_COMMAND} -E env ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)
我正在尝试创建一个使用一些环境变量运行的自定义命令,例如 LDFLAGS,如果它的值包含空格,则需要用引号引起来:
LDFLAGS="-Lmydir -Lmyotherdir"
由于 CMake 的转义规则,我找不到在 CMake 自定义命令中包含此参数的方法。到目前为止,这是我尝试过的方法:
COMMAND LDFLAGS="-Ldir -Ldir2" echo blah VERBATIM)
产量"LDFLAGS=\"-Ldir -Ldir2\"" echo blah
COMMAND LDFLAGS=\"-Ldir -Ldir2\" echo blah VERBATIM)
产量LDFLAGS=\"-Ldir -Ldir2\" echo blah
似乎我得到了整个字符串的引号,或者转义引号在用作命令的一部分时无法解析。
我希望能有一种方法来包含文字双引号,或者作为一种更好的方法来为命令设置环境变量。请注意,我仍在使用 CMake 2.8,因此我没有 3.2 中可用的新 "env" 命令。
请注意,这不是
好的,我删除了原来的答案,因为@Florian 提出的答案更好。多个引用的 args 需要进行一项额外的调整。考虑这样的环境变量列表:
set(my_env_vars LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")
为了产生所需的扩展,转换为字符串,然后将 ;
替换为 space。
set(my_env_string "${my_env_vars}") #produces LDFLAGS="...";CFLAGS="..."
string(REPLACE ";" " " my_env_string "${my_env_string}")
然后您可以继续@Florian 的精彩回答并添加自定义启动规则。如果您的字符串中需要分号,那么您需要先将它们转换为其他内容。
请注意,在这种情况下,我不需要使用 env
:
set_target_properties(mytarget PROPERTIES RULE_LAUNCH_CUSTOM "${my_env_string}")
这当然取决于你的shell。
再想一想,我的原始答案如下,因为我也有无法访问目标名称的情况。
set(my_env LDFLAGS=\"-Ldir -Ldir2" CFLAGS=\"-Idira -Idirb\")
add_custom_command(COMMAND sh -c "${my_env} grep LDFLAGS" VERBATIM)
此技术仍然需要替换列表->字符串转换中的分号。
最明显的选择——在达到 COMMAND
的边界时通常被推荐,尤其是对于旧版本的 CMake——是使用外部脚本。
我只是想添加一些简单的 COMMAND
变体,这些变体可以正常工作并且不需要 shell,但是 - 我不得不承认 - 仍然部分依赖于平台。
一个例子是只将引用的部分放入变量中:
set(vars_as_string "-Ldir -Ldir2") add_custom_target( QuotedEnvVar COMMAND env LD_FLAGS=${vars_as_string} | grep LD_FLAGS )
实际上确实转义了 space 而不是引号。
另一个例子是添加转义引号作为 "launcher" 规则:
add_custom_target( LauncherEnvVar COMMAND env | grep LD_FLAGS ) set_target_properties( LauncherEnvVar PROPERTIES RULE_LAUNCH_CUSTOM "env LD_FLAGS=\"-Ldir -Ldir2\"" )
编辑:添加了无需转义引号的多个引用参数的示例
另一个示例是在函数中 "hide some of the complexity" 并且 - 如果您想将其添加到所有自定义命令调用 - 使用 global/directory
RULE_LAUNCH_CUSTOM
属性:function(set_env) get_property(_env GLOBAL PROPERTY RULE_LAUNCH_CUSTOM) if (NOT _env) set_property(GLOBAL PROPERTY RULE_LAUNCH_CUSTOM "env") endif() foreach(_arg IN LISTS ARGN) set_property(GLOBAL APPEND_STRING PROPERTY RULE_LAUNCH_CUSTOM " ${_arg}") endforeach() endfunction(set_env) set_env(LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb") add_custom_target( MultipleEnvVar COMMAND env | grep -E 'LDFLAGS|CFLAGS' )
备选方案(对于 CMake >= 3.0)
我想我们在这里真正要找的东西(除了
cmake -E env ...
)被命名为 Bracket Argument 并且允许任何字符而不需要添加反斜杠:set_property( GLOBAL PROPERTY RULE_LAUNCH_CUSTOM [=[env LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb"]=] ) add_custom_target( MultipleEnvVarNew COMMAND env | grep -E 'LDFLAGS|CFLAGS' )
参考资料
您需要 三个 个反斜杠。我最近需要这个来从 PkgConfig 获取预处理器定义并将其应用于我的 C++ 标志:
pkg_get_variable(SHADERDIR movit shaderdir)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSHADERDIR=\\"${SHADERDIR}\\"")
一些 folks 建议使用 ${CMAKE_COMMAND} 并将您的可执行文件作为参数传递,例如:
COMMAND ${CMAKE_COMMAND} -E env "$(WindowsSdkDir)/bin/x64/makecert.exe" ...
这对我有用。
Florian 的回答在几个方面是错误的:
- 将引用部分放在变量中没有区别。
- 你绝对应该使用
VERBATIM
。它修复了特定于平台的引用错误。 - 你绝对不应该为此使用
RULE_LAUNCH_CUSTOM
。它不适用于此,仅适用于某些生成器。 - 您不应该使用
env
作为命令。它在 Windows. 上不可用
事实证明,OP 代码不起作用的真正原因是 CMake 总是完全引用 COMMAND
之后的第一个单词,因为它应该是可执行文件的名称。你根本不应该把环境变量放在第一位。
例如:
add_custom_command(
OUTPUT q1.txt
COMMAND ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)
add_custom_target(q1 ALL DEPENDS q1.txt)
$ VERBOSE=1 make
...
"ENV_VAR=\"a b\"" echo hello > q1.txt
/bin/sh: ENV_VAR="a b": command not found
那么如何传递带空格的环境变量呢?简单。
add_custom_command(
OUTPUT q1.txt
COMMAND ${CMAKE_COMMAND} -E env ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)