CMake Lib Manager
C++ 第三方类库本地管理
面向本机(macOS / Homebrew / vcpkg)的三种主流方式:
- 系统包管理器(Homebrew、vcpkg)
- 仅有源码:CPM / FetchContent
- Git submodule
原则:钉版本、可复现、优先项目内声明依赖,少往 /usr/local 全局乱装。
0. 本机路径速查
| 用途 | 路径 |
|---|---|
| Homebrew 前缀 | /opt/homebrew |
| vcpkg 根目录 | $HOME/vcpkg(即 /Users/songhoujin/vcpkg) |
| vcpkg 安装前缀(给 CMake 用) | $HOME/vcpkg/installed/arm64-osx |
| vcpkg 构建暂存 | $HOME/vcpkg/packages/<pkg>_arm64-osx |
| vcpkg toolchain | $HOME/vcpkg/scripts/buildsystems/vcpkg.cmake |
| 归档工具 | AR=/usr/bin/ar(勿用 binutils 的 GNU ar) |
| HTTP 代理(Clash) | http://127.0.0.1:17890(http_proxy/https_proxy/all_proxy 均用 http://,勿对 17890 使用 socks5://) |
export AR=/usr/bin/ar
export VCPKG_ROOT=$HOME/vcpkg
export http_proxy=http://127.0.0.1:17890
export https_proxy=http://127.0.0.1:17890
export HTTP_PROXY=$http_proxy HTTPS_PROXY=$https_proxy
export all_proxy=http://127.0.0.1:17890 ALL_PROXY=$all_proxy1. 系统包管理器:Homebrew / vcpkg
有 formula / port 时优先用包管理器:多项目共用、升级清晰、find_package 友好。
1.1 Homebrew
brew install fmt ftxui entt
brew --prefix fmt # 查看单包前缀
ls "$(brew --prefix)/lib/cmake"CMake 使用:
cmake -S . -B build -DCMAKE_PREFIX_PATH="$(brew --prefix)"
cmake --build buildcmake_minimum_required(VERSION 3.20)
project(demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
find_package(fmt CONFIG REQUIRED)
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE fmt::fmt)安装位置: /opt/homebrew/{include,lib,lib/cmake,share}(Apple Silicon)。
1.2 vcpkg
export AR=/usr/bin/ar VCPKG_ROOT=$HOME/vcpkg
# 代理见上文;确认:env | grep -i proxy 中不应出现 socks5://127.0.0.1:17890
vcpkg install libassert unordered-dense mp-units
vcpkg listCMake 使用(推荐带 toolchain):
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build buildcmake_minimum_required(VERSION 3.20)
project(demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
find_package(libassert CONFIG REQUIRED)
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE libassert::assert)安装位置:
- 给编译器用的:
$HOME/vcpkg/installed/arm64-osx/{include,lib,share} packages/仅为构建中转,不要把它当CMAKE_PREFIX_PATH
1.3 何时用 brew、何时用 vcpkg
| 情况 | 建议 |
|---|---|
| 有 brew formula,且要系统级共用 | Homebrew |
| 无 brew / 要与 CMake 深度集成 / 钉 triplet | vcpkg |
| macOS 预发布导致 bottle 异常 | 可改 vcpkg,或 brew install --build-from-source(视公式而定) |
2. 仅有源码:CPM / FetchContent
无 brew、无 vcpkg port(或故意跟 git)时,在 本项目 CMake 里拉取源码。默认只进当前 build/,不污染系统。
典型库:NVIDIA/stdexec、alibaba/yalantinglibs 等。
2.1 原生 FetchContent
cmake_minimum_required(VERSION 3.24)
project(demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
FetchContent_Declare(
stdexec
GIT_REPOSITORY https://github.com/NVIDIA/stdexec.git
GIT_TAG <钉死的 tag 或 commit> # 勿长期裸追 main
)
FetchContent_MakeAvailable(stdexec)
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE STDEXEC::stdexec) # 目标名以该库文档为准落盘位置(配置后):
| 路径 | 内容 |
|---|---|
build/_deps/<name>-src/ | 下载的源码 |
build/_deps/<name>-build/ | 该依赖的构建目录 |
build/_deps/<name>-subbuild/ | 下载用子工程 |
删除 build/ 即清除缓存;换机器需重新 cmake -B build(需能访问 Git 仓库)。
2.2 CPM.cmake(推荐封装)
一次引入 CPM,之后一行加依赖:
mkdir -p cmake
curl -fsSL -o cmake/CPM.cmake \
https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/CPM.cmakecmake_minimum_required(VERSION 3.24)
project(demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
include(cmake/CPM.cmake)
# 形式:gh:owner/repo#tag_or_commit
CPMAddPackage("gh:NVIDIA/stdexec#<钉死的版本>")
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE STDEXEC::stdexec)CPM 仍基于 FetchContent,缓存同样在 build/_deps/(也可设 CPM_SOURCE_CACHE 指向如 $HOME/.cache/CPM 跨项目复用下载)。
cmake -S . -B build -DCPM_SOURCE_CACHE=$HOME/.cache/CPM
cmake --build build2.3 可选:安装到用户前缀(多玩具项目共用)
cmake -S /path/to/stdexec -B /tmp/stdexec-build \
-DCMAKE_INSTALL_PREFIX=$HOME/.local \
-DCMAKE_BUILD_TYPE=Release
cmake --build /tmp/stdexec-build
cmake --install /tmp/stdexec-build
# 其它项目:
cmake -S . -B build -DCMAKE_PREFIX_PATH=$HOME/.local落盘: $HOME/.local/{include,lib,lib/cmake}。正式项目仍更推荐 FetchContent/CPM 钉在仓库内。
3. Git submodule
需要源码进仓库、可审计、可离线构建时使用。
3.1 添加与更新
cd /path/to/your-project
git submodule add https://github.com/NVIDIA/stdexec.git third_party/stdexec
# 钉到具体提交
cd third_party/stdexec && git checkout <commit> && cd -
git add third_party/stdexec
git commit -m "Pin stdexec to <commit>"
# 新克隆机器:
git clone --recurse-submodules <your-repo-url>
# 或已克隆后:
git submodule update --init --recursive3.2 CMake 接入
cmake_minimum_required(VERSION 3.20)
project(demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(third_party/stdexec)
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE STDEXEC::stdexec)若上游不是「可 add_subdirectory 的 CMake 工程」,可改为:
target_include_directories(demo PRIVATE third_party/some_header_only/include)3.3 落盘位置
| 路径 | 内容 |
|---|---|
<项目>/third_party/<库>/ | 源码(随 submodule 提交指针版本) |
build/ | 你自己工程的构建树(依赖若被 add_subdirectory,对象文件也在 build 里) |
4. 三种方式怎么选
| 场景 | 选 |
|---|---|
| 有 brew / vcpkg,多项目共用 | §1 包管理器 |
| 无发行包、跟上游、单项目 | §2 CPM / FetchContent |
| 要进 git、审计、离线 CI | §3 submodule |
| 仅本机随便玩 | $HOME/.local 或 ~/src/...(非正式) |
共同要求:
- 钉 tag / commit,避免默默漂在
main - CI 与文档写清:代理、
AR、CMAKE_TOOLCHAIN_FILE - 同一依赖不要 brew + vcpkg + FetchContent 混装三份,除非有意隔离
5. 最小可粘贴工程骨架
myapp/
CMakeLists.txt
cmake/CPM.cmake # 若用 CPM
third_party/... # 若用 submodule
src/main.cppCMakeLists.txt 混合示例(包管理器 + CPM):
cmake_minimum_required(VERSION 3.24)
project(myapp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
# 来自 brew / vcpkg(需 CMAKE_PREFIX_PATH 或 vcpkg toolchain)
find_package(fmt CONFIG REQUIRED)
# 仅有源码
include(cmake/CPM.cmake)
CPMAddPackage("gh:NVIDIA/stdexec#<version>")
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt STDEXEC::stdexec)配置示例:
# 只用 brew
cmake -S . -B build -DCMAKE_PREFIX_PATH="$(brew --prefix)"
# 只用 vcpkg
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake
# brew + vcpkg 同时找包时,toolchain + PREFIX 可一起设(注意别重复链接同一库的两套)6. 排错速记
| 现象 | 处理 |
|---|---|
vcpkg curl 35 / SSL timeout | 检查代理:all_proxy 勿对 Clash HTTP 口用 socks5://;统一 http://127.0.0.1:17890 |
vcpkg archive member '/' not a mach-o | export AR=/usr/bin/ar,并从 PATH 去掉 binutils 的 ar |
find_package 找不到 | 查 CMAKE_TOOLCHAIN_FILE / CMAKE_PREFIX_PATH;vcpkg 用 installed/arm64-osx 而非 packages/ |
| FetchContent 每次重下 | 设 CPM_SOURCE_CACHE,或改用 submodule |
文档用途:本机第三方 C++ 库管理备忘。可按项目需要删减示例中的库名与版本钉点。