我刚刚读了CMake的Config-File Package"概念",听起来很有希望。我非常喜欢它的一点是,如果我自己创建一个配置文件包,我可以指定它所依赖的其他包。我的问题是:我怎么能创建一个配置文件包是"可重新定位",并依赖于一个查找模块包(如boost)?
更详细地说:假设我想创建一个名为HyDi的包。cmake文档很好地解释了如何创建相应的hydicconfig。cmake和hydtarget。自动生成文件。CMakeLists.txt的一个非常简单的版本是:
project(HyDi)
find_package(Boost COMPONENTS program_options)
add_library(HyDi foo.cpp foo.hpp)
target_include_directories(HyDi PUBLIC INTERFACE ${Boost_INCLUDE_DIRS})
target_link_libraries(HyDi ${Boost_LIBRARIES})
target_compile_options(HyDi INTERFACE PUBLIC "-std=c++11")
install(TARGETS HyDi EXPORT HyDiTarget
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(FILES foo.hpp DESTINATION include)
configure_file(cmake/HyDiConfig.cmake
"${CMAKE_CURRENT_BINARY_DIR}/HyDi/HyDiConfig.cmake"
COPYONLY
)
set(ConfigPackageLocation lib/cmake/HyDi)
install(EXPORT HyDiTarget FILE HyDiTargets.cmake
NAMESPACE Upstream:: DESTINATION ${ConfigPackageLocation} )
install(FILES cmake/HyDiConfig.cmake DESTINATION ${ConfigPackageLocation})
对应的hydicconfig。cmake是:
include(CMakeFindDependencyMacro)
find_dependency(Boost COMPONENTS program_options)
include("${CMAKE_CURRENT_LIST_DIR}/HyDiTargets.cmake")
然而,如果我安装这个库,HyDiTargets。cmake文件将包含硬编码的Boost库的包含路径,因此不可重定位。
请注意,cmake文档给出了一个示例,说明如何不包含我的版本的boost库。但遗憾的是,他们没有解释如何做得更好。
我知道我可以使用cmake构建boost,然后可以将boost作为配置文件包导入,以便我的HydiTargets。Cmake可以重新定位。但是这种方法并不适用于提供Findxxx的所有其他库。cmake文件。
实际上,当注入"硬编码"路径来增强库时(你做错了),这样做是正确的。因为在你的库被编译和安装之后,它应该"链接"到一个非常特定的boost版本(当它在你的库编译的时候)——即它的头文件和静态/动态库。
考虑这样一个场景:在成功安装了你的库之后,有人并行安装了一个新版本的boost库(或者你依赖的任何其他第三方库)(是的,boost和其他一些库可以共存于同一个安装前缀中)。为了使它看起来像一个真实的示例,假设它与以前的版本不兼容ABI。现在,如果那个"幸运的"开发人员想要使用你的(已经编译和安装的)库(使用导出的目标和提供的HyDiConfig.cmake
),他会遇到麻烦:
- 你的库已经链接到"以前"的boost版本(记住ABI与新版本不兼容);
- 所以当你以某种方式替换"硬编码"路径并找到新版本时(就像你在
HyDiConfig.cmake
中试图做的那样),你的"幸运"客户会因为你的混乱而生气!
这不仅仅是关于boost…对于所有第三方库的相同策略:它们应该保持与编译时的相同(或者至少是ABI兼容,如果我们谈论的是运行时的动态链接,但这是一个单独的故事)。
此外,你的用户可能甚至没有在他的应用程序中使用boost(但安装了多个版本)——为什么你要找到smth?你已经知道(感谢CMake和硬编码路径)你的库"需要"什么boost版本!所以在这种情况下,发现史密斯是完全错误的!你的库已经编译、链接并安装了!
另一种情况:他想使用其他(更新)版本的boost…根据find_package(boost)
和find_package(yourLib)
的顺序,结果可能会有所不同…但他无论如何都会对你生气!