CMake compare to empty string with STREQUAL failed

匿名 (未验证) 提交于 2019-12-03 02:44:02

问题:

I always think that if you want to compare two strings (but not variables) all you need to do is to quote it like that:

if("${A}" STREQUAL "some string") 

but now I find out that this code sometimes print oops:

cmake_minimum_required(VERSION 2.8)  if("d" STREQUAL "")   message("oops...") endif() 

May be it's bug (because it prints with Xcode, but not with make)? Or there is some special variables?

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

Update

There is command string without described problems:

string(COMPARE EQUAL "${A}" "" result) if(result)   message("...") endif() 

Update 2

The behaviour I've expected implemented since CMake 3.1.0 (see CMP0054).

Output of the 3.0.2 test:

CMake version: 3.0.2 Quoted test Surprise! Unquoted test Surprise! 

Output of the 3.1.0 test:

CMake version: 3.1.0 Quoted test OK Unquoted test Surprise! 

回答1:

You ran into a rather annoying "it's not a bug, it's a feature" behavior of CMake. As explained in the documentation of the 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. 

Well, the convenience turned out to be an inconvenience. In your example the the string "d" is treated as a variable named d by the if command. If the variable d happens to be defined to the empty string, the message statement will print "oops...", e.g.:

set (d "") if("d" STREQUAL "")   # this branch will be taken   message("oops...") else()   message("fine") endif() 

This can give surprising results for statements like

if("${A}" STREQUAL "some string") 

because there can be an unintended double expansion of the first argument if the variable A happens to be defined to a string which is also the name of a CMake variable, e.g.:

set (A "d") set (d "some string")    if("${A}" STREQUAL "some string")   # this branch will be taken   message("oops...") else()   message("fine") endif() 

Possible work-arounds:

You can add a suffix character to the string after the ${} expansion which prevents the if statement from doing the automatic evaluation:

set (A "d") set (d "some string") if("${A} " STREQUAL "some string ")   message("oops...") else()   # this branch will be taken   message("fine") endif() 

Do not use ${} expansion:

set (A "d") set (d "some string") if(A STREQUAL "some string")   message("oops...") else()   # this branch will be taken   message("fine") endif() 

To prevent unintended evaluation on the right side of STREQUAL use MATCHES with a CMake regular expression instead:

if(A MATCHES "^value$")   ... endif() 

Addendum: CMake 3.1 no longer does double expansions for quoted arguments. See the new policy.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!