如何使用 FetchContent 将模块化 boost 构建正确集成到我的 CMake 项目中?

sh-*_*sh- 9 c++ boost cmake dependency-management

CMake FetchContent 是管理构建依赖项的好方法,通过将依赖项集成到您的构建中并从源代码以及您自己的源代码构建它。

我也想用 Boost 来做到这一点。CMake 对 Boost 的支持正在稳步改善,这一事实令我深受鼓舞。

当然,由于 Boost 是一个大包,并且很少在项目中使用所有 Boost 库,因此将整个 Boost 源拉入自己的构建中会相当浪费。考虑到 Boost 项目的模块化,使用 git 子模块,仅获取实际使用的库的源代码会更加智能和高效,并且 FetchContent 通过其 GIT_SUBMODULES 选项支持这一点。

然而,这似乎并不能满足 Boost 库之间的依赖关系。我需要手动处理这个问题,还是有更智能的解决方案?

此外,在这种情况下如何控制安装?许多 Boost 库都是仅包含头文件的,我不希望在安装中包含头文件,因为我只将它们用于我的构建。有没有办法告诉 CMake 我不想从使用 FetchContent 获取的内容中安装任何内容?

我读过 Craig Scott 的书,当然还有 CMake 文档,但是关于此类问题的信息并不多。

但也许我正在尝试一些我不应该做的事情。其他人是否尝试过此操作,并且可以向我展示它是如何正确完成的?

Bow*_*ens 0

我尝试过 git submodules、ExternalProject、FetchContent 和其他方法来获取我们的依赖项(包括 boost)。我现在使用 vcpkg,我很满意。我没有使用过 Conan 或 Spack,但我印象中它们也很棒。因此,我建议使用包管理器。

要在清单模式下使用 vcpkg 获得提升,您:

  • 将 vcpkg 添加为存储库的子模块并引导它(请参阅https://vcpkg.io/en/getting-started)。
  • 将包含依赖项的 vcpkg.json 文件添加到项目的顶层。
  • 确保将其CMAKE_TOOLCHAIN_FILE设置为 vcpkg 工具链文件,并且通过设置 来链式加载您的工具链文件(如果有)VCPKG_CHAINLOAD_TOOLCHAIN_FILE

vcpkg.json 文件可能如下所示:

{
  "name": "sample",
  "builtin-baseline":"030c53833b977f1580b2a4817bb22edbdde606d4",
  "version": "13.0.0",
  "dependencies": [
    "benchmark",
    "boost-asio",
    "boost-container",
    "boost-date-time",
    "boost-filesystem",
    "boost-histogram",
    "boost-thread"       
  ]
}
Run Code Online (Sandbox Code Playgroud)

CMakePresets.json 可能看起来像这样(如果您不使用 CMakePresets.json 文件,则需要调整用于控制工具链文件的任何内容):

{
    "version": 3,
    "configurePresets": [
        {
            "name": "sample-defaults",
            "hidden": true,
            "binaryDir": "${sourceParentDir}/build/${sourceDirName}-${presetName}",
            "cacheVariables": {
                "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
                "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/scripts/clang17.cmake"
            }
        },
        ...
Run Code Online (Sandbox Code Playgroud)

然后你只需find_package()在你的 CMakeLists.txt 中:

cmake_minimum_required(VERSION 3.21)

project(
    Sample-ThirdParty
    LANGUAGES CXX
    VERSION 2023.0.0
)

find_package(Boost REQUIRED COMPONENTS container filesystem thread)
...
Run Code Online (Sandbox Code Playgroud)

不可否认,以下内容(取自@sehe提供的链接)似乎效果很好:

cmake_minimum_required(VERSION 3.21)
project(boost_test)
include(FetchContent)
set(BOOST_ENABLE_CMAKE ON)
FetchContent_Declare(build_boost
     GIT_REPOSITORY https://github.com/boostorg/boost.git
     GIT_TAG boost-1.82.0
)
FetchContent_GetProperties(build_boost)
if(NOT build_boost_POPULATED)
     FetchContent_Populate(build_boost)
     add_subdirectory(
         ${build_boost_SOURCE_DIR}
         ${build_boost_BINARY_DIR}
         EXCLUDE_FROM_ALL
     )
endif()
add_executable(boost_test boost_test.cpp)
target_link_libraries(boost_test PRIVATE Boost::format)
Run Code Online (Sandbox Code Playgroud)

但是,我认为我不会再继续使用 FetchContent。现在我们已经为我们的项目设置了 vcpkg,这意味着我们可以轻松地尝试新的依赖项。我喜欢将依赖项记录在一个位置。它还使 CMakeLists.txt 文件尽可能简单。

我意识到我现在有一个额外的依赖项,那就是vcpkg。然而,我的观点是,vcpkg 的维护者提供的价值比我管理 vcpkg 的成本更多。他们提供的一些东西:

  • 对静态链接等设置的统一控制。
  • 项目的良好默认设置(例如 NLopt 默认为其他几种语言构建绑定,但这些被禁用)。
  • 传递依赖。
  • 测试库之间的兼容性。