如何在自定义CMake命令中包含文字双引号?

时间:2016-09-07 11:21:10

标签: cmake escaping quotes literals

我正在尝试创建一个与某些环境变量一起运行的自定义命令,例如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”命令。

请注意,这不是 When to quote variables? 的副本,因为这些引用方法都不适用于此特定情况。

5 个答案:

答案 0 :(得分:5)

显而易见的选择 - 通常在使用COMMAND的边界时建议使用外部脚本,而不是使用旧版本的CMake。

我只是想添加一些简单的COMMAND变种,它们确实有用并且不需要shell,但是 - 我必须承认 - 仍然部分依赖于平台。

  • 一个例子是只将引用的部分放入变量中:

    set(vars_as_string "-Ldir -Ldir2")
    add_custom_target(
        QuotedEnvVar
        COMMAND env LD_FLAGS=${vars_as_string} | grep LD_FLAGS
    )
    

    实际上它逃脱了空间而不是引号。

  • 另一个例子是使用转义引号添加它作为"启动器"规则:

    add_custom_target(
        LauncherEnvVar
        COMMAND env | grep LD_FLAGS
    )
    set_target_properties(
        LauncherEnvVar 
        PROPERTIES RULE_LAUNCH_CUSTOM "env LD_FLAGS=\"-Ldir -Ldir2\""
    )
    

编辑:添加多个引用参数的示例,而无需转义引号

  • 另一个例子是"隐藏一些复杂性"在函数中 - 如果要将其添加到所有自定义命令调用中 - 请使用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'
    )
    

<强>参考

答案 1 :(得分:1)

好的,我删除了原来的答案,因为@Florian提出的答案更好。多个引用的args需要另外一个调整。考虑一下环境变量列表:

set(my_env_vars LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")

为了产生所需的扩展,请转换为字符串,然后用空格替换;

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)

此技术仍然需要替换list-&gt;字符串转换中的分号。

答案 2 :(得分:1)

您需要三个反斜杠。我最近需要这个来从PkgConfig获取预处理器定义,并将其应用于我的C ++标志:

pkg_get_variable(SHADERDIR movit shaderdir)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSHADERDIR=\\\"${SHADERDIR}\\\"")

答案 3 :(得分:0)

有些folks建议使用$ {CMAKE_COMMAND}并将可执行文件作为参数传递,例如:

COMMAND ${CMAKE_COMMAND} -E env "$(WindowsSdkDir)/bin/x64/makecert.exe" ...

对我有用。

答案 4 :(得分:0)

弗洛里安的回答在几个方面是错误的:

  • 将引用的部分放在变量中没有区别。
  • 您绝对应该使用 VERBATIM。它修复了特定于平台的引用错误。
  • 您绝对不应该为此使用 RULE_LAUNCH_CUSTOM。它不适用于此目的,仅适用于某些生成器。
  • 您不应使用 env 作为命令。它在 Windows 上不可用。

事实证明 OPs 代码不起作用的真正原因是 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
)