9

CMake FetchContent is a great way to manage build dependencies, by integration the dependency into your build and build it from source along with your own sources.

I would like to do this with Boost, too. I am encouraged by the fact that CMake support for Boost is steadily improving.

Of course since Boost is a large package, and one rarely uses all Boost libraries in a project, it would be rather wasteful to pull the entire Boost sources into one's own build. Given the modularity of the Boost project, using git submodules, it would be much more intelligent and efficient to only fetch the sources for the libraries actually used, and FetchContent supports this via its GIT_SUBMODULES option.

However, this doesn't seem to cater for dependencies between the Boost libraries. Do I need to handle this manually, or is there a more intelligent solution?

Furthermore, how do I control installation in this scenario? Many Boost libraries are header-only, and I don't want the headers included in my installation, since I'm only using them for my build. Is there a way to tell CMake that I don't want anything installed from what I fetch with FetchContent?

I have read Craig Scott's book, and of course the CMake documentation, but there's not much information about this sort of problem.

But maybe I'm trying something that I shouldn't be doing. Have others tried this, and can show me how it's done properly?

sh-
  • 941
  • 6
  • 13
  • 3
    "Is there a way to tell CMake that I don't want anything installed from what I fetch with FetchContent?" - Yes, it is possible, see e.g. that question: https://stackoverflow.com/questions/65527126/disable-install-for-fetchcontent. – Tsyvarev Jul 10 '21 at 15:25
  • 2
    You're probably better off using a dedicated package manager like [Conan](http://conan.io/) than trying to implement it all yourself – Alan Birtles Jul 10 '21 at 16:07
  • 1
    "CMake FetchContent is a great way to manage build dependencies" -- I think that claim is dubious for the exact reason you just gave. Use something like [vcpkg](https://vcpkg.io) or [Conan](http://conan.io/) for this. – Alex Reinking Jul 10 '21 at 16:07
  • Re. vcpkg or Conan, isn't that tantamount to replacing a dependency with an even bigger one? – sh- Jul 10 '21 at 16:57
  • You are not replacing the boost dependency, but adding a tool to your toolbelt. If you are only using Boost for this only project, and you are not going to need other libraries in it or you are not going to do more projects in C++ that require any other dependency, then, yes, it might be overkill. Otherwise, it is an investment, as other tools, initially it requires some extra effort, and it pays off the more you use it. – drodri Jul 11 '21 at 23:43
  • 1
    @drodri To my ears that describes more tools to lock-in. In my experience it gets hard to make all the tools work together, and keep it that way (over time, platforms). Not to mention the added supply chain dependency where some maintainers need to develop your particular brand of package. I happen to know that CMake is being integrated into Boost Org and, I too, would love to know more about the status of it and how it may be used to avoid adding more specialized tools, especially when your project already uses CMake (which is very common). – sehe Jul 12 '21 at 10:00
  • 1
    @sehe: definitely, it is one tool more, that is what I was trying to say, it is worth if your problem is above a threshold, otherwise it is overkill. Having boost further embracing CMake (which has been ongoing effort for years now, not sure about timeline), won't make other dependency problems disappear, I was just pointing out that it is not a "tantamount" replacement of one dependency for another. – drodri Jul 13 '21 at 13:10
  • 1
    Highly relevant recent discussion on the Boost mailing list: https://lists.boost.org/Archives/boost/2021/07/251765.php /cc @drodri – sehe Jul 17 '21 at 22:01

1 Answers1

0

I have tried git submodules, ExternalProject, FetchContent and other approaches for getting our dependencies (including boost). I now use vcpkg and I am pretty content. I have not used Conan or Spack but I the impression they are great too. As a result, I would recommend using a package manger.

To get boost using vcpkg in manifest mode you:

  • Add vcpkg as a submodule of your repository and bootstrap it (see https://vcpkg.io/en/getting-started).
  • Add a vcpkg.json file with your dependencies to the top level of your project.
  • Ensure that CMAKE_TOOLCHAIN_FILE is set to the vcpkg toolchain file and your toolchain file is chain-loaded (if you have one) by setting VCPKG_CHAINLOAD_TOOLCHAIN_FILE.

A vcpkg.json file might look like:

{
  "name": "sample",
  "builtin-baseline":"030c53833b977f1580b2a4817bb22edbdde606d4",
  "version": "13.0.0",
  "dependencies": [
    "benchmark",
    "boost-asio",
    "boost-container",
    "boost-date-time",
    "boost-filesystem",
    "boost-histogram",
    "boost-thread"       
  ]
}

A CMakePresets.json might then look something like (if you are not using CMakePresets.json files, you will need to adjust whatever you use to control the toolchain file):

{
    "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"
            }
        },
        ...

Then you just find_package() in your 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)
...

Admittedly the following (taken from link provided by @sehe) seems to work pretty well:

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)

However, I don't think I would go back to using FetchContent. Now that we have vcpkg set up for our project means that we can experiment with new dependencies trivially. I like that the dependencies are documented in a single location. It also keeps the CMakeLists.txt file(s) as simple as possible.

I realise that I now have an extra dependency, that is vcpkg. However, my view is that the maintainers of vcpkg are providing more value than it costs me to manage vcpkg. Some of the things they provide:

  • Unified control over settings such as static linking.
  • Good defaults for projects (eg NLopt defaults to building bindings for several other languages but these are disabled).
  • Transitive dependencies.
  • Testing of compatibility of libraries with each other.
Bowie Owens
  • 2,798
  • 23
  • 20