MantisBT - CMake
View Issue Details
0015335CMakeCMakepublic2015-01-04 21:192015-06-01 08:38
Brian Chojnowski 
 
normalmajoralways
closedno change required 
LinuxCentOS7
CMake 3.1 
 
0015335: if () evaluates to FALSE for quoted constants/variables where the contents are non-null and not defined constants
An if statement should evaluate to TRUE if the variable is not-null and is not a defined false constant.

From the documentation:

if(<constant>)
True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. False if the constant is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND. Named boolean constants are case-insensitive. If the argument is not one of these constants, it is treated as a variable.
if(<variable>)
True if the variable is defined to a value that is not a false constant. False otherwise. (Note macro arguments are not variables.)
set(myvar "not a false constant")
message(STATUS "myvar=${myvar}")
if(myvar)
    message(STATUS "un quoted variable name = TRUE")
endif()
if(${myvar})
    message(STATUS "un quoted variable contents = TRUE")
endif()
if("${myvar}")
    message(STATUS "quoted variable = TRUE")
endif()

Output:

Eclipse version is set to 4.4 (). Adjust CMAKE_ECLIPSE_VERSION if this is wrong.
myvar=test string
un quoted variable name = TRUE
Configuring done
No tags attached.
Issue History
2015-01-04 21:19Brian ChojnowskiNew Issue
2015-01-08 12:14Brad KingNote Added: 0037633
2015-01-08 12:14Brad KingStatusnew => resolved
2015-01-08 12:14Brad KingResolutionopen => no change required
2015-01-08 12:18Brian ChojnowskiNote Added: 0037635
2015-01-08 12:21Brian ChojnowskiNote Added: 0037636
2015-01-08 12:29Brad KingNote Added: 0037638
2015-01-08 12:45Brian ChojnowskiNote Added: 0037639
2015-01-08 12:51Brad KingNote Added: 0037640
2015-01-08 12:56Brian ChojnowskiNote Added: 0037641
2015-01-08 12:58Brad KingNote Added: 0037642
2015-01-08 13:03Brad KingNote Added: 0037643
2015-01-08 13:04Brian ChojnowskiNote Added: 0037644
2015-01-08 13:06Brian ChojnowskiNote Added: 0037645
2015-01-08 13:14Brad KingNote Added: 0037646
2015-01-08 13:26Brian ChojnowskiNote Added: 0037647
2015-01-08 13:34Brad KingNote Added: 0037648
2015-01-08 13:39Brian ChojnowskiNote Added: 0037649
2015-01-08 13:43Brad KingNote Added: 0037650
2015-01-08 13:45Brad KingNote Added: 0037651
2015-01-08 13:50Brian ChojnowskiNote Added: 0037652
2015-01-08 14:15Brad KingNote Added: 0037654
2015-01-08 14:17Brian ChojnowskiNote Added: 0037655
2015-06-01 08:38Robert MaynardNote Added: 0038831
2015-06-01 08:38Robert MaynardStatusresolved => closed

Notes
(0037633)
Brad King   
2015-01-08 12:14   
The if(<variable>) case refers to when <variable> is the name of a variable, not a reference to a variable.

For

 if(${myvar})

the if() command sees

 if(not\ a\ false\ constant)

which is not a defined variable or a true constant.

For

 if("${myvar}")

the if() command sees

 if("not a false constant")

which is not a defined variable or a true constant.
(0037635)
Brian Chojnowski   
2015-01-08 12:18   
However, from the documentation of the if(<constant>) case:

If the argument is not one of these constants, it is treated as a variable.
if(<variable>)
(0037636)
Brian Chojnowski   
2015-01-08 12:21   
So am I reading your notes correctly in that there is no defined rule for if(<not a true constant>) and if(<not a true variable>) ??

If so, seems like we should define the behavior. in this case.
(0037638)
Brad King   
2015-01-08 12:29   
Re 0015335:0037636: If it is not a defined constant or one of the later cases that involves a keyword then it is treated as the if(<variable>) case. That case defines the not-defined case as false (see text "False otherwise.").
(0037639)
Brian Chojnowski   
2015-01-08 12:45   
if(<variable>)
True if the variable is defined to a value that is not a false constant. False otherwise. (Note macro arguments are not variables.)

This statement says that if the variable does not resolve to a false constant than the if() will evaluate true. The "False otherwise" sentence therefore applies to the case where the variable does resolve to a false constant.

