我一直认为,如果你想比较两个字符串(但不是变量),你需要做的就是引用它:
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!
答案 0 :(得分:32)
你遇到了一个相当恼人的“它不是一个bug,它是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
右侧的意外评估,请使用CMake regular expression代替MATCHES
:
if(A MATCHES "^value$")
...
endif()
附录:CMake 3.1不再对引用的参数进行双重扩展。请参阅new policy。
答案 1 :(得分:3)
从CMake 3.1开始,有新的规则variable expansions in if()
。您可以通过以下方式启用它们:
cmake_minimum_required(3.1)
(或更高版本),或NEW
。即使在这种情况下,也仍然适用,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()