I am writing CMake macros for the first time, and I have a hard time understanding how variables work. Most specifically, ${a}
seems to have a different meaning than "${a}"
.
For example here: Passing a list to a CMake macro
I fail to understand when I am supposed to add quotes, and what are the bigger underlying principles.
You can use the command line to set entries in the Cache with the syntax cmake -D var:type=value , just cmake -D var=value or with cmake -C CMakeInitialCache. cmake . You can unset entries in the Cache with unset(... CACHE) .
Options and variables are defined on the CMake command line like this: $ cmake -DVARIABLE=value path/to/source You can set a variable after the initial `CMake` invocation to change its value. You can also undefine a variable: $ cmake -UVARIABLE path/to/source Variables are stored in the `CMake` cache.
Run CMake and have a look at the cache with the ccmake GUI tool. Then you'll get all the variables. Or run CMake with -LH then you will get all variables printed after configuration.
The type of the variable is used by the cmake-gui to control how that variable is set and displayed, but the value is always stored in the cache file as a string.
Two principles of CMake you have to keep in mind:
Examples
set(_my_text "A B C")
with message("${_my_text}")
would give A B C
set(_my_list A B C)
with message("${_my_list}")
would give A;B;C
set(_my_list "A" "B" "C")
with message("${_my_list}")
would give A;B;C
set(_my_list "A" "B" "C")
with message(${_my_list})
would give ABC
Some Rules of Thumb
There are some rules of thumb you should consider:
a) When your variable contains text - especially one that could contain semicolons - you should add quotes.
Reasoning: A semicolon is a delimiter for list elements in CMake. So put quotes around a text that is supposed to be one (it works everywhere and for me personally looks better with CMake syntax highlighting)
EDIT: Thanks for the hint from @schieferstapel
b) To be more precise: A variable content with spaces that already had quotes does keep those quotes (imagine as it getting part of the variable's content). This works everywhere also unquoted (normal or user-defined function parameters) with the prominent exception of if()
calls, where CMake re-interprets the content of unquoted variables after variable expansion (see also rule of thumb #3 and policy CMP0054: Only interpret if()
arguments as variables or keywords when unquoted)
Examples:
set(_my_text "A B C")
with message(${_my_text})
would also give A B C
set(_my_text "A;B;C")
with if (${_my_text} STREQUAL "A;B;C")
would give if given arguments: "A" "B" "C" "STREQUAL" "A;B;C" Unknown arguments specified
If your variable contains a list you normally don't add quotes.
Reasoning: If you give something like a file list to an CMake command it normally expect a list of strings and not one string containing a list. The difference you can see e.g. in the foreach()
command accepting ITEMS
or LISTS
.
if()
statements are a special case where you normally don't even put the braces.
Reasoning: A string could - after expansion - evaluate again to a variable name. To prevent this it's recommended to just name the variable whose content you want to compare (e.g. if (_my_text STREQUAL "A B C")
).
COMMAND
Examples
set(_my_text "A B C")
with COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}"
would cmake.exe -E echo "A B C"
on VS/Windows cmake -E echo A\ B\ C
on GCC/Ubuntu A B C
set(_my_text "A B C")
with COMMAND "${CMAKE_COMMAND}" -E echo "${_my_text}" VERBATIM
would cmake.exe -E echo "A B C"
on VS/Windows cmake -E echo "A B C"
on GCC/Ubuntu A B C
set(_my_list A B C)
with COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}"
would cmake.exe -E echo A;B;C
A
, B: command not found
, C: command not found
set(_my_list A B C)
with COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
would cmake.exe -E echo "A;B;C"
A;B;C
set(_my_list "A" "B" "C")
with COMMAND "${CMAKE_COMMAND}" -E echo "${_my_list}" VERBATIM
would cmake.exe -E echo "A;B;C"
A;B;C
set(_my_list "A" "B" "C")
with COMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
would cmake.exe -E echo A B C
A B C
set(_my_list "A + B" "=" "C")
with COMMAND "${CMAKE_COMMAND}" -E echo ${_my_list} VERBATIM
would cmake.exe -E echo "A + B" = C
A + B = C
Some Rules of Thumb with add_custom_target()
/add_custom_command()
/execute_process()
There are some rules of thumb you should consider when you use variables in COMMAND
calls:
a) Use quotes for the arguments that contain file paths (like the first argument containing the executable itself).
Reasoning: It could contain spaces and could be reinterpreted as separate arguments to the COMMAND
call
b) See above, works also if the variable set()
did include quotes.
Use quotes only if you want to concatenate something into a single parameter to be passed to executable that is called.
Reasoning: A variable could contain a list of parameters which - when using quotes - won't be correctly extracted (semicolons instead of spaces)
Always add the VERBATIM
option with add_custom_target()
/add_custom_command()
Reasoning: Otherwise the cross-platform behavior is undefined and you could get surprises with your quoted strings.
References
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With