CMake/Language Syntax: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
No edit summary
(Add explicit preformat markup)
Line 16: Line 16:
We refer to each CMake script or <tt>CMakeLists.txt</tt> file as a ''listfile''. The basic syntax of a listfile is extremely simple: a listfile may contain only ''commands'' and ''comments''. Comments start with a <tt>#</tt> character and stop at the end of a line. You may freely mix comments with commands; comments may between or amid commands:
We refer to each CMake script or <tt>CMakeLists.txt</tt> file as a ''listfile''. The basic syntax of a listfile is extremely simple: a listfile may contain only ''commands'' and ''comments''. Comments start with a <tt>#</tt> character and stop at the end of a line. You may freely mix comments with commands; comments may between or amid commands:


<pre>
  # This is a comment.
  # This is a comment.
  COMMAND( arguments go here )
  COMMAND( arguments go here )
Line 22: Line 23:
   arguments are spread        # another comment
   arguments are spread        # another comment
   over several lines )
   over several lines )
</pre>


The names of commands are case ''insensitive''; the usual convention is to type the command names in uppercase. However, the arguments are case ''sensitive''. Thus MESSAGE and message and Message and mESsAgE are the same command:
The names of commands are case ''insensitive''; the usual convention is to type the command names in uppercase. However, the arguments are case ''sensitive''. Thus MESSAGE and message and Message and mESsAgE are the same command:


<pre>
  MESSAGE( hi ) # displays "hi"
  MESSAGE( hi ) # displays "hi"
  message( hi ) # displays "hi" again
  message( hi ) # displays "hi" again
  message( HI ) # displays "HI"
  message( HI ) # displays "HI"
</pre>


The whitespace around the ( and ) parens is optional, all of these commands are the same:
The whitespace around the ( and ) parens is optional, all of these commands are the same:


<pre>
  MESSAGE(hi)
  MESSAGE(hi)
  MESSAGE (hi)
  MESSAGE (hi)
  MESSAGE( hi )
  MESSAGE( hi )
  MESSAGE (hi )
  MESSAGE (hi )
</pre>


Commands are procedure calls and cannot return values. However, you may pass the name of a global variable to some commands, and those commands will store the result there. For example, the <tt>MATH( EXPR ... )</tt> command takes three arguments; the third argument is the expression, and the second argument is the variable to store the result:
Commands are procedure calls and cannot return values. However, you may pass the name of a global variable to some commands, and those commands will store the result there. For example, the <tt>MATH( EXPR ... )</tt> command takes three arguments; the third argument is the expression, and the second argument is the variable to store the result:


<pre>
  MATH( EXPR x "3 + 3" ) # stores the result of 3 + 3 in x
  MATH( EXPR x "3 + 3" ) # stores the result of 3 + 3 in x
  MESSAGE( "x is ${x}" ) # displays "x is 6"
  MESSAGE( "x is ${x}" ) # displays "x is 6"
                         # using quotes so MESSAGE receives only one argument
                         # using quotes so MESSAGE receives only one argument
</pre>


== CMake variables ==
== CMake variables ==
Line 55: Line 63:
Use the SET command to set the value of a variable to some string. The SET command takes two arguments: the name of the variable and its new value, SET(variable value). To access the value of a variable, you perform a ''substitution''. To perform a substitution, use the syntax <tt>${''variablename''}</tt>:
Use the SET command to set the value of a variable to some string. The SET command takes two arguments: the name of the variable and its new value, SET(variable value). To access the value of a variable, you perform a ''substitution''. To perform a substitution, use the syntax <tt>${''variablename''}</tt>:


<pre>
  SET( x 3 )
  SET( x 3 )
  SET( y 1 )
  SET( y 1 )
  MESSAGE( ${x}${y} ) # displays "31"
  MESSAGE( ${x}${y} ) # displays "31"
</pre>


If more than one value is specified, each value is concatenated into one string in which semicolons serve to separate the indivual values. This kind of string is called a list in CMake and can be used with the LIST command. You may use quoting to avoid this:
If more than one value is specified, each value is concatenated into one string in which semicolons serve to separate the indivual values. This kind of string is called a list in CMake and can be used with the LIST command. You may use quoting to avoid this:


<pre>
  SET( x a b c  ) # stores "a;b;c" in x      (without quotes)
  SET( x a b c  ) # stores "a;b;c" in x      (without quotes)
  SET( y "a b c" ) # stores "a b c" in y      (without quotes)
  SET( y "a b c" ) # stores "a b c" in y      (without quotes)
Line 68: Line 79:
  MESSAGE( ${y} )  # prints "a b c" to stdout (without quotes)
  MESSAGE( ${y} )  # prints "a b c" to stdout (without quotes)
  MESSAGE("${y}")  # prints "a b c" to stdout (without quotes)
  MESSAGE("${y}")  # prints "a b c" to stdout (without quotes)
</pre>


In fact, the following are equivalent:
In fact, the following are equivalent:


<pre>
  SET( x a b c )
  SET( x a b c )
  SET( x a;b;c )
  SET( x a;b;c )
  SET( x "a;b;c" )
  SET( x "a;b;c" )
  SET( x;a;b;c )
  SET( x;a;b;c )
