我一直认为,如果你想比较两个字符串(而不是变量),你所需要做的就是像这样引用它:
if("${A}" STREQUAL "some string")
但是现在我发现这段代码有时会打印oops
cmake_minimum_required(VERSION 2.8)
if("d" STREQUAL "")
message("oops...")
endif()
可能是bug (因为它使用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!
发布于 2013-11-15 05:33:38
您遇到了一个相当恼人的CMake行为:“这不是一个bug,而是一个特性”。如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"
被if
命令视为名为d
的变量。如果变量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
的右侧进行意外求值,请改用带有CMake regular expression的MATCHES
:
if(A MATCHES "^value$")
...
endif()
附录: CMake 3.1不再对引用的参数进行双倍扩展。请参阅new policy。
发布于 2020-08-22 01:24:59
从CMake 3.1开始,有了新的规则variable expansions in if()
。如果您执行以下任一操作,则会启用它们:
cmake_minimum_required(3.1)
(或更高版本),或者即使在这种情况下,if
的第一个参数仍然是正确的,即使用与该名称匹配的变量的值来扩展该名称:
set (d "")
if(d STREQUAL "")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
但是,如果第一个参数加了引号,则现在禁用此功能:
set (d "")
if("d" STREQUAL "")
message("oops...")
else()
# due to quotes around "d" in if statement,
# this branch will be taken
message("fine")
endif()
如果您确实希望根据值测试变量的内容,则可以使用经典的无引号语法,也可以使用您建议的"${d}"
语法。感谢新的规则,这将永远不会遭受sakra答案中提到的双重扩展问题:
set (A "d")
set (d "some string")
if("${A}" STREQUAL "d")
# this branch will be taken
message("fine")
elseif("${A}" STREQUAL "some string")
message("oops...")
else()
message("??")
endif()
https://stackoverflow.com/questions/19982340
复制相似问题