编译 Chromium 留念
涛叔之前写文章介绍 DNS SVCB/HTTPS 记录1,说可以用它来解决家庭宽带无法使用 443 端口的问题2。前天收到网友徐嘉鑫来信,讨论相关问题。其中最核心的问题是 Chrome 是否支持使用 HTTPS 记录自定义端口。试验下来发现确实不支持🥹Safari 和 Firefox 都没有问题。而且进一步调研发现居然是原作者有意不实现这个特性。于是便有了一股想改源码的冲动。但改之前需要先完成编译,这小小的第一步也遇到不少问题。本文先记录编译过程中的具体问题,希望能对各位同好有所参考。
在编译之前,需要确保有充分的磁盘空间。我的 Mac 本只有可怜的 256G 空间,而且所剩无几。为此,我斥资一千元专门买了一块 SanDisk 2T 移动固态硬盘。硬盘出厂为了兼容性默认采用 exFAT 格式。我也是想着方便其他设备读写,就没管它。没想到这是我遇到的第一个坑。
整个编译过程最主机的参考资料是官方文档3,需要扶墙阅读。这是 Mac x86 平台的文档。可能是觉得苹果设备磁盘一定够用,文档中就没说磁盘用量。在 Windows 的文档4中则有明确说明:
- 内存 8GB,最好是 16GB 或者更多
- 磁盘空间最少 100GB NTFS 格式。FAT32 不行,因为有些 Git 文件体积超过 4GB,FAT32 不支持。
FAT32 固然不行。但我的磁盘是 exFAT 格式呀,支持超过 4GB 的大文件。所以就没管他。然后就开始同步 Chromium 源代码了。显然,这一步需要一个稳定的梯子🪜如果你没用而又很想同步代码,可以考虑使用我自建的代理。我自己同步的时候下载速度可以达到 20MB/s,算是比较快的了。
但这里有一个问题。我自建的梯子使用安全的 HTTP 代理协议5,也就是说先建立 TLS 会话,然后再通过 HTTP 协议的 CONNECT 请求连接远程服务。但是同步 Chromium 代码需要用到 gclient 工具,它是由 python 开发,使用 python 标准的 urllib 处理 HTTP 请求。这个 urllib 不需要安全 HTTP 代理协议,只能使用明文 HTTP 代理🤦
不用想,明文代理肯定会被阻断!那怎么办呢?我首先想到使用 proxychains 工具。该工具可以拦截 socket 调用,并自动使用代理。但安装之后发现 proxychains 也不支持安全 HTTP 代理。不过再想想🤔我肯定不是第一个碰到这个问题的人。用 Google 搜索🔍关键字 proxychains-ng https proxy
就找到了这个 GitHub Issue6。题主 Daniel15 给出了一个神奇的方案,使用 socat 工具!
socat TCP-LISTEN:1234,bind=127.0.0.1,fork,reuseaddr OPENSSL:example.com:443
socat 是 UNIX 下能用的网络转发工具。之前只是知道它能监听 UNIX 套接字,没想到还能连接 TLS 会话。上面的命令要求 socat 做两件事:
- 在本地监听 TCP 的 1234 端口
- 每当有本地连接建立,就会跟服务器 example.com:443 建议 TLS 加密连接
建议之后,socat 就会不断转发双方的数据!这样,我们就把安全的 HTTP 代理变成了明文 HTTP 代理。优雅的不行˚🦋༘!
接下来就是设置代理环境:
export https_proxy=http://$name:$pass@127.0.0.1:1234
注意,虽然这里用 socat 做了转换,但 HTTP 的代理并没有去掉,需要指定认证信息!
先克隆 depot_tools 仓库,这里面是用来同步代码的工具:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
Git 会自动使用 https_proxy 环境变量指定的代理。连接建立后 socat 会有类似输出,不用管它:
2024/07/20 19:30:19 socat[89509] W OpenSSL: Warning: this implementation does not check CRLs
上述过程很快就会结束,将它的路径添加到 PATH 环境变量,并创建源码目录:
export PATH="$PATH:/path/to/depot_tools"
mkdir chromium && cd chromium
最后开始同步代码:
caffeinate fetch chromium
这里的 caffeinate 是为了阻止 Mac 自动休眠。fetch 是前面 depot_tools 提供的工具。
最终会有类似下面的输出:
Running: gclient root
WARNING: Your metrics.cfg file was invalid or nonexistent. A new one will be created.
Running: gclient config --spec 'solutions = [
{
"name": "src",
"url": "https://chromium.googlesource.com/chromium/src.git",
"managed": False,
"custom_deps": {},
"custom_vars": {},
},
]
'
Running: gclient sync
________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --progress https://chromium.googlesource.com/ch
romium/src.git /Volumes/TS/Codes/chromium/_gclient_src_o8uqj6jt' in '/Volumes/TS/Codes/chromium'
Cloning into '/Volumes/TS/Codes/chromium/_gclient_src_o8uqj6jt'...
remote: Sending approximately 47.68 GiB ...
remote: Counting objects: 1073273, done
remote: Finding sources: 100% (325/325)
remote: Total 23309526 (delta 17070507), reused 23309446 (delta 17070507)
Receiving objects: 100% (23309526/23309526), 47.67 GiB | 20.62 MiB/s, done.
Resolving deltas: 100% (17070507/17070507), done.
Checking objects: 100% (67108864/67108864), done.
整个过程花了大约四十分钟,一共同步了47GB的数据,平均速度有20MB/s。怎么样,我的梯子还可以吧😆代码同步完之后,gclient 还会自动同步编译所需要的工具链。这步跟代码同步是连着的。我们唯一能做的就是确保网络和梯子稳定:
...
[1:39:56] Still working on:
[1:39:56] src/third_party/angle/third_party/VK-GL-CTS/src
Syncing projects: 100% (194/194), done.
Running hooks: 8% (10/120) mac_toolchain
________ running 'python3 src/build/mac_toolchain.py' in '/Volumes/TS/Codes/chromium'
Skipping Mac toolchain installation for mac
Running hooks: 14% (17/120) dsymutil_mac_x64
________ running 'python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s src/tools/clang/dsymutil/bin/dsymutil.x64.sha1 -o src/tools/clang/dsymutil/bin/dsymutil' in '/Volumes/TS/Codes/chromium'
NOTICE: You have PROXY values set in your environment, but gsutil in depot_tools does not (yet) obey them.
Also, --no_auth prevents the normal BOTO_CONFIG environment variable from being used.
To use a proxy in this situation, please supply those settings in a .boto file pointed to by the NO_AUTH_BOTO_CONFIG environment variable.
0> Downloading src/tools/clang/dsymutil/bin/dsymutil@05a1fbfceb62efb3ce10c94f1c7dd40b56e406f1...
Downloading 1 files took 13.644915 second(s)
Hook 'python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s src/tools/clang/dsymutil/bin/dsymutil.x64.sha1 -o src/tools/clang/dsymutil/bin/dsymutil' took 13.76 secs
Hook 'python3 src/testing/generate_location_tags.py --out src/testing/location_tags.json' took 21.29 secs
Running hooks: 100% (120/120), done.
Running: git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*'
Running: git config diff.ignoreSubmodules dirty
所有过程都同步完,大约占了80GB的空间。这个数字忘记存档了😂因为我用了 exFAT 系统,还遇到磁盘空间爆炸的问题。所有代码同步完成后,居然已经占用了 1TB 的空间。我当时也没当回事,就开始编译。结果各种报错。可惜报错内容没有存档,无法分享给大家。
后来我和一个朋友讨论,它说可能是 exFAT 文件系统的问题。如果小文件太多,可能会浪费很多磁盘空间。我听后觉得言之有理,赶紧把磁盘格式化成 APFS 重新同步再编译,这次没有问题了。
编译之前需要初始化目标目录,用来保存编译出来的 Chromium 和各类中间文件:
cd src
gn gen out/Default
为了方便后续重复编译,为改代码做准备,我根据官方文档开启 ccache 缓存。通过如下命令编辑编译配置:
gn args out/Default
它会打开默认编辑器,我用的是 Vim。添加如下一行,开启 ccache:
cc_wrapper="env CCACHE_SLOPPINESS=time_macros ccache"
最后的最后,启动编译:
caffeinate autoninja -C out/Default chrome
然后就是漫长的等待⌛️了。我的 Mac 是 2020 款,Intel 四核八线程 i7 处理器,主频 1.7GHz,不知道能睿频到多少。内存是 16GB。这就个配置,晚上 11 点半,一直跑到第二天 18 点,足足用来了 18.5 个小时。上一次让电脑通宵达旦的工作要追溯到大学时代,宿命里的网只有 1Mbps,用迅雷顶着 128KB/s 的速度下几个 G 的文件😂要不是有真爱,现在又有多少人愿意折腾呢?
整个过程中 CPU 基本跑满,笔记本和移动硬盘都有点烫。我用风扇对着它们吹,希望能降降温。
编译完成后打开亲手构建的 Chromium:
out/Default/Chromium.app/Contents/MacOS/Chromium --use-mock-keychain --disable-features=DialMediaRouteProvider
上述命令中的参数也来自官方文档,目的是为了避免每次重新构建后系统提示:
Chromium wants to use your confidential information stored in "Chromium Safe Storage" in your keychain.
Do you want the application "Chromium.app" to accept incoming network connections?
这是关于页面的截图:
最后检查🧐整个过程消耗磁盘 142G。如果大家也想体验,买个 1T 的硬盘就可以了😄
俗话说,万事开头难。今天完成第一次编译就是很好的开始。至于能否通过修改源码来解决开头说的端口问题,且看下回分解。