Common Syntax of CMake: If Statements

Previous Highlights:CMake Hello, WorldCMake VariablesCMake Official Tutorial (Basic Project Setup)CMake Official Tutorial (Creating Libraries)CMake Official Tutorial (Usage Requirements)CMake Official Tutorial (Installation and Testing)

Through the official tutorials, we have gained a general understanding of using CMake.

However, to write flexible project configurations and understand the CMakeLists.txt of third-party open-source libraries, we need to master the common syntax involved in CMake.

Today, we will start with the if command, which has the following syntax:

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

More specifically, the if command has the following usage scenarios:

  1. 1. Basic expression evaluation
  2. 2. Logical operator operations
  3. 3. Existence checks
  4. 4. File and path operations
  5. 5. Comparison operations (comparing content of variables, versions, paths)

Basic Expressions

Usage:

if(<constant>)   # evaluate constant
if(<variable>)   # evaluate variable
if(<string>)     # evaluate string

If the constant is <span>1</span>, <span>ON</span>, <span>YES</span>, <span>TRUE</span>, <span>Y</span> or any non-zero number (including floating-point numbers), it is considered true.

If the constant is <span>0</span>, <span>OFF</span>, <span>NO</span>, <span>FALSE</span>, <span>N</span>, <span>IGNORE</span>, <span>NOTFOUND</span>, an empty string or a string ending with <span>-NOTFOUND</span>, it is considered false.Note on constants:

  1. 1. Boolean constant names (like <span>ON</span>/<span>OFF</span>) are case insensitive (e.g., <span>On</span> and <span>oFf</span> are both valid).
  2. 2. If the parameter is not one of the specific constants mentioned above, CMake will treat it as a variable name or a string and will further parse it according to variable expansion rules.

If the given variable is defined and its value is not a false constant (like <span>0</span>, <span>OFF</span>, etc.), then the condition is true; otherwise (including the case where the variable is undefined), it is false.Note on variables:

  1. 1. Macro parameters are not considered variables, so they cannot be evaluated this way.
  2. 2. Environment variables also cannot be tested directly with this syntax, for example, <span>if(ENV{some_var})</span> will always return false. You need to access the environment variable value using <span>$ENV{...}</span> syntax before evaluating.

Strings with quotes are always treated as false, unless one of the following conditions is met:

  1. 1. The value of the string is a true constant (like <span>ON</span>, <span>YES</span>, etc.);
  2. 2. In versions of CMake before 4.0, and if the policy <span>CMP0054</span> is not set to <span>NEW</span>, and the value of the string happens to be a variable name affected by the <span>CMP0054</span> policy.

Specific examples are as follows (CMake ≥4.0):

if("ON")  # true (string content is a true constant)
if("0")   # false (string content is a false constant)
if("Foo") # false (ordinary string)

For CMake <4.0, if the policy <span>CMP0054</span> is not set to <span>NEW</span>, quoted strings might be parsed as variable names. For example:

set(Foo "ON")
if("Foo")  # if CMP0054=OLD -> parsed as the value of variable Foo "ON" -> true
    ######
endif()

Logical Operators

Logical operators include NOT (logical negation), AND (logical conjunction), OR (logical disjunction), with the following forms:

if(NOT <condition>)
if(<cond1> AND <cond2>)
if(<cond1> OR <cond2>)
if((condition) AND (condition OR (condition))) # using parentheses can improve priority

It is important to note that for logical operators, most programming languages have short-circuit evaluation, but AND and OR in CMake do not; thus, all conditions will be checked.

Existence Checks

Usage is as follows:

if(COMMAND <command-name>)  # check if it is a callable command
if(POLICY <policy-id>)      # check if it is an existing policy
if(TARGET <target-name>)    # check if the target exists
if(TEST <test-name>)        # check if the test exists
if(DEFINED <name>|CACHE{<name>}|ENV{<name>})  # check if the variable is defined

Quite simple, no further elaboration.

File and Path Operations

if(EXISTS <path-to-file-or-directory>)        # check if the path exists
if(IS_READABLE <path-to-file-or-directory>)   # check read permission
if(IS_WRITABLE <path-to-file-or-directory>)   # check write permission
if(IS_EXECUTABLE <path-to-file-or-directory>) # check execute permission
if(IS_DIRECTORY <path>) # check if it is a directory
if(IS_SYMLINK <path>)   # check if it is a symbolic link
if(IS_ABSOLUTE <path>)  # check if it is an absolute path

Quite simple, no further elaboration.

Comparison Operations

Comparison operations include numerical comparisons (like LESS, GREATER), string comparisons (like STRLESS, STRGREATER), version comparisons (VERSION_LESS, etc.), and path comparisons (PATH_EQUAL).

Numerical comparisons will convert variables or strings to real numbers, while string comparisons are done lexicographically.

Version comparisons are done component by component, ignoring non-integer parts.

Path comparisons need to handle multiple delimiters, and unlike string comparisons, PATH_EQUAL will compare each path component more strictly.

This section of the manual describes a lot and is quite clear, so I won’t include the manual here.

Notes

  1. 1. The precedence of operators is parentheses, unary tests (like COMMAND, EXISTS, etc.), binary tests (like EQUAL, MATCHES, etc.), NOT operators, followed by AND and OR, in left-to-right order.
  2. 2. This content is organized from the official documentation; for more details, please refer to:
https://cmake.org/cmake/help/latest/command/if.html

Leave a Comment