我一直认为,如果你想比较两个字符串(但不是变量),你需要做的就是像这样引用它:
if("${A}" STREQUAL "some string")
但现在我发现这段代码有时会打印
oops
:cmake_minimum_required(VERSION 2.8)
if("d" STREQUAL "")
message("oops...")
endif()
可能是错误(因为它用 Xcode 打印,而不是用 make 打印)?
还是有一些特殊的变量?
更新
有命令 string没有描述的问题:
string(COMPARE EQUAL "${A}" "" result)
if(result)
message("...")
endif()
更新 2
我期望自 CMake 3.1.0 以来实现的行为(见 CMP0054)。
3.0.2 test 的输出:
CMake version: 3.0.2
Quoted test
Surprise!
Unquoted test
Surprise!
3.1.0 的输出 test :
CMake version: 3.1.0
Quoted test
OK
Unquoted test
Surprise!
最佳答案
您遇到了 CMake 的一个相当烦人的“这不是错误,而是一个功能”行为。如 if command 的文档中所述:
The if command was written very early in CMake's history, predating the ${}
variable evaluation syntax, and for convenience evaluates variables named
by its arguments as shown in the above signatures.
好吧,结果证明方便是不方便的。在您的示例中,字符串
"d"
被视为名为 d
的变量由 if
命令。如果变量d
恰好定义为空字符串,消息语句将打印“oops...”,例如:set (d "")
if("d" STREQUAL "")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
对于像这样的语句,这可能会产生令人惊讶的结果
if("${A}" STREQUAL "some string")
因为如果变量
A
,第一个参数可能会出现意外的双重扩展。恰好定义为一个字符串,该字符串也是 CMake 变量的名称,例如:set (A "d")
set (d "some string")
if("${A}" STREQUAL "some string")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
可能的解决方法:
您可以在
${}
之后的字符串中添加一个后缀字符。阻止 if 语句进行自动评估的扩展:set (A "d")
set (d "some string")
if("${A} " STREQUAL "some string ")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
请勿使用
${}
扩张:set (A "d")
set (d "some string")
if(A STREQUAL "some string")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
防止对
STREQUAL
右侧的意外评估使用 MATCHES
与 CMake regular expression反而:if(A MATCHES "^value$")
...
endif()
附录:CMake 3.1 不再对引用的参数进行双重扩展。见 new policy .
关于CMake与STREQUAL的空字符串比较失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19982340/