如何在仅头文件库中定义CMake变量并使其在依赖作用域可用?
仅头文件库中传递CMake变量给依赖项的最佳方式
这个问题我之前也碰到过,INTERFACE库因为是纯头文件、没有实际编译输出的特性,常规的PARENT_SCOPE变量传递确实不管用——毕竟target_link_libraries只是帮你建立目标间的依赖关系,并不会自动把库的CMake变量拉到你的顶层作用域里来。下面给你两种实用的解决方案,推荐第二种,更符合CMake的模块化思想:
方法一:使用缓存变量(全局可见)
如果你只需要简单传递变量,且不担心全局命名冲突,可以用CMake的缓存变量来实现。缓存变量是全局生效的,只要定义后,任何后续的CMake代码都能访问到。
库的CMakeLists.txt
add_library(SomeLibrary INTERFACE) # 建议给变量加库名前缀,避免和其他库的变量冲突 set(SOMELIBRARY_FOO "Foo is defined" CACHE INTERNAL "Value of FOO from SomeLibrary")
- 这里用
CACHE INTERNAL表示这个变量是内部缓存,不会在CMake GUI中显示,也不会被用户直接修改;如果需要允许用户调整,可以换成CACHE STRING "Description"。
顶层CMakeLists.txt
add_executable(Dummy main.cpp) target_link_libraries(Dummy SomeLibrary) # 直接访问缓存变量 message("Foo=${SOMELIBRARY_FOO}")
方法二:自定义目标属性(推荐,模块化)
这种方法把变量和INTERFACE目标绑定在一起,不会污染全局命名空间,是更规范的CMake实践。目标属性会跟着目标走,只要你链接了这个库,就能通过目标获取对应的属性值。
库的CMakeLists.txt
add_library(SomeLibrary INTERFACE) # 给目标设置自定义属性,同样建议加前缀 set_target_properties(SomeLibrary PROPERTIES SOMELIBRARY_FOO "Foo is defined" )
顶层CMakeLists.txt
add_executable(Dummy main.cpp) target_link_libraries(Dummy SomeLibrary) # 通过get_target_property从目标中获取属性值 get_target_property(FOO SomeLibrary SOMELIBRARY_FOO) message("Foo=${FOO}")
为什么原来的PARENT_SCOPE无效?
PARENT_SCOPE只能把变量传递给当前CMakeLists.txt的直接父作用域(比如你用add_subdirectory引入库目录时,父作用域就是顶层),但如果这个库是通过find_package导入的,或者后续结构调整,这种传递方式就会失效。而且它本质是作用域传递,和目标依赖没有绑定关系,不符合INTERFACE库的设计思路。
内容的提问来源于stack exchange,提问作者Fluffy
相关产品推荐
相关产品推荐

