作为一名长期从事浏览器开发的工程师,我深知编译Chromium这样的大型项目对新手来说有多具挑战性。本文将带你完整走通Chromium 144在macOS上的编译流程,从工具链原理到实操细节,包含我多年积累的避坑经验。
Chromium采用GN+Ninja的双层构建系统,这套组合在现代大型C++项目中堪称典范。理解它们的协作机制对排查编译问题至关重要。
GN的配置文件args.gn采用类似Python的语法,但更强调声明式编程。以下是一个专业开发者常用的配置模板:
python复制# 调试符号配置
is_debug = true # 生成完整调试符号
symbol_level = 2 # 最高级别符号信息
# 目标CPU架构
target_cpu = "x64" # 适配M1需改为"arm64"
# 组件控制
is_component_build = false # 静态链接提升运行效率
enable_nacl = false # 禁用不需要的模块
# 优化选项
blink_symbol_level = 0 # 降低Blink引擎符号级别加速编译
use_thin_lto = true # 启用轻量级LTO优化
关键经验:在开发初期建议开启is_debug,上线前改为is_debug=false并设置symbol_level=0可显著减小二进制体积。
Ninja的智能并行体现在:
实测在MacBook Pro M1 Max(10核)上,完整编译Chromium耗时对比:
| 工具 | 首次编译 | 增量编译 |
|---|---|---|
| Make | 6.5h | 45min |
| Ninja | 3.2h | 8min |
| autoninja | 2.8h | 5min |
执行以下命令确认环境符合要求:
bash复制# 检查Xcode版本
xcodebuild -version # 需要≥13.0
# 检查磁盘空间
df -h / # 建议≥150GB可用空间
# 检查内存
sysctl hw.memsize # 建议≥16GB
使用depot_tools时添加这些参数可加速同步:
bash复制gclient sync --no-history --shallow --jobs=8
参数说明:
常见问题:若遇到git卡顿,尝试执行
git config --global core.preloadindex true
对于插件开发者,建议使用组件化编译:
python复制is_component_build = true
is_component_ffmpeg = true
优点:
缺点:
M1/M2芯片需特殊配置:
python复制target_cpu = "arm64"
use_blink = true
enable_apple_silicon = true
实测性能对比(M1 Max):
| 配置 | 编译时间 | 产物大小 |
|---|---|---|
| x64转译 | 4.1h | 2.8GB |
| 原生arm64 | 2.7h | 2.1GB |
| arm64+优化 | 2.3h | 1.9GB |
推荐使用自动化脚本管理编译:
bash复制#!/bin/zsh
export CCACHE_CPP2=yes
export CCACHE_SLOPPINESS=time_macros
autoninja -C out/Default chrome -j $(sysctl -n hw.ncpu) | tee build.log
关键参数:
在Mac上防止OOM的几种方法:
bash复制sudo mkdir /private/var/vm
sudo touch /private/var/vm/swapfile
sudo chmod 600 /private/var/vm/swapfile
bash复制# 保留2个核心给系统
autoninja -C out/Default chrome -j $(($(sysctl -n hw.ncpu)-2))
bash复制while sleep 5; do
top -l 1 -o mem -stats mem,command | head -n 10
done
开发时建议添加这些参数:
bash复制out/Default/Chromium.app/Contents/MacOS/Chromium \
--enable-logging=stderr \
--v=1 \
--no-sandbox \
--disable-gpu
使用lldb调试自定义构建:
bash复制lldb out/Default/Chromium.app/Contents/MacOS/Chromium
(lldb) breakpoint set -n "MyExtensionFunction"
(lldb) run --test-type
Ninja的增量编译基于:
可通过以下命令强制重建特定目标:
bash复制ninja -C out/Default -t clean chrome
autoninja -C out/Default chrome
启用ccache可提升二次编译速度:
bash复制export CCACHE_DIR="$HOME/.ccache_chromium"
export CCACHE_CPP2=true
gn gen out/Default --args="cc_wrapper=\"ccache\""
缓存命中率查看:
bash复制ccache -s
典型命中率:
| 场景 | 命中率 |
|---|---|
| 全量编译 | 0% |
| 小修改 | 85% |
| 架构切换 | 30% |
bash复制# 更新钥匙串证书
security find-identity -v -p codesigning
bash复制# 使用Chromium内置Python
export PYTHONPATH="$DEPOT_TOOLS/python3"
bash复制# 重新生成所有构建文件
gn gen out/Default --check
编译时实时监控:
bash复制sudo powermetrics --samplers cpu_power,gpu_power -i 1000
关键指标警戒值:
例如仅编译Blink引擎:
bash复制autoninja -C out/Default blink_tests
常用编译目标:
| 目标名称 | 说明 |
|---|---|
| chrome | 完整浏览器 |
| unit_tests | 单元测试 |
| browser_tests | 浏览器功能测试 |
| content_shell | 精简版测试容器 |
在BUILD.gn中添加:
python复制static_library("my_feature") {
sources = [
"my_feature.cc",
"my_feature.h",
]
deps = [
"//base",
"//third_party/icu",
]
}
精简语言包配置:
python复制remove_locales = [ "en-GB", "es-419" ] # 保留en-US和es-ES
配置图标生成:
python复制optimize_webui_icons = true
webui_icon_sizes = [ 16, 32, 64 ] # 只生成必要尺寸
示例workflow片段:
yaml复制jobs:
build:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- run: |
brew install ccache
echo "/usr/local/opt/ccache/libexec" >> $GITHUB_PATH
- run: |
gclient sync
gn gen out/Release --args="is_debug=false"
autoninja -C out/Release chrome
在CI中复用缓存:
bash复制# 上传缓存
tar cf - ~/.ccache_chromium | gzip > ccache.tar.gz
# 下载恢复
[ -f ccache.tar.gz ] && tar xzf ccache.tar.gz -C ~/
使用Ninja的统计功能:
bash复制ninja -C out/Default -t commands chrome > build_steps.txt
ninja -C out/Default -t graph chrome | dot -Tpng > build_graph.png
典型耗时分布:
| 阶段 | 占比 | 优化手段 |
|---|---|---|
| 前端编译 | 45% | 预编译头、ccache |
| 链接 | 30% | 组件化、thinLTO |
| 资源处理 | 15% | 精简资源、并行处理 |
| 其他 | 10% | - |
将编译分为两个阶段:
bash复制# 第一阶段:编译基础库
autoninja -C out/Default base
# 第二阶段:编译剩余部分
autoninja -C out/Default chrome
使用ulimit控制:
bash复制#!/bin/zsh
ulimit -Sv 8000000 # 限制8GB内存
autoninja -C out/Default chrome
配置步骤:
bash复制export GOMA_DIR="${HOME}/goma"
gn gen out/Default --args="use_goma=true"
通过SSH分发任务:
bash复制export NINJA_SUMMON="ssh worker1 ninja $@; ssh worker2 ninja $@"
autoninja -C out/Default chrome
示例smart_build.sh:
bash复制#!/bin/bash
CONFIG="Default"
TARGET="chrome"
# 自动检测变更
if git diff --quiet HEAD^ HEAD -- "*.cc" "*.h"; then
echo "No source changes detected, skipping build"
exit 0
fi
# 根据文件类型决定构建范围
if git diff --name-only HEAD^ HEAD | grep -q "content/"; then
TARGET="content_shell"
fi
autoninja -C out/$CONFIG $TARGET
集成macOS通知:
bash复制autoninja -C out/Default chrome && \
osascript -e 'display notification "Build succeeded" with title "Chromium"'
生成Xcode工程:
bash复制gn gen out/Xcode --ide=xcode
open out/Xcode/all.xcodeproj
tasks.json示例:
json复制{
"version": "2.0.0",
"tasks": [
{
"label": "Build Chromium",
"type": "shell",
"command": "autoninja -C out/Default chrome",
"problemMatcher": ["$gcc"],
"group": "build"
}
]
}
在lldb中:
bash复制breakpoint set -f my_file.cc -l 123 -c 'some_var > 42'
使用ASan检测内存问题:
python复制# args.gn中配置
is_asan = true
启动方式:
bash复制out/Default/Chromium.app/Contents/MacOS/Chromium \
--enable-features=asan
bash复制# 创建开发分支
git new-branch my_feature
# 同步主干更新
git rebase-update
使用git quilt:
bash复制# 创建补丁堆栈
git quilt new my_patches
git quilt add file1.cc
git quilt refresh
在DEPS文件中:
python复制deps = {
"src/third_party/mylib": {
"url": "https://github.com/example/mylib.git@v1.0",
}
}
示例BUILD.gn:
python复制executable("my_tool") {
sources = [ "tool.cc" ]
deps = [ "//base" ]
configs += [ "//build/config:exe_config" ]
}
使用time命令:
bash复制/usr/bin/time -l autoninja -C out/Default chrome
关键指标:
检查二进制:
bash复制dsymutil out/Default/Chromium.app/Contents/MacOS/Chromium
nm -gU out/Default/Chromium | c++filt