CMake FetchContent 拉取失败 connection refused 速查
更新时间:2026-10-24。FAQ 速查页,面向用 CMake
FetchContent/ExternalProject在配置期拉第三方依赖的同学。CMake FetchContent 拉取失败是「配置阶段就联网」带来的新型报错:cmake ..一跑就在背后git clone或下载压缩包,网络稍有不通,配置直接中断。报错的指向集中在网络链路——依赖仓库地址本身不可达、公司代理没配或配了被拦、HTTPS 证书校验过不去、构建机在内网/离线环境却硬拉外网。本篇以报错原文为锚逐条定位;如果是 CMake 版本与工程要求不匹配,请转 CMake 版本不兼容报错速查;配置期找不到编译器,转 CMake 找不到编译器速查。
本文要回答的问题
- FetchContent 到底在
cmake的哪一步联网,报错为什么是配置期而不是编译期? Connection refused与Connection timed out的排查方向差别在哪?- 代理变量配在 shell 里了,为什么 cmake 里的 git 还是不走代理?
- 证书报错
SSL certificate problem该不该关校验? - 完全离线的构建机怎么优雅地用 FetchContent 工程?
一、报错原文与典型现象
报错固定长这样(工程路径以 /proj/demo 占位,仓库地址以 git.example.com 占位):
$ cmake -S . -B build
-- Configuring done
[ 11%] Performing download step (git clone) for 'deps-populate'
Cloning into 'deps-src'...
fatal: unable to access 'https://git.example.com/org/deps.git/': Failed to connect to git.example.com port 443: Connection refused超时与证书的另外两张面孔:
fatal: unable to access 'https://git.example.com/org/deps.git/': Failed to connect to git.example.com port 443 after 75000 ms: Connection timed outfatal: unable to access 'https://git.example.com/org/deps.git/': SSL certificate problem: unable to get local issuer certificate读懂报错抓住三件东西:失败的动作(git clone 还是下载压缩包——FetchContent 两种取法网络栈不同)、失败节点(refused 是对面端口明确拒绝、timed out 是链路中间石沉大海、SSL 是连上了但证书谈不拢)、它在哪一步炸(配置期,意味着连 Makefile 都没生成,make 根本没机会跑)。那句 Performing download step (git clone) 表明这个依赖是按 git 仓库方式拉的,排查时可以直接拿同样的 URL 在 shell 里手工 clone 复现。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
Connection refused 秒回 | 目标端口明确拒绝:仓库地址写错、内网镜像没起来 | git clone <同URL> 手工复现;核对 URL 拼写 | 修正 GIT_REPOSITORY 地址;确认镜像服务在线 |
Connection timed out 卡住几十秒 | 链路不通:防火墙拦、该走代理没走 | curl -v <URL> 看卡在哪一跳 | 给 git/curl 配代理,或换可达镜像 |
shell 里 https_proxy 已配仍不通 | git 不读部分变量或被 .gitconfig 覆盖 | git config --global --get http.proxy | git config --global http.proxy http://<proxy-host>:<port> 显式配 |
SSL certificate problem | 自签证书/公司网关证书未被信任 | curl -vI <URL> 看证书链 | 装 CA 证书进系统信任库;测试环境临时 GIT_SSL_NO_VERIFY=1,禁进生产 |
| 之前能拉、升级后报认证失败 | 访问令牌过期/被回收 | 手工 clone 看是否要求登录 | 更新令牌;改用免交互的凭据管理 |
| 离线机房/隔离网构建 | 环境根本无外网 | 任何外网 URL 都不通 | 预下载源码包,FETCHCONTENT_SOURCE_DIR 指本地 |
| 同样的依赖每次配置都重拉 | 缓存目录被清或 build 目录不复用 | 看 _deps 是否重复下载 | 固定 build 目录复用,或离线预置 |
URL 是 git@ SSH 形式在 CI 上失败 | CI 无 SSH key,或 22 端口被封 | 手工 ssh 复现 | 改 HTTPS 形式,或给 CI 配 deploy key |
三、排查决策图
下面这张图按「报错属于哪一层网络故障」分流:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住两个动作:先脱离 cmake、用同一 URL 在 shell 手工复现(git clone 或 curl -v),把「cmake 的问题」还原成「网络的问题」;再按报错气质分四支——秒拒查地址、超时查链路代理、证书查信任、全不通按离线处理。
四、逐条排查展开
第一步:手工复现,脱离 cmake 变量。 FetchContent 本质是替你跑 git clone 或文件下载,同一条命令拿到 shell 里跑,报错原文一模一样,且可以随便加 -v 看细节:
git clone https://git.example.com/org/deps.git /tmp/probe-deps
curl -vI https://git.example.com/org/deps.git手工能成、cmake 里炸,才轮到怀疑 cmake 的缓存(删 build 目录重配)或 GIT_CONFIG 环境差异;手工也炸,那就是纯网络问题,往下分层。
秒拒与超时是两个方向。 Connection refused 是 TCP 层收到了明确拒绝——目标主机活着但端口没服务,十有八九是 URL 写错(域名拼错、端口不对、该走内网镜像写成了外网),先逐字符核对 GIT_REPOSITORY。Connection timed out 是包发出去石沉大海——防火墙静默丢弃、或该走代理的流量直连了,方向完全相反:查链路与代理而不是地址本身。
代理要配在 git 认的地方。 shell 里的 https_proxy 环境变量,cmake 调起的 git 子进程多数时候能继承,但 .gitconfig 里的 http.proxy 设置优先级更高、且常被历史遗留值覆盖。显式配置最稳:
git config --global http.proxy http://proxy.example.com:8080
git config --global --get-regexp '^http' # 核对生效值配完先手工 clone 验证走通了,再回 cmake 重配。注意代理只解决「出网」,内网镜像场景配了代理反而绕远,该删就删(git config --global --unset http.proxy)。
证书问题别一上来就关校验。 SSL certificate problem: unable to get local issuer certificate 九成是公司出口网关做了 TLS 拦截、它的自签 CA 没装进系统信任库。正解是找运维要 CA 证书装进系统(或设 GIT_SSL_CAINFO 指到该证书文件);GIT_SSL_NO_VERIFY=1 只能当本地临时探路的创可贴,写进 CI/生产等于放弃中间人防护,明令禁止。
离线环境用官方留好的后门。 FetchContent 从设计第一天就考虑了离线:把依赖源码预先下载好放本地目录,配置时指过去即可,一行网络都不走:
cmake -S . -B build -DFETCHCONTENT_SOURCE_DIR_DEPS=/proj/demo/vendor/deps变量名规则是 FETCHCONTENT_SOURCE_DIR_<大写依赖名>。工程化做法是发布流程里把全部 FetchContent 依赖打成 vendor 目录随源码分发,离线构建机统一加这些变量;同时 GIT_TAG 钉到具体提交哈希而不是分支名,保证线上线下拉到的是同一份代码。
重复拉取与缓存。 FetchContent 的下载产物在 build 目录的 _deps/ 下,每次删 build 重配都会重拉——网络差的环境尽量复用 build 目录增量配置;要彻底跳过更新阶段还有 FETCHCONTENT_UPDATES_DISCONNECTED=ON(已拉过的不再 check 更新)。
五、规范做法与预防
- 依赖钉死版本:
GIT_TAG用提交哈希或 tag,不用分支名;镜像地址统一从变量/缓存变量注入,换镜像不改 CMakeLists。 - 内网镜像优先:团队维护内部 git 镜像或制品库,CMakeLists 默认指内网地址,外网直连只作 fallback。
- 离线预置纳入发布流程:vendor 目录随源码包分发,隔离网构建零外网依赖。
- 代理配置集中管理:CI 镜像里预置 git 代理配置与 CA 证书,不依赖每个开发者手工配。
- 配置期网络动作显式化:README 写明「cmake 配置期会拉取哪些依赖」,新人踩坑前先知情。
这一篇在知识体系里的位置
本篇是 Makefile/CMake 排错速查簇的依赖拉取篇,定位「cmake 配置期联网取依赖失败」:FetchContent/ExternalProject 网络问题看本篇;CMake 版本口径的看 CMake 版本不兼容报错速查;找不到编译器的看 CMake 找不到编译器速查;makefile 语法层的看 Makefile missing separator 语法解析报错速查;编译期类型问题的看 error: cannot convert 类型不匹配速查;链接期符号问题的看 undefined reference 链接错误速查。「同一 URL 手工复现、按秒拒/超时/证书分流」的套路在所有拉取类报错间完全通用。
一句话总结
CMake FetchContent 拉取失败先拿同一 URL 在 shell 手工 git clone/curl -v 复现,再按报错气质分流:Connection refused 秒拒查 GIT_REPOSITORY 地址与镜像在线状态,timed out 超时查防火墙并用 git config http.proxy 显式配代理,SSL 证书报错把网关 CA 装进系统信任库(禁关校验进生产),认证失败更新访问令牌,纯离线环境预下载源码包用 FETCHCONTENT_SOURCE_DIR_<名> 指本地。依赖钉哈希、内网镜像优先、vendor 预置纳入发布流程,这条报错即可基本绝迹。