何时引用变量?

Vin*_*nce 32 variables macros cmake

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

例如:将列表传递给cmake宏

我无法理解何时应该添加引号,以及更重要的基本原则是什么.

Flo*_*ian 54

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:仅将if()参数解释为不带引号时的变量或关键字)

    例子:

    • 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()命令接受ITEMS或中看到差异LISTS.

  3. if() 声明是一种特殊情况,通常你甚至不戴牙箍.

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


COMMAND 例子

  • set(_my_text "A B C")COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}"意志
    • 呼吁cmake.exe -E echo "A B C"VS /视窗
    • 呼吁cmake -E echo A\ B\ CGCC/Ubuntu的
    • A B C
  • set(_my_text "A B C")COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}" VERBATIM意志
    • 呼吁cmake.exe -E echo "A B C"VS /视窗
    • 呼吁cmake -E echo "A B C"GCC/Ubuntu的
    • A B C
  • set(_my_list A B C)COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}"意志
    • 呼叫 cmake.exe -E echo A;B;C
    • A,B: command not found,C: 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 中一样)。 (2认同)