[CMake] Explanation....
Johannes Zarl
johannes.zarl at jku.at
Wed Apr 16 05:39:18 EDT 2014
Hi,
On Monday, 14. April 2014, 19:23:19, Theodore Papadopoulo wrote:
> > if ("${arg}" STREQUAL "TOTO") -> if ("TOTO" STREQUAL "TOTO") -> if
> > (B STREQUAL B)
>
> What I do not follow is why there is an implicit evaluation of "TOTO"
> into "B" (in both this case or the next I explicitely asked for a
> string containing the content of the variable ${arg}, if I had
> intended the content of the variable which name is in ${arg} I would
> have written ${${arg}}.
If it is any consolence to you, this is one of the most-hated (anti-)features
of cmake. The best you can do is to embrace this oddity (it's not going to go
away soon), and use a different idiom:
Instead of ``"${var}" STREQUAL "VALUE"'', write:
IF ( var MATCHES "^VALUE$" )
-> The MATCHES expression only does string/variable expansion on the right
side. Therefore you get a well-defined behaviour regardless of any possible
aliasing effects on variable names and values.
> Of course, you are right about what happened, it is just very unsafe.
> That means that if I'm using as a variable name the name of a constant
> used in some other module, there will be very unexpected failures....
You are totally right. I guess if there was a way to change this in a
backwards-compatible way, cmake developers would not hesitate to do so.
> For example taking /usr/share/cmake/Modules/FeatureSummary.cmake as an
> example, if I set a variable PROPERTIES with a value might (untested)
> provoke quite unexpected results (if(NOT "${_props}" STREQUAL
> "PROPERTIES")). Or if I do set(0 1) before calling
> CheckLanguage.cmake (if(CMAKE_${lang}_COMPILER AND "${result}"
> STREQUAL "0")).
You can have even more fun by redefining some version strings:
set(MY_VERSION "2.8.15")
set("2.8.15" hehehe)
if (MY_VERSION VERSION_EQUAL "2.8.15" )
message("All as expected...")
else()
message("I'm so evil!")
endif()
# You can probably guess what this prints out ;-)
IMO one thing that *could* be done would be to deprecate the unsafe
expressions and replace them with some safe version.
> I realize now that this is what probably means the
> if(<variable|string> STREQUAL <variable|string>)
> in the cmake manual. But in my reading that was meaning some
> overloading so that
>
> TOTO is a variable so evaluated into ${TOTO}
> but "TOTO" remains a string and is not evaluated any further.
>
> At least that what I thought (basically at some type system
> differentiating variables and strings)... I'm clearly wrong as:
>
> set(TOTO B)
> if ("B" STREQUAL "TOTO")
> message("AhAh")
> endif()
What helped me to understand it was to see this as a two-step procedure:
1) Parsing: ${variable} gets replaced by its value
2) Execution: IF is called with the strings as argument.
At step 2, the IF statement cannot possibly determine how its arguments looked
before expansion.
> > if ( "_ASDF_${arg}" STREQUAL "_ASDF_TOTO")
>
> Well I knew the technique, but thought it was mainly for protection
> againts empty strings (which "${arg}" should be equivalent). Not sure
> it makes the thing safer though.
>
> Well I guess I need to go and see cmake source code, as I cannot
> understand cery well its evaluation rules.
Sorry for my mistake in the first mail. I wrote my response rather quick, not
pausing to think of better alternatives. Had I invested more time, I would've
given you the solution using "MATCHES" that I explained above. Sorry for the
inconvenience...
Cheers,
Johannes
More information about the CMake
mailing list