I wonder why often variables in CMake are wrapped with a dollar sign and curly brackets. For example, I saw this call in a CMake tutorial.
include_directories(${PROJECT_BINARY_DIR})
But from what I tried, this does the same thing.
include_directories(PROJECT_BINARY_DIR)
When is the wrapping with ${...}
needed and what does it mean? Why are variables often wrapped with this even if it makes no difference?
Local Variables You access a variable by using ${} , such as ${MY_VARIABLE} . 1. CMake has the concept of scope; you can access the value of the variable after you set it as long as you are in the same scope. If you leave a function or a file in a sub directory, the variable will no longer be defined.
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 .
If the PARENT_SCOPE option is given the variable will be set in the scope above the current scope. Each new directory or function creates a new scope. This command will set the value of a variable into the parent directory or calling function (whichever is applicable to the case at hand).
The CMake cache may be thought of as a configuration file. The first time CMake is run on a project, it produces a CMakeCache. txt file in the top directory of the build tree. CMake uses this file to store a set of global cache variables, whose values persist across multiple runs within a project build tree.
Quoting the CMake documentation:
A variable reference has the form
${variable_name}
and is evaluated inside a Quoted Argument or an Unquoted Argument. A variable reference is replaced by the value of the variable, or by the empty string if the variable is not set.
In other words, writing PROJECT_BINARY_DIR
refers, literally, to the string "PROJECT_BINARY_DIR". Encapsulating it in ${...}
gives you the contents of the variable with the name PROJECT_BINARY_DIR.
Consider:
set(FOO "Hello there!") message(FOO) # prints FOO message(${FOO}) # prints Hello there!
As you have probably guessed already, include_directories(PROJECT_BINARY_DIR)
simply attempts to add a subdirectory of the name PROJECT_BINARY_DIR to the include directories. On most build systems, if no such directory exists, it will simply ignore the command, which might have tricked you into the impression that it works as expected.
A popular source of confusion comes from the fact that if()
does not require explicit dereferencing of variables:
set(FOO TRUE) if(FOO) message("Foo was set!") endif()
Again the documentation explains this behavior:
if(<constant>)
True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. False if the constant is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND. Named boolean constants are case-insensitive. If the argument is not one of these constants, it is treated as a variable.
if(<variable>)
True if the variable is defined to a value that is not a false constant. False otherwise. (Note macro arguments are not variables.)
In particular, one can come up with weird examples like:
unset(BLA) set(FOO "BLA") if(FOO) message("if(<variable>): True") else() message("if(<variable>): False") endif() if(${FOO}) message("if(<constant>): True") else() message("if(<constant>): False") endif()
Which will take the TRUE
branch in the variable case, and the FALSE
branch in the constant case. This is due to the fact that in the constant case, CMake will go look for a variable BLA
to perform the check on (which is not defined, hence we end up in the FALSE branch).
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