CMake find_package 可以 "common dependency version aware" 吗?

Can CMake find_package be "common dependency version aware"?

问题:

我正在重做遗留项目中的 make 系统,从目前的神秘版本更改为 CMake。目前,我已经让 CMake 将整个项目视为一个大型 CMake 项目,但我们的代码库如此之大,以至于它破坏了我们投入其中的大部分 IDE。

我们想将其分解,CMake 的 find_package "module mode" 似乎是将其分解为 "feature-sized" 块的理想选择。主要候选者是只需要很少维护的一大块代码,即便如此,它通常也由另一个团队维护。这将使我们能够维护代码,而不是在更新不同代码时不断地重新编译它。

就是说,这段代码在 API 中使用了 Boost 的共享指针,虽然不同版本的共享指针 可能 可以一起工作,但我宁愿不要冒险。因此,理想情况下,包将知道系统正在使用的 "boost" 版本,编译模块时使用的是什么版本的 boost,并且能够重新编译——或者至少,抛出CMake 中的错误或警告——如果两者不匹配。

那么...如何确保常见依赖项的版本在 CMake find_package 模块中匹配?我唯一能想到的就是测试适当的 VERSION 变量,但这似乎......笨重。有什么我想念的吗?

附加信息:

我们正在使用 CMake 3.5.1,但如果这会有所不同,我们可以升级到 3.5.2。这个项目实际上是一个软件产品线(q.v),所以我们计划在未来的某个时候使用更现代的 SPL 软件工程技术(这也是选择 CMake 的另一个原因)。代码库目前位于 Redhat Linux,但理想情况下该技术是跨平台的。

您可以使用 find_packageconfig 模式来允许您的模块向其用户(根项目)公开一些内部属性。

如果您的每个模块都提供 library 目标,您可以使用 属性 包含附加的 Boost 版本来公开该目标,并将此 属性 列在一个特殊的 COMPATIBLE_INTERFACE_STRING 属性.

您的根项目将通过 find_package() 调用包含模块,并将读取这些属性。当它将尝试 link 由此类模块提供的库时,版本兼容性将由 CMake 自动执行:

modA/CMakeLists.txt:

...
find_package(Boost)
add_library(modA_lib ...)
... # Link modA_lib with Boost
# Install modA_lib target and exports it for use in other project.
install(TARGETS modA_lib EXPORT modA_lib)
# Configured -config file is shown below
configure(modA-config.cmake.in modA-config.cmake)
install(EXPORT modA_lib
    DESTINATION share/cmake/modA)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/modA-config.cmake
    DESTINATION share/cmake/modA)

modA/modA-config.cmake.in:

include(@CMAKE_INSTALL_PREFIX@/share/cmake/modA/modA_lib.cmake) # Include file described library target
# Expose linked version of Boost via target's property.
set_property(TARGET modA_lib PROPERTY INTERFACE_BOOST_VERSION @Boost_VERSION@)
# Mark this property as compatibility requirement
set_property(TARGET modA_lib PROPERTY APPEND COMPATIBLE_INTERFACE_STRING BOOST_VERSION)

(modB以类似方式实现)

root/CMakeLists.txt:

find_package(modA) # This imports target modA_lib
find_package(modB) # This imports target modB_lib

add_executable(root_exe <...>)

# Boost version check will be performed here
target_link_libraries(root_exe modA_lib modB_lib)

此外,在根项目中创建的可执行文件可以通过适当的设置请求特定的 Boost 版本 属性:

add_executable(root_exe <...>)
set_property(TARGET root_exe PROPERTY BOOST_VERSION <...>)

在这种情况下,CMake 将禁止其依赖项在其他版本中使用 Boost 库。

更多信息和用法示例请参阅 CMake 构建系统 description