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. Basic expression evaluation
- 2. Logical operator operations
- 3. Existence checks
- 4. File and path operations
- 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. 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. 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. Macro parameters are not considered variables, so they cannot be evaluated this way.
- 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. The value of the string is a true constant (like
<span>ON</span>,<span>YES</span>, etc.); - 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. 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. This content is organized from the official documentation; for more details, please refer to:
https://cmake.org/cmake/help/latest/command/if.html