Or said more plainly, anything that is not a false constant evaluates to TRUE.
(0037640)
Brad King   
2015-01-08 12:51   
Re 0015335:0037639: "False otherwise" is a separate sentence, meaning that the result is false if the case described in the first sentence is not true.
(0037641)
Brian Chojnowski   
2015-01-08 12:56   
I have been trying to get the FindIce.cmake module to work correctly (CentOS 7 environment). The module is failing because the variable that contains the result of a find_library statement...

  foreach(component ${Ice_FIND_COMPONENTS})
    string(TOUPPER "${component}" component_upcase)
    set(component_cache "Ice_${component_upcase}_LIBRARY")
    set(component_found "${component_upcase}_FOUND")
    find_library("${component_cache}" "${component}"
      HINTS ${ice_roots}
      PATH_SUFFIXES ${ice_library_suffixes}
      DOC "Ice ${component} library")
    mark_as_advanced("${component_cache}")
    if("${component_cache}")

The if test evaluates to FALSE, even though it contains a non-empty path to the library.

I built this from source, if that matters.

Strangely, removing the quotes and issuing make clean;make; make install then makes this if () test evaluate TRUE... even though the minimal example in this bug report fails (this code was not in a module, just in the CMakeLists.txt file)
(0037642)
Brad King   
2015-01-08 12:58   
Re 0015335:0037640: Perhaps the wording can be clarified. How about

``if(<variable|string>)``
  True if given a variable that is defined to a value that is not a false
  constant. False otherwise. (Note macro arguments are not variables.)
(0037643)
Brad King   
2015-01-08 13:03   
Re 0015335:0037641: Please ask about the FindIce issue on the mailing list and CC the author of the module: Roger Leigh <rleigh@codelibre.net>
(0037644)
Brian Chojnowski   
2015-01-08 13:04   
I agree the definition needs clarification of some sort. I am still confused as to why if (<string>) where string is not one of the false constants is evaluating as false.
(0037645)
Brian Chojnowski   
2015-01-08 13:06   
if ("not a false constant")
    message(status "string is true")
endif()

This produces no output.
(0037646)
Brad King   
2015-01-08 13:14   
Re 0015335:0037644: The behavior was defined that way for use cases like

 if(COOL_OPTION)
   message(STATUS "cool option enabled")
 endif()

where the COOL_OPTION variable may or may not be defined. This is just like the C preprocessor where code like

 #if COOL_OPTION

will be true only if the symbol is defined to a non-false value.

Does the wording proposed in 0015335:0037642 describe the behavior clearly? (It is not intended to describe the design choice or motivation, just the behavior.)
(0037647)
Brian Chojnowski   
2015-01-08 13:26   
I think the clarification will help. But I still am struggling to see why this also does not work.

if ("not a false constant")
    message(status "string is true")
endif()

This if evaluates to false. "not a false constant" is a defined string and not one of the false constants correct? so I believe this should evaluate to TRUE.
(0037648)
Brad King   
2015-01-08 13:34   
Re 0015335:0037647: There is no

 set("not a false constant" 1)

line so "not a false constant" is not the name of a defined variable. Therefore the string does not name a variable that is defined to a value that is not a false constant.
(0037649)
Brian Chojnowski   
2015-01-08 13:39   
Are you implying that if ("some text here") is not of the form: if(<constant>) ??

If so I understand why I am confused.
(0037650)
Brad King   
2015-01-08 13:43   
Re 0015335:0037649: The documentation of if(<constant>) says "If the argument is not one of these constants, it is treated as a variable".
(0037651)
Brad King   
2015-01-08 13:45   
I've revised the documentation:

 Help: Clarify if(<variable>) documentation
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7a2c3f0c [^]
(0037652)
Brian Chojnowski   
2015-01-08 13:50   
Ok I see, so if ("sometext") is treated as if (sometext).

I think I found why FindIce.cmake worked in 2.8 and not 3.1. I will work with the FindIce developer to update the module.

this code placed in CMakeLists.txt (and not a module that might have the CMFoo54 policy set to NEW):

set(fooref "foo")
set ("${fooref}" "some string")
if ("${fooref}")
    message(status "string is true")
endif()

produces this output:

CMake Warning (dev) at CMakeLists.txt:3 (if):
  Policy CMP0054 is not set: Only interpret if() arguments as variables or
  keywords when unquoted. Run "cmake --help-policy CMP0054" for policy
  details. Use the cmake_policy command to set the policy and suppress this
  warning.

  Quoted variables like "foo" will no longer be dereferenced when the policy
  is set to NEW. Since the policy is not set the OLD behavior will be used.
This warning is for project developers. Use -Wno-dev to suppress it.

statusstring is true
(0037654)
Brad King   
2015-01-08 14:15   
Actually it looks like FindIce was fixed a few days ago for this. I've backported the change for inclusion in 3.1.1:

 FindIce: Port to work with CMP0054 NEW behavior
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cbaf0802 [^]
(0037655)
Brian Chojnowski   
2015-01-08 14:17   
Fantastic. Thank you!
(0038831)
Robert Maynard   
2015-06-01 08:38   
Closing resolved issues that have not been updated in more than 4 months.