5

I am not sure the CMake if() command will treat a symbol in the condition clause as a variable or a string literal. So I did some experiments.

Script1.cmake

cmake_minimum_required(VERSION 3.15)

set(XXX "YYY") #<========== HERE!!

if(XXX STREQUAL "XXX")
    message("condition 1 is true") # If reach here, XXX is treated as string
elseif(XXX STREQUAL "YYY")
    message("condition 2 is true") # If reach here, XXX is treated as variable
endif()

The output is:

condition 2 is true

So I come to below conclusion 1.

For a symbol in the condition clause:

  • If the symbol is defined as a variable before, CMake will treat it as variable and use its value for evaluation.
  • If the symbol is not defined as a variable before, CMake will treat it literally as a string.

Then I did another experiment.

set(ON "OFF")
if(ON)
    message("condition 3 is true") # If reach here, ON is treated as a constant.
else()
    message("condition 4 is true") # If reach here. ON is treated as a variable.
endif()

The output is:

condition 3 is true

So, though ON is explicitly defined as a variable, the if command still treat it as a constant of TRUE value. This directly contradicts to my previous conclusion 1.

So how can I know for sure the CMake if() command will treat a symbol as string or variable??

ADD 1 - 11:04 AM 7/11/2019

It seems the if(constant) form precedes other forms of if() statement. (src)

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 specific constants, it is treated as a variable or string and the following signature is used.

So for now, I have to refer to the above rule first before applying my conclusion 1. (This may be an answer, but I am not sure enough yet.)

smwikipedia
  • 52,824
  • 76
  • 267
  • 432
  • What is wrong with documentation you refers to? It describes every behavior you observe. What is a **question**? – Tsyvarev Jul 11 '19 at 07:43
  • The doc is correct so far. I added it as an explanation/reference. – smwikipedia Jul 11 '19 at 07:44
  • Again, what is a **question** stated in the question post for which you want to have an answer? If your `ADD 1` actually **answers** the question, please move it from the question post to the **answer post**. – Tsyvarev Jul 11 '19 at 07:50

1 Answers1

3

Welcome to the wilderness of CMake symbol interpretation.

If the symbol exists as a variable, then the expression is evaluated with the value of the variable. Otherwise, the name of the variable (or literal, as you said) is evaluated instead.

The behavior becomes a little more consistent if you add the ${ and } sequences. Then the value of the variable is used in the evaluation every single time. If the variable doesn't exist or has not been assigned a value, then CMake uses several placeholder values that evaluate to "false". These are the values you mentioned in the latter part to your post.

I believe this is done this way for backwards compatibility, which CMake is really good about. For most of the quirky things CMake does, it's usually in the name of backwards compatibility.

As for the inconsistent behavior you mentioned in the "ON" variable, this is probably due to the precedence in which CMake processes the command arguments. I would have to figure that the constants are parsed before the symbol lookup occurs.

So when it comes to knowing/predicting how an if statement will evaluate, my best answer is experience. The CMake source tree and logic is one magnificent, nasty beast.

There's been discussions on adding an alternative language (one with perhaps a functional paradigm), but it's a quite large undertaking.

tay10r
  • 3,952
  • 1
  • 20
  • 43
  • I agree with you on that `constant are parsed before symbol lookup occurs`. My quote seems to be saying so. – smwikipedia Jul 11 '19 at 03:19
  • 1
    Let me look at the source code and verify this before I confirm that. I'm about %80 sure that this happens in a file called cmMakefile.cxx in their source tree, looking now. – tay10r Jul 11 '19 at 03:21
  • 1
    Yeah I'm sorry, I'm not as familiar with CMake source code as I used to be. The expression parser evaluates the arguments after the variables and constants have been preprocessed, so it has little to do with the `if` or `while` commands specifically. – tay10r Jul 11 '19 at 03:37