使用PARENT_SCOPE设置的变量在相应的子范围中为空.为什么?

nil*_*ils 11 cmake

请考虑以下最小示例:

.
??? bar
?   ??? CMakeLists.txt
??? CMakeLists.txt
Run Code Online (Sandbox Code Playgroud)

这里./CMakeLists.txt

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}" )
Run Code Online (Sandbox Code Playgroud)

并且./bar/CMakeLists.txt

set( BAR "Exists in parent scope only." PARENT_SCOPE )
message( STATUS "Variable BAR in ./bar/ = ${BAR}" )
Run Code Online (Sandbox Code Playgroud)

输出的相关部分cmake是这样的:

...
-- 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.
...
Run Code Online (Sandbox Code Playgroud)

由于变量BAR放在父作用域中,我希望它在当前的子作用域中(以及FOO后面的作用域)可用 - 就像变量一样,它定义为父作用域的开头.但是从上面的行可以看出变量BAR是空的./bar/CMakeLists.txt,这引出了以下问题:

为什么修改后的父作用域不能在子作用域中立即访问./bar/?这可以减轻吗?如果有,怎么样?如果不是,什么是解决方案?还是我完全错过了一些明显的东西?

上下文:我的项目由几个可执行文件和库组成.对于库,例如bar,我想设置一个变量bar_INCLUDE_DIR,该变量被添加到任何依赖可执行文件的包含路径中,即target_include_directories( my_target PUBLIC bar_INCLUDE_DIR ).

Pet*_*ter 8

我没有看到任何与SET命令文档不一致的内容

如果存在PARENT_SCOPE,则变量将在当前范围上方的范围内设置.每个新目录或函数都会创建一个新范围.此命令将变量的值设置为父目录或调用函数(适用于手头的情况).

./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
Run Code Online (Sandbox Code Playgroud)

你可以随时做:

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

PARENT_SCOPE在安装中交付的模块中使用Grep ,例如FindGTK2

if(GTK2_${_var}_FOUND)
   set(GTK2_LIBRARIES ${GTK2_LIBRARIES} ${GTK2_${_var}_LIBRARY})
   set(GTK2_LIBRARIES ${GTK2_LIBRARIES} PARENT_SCOPE)
endif()
Run Code Online (Sandbox Code Playgroud)

  • 好吧,考虑一个变量`FOO`,它在父作用域中定义,然后这个变量在子作用域中也可用(参见更新的例子).那么,如果两个生活在同一个(父)范围内,为什么在子范围内不能使用"BAR"?我希望文档提到这样的行为. (2认同)

Ant*_*nio 7

彼得很好地解释了这种行为的原因.

我通常在这种情况下使用的解决方法是设置一个缓存变量,该变量随处可见:

set(BAR "Visible everywhere"
        CACHE INTERNAL ""
)
Run Code Online (Sandbox Code Playgroud)

INTERNAL是让它从cmake-gui看不到.INTERNAL如果您在文件夹结构中更改某些内容,则确保它已更新.空字符串是一个描述字符串,如果您认为有必要,可以填写该字符串.

但请注意,只要有可能,正确的方法是尽可能将属性附加到目标,例如使用FORCE,并通过设置依赖项将它们传播到其他目标.


Lin*_*cer 6

上下文:我的项目由几个可执行文件和库组成。对于一个库,例如 bar,我想设置一个变量 bar_INCLUDE_DIR,它被添加到任何依赖的可执行文件的包含路径中。

有比在父作用域中设置变量更好的方法来做到这一点。CMake 允许目标指定依赖目标可以使用的包含目录、预处理器符号等。在您的情况下,您可以使用target_include_directories

例如:

target_include_directories(my_target PUBLIC my_inc_dir)
Run Code Online (Sandbox Code Playgroud)

  • 啊啊,现在我明白你的意思了。确实好多了。感谢您的坚持! (2认同)