cmake

Why the first on is true and next is false?


cmake_minimum_required(VERSION 3.20)

set(on "OFF")

if(on)
    message("ON") 
else()
    message("OFF")
endif()

if(${on}) 
    message("ON")
else()
    message("OFF") 
endif()
$ cmake -P test.cmake
ON
OFF

basic-expressions

True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number (including floating point numbers). 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 specific constants, it is treated as a variable or string (see Variable Expansion further below) and one of the following two forms applies.

My understanding of this problem is that

For predefined constants ON, it equivalent to on.

For if(on), on will be parsed as predefined constant ON.

For if(${on}), ${on} will be parsed as "OFF", which equivalent to OFF.

I don't know if my understanding is correct.

What is on?


Solution

  • What is on?

    It's a string of two characters.
    All CMake variables are strings (or lists, which are semi-colon separated strings). How a variable is interpreted depends on the context.

    You already cite the correct section from CMake's documentation on if. It states that if the argument is (among other things) ON (case-insensitive), it's a constant and evaluates to "true". If it's none of the magic constants, it's treated as a variable or a string. Your examples never get there, though.

    The section on variable expansion points out that ${} evaluation happens before if ever sees the arguments. It also features an example that's pretty much like your example, only that it uses much less confusing variable names.

    To wrap this up:

    Solution: don't use the names of constants for your variables. A statement like set(on OFF) looks like deliberate obfuscation.