【问题标题】:When should I quote CMake variables?我什么时候应该引用 CMake 变量?
【发布时间】:2016-06-21 05:37:28
【问题描述】:

我是第一次编写 CMake 宏,我很难理解变量是如何工作的。更具体地说,${a} 似乎与 "${a}" 具有不同的含义。

例如这里:Passing a list to a CMake macro

我不明白什么时候应该添加引号,以及更大的基本原则是什么。

【问题讨论】:

    标签: variables cmake macros


    【解决方案1】:

    你必须牢记的两个 CMake 原则:

    1. CMake 是一种脚本语言,参数在变量展开后进行评估
    2. CMake 区分普通字符串和列表变量(带有分号分隔符的字符串)

    示例

    • set(_my_text "A B C")message("${_my_text}") 将给 A B C
    • set(_my_list A B C)message("${_my_list}") 将给 A;B;C
    • set(_my_list "A" "B" "C")message("${_my_list}") 将给 A;B;C
    • set(_my_list "A" "B" "C")message(${_my_list}) 将给 ABC

    一些经验法则

    您应该考虑一些经验法则:

    1. a) 当您的变量包含文本(尤其是可能包含分号的文本)时,您应该添加引号。

      推理:分号是 CMake 中列表元素的分隔符。所以在一个应该是一个文本的地方加上引号(它在任何地方都有效,对我个人来说,使用 CMake 语法突出显示效果更好)

      编辑:感谢@schieferstapel 的提示

      b) 更准确地说:带有空格且已包含引号的变量内容确实保留了这些引号(想象一下,它获取了变量内容的一部分)。这在任何地方也适用于不带引号的(普通或用户定义的函数参数),if() 调用的显着例外,其中 CMake 在变量扩展后重新解释不带引号的变量的内容(另请参见经验法则 #3 和策略 CMP0054: Only interpret if() arguments as variables or keywords when unquoted )

      示例:

      • set(_my_text "A B C")message(${_my_text}) 也会给 A B C
      • set(_my_text "A;B;C")if (${_my_text} STREQUAL "A;B;C") 将给 if given arguments: "A" "B" "C" "STREQUAL" "A;B;C" Unknown arguments specified
    2. 如果您的变量包含一个列表,您通常不会添加引号。

      推理:如果你给 CMake 命令提供文件列表之类的东西,它通常需要一个字符串列表,而不是一个包含列表的字符串。您可以看到的差异,例如在foreach() 命令中接受ITEMSLISTS

    3. if() 语句是一种特殊情况,您通常甚至不放置大括号。

      推理:一个字符串可以 - 在扩展之后 - 再次评估为一个变量名。为防止这种情况发生,建议只命名要比较其内容的变量(例如if (_my_text STREQUAL "A B C"))。


    COMMAND 示例

    • set(_my_text "A B C")COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}"
      • VS/Windows 上调用 cmake.exe -E echo "A B C"
      • GCC/Ubuntu 上调用 cmake -E echo A\ B\ C
      • A B C
    • set(_my_text "A B C")COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}" VERBATIM
      • VS/Windows 上调用 cmake.exe -E echo "A B C"
      • GCC/Ubuntu 上调用 cmake -E echo "A B C"
      • A B C
    • set(_my_list A B C)COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}"
      • 致电cmake.exe -E echo A;B;C
      • AB: command not foundC: command not found
    • set(_my_list A B C)COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
      • 致电cmake.exe -E echo "A;B;C"
      • A;B;C
    • set(_my_list "A" "B" "C")COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
      • 致电cmake.exe -E echo "A;B;C"
      • A;B;C
    • set(_my_list "A" "B" "C")COMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
      • 致电cmake.exe -E echo A B C
      • A B C
    • set(_my_list "A + B" "=" "C")COMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
      • 致电cmake.exe -E echo "A + B" = C
      • A + B = C

    一些经验法则add_custom_target()/add_custom_command()/execute_process()

    COMMAND 调用中使用变量时应考虑一些经验法则:

    1. a) 为包含文件路径的参数使用引号(例如包含可执行文件本身的第一个参数)。

      推理:它可以包含空格,并且可以重新解释为 COMMAND 调用的单独参数

      b) 见上文,如果变量 set() 确实包含引号,也可以使用。

    2. 在您想将某些内容连接成单个参数以传递给被调用的可执行文件时使用引号。

      推理:一个变量可能包含一个参数列表 - 当使用引号时 - 将无法正确提取(分号而不是空格)

    3. 始终将VERBATIM 选项与add_custom_target()/add_custom_command() 一起添加

      推理:否则跨平台行为是未定义的,您可能会对引用的字符串感到惊讶。

    参考文献

    【讨论】:

    • -1 因为第一条经验法则 #1 背后的推理是错误的。如果您将变量传递给函数(func(${X}),不带引号)并且X 包含空格,X 仍然只是一个参数,并且不会像您说的那样被扩展/评估。引用每个可能包含带空格的路径的变量太容易出错(就像在例如 POSIX shell 中一样)。
    • @schieferstapel 感谢您的提示。你是对的,在这种情况下,不需要引号。我相应地更新了我的答案。但是我仍然认为如果我不知道变量是否包含列表,那将是必要的。我必须再次检查add_custom_command() 部分(以为我当时已经测试过了,但我会仔细检查)。
    • 这就是我转向介子的真正原因。 CMake 被这些事情困扰,以至于多年后我几乎不记得如何使用它了。
    猜你喜欢
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2015-03-30
    • 1970-01-01
    • 2022-01-19
    相关资源
    最近更新 更多