我什么时候应该引用 CMake 变量? [英] When should I quote CMake variables?
问题描述
我是第一次编写 CMake 宏,我很难理解变量是如何工作的.最具体地说,${a}
似乎与 "${a}"
的含义不同.
我不明白什么时候应该添加引号,以及更大的基本原则是什么.
你必须牢记的 CMake 的两个原则:
- CMake 是一种脚本语言,在扩展变量后评估参数
- 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")
withmessage(${_my_list})
会给出ABC
莉>
一些经验法则
您应该考虑一些经验法则:
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")
withif (${_my_text} STREQUAL "A;B;C")
会给出if给定参数:A"B"C"STREQUAL"A;B;C"指定未知参数
如果您的变量包含一个列表,您通常不会添加引号.
推理:如果您向 CMake 命令提供类似文件列表的内容,它通常需要一个字符串列表,而不是一个包含列表的字符串.您可以看到的差异,例如在
foreach()
命令中接受ITEMS
或LISTS
.if()
语句是一种特殊情况,您通常甚至不放置大括号.推理:一个字符串可以 - 扩展后 - 再次评估为变量名称.为防止出现这种情况,建议仅命名要比较其内容的变量(例如
if (_my_text STREQUAL "A B C")
).
<小时>
COMMAND
示例
set(_my_text "A B C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}"
- 调用
cmake.exe -E echo "A B C"
在 VS/Windows - 在GCC/Ubuntu上调用
cmake -E echo A B C
- 给
A B C
- 调用
set(_my_text "A B C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}" VERBATIM
- 调用
cmake.exe -E echo "A B C"
在 VS/Windows - 在 GCC/Ubuntu 上调用
cmake -E echo "A B C"
- 给
A B C
- 调用
set(_my_list A B C)
withCOMMAND "${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)
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
- 调用
cmake.exe -E echo "A;B;C"
- 给
A;B;C
- 调用
set(_my_list "A" "B" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
- 调用
cmake.exe -E echo "A;B;C"
- 给
A;B;C
- 调用
set(_my_list "A" "B" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo ${_my_list}逐字
会- 调用
cmake.exe -E echo A B C
- 给
A B C
- 调用
set(_my_list "A + B" "=" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
- call
cmake.exe -E echo "A + B" = C
- 给
A + B = C
- call
add_custom_target()
/add_custom_command()
/execute_process()
在 COMMAND
调用中使用变量时,应考虑一些经验法则:
a) 对包含文件路径的参数使用引号(例如包含可执行文件本身的第一个参数).
推理:它可以包含空格,并且可以重新解释为
COMMAND
调用的单独参数b) 如上所示,如果变量
set()
确实包含引号,也可以使用.如果您想将某些内容连接到单个参数中以传递给被调用的可执行文件,请仅使用引号.
推理:一个变量可能包含一个参数列表——当使用引号时——不会被正确提取(分号而不是空格)
始终使用
添加add_custom_target()
/add_custom_command()
VERBATIM
选项推理:否则跨平台行为是未定义的,您可能会对引用的字符串感到惊讶.
参考资料
I am writing CMake macros for the first time, and I have a hard time understanding how variables work. Most specifically, ${a}
seems to have a different meaning than "${a}"
.
For example here: Passing a list to a CMake macro
I fail to understand when I am supposed to add quotes, and what are the bigger underlying principles.
Two principles of CMake you have to keep in mind:
- CMake is a script language and arguments are evaluated after the variables are expanded
- CMake differentiates between normal strings and list variables (strings with semicolon delimiters)
Examples
set(_my_text "A B C")
withmessage("${_my_text}")
would giveA B C
set(_my_list A B C)
withmessage("${_my_list}")
would giveA;B;C
set(_my_list "A" "B" "C")
withmessage("${_my_list}")
would giveA;B;C
set(_my_list "A" "B" "C")
withmessage(${_my_list})
would giveABC
Some Rules of Thumb
There are some rules of thumb you should consider:
a) When your variable contains text - especially one that could contain semicolons - you should add quotes.
Reasoning: A semicolon is a delimiter for list elements in CMake. So put quotes around a text that is supposed to be one (it works everywhere and for me personally looks better with CMake syntax highlighting)
EDIT: Thanks for the hint from @schieferstapel
b) To be more precise: A variable content with spaces that already had quotes does keep those quotes (imagine as it getting part of the variable's content). This works everywhere also unquoted (normal or user-defined function parameters) with the prominent exception of
if()
calls, where CMake re-interprets the content of unquoted variables after variable expansion (see also rule of thumb #3 and policy CMP0054: Only interpretif()
arguments as variables or keywords when unquoted)Examples:
set(_my_text "A B C")
withmessage(${_my_text})
would also giveA B C
set(_my_text "A;B;C")
withif (${_my_text} STREQUAL "A;B;C")
would giveif given arguments: "A" "B" "C" "STREQUAL" "A;B;C" Unknown arguments specified
If your variable contains a list you normally don't add quotes.
Reasoning: If you give something like a file list to an CMake command it normally expect a list of strings and not one string containing a list. The difference you can see e.g. in the
foreach()
command acceptingITEMS
orLISTS
.if()
statements are a special case where you normally don't even put the braces.Reasoning: A string could - after expansion - evaluate again to a variable name. To prevent this it's recommended to just name the variable whose content you want to compare (e.g.
if (_my_text STREQUAL "A B C")
).
COMMAND
Examples
set(_my_text "A B C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}"
would- call
cmake.exe -E echo "A B C"
on VS/Windows - call
cmake -E echo A B C
on GCC/Ubuntu - give
A B C
- call
set(_my_text "A B C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}" VERBATIM
would- call
cmake.exe -E echo "A B C"
on VS/Windows - call
cmake -E echo "A B C"
on GCC/Ubuntu - give
A B C
- call
set(_my_list A B C)
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}"
would- call
cmake.exe -E echo A;B;C
- give
A
,B: command not found
,C: command not found
- call
set(_my_list A B C)
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
would- call
cmake.exe -E echo "A;B;C"
- give
A;B;C
- call
set(_my_list "A" "B" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
would- call
cmake.exe -E echo "A;B;C"
- give
A;B;C
- call
set(_my_list "A" "B" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
would- call
cmake.exe -E echo A B C
- give
A B C
- call
set(_my_list "A + B" "=" "C")
withCOMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
would- call
cmake.exe -E echo "A + B" = C
- give
A + B = C
- call
Some Rules of Thumb with add_custom_target()
/add_custom_command()
/execute_process()
There are some rules of thumb you should consider when you use variables in COMMAND
calls:
a) Use quotes for the arguments that contain file paths (like the first argument containing the executable itself).
Reasoning: It could contain spaces and could be reinterpreted as separate arguments to the
COMMAND
callb) See above, works also if the variable
set()
did include quotes.Use quotes only if you want to concatenate something into a single parameter to be passed to executable that is called.
Reasoning: A variable could contain a list of parameters which - when using quotes - won't be correctly extracted (semicolons instead of spaces)
Always add the
VERBATIM
option withadd_custom_target()
/add_custom_command()
Reasoning: Otherwise the cross-platform behavior is undefined and you could get surprises with your quoted strings.
References
- CMake: difference between ${} and "${}"
- What's the CMake syntax to set and use variables?
- Looping over a string list
- CMake compare to empty string with STREQUAL failed
这篇关于我什么时候应该引用 CMake 变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!