13

我有一个 cmake 项目,其中有一些模块,我正在使用 Find-*.cmake 将共享模块包含在应用程序中。为了不考虑我添加的每个模块,我LIB为链接器定义了一种全局变量:

# inside a Find-*.cmake or in the CMakeLists.txt of the modules:
set(LIB ${LIB} ...)

因此,在使用某些模块的最终应用程序之一中,我可以这样做:

target_link_libraries(${APP_NAME} ${LIB})

然后,我希望将已编译的模块放入其中,/project_path/modules/foo/build这样如果一个模块真的很大,无法编译,则可以为所有使用它的应用程序编译一次。我实现这一点的方法是以这种方式从 Find-*.cmake 加载模块的 CMakeLists.txt :

# Inside FindFoo.cmake, for loading /project_path/modules/foo/CMakeLists.txt
# and compile it in /project_path/modules/foo/build
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME} 
                 ${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME}/build
)
include_directories(${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME}/include)

但是有时会发生某些模块需要另一个模块,以便add_subdirectory创建新的范围并且可以正确加载LIB但无法编写它(当我使用set它时,它处于更深的范围而不更改更高的范围)。为了绕过这个,我必须在)中添加PARENT_SCOPEset。所以我尝试将它添加到一些我认为可以嵌套并隐藏在某些依赖项中的模块中,但编译我突然遇到的所有应用程序:

CMake Warning (dev) at /path_to_repo/cmake/FindFooX.cmake:6 (set):
  Cannot set "LIB": current scope has no parent.
Call Stack (most recent call first):
  CMakeLists.txt:14 (find_package)
This warning is for project developers.  Use -Wno-dev to suppress it.

我担心这可能会因我需要的模块或模块本身的依赖树而因应用程序而异,所以我正在寻找更清洁的解决方案。

4

2 回答 2

34

您可以通过使用具有 GLOBAL 范围的属性来“模拟” GLOBAL 变量行为:

SET_PROPERTY(GLOBAL PROPERTY MyGlobalProperty "MyGlobalPropertyValue")

然后你可以使用提取你的全局属性

GET_PROPERTY(MyLocalVariable GLOBAL PROPERTY MyGlobalProperty)

然后,MyLocalVariable包含“MyGlobalPropertyValue”。

因为 PARENT_SCOPE 将变量定义扩展到唯一的父目录(而不是其父目录),所以在某些情况下它是不够的,例如,如果你有一个很深的源代码树......

于 2015-03-25T08:16:22.280 回答
26

默认情况下,CMake 中的所有变量都是本地变量。虽然您可以使用参数将局部变量的范围增加一层,但这对于函数PARENT_SCOPE的返回值很有意义。

另一方面,对于查找脚本,您通常需要全局变量的行为:一旦任何人调用查找脚本,您希望结果在任何地方都可用。特别是,对同一个 find 脚本的第二次调用应该只是重用第一次调用的结果。在 CMake 中,这是通过将变量存储到缓存中来实现的。各种find_*调用已经自动执行此操作,因此您应该更喜欢使用那些适用的调用。对于任何其他自定义变量,set还提供存储到缓存的功能:

set(MY_GLOBAL_VARIABLE "Some value" CACHE STRING "Description")

请注意,局部变量可以在其范围内隐藏同名的缓存变量。

于 2013-10-14T09:02:30.937 回答