This article is the supplementary material of Build using CMake.
Command Invocations
A CMake source file is just a sequence of Command Invocations. A command invocation
is an identifier followed by paren-enclosed arguments. Arguments are seperated by space
. For examlpe:
1 | add_executable(hello world.c) |
Argument
There are three types of arguments. Brackets and Qouted Arguments are used for constructing long, usually multi-line arguments, typically, the text of message.
Bracket Argument
This syntax is inspired by the long bracket syntax
of Lua
. The format of open bracket is '[' '='* '['
whereas the format of close bracket is ']' '='* ']'
. The =
could repeat zero or multiple times; The bracket with same number of =
will be paired together.
All text between the paired brackets will be treated as exactly one bracket argument. No nest, No Evaluation will be performed. For example:
1 | message([=[ |
Quoted Argument
A quoted argument is all the text between a pair of double-quote characters. Different from bracket argument, both Escape Sequences
and Variable References
will be evaluated here. The line continuation character \
is optional here. For example:
1 | message(" |
Unquoted Argument
An unquoted argument is not enclosed by any quoting syntax. It may not contain any whitespace, (
, )
, #
, "
, or \
except when escaped by a backslash. Both Escape Sequences and Variable References are evaluated. An unquoted argument may be treated as zero or a list arguments that splitted by ;
(not \;
), which is same as List
. For example:
1 | foreach(arg |
The output will be 1
2
3
4
5
6
7
8NoSpace
Escaped Space
This
Divides
Into
Five
Arguments
Escaped;Semicolon
Lists
A list of elements is represented as a string by concatenating the elements separated by ;
. For example, the set()
command stores multiple values into the destination variable as a list:
1 | set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c" |
Lists are meant for simple use cases such as a list of source files and should not be used for complex data processing tasks. Most commands that construct lists do not escape ; characters in list elements, thus flattening nested lists:
1 | set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c" |
Variable
Variables are the basic unit of storage in the CMake Language. They are always of string type, though some commands may interpret them as values of other types. Variable are case-sensitive
; It's recommended to use alphanumeric characters with _
and -
only.
Reserved Words
- Begin with
CMAKE_
or_CMAKE_
(upper-, lower-, or mixed-case) - Begin with
_
followed by the name of any CMake Command.
Please visit https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#manual:cmake-commands(7) for the list of cmake commands.
Set and Unset
Signatures <value>...
expect zero or more arguments. Multiple arguments will be joined as a semicolon-separated list to form the actual variable value to be set. Zero arguments will cause normal variables to be unset.
Set Normal Variable
1 | set(<variable> <value>... [PARENT_SCOPE]) |
If the PARENT_SCOPE
option is given, then the variable will be set in the scope above the current scope.
Set Cache Entry
1 | set(<variable> <value>... CACHE <type> <docstring> [FORCE]) |
Sets the given cache
Type
should be one of the following:BOOL
: Boolean ON/OFF value. cmake-gui offers acheckbox
.FILEPATH
: Path to a file on disk. cmake-gui offers afile dialog
.PATH
: Path to a directory on disk. cmake-gui offers afile dialog
.STRING
: A line of text. cmake-gui offers a text field or a drop-down selection if the STRINGS cache entry property has been set.INTERNAL
A line of text. cmake-gui does not show internal entries. They may be used to store variables persistently across runs. Use of this type impliesFORCE
.
<docstring>
should be a line of text providing a quick summary of the option for presentation to cmake-gui users.FORCE
should be used when it's required to overwrite the value of this entry. Since cache entries are meant to provide user-settable values, this does not overwrite existing cache entries by default.
if the Type
is PATH
or FILEPATH
and the value
provided is a relative path, the set command will treat the path as relative to the current working directory and convert it to an absolute path.
Set Environment Variable
1 | set(ENV{<variable>} [<value>]) |
If more than one arguments passed, extras will be ignored and an author warning is issued.
Unset Variables
1 | unset(<variable> [CACHE | PARENT_SCOPE]) |
Scope
Variables have dynamic scope. Each variable set
or unset
creates a binding in the corresponding scope.
Each new directory or function creates a new scope. When evaluating the variable references
, CMake first searches the function call stack: if a set
binding is found, use it; Else if no binding or unset
binding is found, searches the current directory scope, and the cache scope respectively. If there's no binding in all scopes, CMake evaluates it as an empty string.
Function Scope
A variable set
or unset
binds in function
is visible only within the current and nested functions.
Directory Scope
Each directory in the source tree has its own variable bindings. Before processing the CMakeLists.txt file for the directory, CMake copies all variable bindings defined in the parent directory, and initialize a new directory scope.
A variable set
or unset
outside the functions binds to the current directory scope.
Persistent Cache
CMake stores a separate set of cache
variables that persist across multiple runs within a project build tree. Cache entries have an isolated binding scope and coule be modified only by explicit request.
Variable References
Normal Variables
A variable reference has the form ${<variable>}
; When it appears inside a Quoted Argument
or an Unquoted Argument
, it is evaluated and replaced by the value
of the variable, or by an empty string
if it is not set. Variable references can nest
and are evaluated from the inside out. For example
1 | set(inner_var foo) |
The output will be 1
nest variable value is :999
The if()
command has a special condition syntax that allows for variable references in the short form <variable>
instead of ${<variable>}
. However, environment and cache variables always need to be referenced as $ENV{<variable>}
or $CACHE{<variable>}
.
Environment Variable Reference
Environment variable references have the form $ENV{<variable>}
. Environment variables have global scope in a CMake process and never cached. set()
and unset()
commands only temporarily affect the running CMake process, without altering the actual system environment, the process called from current process or the environment of subsequent build or test process.
Cache Variable Reference
A cache variable reference has the form $CACHE{<variable>}
.
Control Structures
Conditional Blocks
1 | if(<condition>) |
Conditions
Type of Test | Identifier |
---|---|
Unary | EXISTS , IS_DIRECTORY , IS_SYMLINK , IS_ABSOLUTE , COMMAND |
Binary | EQUAL , LESS , LESS_EQUAL , GREATER , GREATER_EQUAL , STREQUAL , STRLESS , STRLESS_EQUAL , STRGREATER , STRGREATER_EQUAL , VERSION_EQUAL , VERSION_LESS , VERSION_LESS_EQUAL , VERSION_GREATER , VERSION_GREATER_EQUAL , MATCHES |
Boolean | NOT , AND , OR |
Behaviors of path cheking are well-defined only for full path.
Other useful tests:
if(TARGET target-name)
to check if the given name is an existing logical target name created byadd_executable()
,add_library()
, oradd_custom_target()
if(TEST test-name)
to check if the given name is an existing test name created by theadd_test()
.if(file1 IS_NEWER_THAN file2)
returnsTrue
iffile1
is newer thanfile2
or if one of the two files doesn’t exist.if(<variable|string> IN_LIST <variable>)
to check if the given element is contained in the named list variable.if(DEFINED <name>|CACHE{<name>}|ENV{<name>})
to check if the variable is defined.
Variable Expansion
Normal variable evaluation with ${}
applies before the if
command even receives the arguments; Therefore, within condition statements that accepting <variable|string>
, automatic evaluation
is applied. Developers is instead excepted to pass the variable directly without ${}
enclosed.
Loops
break()
, continue()
For Each
1 | foreach(<loop_var> <items>) |
<items>
is a list of items that are separated by ;
or . At the beginning of each iteration,
loop_var
will be set to the value of the current item.
Variants
Iterate from
0
orstart
if set to stop (inclusive), with step:1
foreach(<loop_var> RANGE [<start>] <stop> [<step>])
Iterate over a list of items.
1
foreach(<loop_var> IN LISTS [<lists>])
<lists>
is a whitespace or semicolon separated list of list-valued variables. For example,This will print numbers from1
2
3
4
5
6
7
8set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
message(STATUS "${X}")
endforeach()1
to8
.- Iterate over multiple lists simultaneously
1
foreach(<loop_var>... IN ZIP_LISTS <lists>)
<lists>
is also a whitespace or semicolon separated list of list-valued variables.- If only one
loop_var
given, then access the values vialoop_var_N
correspondingly; - If multiple variable names passed, the number of variable and the number of lists should match;
- If any of the lists are shorter, the corresponding iteration variable become undefined. Both yield
1
2
3
4
5
6
7
8
9
10list(APPEND English one two three four)
list(APPEND Bahasa satu dua tiga)
foreach(num IN ZIP_LISTS English Bahasa)
message(STATUS "${num_0}, ${num_1}")
endforeach()
foreach(en ba IN ZIP_LISTS English Bahasa)
message(STATUS "${en}, ${ba}")
endforeach()1
2
3
4-- one, satu
-- two, dua
-- three, tiga
-- four,
- If only one
While
1 | while(<condition>) |
Function and Macro
macro
is very similar to function
. They are defined by
1 | function(<name> [<arg1> ...]) |
and
1 | macro(<name> [<arg1> ...]) |
- The
name
of functions or marcros are case-insensitive. - They could be invoked via
<identifier>([args])
orcmake_language(CALL <identifier>)
- When a function or marcro is invoked, CMake first evaluates (
${arg1}
, ...) with the arguments passed, and then invoked them as normal commands. - For each invoking, there are some implicit variables available:
ARGC
: the number of arguments.ARGV
holds the list of all arguments passed to the function; Alternatively, the arguments could be accessed viaARGV0
,ARGV1
...
- In a function,
ARGC
,ARGV
andARGV0
are true variables; In a macro, they are not, they are string replacements. - A function is executed by transferring control from the calling statement to the function body. A macro is executed as if the macro body were pasted in place of the calling statement. This has the consequence that a
return()
in a macro body does not just terminate execution of the macro but also the control from the scope of the macro call.
Comments
Bracket Comment
Bracket Comments adopt the same syntax as bracket argument, with a #
immediately ahead. It's helpful to construct multi-line comment or inline comments that terminated in the middle and followed by other arguments.
1 | #[[This is a bracket comment. |
The output will be
1 | First Argument |
Line Comment
Line comments are the content between #
and the end of the line.