Search code examples
cmakecmake-scopes

Variables set with PARENT_SCOPE are empty in the corresponding child scope. Why?


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 ).


Solution

  • 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.

    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:

    target_include_directories(my_target PUBLIC my_inc_dir)