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

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:

set(BAR "Visible everywhere"
        CACHE INTERNAL ""
)

INTERNAL is to make it not visible from cmake-gui. INTERNAL implies FORCE, 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.


I do not see anything that is not consistent with the SET command documentation

If PARENT_SCOPE is present, 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).

./bar/CMakeLists.txt

set( BAR "This is bar." PARENT_SCOPE ) #<-- Variable is set only in the PARENT scope
message( STATUS "Variable BAR in ./bar/ = ${BAR}" ) #<--- Still undefined/empty

You can always do:

set( BAR "This is bar." ) #<-- set in this scope
set( BAR ${BAR} PARENT_SCOPE ) #<-- set in the parent scope too

Grep for PARENT_SCOPE in the delivered modules in your installation, for example FindGTK2

if(GTK2_${_var}_FOUND)
   set(GTK2_LIBRARIES ${GTK2_LIBRARIES} ${GTK2_${_var}_LIBRARY})
   set(GTK2_LIBRARIES ${GTK2_LIBRARIES} PARENT_SCOPE)
endif()

If you only need to set a variable both in the local and parent scope, a macro can help reduce duplication:

macro(set_local_and_parent NAME VALUE)
  set(${ARGV0} ${ARGV1})
  set(${ARGV0} ${ARGV1} PARENT_SCOPE)
endmacro()

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)

Tags:

Cmake