6、下载源配置:GIT_REPOSITORY、URL下载方式、SVN支持、本地路径引用
说到 FetchContent 的下载源配置,这其实是整个依赖管理中最核心的一环。你想想看,不管你的项目结构多漂亮,如果源码下载不下来,一切都是白搭。我个人习惯把下载源分成四类:Git 仓库、普通 URL、SVN 仓库,还有本地路径。今天咱们就一个一个说清楚。
GIT_REPOSITORY:最常用的方式
说实话,现在绝大多数开源项目都托管在 Git 仓库上。所以 GIT_REPOSITORY 是我用得最多的配置项。它的用法很简单,直接指定仓库地址就行。
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.1.0
)
这里有个细节我要强调一下:GIT_TAG 不只是能写版本号。你可以写分支名、commit hash,甚至是 tag 名。我在项目中遇到过一个问题——有人直接写 main 分支,结果过了一个月再构建,代码变了,编译不过了。所以我的建议是:永远指定一个固定的 commit hash 或 release tag。
GIT_SHALLOW 与 GIT_PROGRESS
还有一个我特别想提的选项——GIT_SHALLOW。这个参数可以让 CMake 做浅克隆,只下载最新版本的代码,不拉取整个历史。对于大型仓库来说,这能省下不少时间和磁盘空间。
FetchContent_Declare(
protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
GIT_TAG v21.12
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
GIT_PROGRESS 这个选项也挺实用。默认情况下,FetchContent 下载时不会显示进度条,你只能干等着。加上这个选项,就能看到下载进度了。嗯,特别是下载大项目时,心里会踏实很多。
URL 下载方式:没有 Git 怎么办?
有些项目没有 Git 仓库,或者你只想下载一个压缩包。这时候就要用 URL 方式了。说白了,就是直接给一个下载链接。
FetchContent_Declare(
mylib
URL https://example.com/downloads/mylib-1.2.3.tar.gz
URL_HASH SHA256=abc123...
)
URL_HASH!不加的话,CMake 每次构建都会重新下载,因为无法判断文件是否变化。我刚开始用的时候没加这个,每次改个 CMakeLists.txt 都要等半天下载,后来才发现是 hash 的问题。
URL 方式支持多种压缩格式:.tar.gz、.zip、.tar.bz2 等等。CMake 会自动解压,你不需要写额外的解压命令。
SVN 支持:老项目也能用
虽然 Git 是主流,但有些企业内部还在用 SVN。FetchContent 也考虑到了这一点,提供了 SVN_REPOSITORY 选项。
FetchContent_Declare(
legacy_lib
SVN_REPOSITORY https://svn.example.com/legacy_lib/trunk
SVN_REVISION -r1234
)
这里要注意,SVN 的版本号是整数,不是 hash。而且 SVN 的下载速度通常比 Git 慢,因为它是逐个文件拉取的。我在一家传统企业里见过这种情况,他们的构建服务器上甚至没有装 Git,只能用 SVN。嗯,这时候 FetchContent 的 SVN 支持就派上用场了。
find_package(Subversion)。如果找不到,就 fallback 到其他下载方式。
本地路径引用:离线开发的神器
最后说说本地路径。这个功能我特别喜欢,尤其是在飞机上或者网络不好的时候。你可以直接把依赖指向本地的一个目录,这样就不需要联网下载了。
FetchContent_Declare(
mylib
SOURCE_DIR /home/user/projects/mylib
)
或者更灵活一点,结合 URL 和 SOURCE_DIR 一起用:
FetchContent_Declare(
mylib
URL https://example.com/mylib.tar.gz
SOURCE_DIR /path/to/local/cache/mylib
)
当 SOURCE_DIR 指定的路径存在时,FetchContent 会直接使用它,不会去下载。这个机制可以用来做缓存,也可以用来做离线开发。
SOURCE_DIR 时,CMake 不会检查目录里的内容是否是最新的。如果你改了本地目录的代码,需要手动删除 _deps 目录下的相关文件夹,或者清理 CMake 缓存,才能让 FetchContent 重新同步。
四种方式对比
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| GIT_REPOSITORY | 开源项目、Git 托管 | 支持分支、tag、commit | 需要安装 Git |
| URL | 压缩包、无 Git 环境 | 简单直接 | 不支持增量更新 |
| SVN_REPOSITORY | 企业内部、老项目 | 兼容 SVN 工作流 | 速度慢、需要 SVN 客户端 |
| SOURCE_DIR | 离线开发、本地缓存 | 无需网络、速度快 | 需要手动管理同步 |
知识体系总览
下面这张图帮你理清这四种下载方式的关系和选择逻辑:
这张图把四种方式的关系梳理得很清楚。你从上往下看,先确定你的依赖托管在哪里,再选择合适的配置方式。我个人建议:能用 Git 就用 Git,因为它最灵活,支持精确版本控制。如果网络受限,就退而求其次用 URL 或本地路径。
if(DEFINED CACHE{USE_LOCAL}) 做切换。这样开发人员在本地可以用 URL 加速,CI 服务器上用 Git 保证版本一致。效果非常好。
好了,关于下载源配置就讲到这里。记住一句话:选对下载方式,你的依赖管理就成功了一半。剩下的就是版本控制和缓存策略了,那些我们后面再聊。