CPM.cmake 是一个轻量级、现代化的 CMake 包管理器,它基于 CMake 的 FetchContent 模块构建,允许你在 CMake 项目中以声明式方式引入第三方依赖。与传统的包管理器(如 vcpkg、Conan)不同,CPM 不需要额外安装工具,只需在 CMakeLists.txt 中包含一个脚本即可使用。
1. 什么是 CPM.cmake?
- 全称:CMake Package Manager
- 特点 :
- 无需外部依赖(仅需 CMake ≥ 3.14)
- 自动下载、配置、构建和链接依赖
- 支持 Git、URL、本地路径等多种来源
- 依赖可被多个项目共享(通过缓存)
- 与 CMake 原生集成,语法简洁
GitHub 仓库:https://github.com/cpm-cmake/CPM.cmake
2. 快速开始
2.1 安装 CPM.cmake
在你的项目根目录的 CMakeLists.txt 文件开头添加以下代码:
cmake
# 下载并包含 CPM.cmake
include(FetchContent)
FetchContent_Declare(
CPM
GIT_REPOSITORY https://github.com/cpm-cmake/CPM.cmake.git
GIT_TAG v1.10.0 # 检查最新版本:https://github.com/cpm-cmake/CPM.cmake/releases
)
FetchContent_MakeAvailable(CPM)
✅ 推荐:将 CPM.cmake下载到项目中的
cmake/CPM.cmake并通过include(cmake/CPM.cmake)引入,便于版本锁定和离线使用。https://github.com/cpm-cmake/CPM.cmake/releases/
2.2 添加第一个依赖
例如,添加 fmt 库:
cmake
CPMAddPackage("gh:fmtlib/fmt@10.2.1")
这行代码会:
- 从 GitHub 克隆
fmtlib/fmt仓库 - 切换到
10.2.1标签 - 自动调用
add_subdirectory()将其加入构建系统
之后你就可以直接链接:
cmake
target_link_libraries(your_target PRIVATE fmt::fmt)
3. CPMAddPackage 语法详解
CPMAddPackage() 支持多种参数形式:
3.1 简写形式(推荐)
cmake
CPMAddPackage("gh:user/repo@version") # GitHub
CPMAddPackage("gl:user/repo@version") # GitLab
CPMAddPackage("bb:user/repo@version") # Bitbucket
示例:
cmake
CPMAddPackage("gh:nlohmann/json@v3.11.2")
3.2 完整参数形式
cmake
CPMAddPackage(
NAME your_dep_name # 可选,默认为 repo 名
GITHUB_REPOSITORY "user/repo"
VERSION "1.2.3"
GIT_TAG "v1.2.3" # 优先于 VERSION
OPTIONS "OPTION1 ON" "OPTION2 OFF"
EXCLUDE_FROM_ALL TRUE # 不自动构建(仅配置)
)
3.3 从 URL 或本地路径添加
cmake
CPMAddPackage(
NAME mylib
URL https://example.com/mylib.zip
URL_HASH SHA256=abc123...
)
# 或本地路径(用于调试或私有库)
CPMAddPackage(
NAME local_lib
SOURCE_DIR "${CMAKE_SOURCE_DIR}/third_party/mylib"
)
4. 高级用法
4.1 条件性添加依赖(避免重复)
CPM 会自动检测是否已添加同名包,但你也可以显式检查:
cmake
if(NOT TARGET nlohmann_json::nlohmann_json)
CPMAddPackage("gh:nlohmann/json@v3.11.2")
endif()
4.2 传递 CMake 选项给依赖
有些库支持自定义构建选项(如 BUILD_SHARED_LIBS):
cmake
CPMAddPackage(
NAME fmt
GITHUB_REPOSITORY fmtlib/fmt
GIT_TAG 10.2.1
OPTIONS
"FMT_INSTALL OFF"
"FMT_DOC OFF"
)
4.3 共享缓存(加速 CI 和多项目构建)
CPM 默认使用 CMake 的全局缓存目录(通常为 ~/.cache/CMake/CPM),多个项目会共享已下载的依赖,避免重复克隆。
可通过环境变量自定义缓存路径:
bash
export CPM_SOURCE_CACHE=/path/to/shared/cache
5. 完整示例项目
目录结构:
my_project/
├── CMakeLists.txt
├── main.cpp
└── cmake/
└── CPM.cmake # (可选)本地副本
CMakeLists.txt:
cmake
cmake_minimum_required(VERSION 3.14)
project(MyApp LANGUAGES CXX)
# 引入 CPM
include(cmake/CPM.cmake) # 或使用 FetchContent 方式在线获取
# 添加依赖
CPMAddPackage("gh:fmtlib/fmt@10.2.1")
CPMAddPackage("gh:gabime/spdlog@v1.13.0")
# 创建可执行文件
add_executable(app main.cpp)
# 链接依赖
target_link_libraries(app PRIVATE fmt::fmt spdlog::spdlog)
target_compile_features(app PRIVATE cxx_std_17)
main.cpp:
cpp
#include <fmt/core.h>
#include <spdlog/spdlog.h>
int main() {
fmt::print("Hello from fmt!\n");
spdlog::info("Hello from spdlog!");
return 0;
}
构建命令:
bash
mkdir build && cd build
cmake ..
cmake --build .
./app
6. 最佳实践
- ✅ 固定版本号:始终指定明确的 Git Tag 或 Commit,避免意外更新。
- ✅ 使用简写语法 :
gh:user/repo@tag更简洁且不易出错。 - ✅ 避免在函数/宏中调用 CPMAddPackage:可能导致作用域问题。
- ✅ CI 中启用缓存 :设置
CPM_SOURCE_CACHE加快构建速度。 - ❌ 不要混合 CPM 与其他包管理器:可能引起冲突。
7. 常见问题
Q: CPM 和 vcpkg/Conan 有什么区别?
A: CPM 是"源码嵌入式"管理器,直接将依赖作为子项目编译;而 vcpkg/Conan 通常预编译二进制。CPM 更适合希望完全控制构建过程的项目。
Q: 如何离线使用?
A: 将 CPM.cmake 脚本和依赖源码缓存到本地,或使用 SOURCE_DIR 指向本地副本。
Q: 支持私有仓库吗?
A: 支持!只要 Git 可访问(如配置 SSH 密钥),即可使用完整 Git URL:
cmake
CPMAddPackage(
GIT_REPOSITORY git@github.com:your/private-repo.git
GIT_TAG v1.0.0
)
8. 参考资料
- 官方 GitHub:https://github.com/cpm-cmake/CPM.cmake
- 示例项目:https://github.com/cpm-cmake/cpm-example
- CMake FetchContent 文档:https://cmake.org/cmake/help/latest/module/FetchContent.html
📌 提示:截至 2026 年,CPM.cmake 已成为许多现代 C++ 项目的首选依赖管理方案,尤其适合中小型项目和快速原型开发。