FetchContent 使用
FetchContent 是现代 CMake(3.11+)提供的依赖获取方式:在 配置阶段 拉取第三方源码,并把它作为子工程加入当前构建(通常通过 add_subdirectory)。它特别适合:
- 依赖规模不大、希望“一次配置就能拉齐源码”
- CI 或新同事一键构建(不要求预装依赖)
- 依赖本身也使用 CMake 构建
示例:拉取并使用 fmt
cmake_minimum_required(VERSION 3.15)
project(demo LANGUAGES CXX)
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(fmt)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE fmt::fmt)
配置与构建:
cmake -S . -B build
cmake --build build -j
常用选项
固定版本(强烈建议)
- 用
GIT_TAG固定到某个 release/tag/commit,避免“今天能构建,明天拉最新就坏了”。
关闭依赖的测试/示例(常用)
很多依赖默认会编译测试/示例,会拖慢构建。通常可以在 FetchContent_MakeAvailable() 之前设置它的选项(不同项目选项名不同):
set(FMT_TEST OFF CACHE BOOL "" FORCE)
set(FMT_DOC OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(fmt)
FetchContent 与 find_package 的配合策略
工程里常见的最佳实践是:优先使用系统/预装依赖,找不到再用 FetchContent 兜底:
find_package(fmt CONFIG QUIET)
if(NOT fmt_FOUND)
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(fmt)
endif()
add_executable(app main.cpp)
target_link_libraries(app PRIVATE fmt::fmt)
这样在“有包管理器的环境”走 find_package,在“干净环境/CI”自动拉取构建。
常见问题
- 构建目录膨胀:FetchContent 会把依赖也放进同一 build 树,依赖多时 build 体积变大。
- 网络不稳定:CI 可能需要缓存(如缓存 build 目录或依赖下载目录)。
- 依赖不是 CMake 工程:FetchContent 只能“拿源码”,但能否
add_subdirectory取决于依赖是否提供 CMakeLists。
何时不要用 FetchContent
- 依赖很大、编译很慢、需要严格隔离构建(更适合
ExternalProject或 Superbuild) - 交叉编译/多工具链下,需要依赖与主工程分离安装前缀
小结
FetchContent:配置阶段拉源码、在同一 build 树里构建依赖,易用、现代、适合中小依赖。- 与
find_package(QUIET)配合,可以同时兼顾“系统包优先”和“一键构建”。