Problem Statement
Currently there is no standard way to consume external CMake code.
Which makes it challenging to share CMake code. Which is problematic for organizations, companies, package managers, etc.
Example 1: vcpkg
Lets take vcpkg as an example.
Currently the recommended strategy for consuming vcpkg is to make it a submodule for your project. At one point FetchContent was recommended. But that recommendation was removed:
As I understand the FetchContent recommendation was removed for performance, and FetchContent not working well if used before the first project call (FetchContent / CMAKE_MAKE_PROGRAM issue - #6 by ben.boeckel).
As a result the majority of users consume vcpkg with a submodule. Which isn’t an ideal workflow for everyone.
Example 2: cpm (CMake package manager)
CPM unlike vcpkg only has 1 file with all the logic it needs. This is likely to make it easier to distribute to users.
CPM recommends multiple methods for using it. Either copy pasting the file into your project. Using wget. Or writing some CMake code to grab it for you.
set(CPM_DOWNLOAD_VERSION 0.34.0)
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endif()
include(${CPM_DOWNLOAD_LOCATION})
While this can work it’s not ideal for both users of CPM or the author of CPM.
Solution Proposal
A built in CMake package manager that borrows the syntax of FetchContent.
However, it does NOT call ExternalProject under the hood. Because we are not trying to build C++ projects. We are just trying to incorporate CMake modules.
vcpkg
cmake_minimum_required(VERSION 3.XY)
cmake_module_manager(vcpkg
GIT_REPOSITORY https://github.com/microsoft/vcpkg/
GIT_TAG 2022.09.27
GIT_SHALLOW OFF # vcpkg needs full history
)
set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake")
project(FOOBAR LANGUAGES "CXX")
cpm
cmake_minimum_required(VERSION 3.XY)
project(FOOBAR LANGUAGES "CXX")
cmake_module_manager(CPM
GIT_REPOSITORY https://github.com/cpm-cmake/CPM.cmake
GIT_TAG v0.38.0
MODULE_PATH cmake/ # Append to CMake module path
)
include(CPM)
CPMAddPackage("gh:fmtlib/fmt#7.1.3")
CPMAddPackage("gh:nlohmann/json@3.10.5")
CPMAddPackage("gh:catchorg/Catch2@3.2.1")
Ideally there is an easy way to cache/delete what cmake_module_manager
retrieves for the user. So that CI doesn’t constantly have to fetch the same thing. Which means downloads must be redirectable outside the BINARY_DIR
.
Taking inspiration from CPM I think a combo cache/environment variable would address this.
Or perhaps vcpkg’s caching solution is more appropriate:
Thoughts?
- @TheLartians for CPM
- @Neumann-A for vpckg