Library / SDK
cpm-cmake/CPM.cmake avatar
cpm-cmake/CPM.cmake

CPM.cmake: dependency management for CMake without a system package manager

📦 CMake's missing package manager. A small CMake script for setup-free, cross-platform, reproducible dependency management.

4,136 stars226 forksCMakeMIT

At a glance

What is it?
CPM.cmake is a single CMake script that wraps FetchContent with version resolution, a source cache and a shorthand URI syntax. It suits projects that want dependencies declared inside CMakeLists.txt rather than installed on the host.
Who is it for?
Adopt CPM.cmake if your dependencies are CMake projects or downloadable archives and you want them pinned in CMakeLists.txt rather than installed on the machine. Do not adopt it if you need prebuilt binaries, a curated package registry, or support for toolchains that cannot run CMake at configure time; CPM builds from source.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly CMake, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap CPM.cmake fills between FetchContent and a system package manager

CMake ships FetchContent, which can download and add a dependency at configure time. What it does not ship is a version convention, a shared download cache across build trees, or a compact way to write down where a package comes from. CPM.cmake is described in its README as a thin wrapper around FetchContent that adds version control, caching and a simple API. The target audience is C and C++ projects that already build with CMake and want their dependency list to live in the repository instead of in a developer's home directory.

The README makes a strong claim about scope: any downloadable project or resource can be added as a version-controlled dependency, and nothing has to be modified or packaged first. That is the practical difference from a binary package manager. There is no recipe to write, no port to maintain, no registry to publish to. If a project has a git URL or an archive URL, CPM can pull it. The cost of that convenience is that everything is built from source on the machine doing the configure step, which is a real trade-off discussed further down.

How CPMAddPackage resolves a name, a version and a source

The central function is CPMAddPackage. According to the README it accepts NAME, VERSION, PATCHES, OPTIONS and DOWNLOAD_ONLY as named parameters, and forwards the remaining origin parameters to FetchContent_Declare. The version and the git tag are linked by convention: if GIT_TAG is not given explicitly it defaults to v(VERSION), and if VERSION is omitted CPM can infer it from the git tag in common cases. That inference is what makes the short form work.

The shorthand syntax is the part most projects end up using. A string of the form uri@version, uri#tag or uri@version#tag is parsed into a full dependency declaration. Prefixes gh:, gl: and bb: expand to GitHub, GitLab and Bitbucket URLs respectively; anything else is used verbatim as a git URL. Packages added through the shorthand are automatically given the EXCLUDE_FROM_ALL and SYSTEM flags, so their targets do not build unless something links them and their headers are treated as system headers. The longer named-parameter form does not apply those flags for you, which is a detail worth knowing when warning output from a dependency suddenly appears in your own build.

ARCHIVE_URL is not a separate parameter. The README shows archive packages passed as a single URL string, optionally with a version suffix or an MD5 fragment, and the version is inferred from the URL when it is not stated. A branch name such as master is accepted as a GIT_TAG, but the README explicitly says this is not recommended because such packages are only updated when the cache is cleared.

Installing CPM.cmake and adding a first dependency

There is no package to install. The README says to add the latest release of CPM.cmake or get_cpm.cmake to the project's cmake directory, and gives a command that downloads the release asset directly into that path.

bash
mkdir -p cmake
wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake

On Windows the README offers the PowerShell equivalent, which creates the directory and writes the same file:

powershell
New-Item -ItemType Directory -Force -Path "cmake"
Invoke-WebRequest -Uri "https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake" -OutFile "cmake/CPM.cmake"

After that, include the script and call CPMAddPackage. The README's full example uses CMake 3.14 as the minimum and pins three dependencies, then links their exported targets:

cmake
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyProject)
add_executable(main main.cpp)
include(cmake/CPM.cmake)
CPMAddPackage("gh:fmtlib/fmt#7.1.3")
CPMAddPackage("gh:nlohmann/[email protected]")
CPMAddPackage("gh:catchorg/[email protected]")
target_link_libraries(main fmt::fmt nlohmann_json::nlohmann_json Catch2::Catch2WithMain)

If the dependency uses modern CMake, its targets exist as soon as the call returns and can be linked directly, which is what the target_link_libraries line does here. For projects that do not export targets, the README points to the snippets section and the wiki, where targets are created manually after the download. The examples directory in the repository carries complete projects for fmt, json, Catch2, Boost, asio, spdlog, yaml and others, which is the fastest way to see a working configuration before writing your own.

Where CPM.cmake is the wrong tool: source builds, tags and patches

CPM.cmake downloads source and configures it. It does not fetch prebuilt binaries. On a project with a large dependency graph this shifts work onto every machine that configures the build, and onto CI, which is a cost a binary package manager would not impose. If your team cannot compile dependencies from source on each platform it targets, this is the wrong layer to solve the problem at.

Version pinning has a sharp edge too. The README states that a GIT_TAG set to a commit or a branch is only updated when the cache is cleared, and its supply chain note recommends immutable commit hashes over tags or branches because tags and branches can be moved. Following that advice means every dependency update is a manual edit of a hash, not a version bump. The convenience of uri@version and the safety of a commit hash pull in opposite directions, and the README does not resolve that tension for you.

