macOS上获取Chromium 144源码:depot_tools与gclient实战指南
如果你已经坚持到这一步说明 Chromium 144 编译这条路上最劝退你的难题已经在前面解决得差不多了。接下来这个环节就是每天都会被问到的“获取源代码”。很多刚接触 Chromium 构建的人以为编译是从ninja -C out/... chrome开始的但我可以负责任地说超过一半的坑在你敲下第一条编译命令之前就已经埋好了而其中面积最大的雷区恰恰就是本文标题里写的“获取源代码”这五个字。这一篇我会把 macOS 上获取 Chromium 144 源码的完整过程拆开讲为什么 Chromium 不能像普通开源项目那样直接git clone为什么必须有 depot_tools 这套看起来非常玄学的工具链以及我在实际同步过程中遇到的那些网络、文件系统、权限相关的坑。如果你准备在 macOS 上编译 Chromium 144但还卡在“源码拉不下来”这一步那这篇应该能帮你省下好几个小时的排查时间。1. 先搞明白Chromium 为什么偏要用 depot_tools 这套东西1.1 一个 Chromium 不是“一个仓库”而是几百个仓库很多人第一次接触 Chromium 源码时都会有个天然疑问我直接把官方仓库克隆下来不就行了答案是不行而且原因很实在。Chromium 的源码结构并不是一个完整的单体仓库。主仓库里确实有src/下的几万个文件但大量第三方库、工具链、测试数据并不在主仓库里而是通过一个叫DEPS的文件描述依赖关系。简单来说DEPS文件是一份“依赖清单”里面声明了每个子仓库对应哪个提交号或分支以及需要额外补充的二进制资源。真正要把一个能编译的 Chromium 144 源码树组装出来你需要同时把主仓库和上百个子仓库全部按特定版本取下来并对齐。这种情况下普通git clone只能给你一个空壳。你会看到src/third_party下面一堆目录存在但里面要么是空的要么是过期内容。直接跑构建各种缺头文件、缺静态库的报错会接踵而来。一个比较贴切的比喻Chromium 源码更像是一张“装配图纸”加上一大批零件清单图纸在主仓库里零件散落在几十个不同的上游仓库。你需要一个管理员来按清单、按版本号逐一把零件取回来、放到正确的位置——这个管理员就是gclient。1.2 depot_tools 里不只是一个工具macOS 上获取 Chromium 源码的第一步是先安装一个叫depot_tools的工具集。很多人误以为它是“又一个版本管理工具”其实它是 Chromium 开发流程里的一整套流水线入口。depot_tools 里最核心的几个组件gclient负责解析DEPS文件按声明逐个拉取依赖仓库并把所有仓库的版本协调到一个可编译的整体状态。fetch一个封装命令用于初始化项目目录生成.gclient配置文件然后自动调用gclient sync完成首轮同步。gnChromium 的构建文件生成器。它把高层的构建配置翻译成 ninja 最终执行的低层规则。ninja最终的编译执行器负责并行调度 C 编译任务。所以在“获取源代码”这个阶段你真正的主战场是fetch和gclient sync其他工具会在编译篇才正式出场。但你必须先装上整套 depot_tools因为后续每一步都要用到它们。1.3 在 macOS 上最容易踩的认知误区在 Linux 上获取 Chromium 源码和 macOS 上有一个本质区别那就是文件系统。macOS 默认的 APFS 卷宗通常是不区分大小写的也就是说Foo.cpp和foo.cpp会被系统视为同一个文件。Chromium 源码里偏偏存在大量只靠大小写区分的目录和文件例如某些平台相关的头文件。如果直接在默认文件系统上同步gclient在 checkout 时会因为“目标文件已存在”而失败或者更隐蔽地出现文件内容被覆盖的情况。这不是偶发问题而是几乎必然踩中的地雷。所以只要是在 macOS 上搞 Chromium 编译我的第一建议永远是不要直接在默认主分区上操作先创建一个区分大小写的 APFS 卷宗再把所有源码放到这个卷宗上。这一点后面我会给出具体的操作命令。2. 动手前的环境检查不检查sync 必挂2.1 磁盘空间你以为的够用和实际的差距先说一个我亲测过多次的数据。Chromium 144 的源码树注意只是源码不含编译产物完整同步下来之后通常要占用 20GB 到 30GB 左右的磁盘空间其中.git目录本身就是一个吞空间的大户。这还不算完因为 Chromium 主仓库的 git 历史极其庞大首次同步时 gclient 还要为每个子仓库建立本地 git 缓存这也会临时占用额外空间。如果后续还要编译光是一个 debug 版本的构建中间文件就可能再吃掉 40GB 到 80GB。所以我的经验是在 macOS 上为 Chromium 项目预留至少 80GB 到 100GB 的可写空间。有几次我见到有人因为磁盘不够导致gclient sync在执行到一半时挂掉报错信息却很模糊。这种问题最坑的地方在于它不是一步到位地告诉你“磁盘满了”而是表现为某些文件写入失败、hooks 执行报错让人误以为是网络或权限问题。建议行动用df -h查看卷宗的剩余空间。创建一个独立卷宗时直接指定大小例如 100GB 或更大。整个过程密切关注空间变化如果发现卷宗见底立即停止并清理。2.2 Xcode 与 Command Line Tools 的版本匹配Chromium 的编译脚本在 macOS 上依赖 Xcode 提供的 SDK、编译器和各种工具链。获取源代码阶段其实不会直接执行编译某些 hooks 却会下载和校验工具链所以 Xcode 环境不对也会导致同步失败。实际项目中常见的两个问题第一个是没有安装完整版 Xcode只装了 Command Line Tools。某些 hook 在查找 SDK 路径时会直接扑空。第二个是 Xcode 的许可协议没有接受任何调用命令行的操作都会弹出一段“需要同意许可协议”的提示或者干脆静默失败。建议直接执行以下操作xcode-select -p如果输出路径指向 Command Line Tools而不是完整版 Xcode 的路径就需要用xcode-select -s切换。然后再执行sudo xcodebuild -license accept保证 Xcode 的路径和许可状态都没有问题再继续后面的步骤。这一步做不好后面 gclient sync 跑到 hooks 阶段时报错会非常莫名其妙。2.3 Python、Git、文件系统三个容易被忽略的细节Chromium 的脚本体系对 Python 3 有硬性依赖。macOS 系统自带/usr/bin/python3但版本可能偏低。某些依赖脚本如果遇到不支持的语法会在同步过程中间突然抛异常。我个人的建议是直接用 Homebrew 装一个较新的 Python 3比如 3.11 或 3.12并确保它在PATH中位于系统自带 Python 之前。这不影响系统稳定性也不会和系统脚本产生冲突因为 Chromium 工具链会在自己的环境中引导 Python。Git 的版本最好也不要太老。Chromium 的仓库基础设施使用了一些较新的 git 特性如果你的 macOS 自带 git 版本过旧可能会在fetch时出现奇怪错误。建议执行git --version确认版本太旧就用 Homebrew 升级。最后是文件系统。上面也提到了macOS 默认大小写不敏感而 Chromium 源码强烈依赖大小写敏感环境。创建大小写敏感卷宗的命令一般是这样的sudo diskutil apfs addVolume /System/Volumes/Data Case-sensitive APFS chromium-dev -role d这个命令会在当前磁盘的数据卷里新建一个名为chromium-dev的 APFS 卷宗大小按需自动分配。创建完成后所有源码和构建目录都放到这个卷宗下面操作。这一步做对了后面会省掉至少一半的疑难杂症。提示不要偷懒在默认卷上直接开始也别想靠大小写不敏感环境碰运气。Chromium 仓库里真实存在仅大小写不同的文件名这是硬性冲突没有任何技巧可以绕过。3. 正式操作fetch chromium 与 gclient sync 实战3.1 安装 depot_tools环境准备好之后第一步是把 depot_tools 拉下来。你需要一个目录专门存放它我会放到~/depot_tools这样后续引用起来比较方便。git clone depot_tools 仓库地址 ~/depot_tools具体仓库地址可以参考 Chromium 官方文档的指引。拉下来之后要把这个目录加进PATH这样fetch、gclient、gn这些命令才能在终端里直接用。export PATH$HOME/depot_tools:$PATH这个 export 只在当前终端会话有效。为了以后不用重复设置推荐把它写进 shell 配置文件比如~/.zshrc或~/.bash_profileecho export PATH$HOME/depot_tools:$PATH ~/.zshrc source ~/.zshrc然后检查一下工具是否就绪gclient --version如果能看到版本输出说明工具链已经能用了。这里有个小细节depot_tools 首次运行时会自动下载或更新自身依赖所以终端里也许会出现一段更新日志耐心等它跑完。3.2 用 fetch 初始化项目结构接下来选择一个工作目录。这个目录最好是前面提到的大小写敏感卷宗比如/Volumes/chromium-dev。我先在里面建一个专门的文件夹并进入目录mkdir /Volumes/chromium-dev/chromium144 cd /Volumes/chromium-dev/chromium144然后执行fetch --nohooks chromium这里我刻意加了--nohooks参数。fetch 命令默认会直接完成整个初始化流程写入.gclient配置、创建src目录、执行第一轮gclient sync最后运行 hooks。加上--nohooks之后可以先把源码同步到完整状态再单独控制 hooks 的执行时机。尤其是网络环境不够理想的时候这样可以避免下载源码和下载工具链挤在一起发生竞争。fetch 执行过程中会做这些事在当前目录生成.gclient文件记录解决方案配置。创建src目录开始拉取主仓库代码。自动调用 gclient 按DEPS文件同步各个子仓库。如果没加--nohooks同步完成后会立即执行 hooks。整个过程最考验耐心。首次同步数据量通常在 10GB 以上具体时间完全取决于网络状况。有些人以为程序卡死了就提前终止其实它可能在静默拉取一个大仓库。我的建议是先让它跑除非连续几十分钟没有任何进展。3.3 gclient sync 的三个阶段如果你已经用fetch --nohooks chromium完成了初始化实际上已经触发了一轮 gclient sync。为了让理解更透彻我需要单独把它拆开讲。gclient sync的阶段大致分为三个阶段一解析依赖描述。gclient 会读取src/DEPS文件计算要同步哪些仓库、需要 checkout 到哪个提交号、有哪些 hooks 需要注册。这个阶段通常在几十秒内完成。阶段二按清单 checkout 子仓库。gclient 会以src目录为基础把每个依赖仓库拉取到指定 commit。这个过程非常耗时因为依赖仓库数量多而且会先后创建大量 git 对象。阶段三运行 hooks。hooks 是很多自定义脚本用于下载额外的二进制工具、生成一些必需文件。比如某些工具链组件、翻译数据、测试资源都是在这个阶段落到磁盘上的。hook 失败是新手最常遇到的问题。如果希望在同步阶段跳过 hooks可以这样gclient sync --nohooks全部仓库 checkout 完成后再手动执行 hooksgclient runhooks这么拆开的好处很明显源码树到位之后你可以先检查文件是否完整再去补跑资源下载。两个大任务分开执行出问题时更容易定位原因。3.4 关于并行数与执行时长的预期管理Chromium 官方并不建议在gclient sync时盲目加并行参数。默认情况下gclient 已经会根据依赖关系合理调度各个仓库的拉取顺序。如果网络条件一般我用-j 8或-j 16实测过有时反而会因为并发太高导致部分仓库下载超时。在获取源代码阶段我更推荐的策略是一次性跑完中途不要频繁打断。首次同步在良好网络条件下大约需要 30 分钟到 2 小时不等。如果超过 3 小时还没结束那大概率是网络问题而不是工具问题。由于 Chromium 的 git 缓存机制设计得比较合理中途断了也不需要从零开始。gclient 会利用本地已经拉取的 git 对象再次同步时只补充缺失部分。所以不要怕失败跑失败了就再跑一次这是很正常的节奏。4. 网络问题不玄学sync 卡住和恢复的实操4.1 先确认网络环境本身是否可达获取 Chromium 源码对网络要求比较高这一点绕不开。很多人一遇到gclient sync卡住就开始怀疑命令写错或者目录有问题其实更可能是网络层面的原因。判断方法很简单先用git直接测试一下官方代码仓库是否可达git ls-remote Chromium 官方代码仓库地址 HEAD如果这条命令能正常返回一个 commit 哈希说明基础网络到代码仓库是通的问题可能出在后续的某个子仓库或者 hooks 下载源。如果这条命令就卡住或超时那说明根本还没到 gclient 的层面需要先解决网络可达性问题。在确认网络环境可达之后再跑 gclient能少走很多弯路。4.2 卡住时怎么判断是正常等待还是死掉了gclient sync 运行期间终端上会显示当前正在处理的项目名称。但有一个比较坑的现象某些大型仓库的 fetch 阶段屏幕上可能长时间没有任何输出CPU 和磁盘占用却很高。这时候它其实是正常的正在本地整理 git 对象。我的判断顺序是这样的观察磁盘 I/O。如果磁盘持续读写说明还在工作。观察网络活动。如果还有大量下行流量说明在拉取数据。观察输出频率。如果十几分钟完全无输出且无磁盘写可能是卡在了某个网络请求上。如果是第三种情况通常直接中断重跑即可。gclient 有断点续传能力不会因为一次中断就前功尽弃。重跑的时候还是同样的目录同样会复用已有的 git 缓存。4.3 增量恢复和必要的重试姿势重复执行gclient sync是我们最常用的恢复方式。如果在一个仓库上反复失败可以尝试删除该仓库的本地目录让 gclient 重新克隆gclient sync --force--force会强制重新 checkout并把本地与目标版本不一致的修改全部丢弃。这个参数我一般在源码目录有异常时使用平时不要乱用因为如果你在自己的分支上有提交--force会把它们覆盖掉。另外gclient 还支持-v参数gclient sync -v开启详细日志之后会输出每个步骤的具体操作更容易看到底卡在哪里。你不需要一次性把日志全看懂只需要盯住最后一个反复出现的 URL 或项目名问题范围就能缩小很多。4.4 同步完成后的自检同步成功并不代表一定没问题。我每次都会做一次简单自检cd /Volumes/chromium-dev/chromium144/src git status正常情况下git status应该显示当前分支处于 clean 状态没有未提交的本地改动。如果发现大量文件被修改或删除说明之前可能有中断导致的残留文件需要谨慎处理。再检查几个关键目录是否存在比如src/third_party/llvm-build、src/third_party/node。这些目录通常由 hooks 生成或填充如果缺失说明gclient runhooks还没有完整执行完。gclient runhooks补跑一次总能解决大部分“目录缺失”问题。如果补跑之后还是缺才需要根据具体报错逐一定位。5. 常见问题与排查技巧实录5.1 常见错误对照表我把这些年在 macOS 上获取 Chromium 源码时遇到的一些典型问题整理成了表格方便你按现象快速定位报错现象常见原因处理办法checkout 时提示 file exists 或 case-insensitive 相关错误文件系统不区分大小写把项目迁移到大小写敏感的 APFS 卷宗gclient命令找不到PATH 没配置 depot_tools重新 export PATH 并检查 shell 配置hook 执行时报 Python 模块缺失系统 Python 版本过低安装新版 Python 3 并调整 PATHsync 过程中磁盘空间不足源码和构建目录过大清理旧目录扩大磁盘空间Xcode 相关脚本报错只装了 Command Line Tools 或未接受许可安装完整 Xcode执行xcodebuild -license accept某个子仓库反复下载失败网络波动或并发过高中断重跑必要时加--force下载工具链的 hook 失败工具链服务器连接异常单独执行gclient runhooks重试这张表基本覆盖了 80% 的常见问题。剩下那 20%大多数和具体网络环境绑定需要靠详细日志逐步排查。5.2 换个姿势解决“卡住不动”遇到 gclient 一直停在一个仓库上有一个比其他办法都更有效的姿势先把卡住的这个目录删掉再单独同步。比如卡仓库是src/third_party/some-lib可以这样rm -rf src/third_party/some-lib gclient syncgclient 会发现这个依赖缺失主动重新拉取。这个方法比直接在原目录里反复重试要干净得多因为某些仓库的本地.git状态可能已经被污染了原地重试只会永远卡在同一个位置。另一种情况是 hooks 下载卡住。和源码仓库不同hooks 下载的很多资源是独立的压缩包或二进制文件如果中断会有残留的临时文件影响下次下载。这种情况下找到对应临时目录删除缓存再跑gclient runhooks通常就能恢复正常。5.3 一些值得长期保留的个人习惯我自己的一个习惯是每次完整同步成功之后不着急配置构建而是先给整个工作目录做个标记。具体做法是在日志里记录当前的仓库 commit 号、.gclient内容、以及磁盘占用情况。这样一旦后续构建出现问题能快速判断是不是源码基础阶段就留下了隐患。另外尽量别把源码放到受系统文件保护或同步备份工具扫描的目录里。比如有些云盘目录会实时扫描文件变化Chromium 源码树里文件数量极多扫描过程会产生大量文件事件导致磁盘 I/O 异常高严重拖慢同步速度。还有一点是关于清理的。很多人为了省空间会把src/.git目录删掉。这样做在获取源代码阶段看起来没什么影响但到了后续打开分支、查看历史、更新代码的时候会非常痛苦。Chromium 的主仓库 git 历史对版本管理非常重要不建议为了省几十 GB 就把它删掉。真到了缺空间的地步更好的选择是清理已经构建完的中间产物或者转移不常用的旧构建目录。最后补充一点个人的口头建议写到这里其实已经覆盖了在 macOS 上获取 Chromium 144 源码的主要环节。从文件系统准备到 depot_tools 安装从 fetch 初始化到 gclient sync 的断点恢复每一步我都实际踩过坑也反复调整过操作顺序。我个人在 mac 上同步 Chromium 源码时最喜欢的组合是“大小写敏感卷宗 fetch --nohooks 断点重试”这套流程在多次项目实践中都表现得比较稳。希望这篇能把你在“获取源代码”这一步消耗的时间压到最短。接下来等源码完整落在磁盘上你就可以开始准备构建配置了。