Consider the following minimal example:
.
├── bar
│ └── CMakeLists.txt
└── CMakeLists.txt
where ./CMakeLists.txt
is
project( foo )
cmake_minimum_required( VERSION 2.8 )
set( FOO "Exists in both, parent AND in child scope." )
add_subdirectory( bar )
message( STATUS "Variable BAR in ./ = ${BAR}" )
message( STATUS "Variable FOO in ./ = ${FOO}" )
and ./bar/CMakeLists.txt
is
set( BAR "Exists in parent scope only." PARENT_SCOPE )
message( STATUS "Variable BAR in ./bar/ = ${BAR}" )
The relevant part of the output of cmake
is this:
...
-- Variable BAR in ./bar/ =
-- Variable FOO in ./bar/ = Exists in both, parent AND in child scope.
-- Variable BAR in ./ = Exists in parent scope only.
-- Variable FOO in ./ = Exists in both, parent AND in child scope.
...
Since the variable BAR
is placed into the parent scope I would expect it to be available in the current child scope as well (and in those that follow) -- just like the variable FOO
, which is defined the parent scope to begin with. But as can be seen in the above lines the
variable BAR
is empty in ./bar/CMakeLists.txt
, which lead me to
the following questions:
Why is the modified parent scope not immediately accessible in the child
scope, ./bar/
? Can this be mitigated? If yes, how? And if no, what is a
work-around? Or am I completely missing something obvious?
Context: my project consists of several executables and libraries. For a
library, e.g. bar
, I'd like to set a variable bar_INCLUDE_DIR
which
is added to the include paths of any depending executable, i.e. target_include_directories( my_target PUBLIC bar_INCLUDE_DIR )
.
There is a much better way to do this than to set variables in the parent scope. CMake allows a target to specify include directories, preprocessor symbols etc. that depending targets can use. In your case, you can use target_include_directories.
For example:
I do not see anything that is not consistent with the SET command documentation
./bar/CMakeLists.txt
You can always do:
Grep for
PARENT_SCOPE
in the delivered modules in your installation, for example FindGTK2Each variable in the cmake has it's own scope so it is dangerous use case where a variable automatically propagates in a child context, because it can interfere with it from a parent scope!
But you can set just another variable in a child scope to test it later instead of rereading a parent one:
./bar/CMakeLists.txt
:Now, if you have loops in your code, then you can test both variables:
Peter explained well the reason for this behaviour.
A workaround I usually use in this case is to set a cached variable, which will be visible everywhere:
INTERNAL
is to make it not visible from cmake-gui.INTERNAL
impliesFORCE
, making sure it gets updated if you change something for example in your folder structure. The empty string is a description string, that you might want to fill if you believe it's necessary.Note, though, that the correct approach is attaching properties to targets whenever possible, like using
target_incude_directories
, and propagate them to other targets by setting dependencies.