CMake:配置文件包依赖于查找模块包的推荐方式



我刚刚读了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)的顺序,结果可能会有所不同…但他无论如何都会对你生气!

最新更新