Variables set with PARENT_SCOPE are empty in the corresponding area of ​​the child. What for?

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 cmake output 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 BAR variable is placed in the parent area, I expect it to be available in the current child area (and in the following) - just like the FOO variable, which defines the parent area to start with. But, as can be seen from the above lines, the BAR variable is empty in ./bar/CMakeLists.txt , which leads me to the following questions:

Why is the changed parent region inaccessible to the child scope, ./bar/ ? Can this be mitigated? If so, how? And if not, then what to work around? Or am I completely missing something obvious?

Context: my project consists of several executable files and libraries. For a library, for example. BAR , I would like to set the variable bar_INCLUDE_DIR , which is added to the included paths of any dependent executable, i.e. target_include_directories( my_target PUBLIC bar_INCLUDE_DIR ) .

+5
source share
3 answers

Context: my project consists of several executable files and libraries. For a library, for example. bar, I would like to set the variable bar_INCLUDE_DIR, which is added to the paths to include any executable file.

There is a much better way to do this than to set variables in the parent scope. CMake allows the target to specify inclusion directories, preprocessor characters, etc., which can be used depending on the goals. In your case, you can use target_include_directories .

For instance:

 target_include_directories(my_target PUBLIC my_inc_dir) 
+2
source

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 area above the current area. Each new directory or function creates a new scope. This command sets the value of the variable to the parent directory or the calling function (depending on what is applicable to the case in question).

./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 supplied 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() 
+5
source

Peter explained the reason for this behavior.

The workaround that I usually use in this case is to set a cached variable that will be visible everywhere:

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

INTERNAL is to make it invisible from cmake-gui. FORCE is to make sure that it is updated if you change something, for example, in your folder structure. An empty line is a description line that you can fill out if you think necessary.

+5
source

All Articles