接着上一篇,来说说这次在 Linux 上编译时踩的各种坑。
因为之前已经在 Windows 和 Mac 上搞过一轮,加上有 AI 老师傅指点,我以为这次只是跑两个脚本那么简单。没想到一开始就翻了车。
首先是确定使用哪个 Linux 版本。按照 GPT 老师的建议,最好用 Electron 1.8.0 发布时的官方环境 —— Ubuntu 16.04。可惜我手头那台 Linux 机器早几年就升到了 20.04,不太想为了这个重装系统。而且 Electron 编译起来非常庞大,放 VM 里跑也不现实。
这时 GPT 老师突然灵光一闪:为什么不用 Docker?
我以前没怎么碰过 Docker,以为它只是 Linux 的进程隔离工具。结果发现连 Mac 上也能跑,于是就装了一下。很顺利地创建了一个 Ubuntu 16.04 的环境——这算是 VM 吗?还是进程隔离?搞不清楚,但总之新买的 M2 机器终于有了用武之地。
接下来运行 scripts/bootstrap.py
,结果立刻报错:文件下载失败。查了一圈才知道,Electron 1.8.0 已经是上古版本,当年开发者把一些关键文件放在 Amazon S3 上。可惜这些 S3 容器现在都挂了。
换句话说,当年 Electron 相较于 nw.js 的一个“先进设计” —— 不需要自己编译 libchromiumcontent,而是用官方共享的预编译版本来加快流程 —— 现在彻底失效了。
没办法,我只能亲自编译这个庞然大物的 libchromiumcontent。先是在 Docker 里尝试拉取指定版本的代码,然后添加 Electron 的 patch,准备编译。可惜这只是我的美好想象,第一步拉取代码就失败了。
原因是 Google 的代码实在太大,他们还特地设计了一个工具来同时sync几十个仓库。Docker 给的内存又太小,每次clone到 80% 左右就崩了。
找到了问题,就把 Docker 的内存和硬盘配额都拉大。总算把所有代码clone下来了。好在 Google 还算厚道,老版本的代码都还在,接下来的编译过程还算顺利。
编译完成后,把生成的 lib 文件重命名为指定的 commit id,丢回 Electron 的目录,bootstrap 就能跳过失败的下载步骤了。
当然,问题还没完。很快又出现了依赖包下载失败的问题,这次是某个 sysroots 压缩包。问了 GPT,才知道 Linux 编译为了避免头文件版本不一致,引入了类似 Windows SDK 的概念,把一整套头文件、库文件打包起来统一管理。
好在这些文件还能在 GitHub 上搜到,我重新创建了一份,填上去就行了。
终于,bootstrap 跑通了,可以开始编译 Electron 本体了。
意外的是,编译和链接过程都异常顺利,顺利得让我有点害怕。果不其然,最后生成的 binary 文件不太对劲,有整整 2G —— 显然还没 strip。Electron 提供了一个 create-dist.py
脚本来处理发布包,但它默认还要执行一些文档生成的流程。只好小改一下脚本,去掉这些额外步骤,然后就得到了大小正常的发布包。
下一步是实机测试,我拿到 Ubuntu 20.04 环境中一测,果然又报错,提示缺少各种动态链接库。
于是我开始一一排查,把缺失的库都摘出来,统一放到发布目录的 lib
文件夹中,然后套一层启动脚本,把 LD_LIBRARY_PATH
指向自己的 lib
目录。终于,程序能正常运行了。
然后是重头戏:部署到 Steam Deck 上看看吧。果然还是报动态库缺失的错误。继续手动补,直到 Electron 成功打开窗口,游戏主界面也能正常显示。
成功了吗?我正想叉会儿腰,结果一进游戏场景直接报错……
这才发现,Steam Deck 的桌面模式和 Steam 启动环境之间还有些差异。折腾半天,终于意识到可能是编码的问题。错误日志提示是某个汉字命名的文件找不到。
我打印了两种环境下的变量,果然,在 Steam 的启动环境中,LC_ALL
和 LANG
被设为了中文 GBK,而我整个程序用的都是 UTF-8。
知道原因就好办了:在启动脚本中强制把 LANG
和 LC_ALL
设成 en_US.UTF-8
。
最后检查了一遍工作路径、存档目录这些,没再出啥问题。
Linux 版本,终于搞定!
总结:
- Docker 非常好用,但拉取大仓库还是得调高内存和硬盘。
- Linux 的编译环境必须固定头文件版本,打包发布时还得附带所需动态链接库。可以用 Steam Deck 进行真实环境测试,Steam 启动器自带部分常用库,只需补少数缺失项。
- 一定要完整测试整套环境。Linux 环境变化太多,Steam 与桌面环境也可能差异极大。