Brave浏览器源码编译与定制:从chromium_src覆盖到避坑实践

发布时间:2026/10/15 17:31:12
Brave浏览器源码编译与定制:从chromium_src覆盖到避坑实践
简介brave-browser-master.zip 是 Brave 浏览器官方源码仓库的完整快照面向对浏览器内核、隐私防护机制与开源项目工程化感兴趣的开发者尤其适合想研究基于 Chromium 内核如何实现广告拦截、追踪脚本屏蔽与付费广告模式的进阶学习者。压缩包共 62 个文件约 172KB以 28 个 js 脚本为核心涵盖同步、补丁更新、本地化与构建等自动化流程另有 9 个 md 文档、4 个 json 配置、4 个 rst 说明及 py、bat、makefile 等辅助文件构成一套可读性较强的工程骨架。目录中 scripts 与 lib 模块集中了 gitPatcher、l10nUtil、calculateFileChecksum 等工具脚本docs 与 vendor 目录则提供文档与依赖说明便于理解 Brave 的构建与发布链路。目前已有 335 人学习下载适合作为浏览器源码阅读、隐私功能实现与前端工程化实践的参考素材。1. 拿到 brave-browser-master.zip 之后一个浏览器源码包到底能拿来做什么很多人第一次看到brave-browser-master.zip这种命名第一反应是「这不就是个浏览器安装包吗」解压完发现里面全是BUILD.gn、package.json、patches/、chromium_src/这类东西直接懵掉。它不是一个能双击运行的成品而是一份基于 Chromium 的浏览器工程源码快照核心价值在于你能看到「一个浏览器产品是怎么在 Chromium 之上做减法、做加法、做替换」的完整工程结构。对做客户端、做隐私功能、做定制发行版的团队来说这份源码包解决的是「我想改浏览器行为但不知道从哪一层下手」的问题。适合三类人想研究浏览器架构的客户端工程师、需要做定制化发行版的团队、以及想搞清楚「浏览器隐私功能到底改在哪」的安全方向从业者。下面我按「先看懂结构、再跑起来、再改一处、最后避坑」的顺序讲。2. 先拆包再谈编译brave-browser-master.zip 的目录结构与依赖关系拿到源码包别急着gn gen先花二十分钟把目录结构摸清楚能省掉后面几小时的编译报错排查。这个包本质是 Chromium 的一个「上层工程」它不包含 Chromium 全部源码而是通过DEPS文件去拉取指定版本的 Chromium再叠加自己的补丁和新增模块。2.1 顶层目录里哪几个是必须认识的解压后你会看到一堆目录真正需要先认识的是这几个目录/文件作用是否要动chromium_src/对 Chromium 原生代码的覆盖与替换改行为主战场patches/以补丁形式修改 Chromium 源码谨慎改components/自研功能模块如隐私统计、奖励系统加功能主战场browser/浏览器进程层逻辑常改build/编译配置与工具链脚本少动DEPS声明依赖的 Chromium 版本与第三方仓库版本锁定关键package.json前端资源与构建脚本入口改 UI 时看chromium_src/这个目录是理解整个工程的关键。它的机制是目录结构镜像 Chromium 源码树编译时同名文件会覆盖原生实现。比如你想改某个网络请求的默认行为不需要去改 Chromium 源码只要在chromium_src/下放一个同路径文件重写对应函数即可。这是「不 fork Chromium 也能改行为」的核心手段。DEPS文件决定了你拉取哪个 Chromium 版本。常见做法是源码包里的DEPS已经锁定了某个 commit hash你直接按它拉取不要自己改成 latest否则补丁大概率打不上。2.2 依赖拉取gclient 与 depot_tools 的最小配置编译前必须先准备好 Chromium 的构建工具链。常见做法是安装depot_tools并把它加到 PATH 最前面# 假设 depot_tools 已克隆到本地某目录 export PATH$PWD/depot_tools:$PATH # 在源码包根目录执行按 DEPS 拉取依赖 gclient sync --with_branch_heads --with_tags # 如果只想拉取不更新加 --nohooks 先看依赖树 gclient sync --nohooks逻辑说明gclient是 Chromium 生态的依赖管理工具它会读DEPS文件把 Chromium 源码、第三方库按声明的版本拉到src/目录下。--with_branch_heads和--with_tags是为了让后续切分支或查版本时不用重新拉。--nohooks会跳过拉取后的自动脚本执行适合先确认依赖是否完整。参数说明gclient sync的耗时取决于网络和磁盘首次拉取 Chromium 全量源码通常几十 GB建议预留足够空间。如果中途失败重复执行gclient sync即可续传不要删掉已拉取的部分。提示DEPS里的 Chromium 版本和patches/里的补丁是配套的。如果你手动改了 Chromium 版本补丁应用阶段会大量报hunk FAILED这时候要么回退版本要么逐个手动 rebase 补丁。2.3 生成构建配置gn gen 的参数怎么设依赖拉齐后进入src/目录生成构建配置cd src # 生成 release 配置关闭调试符号以加快编译 gn gen out/Release --argsis_debugfalse is_official_buildtrue symbol_level0 # 如果只是本地验证功能用 debug 配置更快出包 gn gen out/Debug --argsis_debugtrue symbol_level1逻辑说明gn gen根据--args生成 Ninja 构建文件。is_official_buildtrue会启用官方发行版的优化选项但编译时间显著增加本地验证功能时用is_debugtrue更划算。symbol_level0表示不生成调试符号能省大量磁盘和时间。参数说明out/Release和out/Debug是输出目录名可以自定义。--args里的参数可以后续用gn args out/Release打开编辑器修改改完重新gn gen即可不用重新拉依赖。3. 把浏览器跑起来从 gn gen 到本地可执行文件的最小路径配置生成之后就是编译。这一步最容易翻车的地方不是命令写错而是资源不够——Chromium 级别的工程对内存和磁盘的消耗远超一般项目。3.1 编译目标怎么选不要一上来就全量全量编译一个浏览器工程在普通开发机上动辄几小时。常见做法是先编译一个最小可运行目标确认工具链没问题再逐步扩大# 先编译 chrome 主目标最小编译单元之一 autoninja -C out/Debug chrome # 如果只想验证某个模块可以编译对应 target autoninja -C out/Debug brave_browser逻辑说明autoninja是对 Ninja 的封装会自动根据 CPU 核数调整并行度。-C out/Debug指定构建目录chrome是主可执行目标。首次编译会编译大量依赖后续增量编译只重编改动部分。参数说明如果机器内存小于 16GB建议加-j 4限制并行数否则容易触发 OOM。磁盘方面debug 构建目录通常 40GB 起步release 更大提前清理空间。3.2 编译产物在哪、怎么启动编译成功后可执行文件在out/Debug/下# 启动编译出的浏览器 ./out/Debug/chrome # 指定用户数据目录避免污染默认配置 ./out/Debug/chrome --user-data-dir/tmp/brave-test-profile逻辑说明--user-data-dir指定独立的用户数据目录方便反复测试且不影响本机已有配置。调试时常用--enable-loggingstderr --v1把日志打到终端排查启动阶段问题。参数说明--v1是日志级别数值越大越详细排查具体模块时可以调到--v2甚至更高但日志量会暴涨建议配合grep过滤。3.3 增量编译与快速验证循环改一处代码后重新编译不需要重跑gn gen直接autoninja即可。典型循环是# 改完代码后 autoninja -C out/Debug chrome ./out/Debug/chrome --user-data-dir/tmp/brave-test-profile逻辑说明Ninja 会做依赖分析只重编受影响的目标。改components/下的模块通常几分钟内完成改chromium_src/覆盖的文件可能触发较大范围重编。参数说明如果发现改动没生效先确认改的文件是否在编译目标的依赖链上。chromium_src/的覆盖机制要求路径和文件名与 Chromium 原生完全一致差一个字符都不会生效。4. 改一处真实行为在 chromium_src 里覆盖一个默认配置看懂结构、跑通编译之后最有价值的验证是「改一处行为并看到效果」。这一章用一个具体例子走通全流程修改浏览器启动时的某个默认开关。4.1 找到要覆盖的源文件路径假设你想改的是某个默认启用状态的配置项。先在 Chromium 源码里定位它的定义位置比如某个 feature flag 定义在chrome/browser/下的某个文件里。然后在chromium_src/下创建镜像路径# 假设原生路径是 chrome/browser/example/feature_config.cc mkdir -p chromium_src/chrome/browser/example/ touch chromium_src/chrome/browser/example/feature_config.cc逻辑说明chromium_src/的覆盖是「整文件替换」不是「部分覆盖」。你需要在覆盖文件里包含原生头文件然后重写你要改的函数或常量。常见写法是#include src/chrome/browser/example/feature_config.cc再补充自己的逻辑但更稳妥的是直接重写完整实现。参数说明覆盖文件的路径必须与 Chromium 源码树中的路径完全一致包括大小写。构建系统在编译时会优先使用chromium_src/下的版本。4.2 写覆盖实现并处理编译依赖覆盖文件里通常需要引用原生类型和宏// chromium_src/chrome/browser/example/feature_config.cc #include chrome/browser/example/feature_config.h // 重写默认值把原本 true 改成 false namespace example { const base::Feature kExampleFeature{ExampleFeature, base::FEATURE_DISABLED_BY_DEFAULT}; } // namespace example逻辑说明这里把 feature 的默认状态从启用改为禁用。base::FEATURE_DISABLED_BY_DEFAULT是 Chromium 的 feature 宏控制运行时默认值。覆盖文件编译进目标后所有引用该 feature 的代码都会拿到新默认值。参数说明如果原生文件里有多个符号覆盖文件必须全部提供否则链接阶段会报未定义符号。建议先完整复制原生实现再只改需要改的部分避免遗漏。4.3 验证改动是否生效编译并启动后通过日志或界面确认行为变化autoninja -C out/Debug chrome ./out/Debug/chrome --user-data-dir/tmp/brave-test-profile --enable-loggingstderr --v1 21 | grep -i ExampleFeature逻辑说明通过日志过滤确认 feature 状态。如果日志里显示该 feature 为 disabled说明覆盖生效。也可以在浏览器内部的功能页里查看 feature 状态具体入口取决于该 feature 是否暴露了查询接口。参数说明grep -i忽略大小写避免因日志格式差异漏掉。如果日志里完全没有该 feature 的记录可能是日志级别不够或该 feature 不在启动路径上需要换验证方式。5. 避坑与排查编译定制浏览器最容易翻车的 5 个点这一章是我自己在折腾这类工程时踩过的坑按「现象 → 原因 → 解决」整理能帮你省掉大量试错时间。5.1 现象gclient sync 卡住或反复失败原因Chromium 依赖拉取涉及大量仓库网络抖动或磁盘空间不足都会导致中断。另外DEPS里如果引用了需要额外权限的仓库也会卡住。解决先确认磁盘剩余空间大于 100GB然后重复执行gclient sync它会续传而不是重来。如果某个仓库反复失败可以单独进到对应目录手动git fetch。实在不行用gclient sync --nohooks --no-history减少拉取量但后续切版本会受限。5.2 现象gn gen 报错说找不到某个 build 参数原因--args里的参数名拼写错误或者该参数在当前 Chromium 版本里已被重命名/移除。Chromium 的 build 参数在不同版本间会变动。解决用gn args out/Debug --list列出当前版本支持的全部参数确认参数名。不要照搬旧教程里的参数版本对不上就会报错。如果只是本地验证很多优化参数可以直接省略用默认值。5.3 现象编译到一半 OOM 被 kill原因Chromium 编译的单个链接步骤内存占用很高并行数设太大就会触发系统 OOM killer。解决降低并行数autoninja -C out/Debug -j 4 chrome或者给机器加 swap。如果经常编译建议内存至少 32GB。另外is_official_buildtrue会显著增加内存占用本地验证时不要开。5.4 现象改了 chromium_src 下的文件但行为没变原因覆盖文件的路径或文件名与原生不一致构建系统没把它当作覆盖版本或者改动没触发重编Ninja 认为文件没变。解决先确认路径完全一致包括目录层级和大小写。然后touch一下覆盖文件强制重编或者删掉out/Debug/obj/下对应目标再编。如果还不生效检查该文件是否真的在编译目标的依赖链上有些文件只在特定构建配置下才被包含。5.5 现象patches 应用失败大量 hunk FAILED原因DEPS里的 Chromium 版本和patches/不匹配或者你手动改过 Chromium 源码导致补丁上下文对不上。解决先确认DEPS里的版本没有被改动。如果确实需要换版本补丁要逐个手动 rebase用git apply --reject生成.rej文件后手动合并。这是最耗时的坑能不改版本就不改。6. 进阶技巧用覆盖机制做最小改动验证与版本升级走到这里你已经能编译、能改行为、能排查常见问题。最后分享一个我常用的技巧用最小覆盖文件做行为验证而不是直接改 Chromium 源码。具体做法是每次想验证一个行为改动先在chromium_src/下建一个只包含必要符号的覆盖文件编译验证通过后再决定是否把这个改动整理成正式补丁。这样做的好处是改动范围可控升级 Chromium 版本时只需要重新检查覆盖文件而不是在一堆补丁里找冲突。验证覆盖是否生效我一般用三步步骤操作判断标准1编译后启动加--enable-loggingstderr --v1日志里能看到目标模块的初始化记录2在功能页或通过接口查询该配置状态状态与覆盖文件里写的一致3回退覆盖文件重新编译状态恢复原生默认值证明覆盖是唯一变量版本升级时的习惯是先把DEPS里的 Chromium 版本升上去gclient sync拉新代码然后只编译不应用补丁确认基线能过。再逐个应用patches/每应用一个就编译一次把冲突隔离在单个补丁范围内。最后检查chromium_src/下的覆盖文件看原生实现是否变了签名或行为变了就同步更新。这套流程听起来笨但比一次性全量升级再面对几十个报错要快得多。我自己的血泪经验是永远不要在没跑通基线的情况下动补丁否则你分不清是版本问题还是补丁问题。希望帮到你。本文还有配套的精品资源点击获取