</pre>


However, this does 'not' work:
However, this does 'not' work:


<pre>
  SET( "x;a;b;c" )
  SET( "x;a;b;c" )
</pre>


Of course, the arguments to SET itself can come from substitutions:
Of course, the arguments to SET itself can come from substitutions:


<pre>
  SET( x y A B C )              # stores "y;A;B;C" in x (without quote)
  SET( x y A B C )              # stores "y;A;B;C" in x (without quote)
  SET( ${x} )                  # => SET( y;A;B;C ) => SET( y A B C)
  SET( ${x} )                  # => SET( y;A;B;C ) => SET( y A B C)
Line 90: Line 107:
  SET( y ${x} )                # => SET( y y = x ) => stores "y;=;x" in y (without quotes)
  SET( y ${x} )                # => SET( y y = x ) => stores "y;=;x" in y (without quotes)
  MESSAGE( ${y} )              # prints "y=x" to stdout (without quotes)
  MESSAGE( ${y} )              # prints "y=x" to stdout (without quotes)
</pre>


The value can be the empty string, "":
The value can be the empty string, "":


<pre>
  SET( x "" )
  SET( x "" )
</pre>


If there is no value specified, then the variable is UNSET, so that it is like the variable never existed:
If there is no value specified, then the variable is UNSET, so that it is like the variable never existed:


<pre>
  SET( x )
  SET( x )
  IF(DEFINED x)
  IF(DEFINED x)
   MESSAGE("This will never be printed")
   MESSAGE("This will never be printed")
  ENDIF(DEFINED x)
  ENDIF(DEFINED x)
</pre>


However, this is more obviously performed with the UNSET command:
However, this is more obviously performed with the UNSET command:


<pre>
  UNSET( x )
  UNSET( x )
</pre>


=== Substitution of command names ===
=== Substitution of command names ===
Substitution only works within arguments to commands. In particular, the name of a command cannot include a substitution; so you cannot store the name of a command in a variable, then run that command. For example, this does not work:
Substitution only works within arguments to commands. In particular, the name of a command cannot include a substitution; so you cannot store the name of a command in a variable, then run that command. For example, this does not work:


<pre>
  SET( command MESSAGE )
  SET( command MESSAGE )
  ${command}( hi )
  ${command}( hi )
  # syntax error
  # syntax error
</pre>


If you insist, the available workaround is to write the command to a temporary file, then INCLUDE the file to run the command.
If you insist, the available workaround is to write the command to a temporary file, then INCLUDE the file to run the command.


<pre>
  SET( command MESSAGE )
  SET( command MESSAGE )
   
   
Line 121: Line 148:
  INCLUDE( temp )                      # ./temp is an unsafe temporary file...
  INCLUDE( temp )                      # ./temp is an unsafe temporary file...
  FILE( REMOVE temp )
  FILE( REMOVE temp )
</pre>


The following code can be used to (a) generate unique / temporary file names and (b) evaluate commands in those files as suggested:
The following code can be used to (a) generate unique / temporary file names and (b) evaluate commands in those files as suggested:


<pre>
  #!/usr/bin/cmake -P
  #!/usr/bin/cmake -P
   
   
Line 148: Line 177:
   file(REMOVE ${_fname})
   file(REMOVE ${_fname})
  endmacro(eval)
  endmacro(eval)
</pre>


An example of this in use:
An example of this in use:


<pre>
  eval("message(\"Hai\")")
  eval("message(\"Hai\")")
   
   
Line 165: Line 196:
   eval("${func_name}(\"Test\")")
   eval("${func_name}(\"Test\")")
  endforeach(func)
  endforeach(func)
</pre>


Output:
Output:


<pre>
  Hai
  Hai
  A: Test
  A: Test
  B: Test
  B: Test
</pre>


