CPM.cmake轻量级包管理器

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. 参考资料


📌 提示:截至 2026 年,CPM.cmake 已成为许多现代 C++ 项目的首选依赖管理方案,尤其适合中小型项目和快速原型开发。

相关推荐
哇哈哈20213 小时前
信号量和信号
linux·c++
多恩Stone4 小时前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
蜡笔小马4 小时前
21.Boost.Geometry disjoint、distance、envelope、equals、expand和for_each算法接口详解
c++·算法·boost
超级大福宝4 小时前
N皇后问题:经典回溯算法的一些分析
数据结构·c++·算法·leetcode
weiabc6 小时前
printf(“%lf“, ys) 和 cout << ys 输出的浮点数格式存在细微差异
数据结构·c++·算法
问好眼6 小时前
《算法竞赛进阶指南》0x01 位运算-3.64位整数乘法
c++·算法·位运算·信息学奥赛
yyjtx6 小时前
DHU上机打卡D31
开发语言·c++·算法
czxyvX6 小时前
020-C++之unordered容器
数据结构·c++
会编程的土豆6 小时前
2.25 做题
数据结构·c++·算法
Ljwuhe7 小时前
类与对象(中)——运算符重载
开发语言·c++