CMake/Language Syntax: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
(Moved syntax info from http://kernigh.pbwiki.com/CMake. This commit only changes PBwiki syntax to MediaWiki syntax and adds a brief 'History' section. I will edit this page again.)
 
(Replace content with link to new CMake community wiki)
 
(17 intermediate revisions by 10 users not shown)
Line 1: Line 1:
'''CMake has its own basic scripting language.''' The script mode <tt>cmake -P &lt;script&gt;</tt> allows you to run arbitrary CMake scripts (except that all commands related to Makefile generation or the CMake cache will fail). Using <tt>cmake -P /dev/stdin</tt> is a good way to play with language: you type your script, type Control-D for end-of-file, and the script runs. This page contains an overview of the language.
{{CMake/Template/Moved}}


__TOC__
This page has moved [https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Language-Syntax here].
 
== Listfiles contain comments and 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:
 
# 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"
 
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:
 
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
 
== All CMake variables are global. ==
Each variable has a global scope. There are no variables in CMake that have a limited static scope (as C variables declared in blocks, or PerlFive "my") or dynamic scope (as PerlFive or ShellScript "local"). ''Variables always contain strings.'' Sometimes, we use the string to store a boolean, a path to a file, an integer, or a list.
 
However, the FOREACH or MACRO command can create a constant parameter of static scope.
 
=== SET and substitution ===
Use the SET command to set the value of a global variable to some string. The SET command takes two arguments, the name of the variable and its new value. To access the value of a variable, you perform a ''substitution''. To perform a substitution, use the syntax <tt>${''variablename''}</tt>:
 
SET( x 3 )
SET( y 1 )
MESSAGE( ${x}${y} ) # displays "31"
 
A SET command with more than two arguments will join the second and after arguments with semicolons, and store the semicolon-delimited list. You may use quoting to avoid this:
 
SET( x main.c engine.c util.c  ) # stores "main.c;engine.c;util.c" in x
SET( y "main.c engine.c util.c" ) # stores "main.c engine.c util.c" in y
 
=== Substitution of command names ===
Substitution only works within arguments to commands. In particular, the name of a command cannot include a substitution. If you have stored the name of the command in a variable, and you must run that command, then 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 )" )
INCLUDE( temp ) # unsafe temporary file...
FILE( REMOVE temp )
 
== 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 ShellScript 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:
 
# 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 are:
 
# If the argument begins with a quote, then the quotes are ''quoting syntax''.
# Otherwise, if the quotes surround whitespace, semicolons or parens to preserve, then the quotes are ''quoting syntax''.
# Otherwise, the quotes are ''literal quotes''.
 
{| border="1"
|| Input                                  || Output
|-
|| <tt>MESSAGE( "Welc"ome ) # rule 1</tt>  || <tt>Welcome</tt>
|-
|| <tt>MESSAGE( Welc"ome" ) # rule 3</tt>  || <tt>Wel"come"</tt>
|-
|| <tt>MESSAGE( Welc"ome)" ) # rule 2</tt> || <tt>Welcome)</tt>
|-
|| <tt>MESSAGE( ""Thanks ) # rule 1</tt>  || <tt>Thanks</tt>
|-
|| <tt>MESSAGE( Thanks"" ) # rule 3</tt>  || <tt>Thanks""</tt>
|}
 
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 <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.
 
MESSAGE( \\\"\ \(\)\#\$\^ ) # this message contains literal characters
 
MESSAGE( \# not a comment )
MESSAGE( \${NotAnExpansion} )
SET( rightparen \) )
 
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 variable.
 
== 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 <tt>/tmp/ME-NOTFOUND</tt> 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.
 
When CMake sees an IF command, then it checks the arguments to the IF command. Is the condition is true, then 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 <tt>if</tt> and <tt>then</tt> and <tt>fi</tt> commands) but it catches programmer errors. There is a way in CMake to disable this strictness, so that a simple <tt>ENDIF()</tt> works.
 
The arguments to IF and WHILE commands may contain substitutions, as any other command:
 
SET( number 4 )
SET( operation OPERATION )
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, <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.
 
== 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 PerlFive or ShellScript, 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.
 
== When CMake wants a variable name, when it wants a substitution. ==
Does <tt>IF( number GREATER 10 )</tt> mean the same as <tt>IF( ${number} GREATER 10 )</tt>? Actually it does, if <tt>number</tt> 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 <tt>number</tt> contains 4. Then <tt>IF( number GREATER 10 )</tt> will notice that <tt>number</tt> is the name of a variable, and CMake tests if 4 is greater than 10. (The test is false.) But <tt>IF( ${number} GREATER 10 )</tt> expands to <tt>IF( 4 GREATER 10 )</tt>, and we hope that <tt>4</tt> 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 PerlFive, 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 subsitutions 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"
 
Some older scripts in ObjectNecromancer have ignored this easy tactic, but use the "STRING( CONFIGURE ... )" command as an unnecessary workaround.
 
== TODO ==
* Describe FOREACH and MACRO on this page
* Mention regular expressions
 
== History ==
[[User:Kernigh|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.

Latest revision as of 15:40, 30 April 2018


The CMake community Wiki has moved to the Kitware GitLab Instance.

This page has moved here.