I thought to use CPM for my project. I got to problem that if CPM adds smth, then it’s cannot be readded.
Example : boost. one package adds only one library from it ( and the dependencies ) , but another package uses some other libs from boost.
Then
package1 adds boost with some options via CPM
package1 adds package2 via CPM
when package2 is trying to add boost with other options via CPM it does nothing, because it assumes that a package with specific version doesn’t need to be reconfigured, if it’s already added.
boost components for package2 aren’t added.
at generating : Boost::component_library is not found.
Let’s assume I can somehow write logic for merging options. But how I can readd smth ? Or , at least, how can I make cmake reconfigure itself with cache variables?
If someone know how to do so, it would be great to share, I can try write the logic and make a PR.
If it’s possible, we can make CPM be automatic in merging options and make it a really great package manager.
all my thoughts about the problem also there are at github
You cannot “undo” an add_subdirectory. You can do it again with a different builddir (add_subdirectory(boost "${CMAKE_CURRENT_BINARY_DIR}/boost-again"), but that will get you 2 Boost builds.
I think you need to gather your requirements first and set up BOOST_INCLUDE_LIBRARIES suitably before ever including Boost.
yea, I can do that. though, I think, I’ll get problem if one project adds a boost lib, another adds it too. then we will have two same targets. It’s prohibited by CMP0002, AFAIK.
About gathering requirements. That’s why I don’t want to gather them manually. I would like to make CPM it do instead of me: getting same lib, merging needed options and cache variables and then reconfigure the lib. That’s why I’m asking about any such capabilities of cmake.
The closest I’m aware of that CMake provides is FetchContent (which I believe is more-or-less mutually exclusive to CPM in practice). @craig.scott knows far more about this module’s coverage of this use case than I do.
My understanding is that CPM is implemented using FetchContent internally, but it’s been a while since I’ve taken a look at it.
As long as you use the same name to refer to a given dependency in calls to FetchContent_Declare(), FetchContent will take care of only adding that dependency to the build once, regardless of how many times FetchContent_MakeAvailable() is called for that dependency. The first such call adds the dependency, subsequent calls re-use that one. Assuming CPM is still implemented in terms of FetchContent, I would expect it to do the same.
FetchContent’s philosophy is “first to declare, wins”. The first FetchContent_Declare() call for a dependency controls how that dependency will be populated. If you’re encountering a situation where two dependencies are pulling in boost and the first one to pull it in isn’t enabling all the options you need, then your main project needs to make its own call to FetchContent_Declare() before pulling in either dependency. Then the first call from your main project will be in control of how boost is brought in.
I suggest you take a look through the FetchContent docs. They go through the way these things work.
With CMP.cmake and/or FetchContents, projects may end with create complexity!
include(cmake/CPM.cmake)
cpmusepackagelock(package-lock.cmake)
# Done as a function so that updates to variables like
# CMAKE_CXX_FLAGS don't propagate out to other
# targets
function(myproject_setup_dependencies)
# For each dependency, see if it's
# already been provided to us by a parent project
# NOTE: The order is also important! CK
# i.e.: spdlog may use catch2 and fmtlib too
# NOTE: needed in test/CMakelinst.txt: include(${Catch2_SOURCE_DIR}/extras/Catch.cmake)
cpmaddpackage("gh:catchorg/Catch2@3.4.0")
if(NOT TARGET fmtlib::fmtlib)
# A git package with both version and tag provided
cpmaddpackage("gh:fmtlib/fmt@9.1.0#9.1.0")
# FIXME(CK): this does not work! No idea why?
# cpmfindpackage("gh:fmtlib/fmt@9.1.0#9.1.0")
endif()
if(NOT TARGET spdlog::spdlog)
# NOTE: you may find an installed version compiled with differrent options!
# TODO(CK) this does not work! cpmfindpackage(
cpmaddpackage(
NAME
spdlog
VERSION
1.12.0
GITHUB_REPOSITORY
"gabime/spdlog"
OPTIONS
"SPDLOG_FMT_EXTERNAL ON")
endif()
if(NOT TARGET CLI11::CLI11)
cpmaddpackage("gh:CLIUtils/CLI11@2.3.2")
endif()
if(NOT TARGET ftxui::screen)
# A git package with both version and tag provided
cpmfindpackage(
NAME
FTXUI
VERSION
5.0.0
GIT_TAG
dd6a5d371fd7a3e2937bb579955003c54b727233
GITHUB_REPOSITORY
"ArthurSonzogni/FTXUI"
OPTIONS
"FTXUI_BUILD_EXAMPLES OFF;FTXUI_BUILD_DOCS OFF")
endif()
if(NOT TARGET tools::tools)
cpmaddpackage("gh:lefticus/tools#update_build_system")
endif()
endfunction()
bash-5.2$ cmake --preset unixlike-gcc-release --fresh | grep -w CPM
-- CPM: Adding package Catch2@3.4.0 (v3.4.0 at /Users/clausklein/.cache/CPM/catch2/fc2d6e70e6b1b691860849b5eeca5a7b84d30f6f)
-- CPM: Adding package fmt@9.1.0 (9.1.0 at /Users/clausklein/.cache/CPM/fmt/5c4bc51f3df5bb907a0028facff05ba4978aa6e5)
-- CPM: Adding package spdlog@1.12.0 (v1.12.0 at -- CPM: Adding package CLI11@2.3.2 (v2.3.2 at /Users/clausklein/.cache/CPM/cli11/9e6fd3fcb946a91f4a10e874dc9d09753d96ed7f)
-- CPM: Using local package FTXUI@5.0.0
-- CPM: Adding package tools@ (update_build_system at /Users/clausklein/.cache/CPM/tools/8c8c55a914858ebfc250a90e65f4f4a988a4e20e)
bash-5.2$
cat build/cpm-package-lock.cmake
# CPM Package Lock
# This file should be committed to version control
# Catch2
CPMDeclarePackage(Catch2
VERSION 3.4.0
GITHUB_REPOSITORY catchorg/Catch2
SYSTEM YES
EXCLUDE_FROM_ALL YES
)
# fmt
CPMDeclarePackage(fmt
VERSION 9.1.0
GIT_TAG 9.1.0
GITHUB_REPOSITORY fmtlib/fmt
SYSTEM YES
EXCLUDE_FROM_ALL YES
)
# spdlog
CPMDeclarePackage(spdlog
NAME spdlog
VERSION 1.12.0
GITHUB_REPOSITORY gabime/spdlog
OPTIONS
"SPDLOG_FMT_EXTERNAL ON"
)
# CLI11
CPMDeclarePackage(CLI11
VERSION 2.3.2
GITHUB_REPOSITORY CLIUtils/CLI11
SYSTEM YES
EXCLUDE_FROM_ALL YES
)
# tools (unversioned)
# CPMDeclarePackage(tools
# GIT_TAG update_build_system
# GITHUB_REPOSITORY lefticus/tools
# SYSTEM YES
# EXCLUDE_FROM_ALL YES
#)
some hints:
1.) try cmake --fresh ...
2.) try cpmusepackagelock(package-lock.cmake)
3.) for complex projects with many dependencies or big libraries like boost: