首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >CMake与具有STREQUAL的空字符串的比较失败

CMake与具有STREQUAL的空字符串的比较失败
EN

Stack Overflow用户
提问于 2013-11-14 23:58:28
回答 2查看 35.9K关注 0票数 43

我一直认为,如果你想比较两个字符串(而不是变量),你所需要做的就是像这样引用它:

代码语言:javascript
复制
if("${A}" STREQUAL "some string")

但是现在我发现这段代码有时会打印oops

代码语言:javascript
复制
cmake_minimum_required(VERSION 2.8)

if("d" STREQUAL "")
  message("oops...")
endif()

可能是bug (因为它使用Xcode打印,而不是make打印)?或者有一些特殊的变量?

  • cmake: 2.8.12,2.8.11.2
  • xcode: 4.6.2,5.0.1

更新

存在没有描述的问题的命令string

代码语言:javascript
复制
string(COMPARE EQUAL "${A}" "" result)
if(result)
  message("...")
endif()

更新2

我期望从CMake 3.1.0 (参见CMP0054)开始就实现的行为。

3.0.2 test的输出

代码语言:javascript
复制
CMake version: 3.0.2
Quoted test
Surprise!
Unquoted test
Surprise!

3.1.0 test的输出

代码语言:javascript
复制
CMake version: 3.1.0
Quoted test
OK
Unquoted test
Surprise!
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-15 05:33:38

您遇到了一个相当恼人的CMake行为:“这不是一个bug,而是一个特性”。如if command文档中所述

代码语言:javascript
复制
 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...",例如:

代码语言:javascript
复制
set (d "")
if("d" STREQUAL "")
  # this branch will be taken
  message("oops...")
else()
  message("fine")
endif()

对于像这样的语句,这可能会产生令人惊讶的结果

代码语言:javascript
复制
if("${A}" STREQUAL "some string")

因为如果变量A恰好定义为也是CMake变量名称的字符串,则可能会意外地对第一个参数进行双重扩展,例如:

代码语言:javascript
复制
set (A "d")
set (d "some string")   
if("${A}" STREQUAL "some string")
  # this branch will be taken
  message("oops...")
else()
  message("fine")
endif()

可能的解决方法:

您可以在${}展开后向字符串添加后缀字符,这会阻止if语句执行自动求值:

代码语言:javascript
复制
set (A "d")
set (d "some string")
if("${A} " STREQUAL "some string ")
  message("oops...")
else()
  # this branch will be taken
  message("fine")
endif()

请勿使用${}扩展:

代码语言:javascript
复制
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 expressionMATCHES

代码语言:javascript
复制
if(A MATCHES "^value$")
  ...
endif()

附录: CMake 3.1不再对引用的参数进行双倍扩展。请参阅new policy

票数 54
EN

Stack Overflow用户

发布于 2020-08-22 01:24:59

从CMake 3.1开始,有了新的规则variable expansions in if()。如果您执行以下任一操作,则会启用它们:

即使在这种情况下,if的第一个参数仍然是正确的,即使用与该名称匹配的变量的值来扩展该名称:

代码语言:javascript
复制
set (d "")
if(d STREQUAL "")
  # this branch will be taken
  message("oops...")
else()
  message("fine")
endif()

但是,如果第一个参数加了引号,则现在禁用此功能:

代码语言:javascript
复制
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答案中提到的双重扩展问题:

代码语言:javascript
复制
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()
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19982340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档