This was included from [http://stackoverflow.com/questions/6370283/how-to-make-temp-directory-in-cmake/13708234#13708234 this post] by the author.
This was included from [http://stackoverflow.com/questions/6370283/how-to-make-temp-directory-in-cmake/13708234#13708234 this post] by the author.
Line 179: Line 213:
To shell script hackers, this is not the same as setting <tt>IFS=\;</tt> in a Bourne shell that follows POSIX. (Because <tt>;</tt> is also a shell operator, we escape it with a backslash.) The difference is that the Bourne shell will only use the <tt>;</tt> delimeter within substitutions, while CMake will use it everywhere:
To shell script hackers, this is not the same as setting <tt>IFS=\;</tt> in a Bourne shell that follows POSIX. (Because <tt>;</tt> is also a shell operator, we escape it with a backslash.) The difference is that the Bourne shell will only use the <tt>;</tt> delimeter within substitutions, while CMake will use it everywhere:


<pre>
  # shell script
  # shell script
  countargs() {
  countargs() {
Line 195: Line 230:
  SET( ARGS a;b;c )
  SET( ARGS a;b;c )
  COUNTARGS( ${ARGS} ) # displays "3"
  COUNTARGS( ${ARGS} ) # displays "3"
</pre>


Importantly, the MESSAGE command has the habit of concatenating all of its arguments! (This is why many examples on this page use quoting so that MESSAGE takes only one argument.) The following three commands are effectively the same:
Importantly, the MESSAGE command has the habit of concatenating all of its arguments! (This is why many examples on this page use quoting so that MESSAGE takes only one argument.) The following three commands are effectively the same:


<pre>
  MESSAGE(This is practice.)            # prints "Thisispractice."
  MESSAGE(This is practice.)            # prints "Thisispractice."
  MESSAGE(  This  is    practice.    ) # prints "Thisispractice."
  MESSAGE(  This  is    practice.    ) # prints "Thisispractice."
  MESSAGE( This;is;practice. )          # prints "Thisispractice."
  MESSAGE( This;is;practice. )          # prints "Thisispractice."
</pre>


=== Quoting ===
=== Quoting ===
You can preserve whitespace, semicolons and parens by quoting entire arguments, as if they were strings in C:
You can preserve whitespace, semicolons and parens by quoting entire arguments, as if they were strings in C:


<pre>
  MESSAGE( "This is practice." )  # prints "This is practice."
  MESSAGE( "This is practice." )  # prints "This is practice."
  MESSAGE( "This;is;practice." )  # prints "This;is;practice."
  MESSAGE( "This;is;practice." )  # prints "This;is;practice."
  MESSAGE( "Hi. ) MESSAGE( x )" ) # prints "Hi. ) MESSAGE( x )"
  MESSAGE( "Hi. ) MESSAGE( x )" ) # prints "Hi. ) MESSAGE( x )"
</pre>


You can also quote ''parts'' of arguments. CMake has to decide whether or not the quotes or quoting syntax (as in shell script) or literal quotes. The rules in CMake 2.4 are:
You can also quote ''parts'' of arguments. CMake has to decide whether or not the quotes or quoting syntax (as in shell script) or literal quotes. The rules in CMake 2.4 are:
Line 231: Line 271:
Quoting does not prevent substitutions. It does, however, prevent CMake from splitting arguments at the semicolons, and allows you to pass empty strings as arguments:
Quoting does not prevent substitutions. It does, however, prevent CMake from splitting arguments at the semicolons, and allows you to pass empty strings as arguments:


<pre>
  SET( SOURCES back.c io.c main.c )
  SET( SOURCES back.c io.c main.c )
  MESSAGE( ${SOURCES}  )      # three arguments, prints "back.cio.cmain.c"
  MESSAGE( ${SOURCES}  )      # three arguments, prints "back.cio.cmain.c"
Line 238: Line 279:
  MESSAGE( ${EMPTY_STRING} )  # zero arguments,  causes CMake Error
  MESSAGE( ${EMPTY_STRING} )  # zero arguments,  causes CMake Error
                               # "MESSAGE called with incorrect number of arguments"
                               # "MESSAGE called with incorrect number of arguments"
</pre>


=== Escapes ===
=== Escapes ===
A backslash <tt>\</tt> in the arguments to a command will start an escape sequence. To use literally any of <tt>"()#$^</tt>, escape the character with a backslash. You may also escape a space (instead of quoting it) and you may use <tt>\\</tt> for a literal backslash.
A backslash <tt>\</tt> in the arguments to a command will start an escape sequence. To use literally any of <tt>"()#$^</tt>, escape the character with a backslash. You may also escape a space (instead of quoting it) and you may use <tt>\\</tt> for a literal backslash.


<pre>
  MESSAGE( \\\"\ \(\)\#\$\^ ) # this message contains literal characters
  MESSAGE( \\\"\ \(\)\#\$\^ ) # this message contains literal characters
 
  MESSAGE( \# not a comment )
  MESSAGE( \# not a comment )
  MESSAGE( \${NotAnExpansion} )
  MESSAGE( \${NotAnExpansion} )
  SET( rightparen \) )
  SET( rightparen \) )
</pre>


There are a few other escape sequences, including <tt>\n</tt> for newline, and possibly others that I forgot. All other escape sequences are invalid and cause a CMake error.
There are a few other escape sequences, including <tt>\n</tt> for newline, and possibly others that I forgot. All other escape sequences are invalid and cause a CMake error.
Line 262: Line 306:
The WHILE command works like the IF command except that it is a loop: after CMake runs the commands between the WHILE and ENDWHILE commands, CMake jumps back to the WHILE command to check whether to run the loop again. Here is an example:
The WHILE command works like the IF command except that it is a loop: after CMake runs the commands between the WHILE and ENDWHILE commands, CMake jumps back to the WHILE command to check whether to run the loop again. Here is an example:


<pre>
  SET( number 4 )
  SET( number 4 )
  # if ${number} is greater than 10
  # if ${number} is greater than 10
Line 267: Line 312:
   MESSAGE( "The number ${number} is too large." )
   MESSAGE( "The number ${number} is too large." )
  ENDIF( number GREATER 10 )
  ENDIF( number GREATER 10 )
 
  # while ${number} is between 0 and 11
  # while ${number} is between 0 and 11
  WHILE( number GREATER 0 AND number LESS 11 )
  WHILE( number GREATER 0 AND number LESS 11 )
Line 273: Line 318:
   MATH( EXPR number "${number} - 1" ) # decrement number
   MATH( EXPR number "${number} - 1" ) # decrement number
  ENDWHILE( number GREATER 0 AND number LESS 11 )
  ENDWHILE( number GREATER 0 AND number LESS 11 )
</pre>


If number is too large, this listfile complains. Otherwise, the loop counts down toward zero and says hi to each number. If number starts at 4, then the messages are "hi 4", "hi 3", "hi 2", "hi 1".
If number is too large, this listfile complains. Otherwise, the loop counts down toward zero and says hi to each number. If number starts at 4, then the messages are "hi 4", "hi 3", "hi 2", "hi 1".
Line 280: Line 326:
The arguments to IF and WHILE commands may contain substitutions, as any other command:
The arguments to IF and WHILE commands may contain substitutions, as any other command:


<pre>
  SET( number 4 )
  SET( number 4 )
  SET( operation GREATER )
  SET( operation GREATER )
Line 286: Line 333:
   MESSAGE( "Oops, ${number} is ${operation} than ${limit}." )
   MESSAGE( "Oops, ${number} is ${operation} than ${limit}." )
  ENDIF( number ${operation} ${limit} )
  ENDIF( number ${operation} ${limit} )
</pre>


The syntax for boolean expressions is given in the CMake manual page, in the section for the IF command. This includes the order of operations (for example, <tt>GREATER</tt> and <tt>LESS</tt> have higher precedence than AND). Note that the operations are case sensitive, because they are arguments: <tt>GREATER</tt> is an operation, <tt>greater</tt> is not.
The syntax for boolean expressions is given in the CMake manual page, in the section for the IF command. This includes the order of operations (for example, <tt>GREATER</tt> and <tt>LESS</tt> have higher precedence than AND). Note that the operations are case sensitive, because they are arguments: <tt>GREATER</tt> is an operation, <tt>greater</tt> is not.
Line 292: Line 340:
A SET command with more than two arguments will join the second and after arguments with semicolons:
A SET command with more than two arguments will join the second and after arguments with semicolons:


<pre>
  SET( letters a b c d ) # sets letters to "a;b;c;d"
  SET( letters a b c d ) # sets letters to "a;b;c;d"
</pre>


A string that contains semicolons is a list. An empty string "" is a list of zero elements, while a nonempty string that contains zero semicolons is a list of one element. For example, you might have a list of source files for a particular target. CMake does not have arrays like Perl or shell script, or linked lists like Lisp; the expectation is that your CMake scripts will use semicolon delimiters in lists.
A string that contains semicolons is a list. An empty string "" is a list of zero elements, while a nonempty string that contains zero semicolons is a list of one element. For example, you might have a list of source files for a particular target. CMake does not have arrays like Perl or shell script, or linked lists like Lisp; the expectation is that your CMake scripts will use semicolon delimiters in lists.
Line 300: Line 350:
CMake splits arguments at semicolons, thus a list will split into multiple arguments. You may store arguments in a list and use them with a later command:
CMake splits arguments at semicolons, thus a list will split into multiple arguments. You may store arguments in a list and use them with a later command:


<pre>
  SET( expression 4 LESS 10 ) # ${expression} is now "4;LESS;10"
  SET( expression 4 LESS 10 ) # ${expression} is now "4;LESS;10"
  IF( ${expression} )        # expands to IF( 4;LESS;10 )
  IF( ${expression} )        # expands to IF( 4;LESS;10 )
   MESSAGE( "CMake believes that 4 is less than 10." )
   MESSAGE( "CMake believes that 4 is less than 10." )
  ENDIF( ${expression} )
  ENDIF( ${expression} )
</pre>


In a CMake project, you might have a variable <tt>sources</tt> for a list of source files. When you call ADD_EXECUTABLE or ADD_LIBRARY to create a target, you may pass <tt>${sources}</tt>.
In a CMake project, you might have a variable <tt>sources</tt> for a list of source files. When you call ADD_EXECUTABLE or ADD_LIBRARY to create a target, you may pass <tt>${sources}</tt>.
Line 314: Line 366:
The first argument to the SET command is a variable name, not a substitution. SET wants to know the name of the variable to set, not the variable's current value. (This is different from Perl, which does not perform substitution.) It remains legitimate to use a substitution if the name of the variable that you want to set is the value of another variable:
The first argument to the SET command is a variable name, not a substitution. SET wants to know the name of the variable to set, not the variable's current value. (This is different from Perl, which does not perform substitution.) It remains legitimate to use a substitution if the name of the variable that you want to set is the value of another variable:


<pre>
  SET( varname number ) # sets varname to "number"
  SET( varname number ) # sets varname to "number"
  SET( ${varname} 4 )  # sets number to "4"
  SET( ${varname} 4 )  # sets number to "4"
</pre>


== CMake may access environment variables. ==
== CMake may access environment variables. ==
You can also substitute the value of an environment variable. The syntax is $ENV{''name''}.
You can also substitute the value of an environment variable. The syntax is $ENV{''name''}.


<pre>
  MESSAGE( "Your Unix home directory is $ENV{HOME}." )
  MESSAGE( "Your Unix home directory is $ENV{HOME}." )
</pre>


Note that "ENV" is the only permitted hash (or map or dictionary, or your name for a set of key-value pairs). If you attempt to access another hash, then CMake will give an error:
Note that "ENV" is the only permitted hash (or map or dictionary, or your name for a set of key-value pairs). If you attempt to access another hash, then CMake will give an error:


<pre>
  MESSAGE( $hi{there} )
  MESSAGE( $hi{there} )
  # causes error "Key hi is not used yet. For now only $ENV{..} is allowed"
  # causes error "Key hi is not used yet. For now only $ENV{..} is allowed"
</pre>


Yes, it is possible to set an environment variable:
Yes, it is possible to set an environment variable:


<pre>
  SET( ENV{PATH} /bin:/usr/bin ) # use a minimal PATH
  SET( ENV{PATH} /bin:/usr/bin ) # use a minimal PATH
</pre>


== Recursive substitutions permit indirect variables. ==
== Recursive substitutions permit indirect variables. ==
CMake can handle recursive substitutions, so that you may let one variable contain the name (or part of the name) of another variable:
CMake can handle recursive substitutions, so that you may let one variable contain the name (or part of the name) of another variable:


<pre>
  SET( varname x )
  SET( varname x )
  SET( x 6 )
  SET( x 6 )
  MESSAGE( "${varname} is ${${varname}}" ) # displays "x is 6"
  MESSAGE( "${varname} is ${${varname}}" ) # displays "x is 6"
</pre>


It is not necessary to employ a workaround like "STRING( CONFIGURE ... )".
It is not necessary to employ a workaround like "STRING( CONFIGURE ... )".

Revision as of 18:32, 24 April 2018

CMake has its own basic scripting language. A new user of CMake, learning this language, mostly needs to know about commands like SET, IF and MESSAGE. Sometimes, the details become lost. How does one manipulate variables? How do quotes and escapes work? Why do FOREACH and MACRO parameters behave strangely? What is the syntax?

CMake bug 6295 asked for documentation of the core syntax. Thus the CMake web site now has a quick introduction to CMake syntax.

This wiki page (formerly [1]) contains an overview of the CMake language, its quirks and its limitations. Anyone may contribute to this page. You may edit, rewrite, refactor, correct or otherwise improve this page. Help other CMake users understand the language and avoid mistakes, contribute to this wiki.

There is another wiki page, CMake:VariablesListsStrings, that has more details about variables and regular expressions.

cmake -P

The script mode cmake -P <script> allows you to run arbitrary CMake scripts (except that all commands related to Makefile generation or the CMake cache will fail). You may use this tool to experiment with the language, or to help create examples for this page. Write your script in a text editor and test your script with cmake -P something.cmake.

If your system is Unix, then cmake -P /dev/stdin is a good way to play with language: you type your script, type Control-D for end-of-file, and the script runs. The Windows equivalent is to run cmake -P con, and to use Control-Z (on a new line, followed by return) for end-of-file.

Listfiles contain comments and commands.

We refer to each CMake script or CMakeLists.txt file as a listfile. The basic syntax of a listfile is extremely simple: a listfile may contain only commands and comments. Comments start with a # character and stop at the end of a line. You may freely mix comments with commands; comments may between or amid commands:

 # This is a comment.
 COMMAND( arguments go here )
 ANOTHER_COMMAND() # this command has no arguments
 YET_ANOTHER_COMMAND( these
   arguments are spread         # another comment
   over several lines )

The names of commands are case insensitive; the usual convention is to type the command names in uppercase. However, the arguments are case sensitive. Thus MESSAGE and message and Message and mESsAgE are the same command:

 MESSAGE( hi ) # displays "hi"
 message( hi ) # displays "hi" again
 message( HI ) # displays "HI"

The whitespace around the ( and ) parens is optional, all of these commands are the same:

 MESSAGE(hi)
 MESSAGE (hi)
 MESSAGE( hi )
 MESSAGE (hi )

Commands are procedure calls and cannot return values. However, you may pass the name of a global variable to some commands, and those commands will store the result there. For example, the MATH( EXPR ... ) command takes three arguments; the third argument is the expression, and the second argument is the variable to store the result:

 MATH( EXPR x "3 + 3" ) # stores the result of 3 + 3 in x
 MESSAGE( "x is ${x}" ) # displays "x is 6"
                        # using quotes so MESSAGE receives only one argument

CMake variables

In versions of CMake<=2.4, almost all variables have global scope within a directory (and in that directory's subdirectories); a notable exception is the FOREACH command, the loop variable of which is local only to the FOREACH body. Also, the parameters (including ARG0, ARG1, ARG2, ARGC, ARGN, and ARGV) of user defined macros are not variables, per se; their values must always be used directly: IF(${some_parameter}) instead of IF(some_parameter).

CMake 2.6 introduces functions, which are essentially macros that have local scope and use real variables (even ARG0, ARG1, ARGC, ARGN, and ARGV are treated as real variables); IF(some_parameter) is perfectly acceptable. Most importantly, global variables are read-only within functions. Whenever a variable is set within a function body, that variable only has local scope, masking any similarly named global variable; outside of the function body, the global variables remain unchanged.

See CMake:VariablesListsStrings about how the ADD_SUBDIRECTORY or SUBDIRS command affects variables in a CMake project.

Values

Variables always contain strings. Sometimes, we use the string to store a boolean, a path to a file, an integer, or a list.

SET and substitution

Use the SET command to set the value of a variable to some string. The SET command takes two arguments: the name of the variable and its new value, SET(variable value). To access the value of a variable, you perform a substitution. To perform a substitution, use the syntax ${variablename}:

 SET( x 3 )
 SET( y 1 )
 MESSAGE( ${x}${y} ) # displays "31"

If more than one value is specified, each value is concatenated into one string in which semicolons serve to separate the indivual values. This kind of string is called a list in CMake and can be used with the LIST command. You may use quoting to avoid this:

 SET( x a b c   ) # stores "a;b;c" in x      (without quotes)
 SET( y "a b c" ) # stores "a b c" in y      (without quotes)
 MESSAGE( a b c ) # prints "abc"   to stdout (without quotes)
 MESSAGE( ${x} )  # prints "abc"   to stdout (without quotes)
 MESSAGE("${x}")  # prints "a;b;c" to stdout (without quotes)
 MESSAGE( ${y} )  # prints "a b c" to stdout (without quotes)
 MESSAGE("${y}")  # prints "a b c" to stdout (without quotes)

In fact, the following are equivalent:

 SET( x a b c )
 SET( x a;b;c )
 SET( x "a;b;c" )
 SET( x;a;b;c )

However, this does 'not' work:

 SET( "x;a;b;c" )

Of course, the arguments to SET itself can come from substitutions:

 SET( x y A B C )              # stores "y;A;B;C" in x (without quote)
 SET( ${x} )                   # => SET( y;A;B;C ) => SET( y A B C)
 MESSAGE( ${y} )               # prints "ABC" to stdout (without quotes)
 SET( y x )                    # stores "x" in y (without quotes)
 SET( ${y} y = x )             # => SET( x y )
 MESSAGE( "\${x} = '${x}'" )   # prints "${x} = 'y;=;x'" to stdout (without quotes)
 SET( y ${x} )                 # => SET( y y = x ) => stores "y;=;x" in y (without quotes)
 MESSAGE( ${y} )               # prints "y=x" to stdout (without quotes)

The value can be the empty string, "":

 SET( x "" )

If there is no value specified, then the variable is UNSET, so that it is like the variable never existed:

 SET( x )
 IF(DEFINED x)
   MESSAGE("This will never be printed")
 ENDIF(DEFINED x)

However, this is more obviously performed with the UNSET command:

 UNSET( x )

Substitution of command names

Substitution only works within arguments to commands. In particular, the name of a command cannot include a substitution; so you cannot store the name of a command in a variable, then run that command. For example, this does not work:

 SET( command MESSAGE )
 ${command}( hi )
 # syntax error

If you insist, the available workaround is to write the command to a temporary file, then INCLUDE the file to run the command.

 SET( command MESSAGE )
 
 # ${command}( hi )
 FILE( WRITE temp "${command}( hi )" ) # writes "MESSAGE( hi )" to ./temp
 INCLUDE( temp )                       # ./temp is an unsafe temporary file...
 FILE( REMOVE temp )

The following code can be used to (a) generate unique / temporary file names and (b) evaluate commands in those files as suggested:

 #!/usr/bin/cmake -P
 
 macro(temp_name fname)
   if(${ARGC} GREATER 1) # Have to escape ARGC to correctly compare
     set(_base ${ARGV1})
   else(${ARGC} GREATER 1)
     set(_base ".cmake-tmp")
   endif(${ARGC} GREATER 1)
   set(_counter 0)
   while(EXISTS "${_base}${_counter}")
     math(EXPR _counter "${_counter} + 1")
   endwhile(EXISTS "${_base}${_counter}")
   set(${fname} "${_base}${_counter}")
 endmacro(temp_name)
 
 # Evaluate expression
 # Suggestion from the Wiki: http://cmake.org/Wiki/CMake/Language_Syntax
 # Unfortunately, no built-in stuff for this: http://public.kitware.com/Bug/view.php?id=4034
 macro(eval expr)
   temp_name(_fname)
   file(WRITE ${_fname} "${expr}")
   include(${_fname})
   file(REMOVE ${_fname})
 endmacro(eval)

An example of this in use:

 eval("message(\"Hai\")")
 
 set(funcs a;b)
 macro(test_a arg)
   message("A: ${arg}")
 endmacro(test_a)
 macro(test_b arg)
   message("B: ${arg}")
 endmacro(test_b)
 
 foreach(func ${funcs})
   set(func_name test_${func})
   eval("${func_name}(\"Test\")")
 endforeach(func)

Output:

 Hai
 A: Test
 B: Test

This was included from this post by the author.

CMake splits arguments unless you use quotation marks or escapes.

Each command in a listfile takes zero or more arguments. CMake separates arguments by whitespace, performs substitutions, then separates arguments by semicolons. That is, if you are just typing literal arguments, then you may use either whitespace or semicolons to separate them. However, if you want a variable substitution to produce multiple arguments, then you need to use semicolons in the variable.

To shell script hackers, this is not the same as setting IFS=\; in a Bourne shell that follows POSIX. (Because ; is also a shell operator, we escape it with a backslash.) The difference is that the Bourne shell will only use the ; delimeter within substitutions, while CMake will use it everywhere:

 # shell script
 countargs() {
   echo $#
 }
 IFS=\;
 countargs a\;b\;c    # displays "1"
 ARGS=a\;b\;c
 countargs $ARGS      # displays "3"
 
 # CMake
 MACRO( COUNTARGS )
   MESSAGE ( ${ARGC} )
 ENDMACRO( COUNTARGS )
 COUNTARGS( a;b;c )   # displays "3"
 SET( ARGS a;b;c )
 COUNTARGS( ${ARGS} ) # displays "3"

Importantly, the MESSAGE command has the habit of concatenating all of its arguments! (This is why many examples on this page use quoting so that MESSAGE takes only one argument.) The following three commands are effectively the same:

 MESSAGE(This is practice.)             # prints "Thisispractice."
 MESSAGE(  This   is    practice.     ) # prints "Thisispractice."
 MESSAGE( This;is;practice. )           # prints "Thisispractice."

Quoting

You can preserve whitespace, semicolons and parens by quoting entire arguments, as if they were strings in C:

 MESSAGE( "This is practice." )  # prints "This is practice."
 MESSAGE( "This;is;practice." )  # prints "This;is;practice."
 MESSAGE( "Hi. ) MESSAGE( x )" ) # prints "Hi. ) MESSAGE( x )"

You can also quote parts of arguments. CMake has to decide whether or not the quotes or quoting syntax (as in shell script) or literal quotes. The rules in CMake 2.4 are:

  1. If the argument begins with a quote, then the quotes are quoting syntax.
  2. Otherwise, if the quotes surround whitespace, semicolons or parens to preserve, then the quotes are quoting syntax.
  3. Otherwise, the quotes are literal quotes.
Input Output
MESSAGE( "Welc"ome ) # rule 1 Welcome
MESSAGE( Welc"ome" ) # rule 3 Welc"ome"
MESSAGE( Welc"ome)" ) # rule 2 Welcome)
MESSAGE( ""Thanks ) # rule 1 Thanks
MESSAGE( Thanks"" ) # rule 3 Thanks""

Quoting does not prevent substitutions. It does, however, prevent CMake from splitting arguments at the semicolons, and allows you to pass empty strings as arguments:

 SET( SOURCES back.c io.c main.c )
 MESSAGE( ${SOURCES}   )      # three arguments, prints "back.cio.cmain.c"
 MESSAGE( "${SOURCES}" )      # one argument,    prints "back.c;io.c;main.c"
 MESSAGE( "" )                # one argument,    prints "" an empty line
 MESSAGE( "${EMPTY_STRING}" ) # one argument,    prints "" an empty line
 MESSAGE( ${EMPTY_STRING} )   # zero arguments,  causes CMake Error
                              # "MESSAGE called with incorrect number of arguments"

Escapes

A backslash \ in the arguments to a command will start an escape sequence. To use literally any of "()#$^, escape the character with a backslash. You may also escape a space (instead of quoting it) and you may use \\ for a literal backslash.

 MESSAGE( \\\"\ \(\)\#\$\^ ) # this message contains literal characters
 
 MESSAGE( \# not a comment )
 MESSAGE( \${NotAnExpansion} )
 SET( rightparen \) )

There are a few other escape sequences, including \n for newline, and possibly others that I forgot. All other escape sequences are invalid and cause a CMake error.

CMake supports boolean variables.

CMake considers an empty string, "FALSE", "OFF", "NO", or any string ending in "-NOTFOUND" to be false. (This happens to be case-insensitive, so "False", "off", "no", and "something-NotFound" are all false.) Other values are true. Thus it matters not whether you use TRUE and FALSE, ON and OFF, or YES and NO for your booleans.

Many scripts expect a string to either be false or contain a useful value, often a path to a directory or a file. You have a potential but rare problem if one of the useful values coincides with falseness. Avoid giving nonsensical names like /tmp/ME-NOTFOUND to your files, executables or libraries.

IF and WHILE control the flow.

Any scripting language provides conditionals and loops. In CMake, the IF command provides conditionals, while the WHILE command provides a loop. These two commands also provide the way to evaluate boolean expressions.

When CMake executes an IF command, it evaluates the arguments to get a boolean condition. If the condition is true, it runs the command between the IF and matching ENDIF commands, else it skips them.

The WHILE command works like the IF command except that it is a loop: after CMake runs the commands between the WHILE and ENDWHILE commands, CMake jumps back to the WHILE command to check whether to run the loop again. Here is an example:

 SET( number 4 )
 # if ${number} is greater than 10
 IF( number GREATER 10 )
   MESSAGE( "The number ${number} is too large." )
 ENDIF( number GREATER 10 )
 
 # while ${number} is between 0 and 11
 WHILE( number GREATER 0 AND number LESS 11 )
   MESSAGE( "hi ${number}")
   MATH( EXPR number "${number} - 1" ) # decrement number
 ENDWHILE( number GREATER 0 AND number LESS 11 )

If number is too large, this listfile complains. Otherwise, the loop counts down toward zero and says hi to each number. If number starts at 4, then the messages are "hi 4", "hi 3", "hi 2", "hi 1".

Note that CMake is very strict, and requires the matching IF and ENDIF (or WHILE and ENDWHILE) commands to have the same arguments. This strictness is not necessary to the language (because CMake may count IF and ENDIF commands to determine the nesting of conditions, similar to how ShellScript counts if and then and fi commands) but it catches programmer errors. There is a way in CMake to disable this strictness, so that a simple ENDIF() works.

The arguments to IF and WHILE commands may contain substitutions, as any other command:

 SET( number 4 )
 SET( operation GREATER )
 SET( limit 10 )
 IF( number ${operation} ${limit} )
   MESSAGE( "Oops, ${number} is ${operation} than ${limit}." )
 ENDIF( number ${operation} ${limit} )

The syntax for boolean expressions is given in the CMake manual page, in the section for the IF command. This includes the order of operations (for example, GREATER and LESS have higher precedence than AND). Note that the operations are case sensitive, because they are arguments: GREATER is an operation, greater is not.

Join a list with semicolons.

A SET command with more than two arguments will join the second and after arguments with semicolons:

 SET( letters a b c d ) # sets letters to "a;b;c;d"

A string that contains semicolons is a list. An empty string "" is a list of zero elements, while a nonempty string that contains zero semicolons is a list of one element. For example, you might have a list of source files for a particular target. CMake does not have arrays like Perl or shell script, or linked lists like Lisp; the expectation is that your CMake scripts will use semicolon delimiters in lists.

CMake provides a LIST command that performs basic operations with list.

CMake splits arguments at semicolons, thus a list will split into multiple arguments. You may store arguments in a list and use them with a later command:

 SET( expression 4 LESS 10 ) # ${expression} is now "4;LESS;10"
 IF( ${expression} )         # expands to IF( 4;LESS;10 )
   MESSAGE( "CMake believes that 4 is less than 10." )
 ENDIF( ${expression} )

In a CMake project, you might have a variable sources for a list of source files. When you call ADD_EXECUTABLE or ADD_LIBRARY to create a target, you may pass ${sources}.

When CMake wants a variable name, when it wants a substitution.

Does IF( number GREATER 10 ) mean the same as IF( ${number} GREATER 10 )? Actually it does, if number is a variable. Some operations in boolean expressions will accept either a variable name or a value. If the name matches a variable name, then CMake uses that variable's value; but if the name does not match a variable name, then CMake uses the direct value.

Suppose the variable number contains 4. Then IF( number GREATER 10 ) will notice that number is the name of a variable, and CMake tests if 4 is greater than 10. (The test is false.) But IF( ${number} GREATER 10 ) expands to IF( 4 GREATER 10 ), and we hope that 4 is not the name of a variable, so CMake tests if 4 is greater than 10.

The first argument to the SET command is a variable name, not a substitution. SET wants to know the name of the variable to set, not the variable's current value. (This is different from Perl, which does not perform substitution.) It remains legitimate to use a substitution if the name of the variable that you want to set is the value of another variable:

 SET( varname number ) # sets varname to "number"
 SET( ${varname} 4 )   # sets number to "4"

CMake may access environment variables.

You can also substitute the value of an environment variable. The syntax is $ENV{name}.

 MESSAGE( "Your Unix home directory is $ENV{HOME}." )

Note that "ENV" is the only permitted hash (or map or dictionary, or your name for a set of key-value pairs). If you attempt to access another hash, then CMake will give an error:

 MESSAGE( $hi{there} )
 # causes error "Key hi is not used yet. For now only $ENV{..} is allowed"

Yes, it is possible to set an environment variable:

 SET( ENV{PATH} /bin:/usr/bin ) # use a minimal PATH

Recursive substitutions permit indirect variables.

CMake can handle recursive substitutions, so that you may let one variable contain the name (or part of the name) of another variable:

 SET( varname x )
 SET( x 6 )
 MESSAGE( "${varname} is ${${varname}}" ) # displays "x is 6"

It is not necessary to employ a workaround like "STRING( CONFIGURE ... )".

TODO

  • Describe ELSE and ELSEIF.
  • Describe FOREACH and MACRO on this page. These commands provide constant parameters, not variables; demonstrate that you cannot SET them. Explain the important rule, constant expansion happens before variable expansion. This rule has consequences when your parameter contains "${" somewhere.

History

Kernigh began to write about the syntax of the language of CMake. At first, the information appeared in a wiki page "The Scripting Language of CMake", http://kernigh.pbwiki.com/CMake. Then Kernigh moved the syntax information to this page at the Kitware Public Wiki.



CMake: [Welcome | Site Map]