PATCHES has its own caveat. The README says patches are applied sequentially with patch and PATCH_OPTIONS, and then recommends setting CPM_SOURCE_CACHE whenever PATCHES is used, linking to issue 577. It does not explain the failure mode in the README text, so the reasoning has to be read from the issue. Treat that recommendation as a requirement rather than a suggestion. There is also no documented rollback procedure for a dependency that a patch breaks; the README is silent on that, and the recovery path is whatever your version control and cache state allow.

CPM.cmake versus vcpkg: manifest in the build file against a separate registry

The comparison people search for is CPM.cmake against vcpkg, and the difference is architectural rather than a matter of features. Vcpkg is a separate tool with its own manifest file, its own installed tree and a curated set of ports that carry build recipes and patches maintained by the vcpkg project. You install it, and your CMakeLists.txt consumes the result through the toolchain file.

CPM.cmake has no separate manifest and no registry. The dependency list is CMake code inside CMakeLists.txt, and the source of truth for a package is its upstream git repository or archive URL. Nothing sits between your build and upstream except the CPM script. That means no port has to exist before you can depend on something, but it also means nobody upstream has verified that the package builds on your platform or carries a fix for a known issue. With vcpkg, that work is done for you and you inherit its currency; with CPM, you inherit upstream's state exactly as it is at the commit you pinned. The two are not mutually exclusive in principle, since CPM only needs a downloadable project, but the mental model and the maintenance burden differ completely.

Maintenance, releases and what the MIT licence means here

The repository is not archived and the last push was on 2026-07-06, the same day as the v0.43.1 release. The two prior releases, v0.42.3 and v0.42.2, both landed on 2026-05-05. That is a steady release rhythm rather than a burst, and the project has a CONTRIBUTING.md and a test directory, so the upgrade path is a tagged release you can pin to.

Upgrading is a file replacement. You swap cmake/CPM.cmake for a newer release asset, or re-run the download command, and then re-configure. Because CPM is a script that runs at configure time rather than a linked library, there is no ABI to reconcile and no runtime component to ship. The upgrade risk sits in behaviour changes to CPMAddPackage and in the CMake version you require, not in binary compatibility.

CPM.cmake is MIT licensed, which is permissive and imposes no copyleft obligation on your own code. That says nothing about the licences of the dependencies you pull in with it. CPM downloads and builds third-party code into your build, so the licence of each package you add is still a question you have to answer separately; the MIT licence on the script does not cover them, and nothing here is legal advice. The repository also carries a requirements.txt pinning clang-format 14.0.6, cmake-format 0.6.11, pyyaml 6.0.3 and six 1.17.0, which are the formatting and tooling pins for contributing to CPM itself, not dependencies of the script you vendor.

Editorial conclusion

Adopt CPM.cmake if your dependencies are CMake projects or downloadable archives and you want them pinned in CMakeLists.txt rather than installed on the machine. Do not adopt it if you need prebuilt binaries, a curated package registry, or support for toolchains that cannot run CMake at configure time; CPM builds from source. Before committing, verify that each dependency's GIT_TAG resolves to an immutable commit hash, that CPM_SOURCE_CACHE is set if you rely on PATCHES, and that your minimum CMake version is at least 3.14 as the README example shows.

Frequently asked questions

How do I use CPM.cmake in a CMake project?

Download the latest release asset into your cmake directory, then add include(cmake/CPM.cmake) to CMakeLists.txt and call CPMAddPackage with either the shorthand string form or the named parameters. Targets exported by the dependency are available immediately after the call.

What is CPM.cmake?

It is a cross-platform CMake script that adds dependency management to CMake, built as a thin wrapper around the FetchContent module. It adds version control, caching and a shorthand API on top of what FetchContent provides.

Where do I download CPM.cmake?

The README points to the latest release of CPM.cmake or get_cpm.cmake on the project's GitHub releases page, and gives a wget command that writes get_cpm.cmake to cmake/CPM.cmake in your project.

Does CPM.cmake work with Boost?

The repository ships an examples/boost directory alongside examples for fmt, json, Catch2 and others, so a worked Boost configuration is part of the project. The README does not describe Boost-specific handling beyond that example.

What does CPM_SOURCE_CACHE do in CPM.cmake?

The README recommends setting it whenever you use the PATCHES parameter, linking to issue 577 for the reasoning. The README does not otherwise document the variable's behaviour.

Can CPM.cmake use a git commit hash instead of a version tag?

Yes. GIT_TAG can be set to a specific commit or a branch name, and the README's supply chain note recommends immutable commit hashes over tags or branches because tags and branches can be moved. It also warns that commit or branch packages are only updated when the cache is cleared.

Official sources

  1. cpm-cmake/CPM.cmake on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cpm-cmake-cpm-cmake.svg)](https://hysenlabs.com/projects/cpm-cmake-cpm-cmake)