1. 龙芯架构下 Electron 安装的整体思路拆解在国产化替代的大背景下,越来越多的项目需要跑在银河麒麟 V10 这类国产操作系统上,而硬件平台也从常见的 x86 转向了龙芯(LoongArch/MIPS 系)。Electron 作为一个基于 Chromium 和 Node.js 的桌面应用框架,官方预编译包几乎清一色是 x86_64 和 arm64,龙芯架构的二进制包基本找不到现成的。这就意味着,想在麒麟 V10 + 龙芯的机器上跑 Electron,不能指望npm install electron一把梭,必须走源码编译或者寻找社区移植版本的路子。我自己在这个组合上折腾了相当长一段时间,踩过的坑从 Node.js 编译不过、到 Chromium 依赖缺失、再到 Electron 链接阶段报错,几乎每个环节都卡过。这篇文章就是把这些经验完整地梳理出来,让后来的人少走弯路。核心思路其实就一句话:先搞定龙芯原生的 Node.js,再基于它去编译 Electron 的源码,最后把编译产物打包成可用的运行时。听起来简单,但每一步都有大量细节。为什么不能直接用 npm 上的 electron 包?因为那个包在安装时会根据当前平台去下载对应的预编译二进制。龙芯架构不在官方支持列表里,下载脚本要么直接报错,要么下载到一个不匹配的 x86 包,运行时报“无法执行二进制文件”。所以必须绕开预编译,走源码编译。整体方案我把它拆成四个阶段:环境准备、Node.js 原生编译、Electron 源码编译、运行时验证与打包。下面逐个展开。1.1 为什么选择源码编译而不是交叉编译交叉编译听起来很美好——在 x86 机器上编译出龙芯的二进制。但 Electron 的构建体系(基于 GN + Ninja)对交叉编译的支持非常有限,尤其是涉及 V8 引擎的 JIT 部分,交叉编译出来的产物在目标机上经常出现指令集不兼容或者运行时崩溃。我试过在 x86 上配 cross toolchain 去编,光是 GN 的 toolchain 配置就折腾了两天,最后编出来的东西跑不起来。所以更稳妥的做法是在龙芯机器上直接编译。虽然龙芯机器的性能相比 x86 有差距,编译一次 Electron 可能要几个小时甚至更久,但胜在可靠。麒麟 V10 自带的 GCC 版本通常够用,如果不够就自己升一个。1.2 麒麟 V10 自带的工具链够不够用麒麟 V10 默认的 GCC 版本一般在 7.x 到 9.x 之间,具体看你的 SP 版本。Electron 较新的版本(比如 20 以上)对 GCC 要求比较高,可能需要 GCC 9 以上。你可以先用gcc --version看一下。如果版本偏低,建议通过系统包管理器升级,或者自己编译一个高版本 GCC 放到/opt下,通过环境变量切换。另外要注意的是,龙芯的 GCC 和 x86 的 GCC 在行为上有一些差异,比如某些优化选项的支持、内联汇编的写法等。编译 Chromium 这种大型项目时,偶尔会遇到龙芯特有的编译错误,需要打补丁。这部分后面会详细说。2. 环境准备与依赖安装的实操要点环境准备这一步看起来是体力活,但实际上最容易出问题。麒麟 V10 的软件源里有些包版本比较老,有些包干脆没有,需要自己找龙芯版本的 rpm 或者 deb 来装。我建议在开始之前先做一次完整的系统更新,把能升的都升到最新,减少后面因为版本不匹配导致的诡异问题。2.1 系统更新与基础开发工具安装先执行系统更新:sudo apt update sudo apt upgrade -y如果你的麒麟 V10 用的是 yum/dnf 系,对应换成sudo yum update -y。更新完之后安装基础开发工具:sudo apt install -y build-essential git python3 python3-pip \ pkg-config libssl-dev libffi-dev libncurses-dev \ libx11-dev libxext-dev libxrandr-dev libxcomposite-dev \ libxcursor-dev libxi-dev libxtst-dev libnss3-dev \ libasound2-dev libcups2-dev libdrm-dev libgbm-dev \ libpango1.0-dev libcairo2-dev libatk1.0-dev libatk-bridge2.0-dev这些包是编译 Chromium 和 Node.js 的基础依赖。注意libgbm-dev和libdrm-dev在部分麒麟版本里可能名字不一样,如果装不上,用apt search找一下对应的包名。提示:麒麟 V10 的源里如果缺少某些包,可以去龙芯社区或者相关开源镜像站找对应的 rpm/deb 手动安装。装的时候注意架构要是 loongarch64 或者 mips64el,别下成 x86 的。2.2 Node.js 原生编译的关键步骤Electron 的编译依赖 Node.js,而且必须是龙芯原生的 Node.js。官方 Node.js 不提供龙芯的预编译包,所以得自己编。我选的是 Node.js 16.x 这个 LTS 版本,兼容性比较好,太新的版本在龙芯上编译容易出问题。下载源码:wget https://nodejs.org/dist/v16.20.2/node-v16.20.2.tar.gz tar -xzf node-v16.20.2.tar.gz cd node-v16.20.2配置编译选项。这里有个关键点:龙芯架构下要确保 V8 的 JIT 能正常工作,所以不能禁用 JIT。配置命令:./configure --prefix=/usr/local/node16 \ --without-snapshot \ --dest-cpu=loongarch64如果你的机器是 mips64el 而不是 loongarch64,把--dest-cpu换成mips64el。--without-snapshot是为了避免在龙芯上生成 snapshot 时出现兼容性问题,虽然会稍微影响启动速度,但稳定性优先。然后开始编译:make -j$(nproc) sudo make install编译过程大概需要 1 到 3 个小时,取决于机器性能。编完之后把 Node.js 加到 PATH:export PATH=/usr/local/node16/bin:$PATH node -v npm -v能正常输出版本号就说明 Node.js 搞定了。2.3 编译过程中常见的依赖缺失处理编译 Node.js 时最常见的报错是缺少libssl或者libcrypto。麒麟 V10 自带的 OpenSSL 版本可能是 1.1.1,Node.js 16 需要的就是这个版本,一般没问题。如果报错说找不到openssl/ssl.h,装一下libssl-dev就行。另一个常见问题是 Python 版本。Node.js 的构建脚本依赖 Python 3,但有些麒麟版本默认python指向 Python 2。这时候要么改软链接,要么在 configure 时指定--python=python3。还有一个坑是龙芯的 GCC 在编译 V8 时可能报“internal compiler error”。这种情况通常是 GCC 的某个优化选项触发了 bug,可以在编译时加上CXXFLAGS="-O2"降低优化级别,或者换一个 GCC 版本。3. Electron 源码编译的完整流程Node.js 搞定之后,就可以开始编 Electron 了。Electron 的编译比 Node.js 复杂得多,因为它包含了 Chromium 这个庞然大物。整个编译流程大致是:拉取源码、安装构建依赖、配置 GN、执行 Ninja 编译、打包产物。3.1 拉取 Electron 源码与版本选择Electron 的版本选择很重要。太新的版本对工具链要求高,太老的版本可能不支持龙芯的某些指令集。我建议选 Electron 22 或者 24 这两个 LTS 版本,相对稳定,社区里龙芯相关的补丁也比较多。拉源码:git clone https://github.com/electron/electron.git cd electron git checkout v24.8.5Electron 的源码里包含了很多子模块,需要同步下来:git submodule update --init --recursive这一步会拉取 Chromium 的源码,体积非常大,网络不好的话可能要很久。建议配置好 git 的代理或者用国内镜像。3.2 构建依赖安装与 GN 配置Electron 提供了一个脚本用来安装构建依赖:./build/install-build-deps.sh但这个脚本主要是针对 x86 的 Ubuntu 写的,在麒麟 V10 + 龙芯上跑会有一堆问题。我的做法是手动安装它需要的包,跳过脚本。前面环境准备里装的那些依赖基本够用,如果编译过程中报缺什么再补。接下来配置 GN。Electron 的构建配置在build/args目录下,可以创建一个loongarch64.gn文件:is_debug = false target_cpu = "loongarch64" is_component_build = false enable_nacl = false use_custom_libcxx = false use_sysroot = false treat_warnings_as_errors = false几个关键参数说明一下。target_cpu指定龙芯架构,use_sysroot = false是因为麒麟 V10 的 sysroot 和 Chromium 默认的不一样,用系统的就行。treat_warnings_as_errors = false是为了避免龙芯 GCC 的一些警告导致编译中断。然后生成构建文件:gn gen out/Release --args="import(\"//build/args/loongarch64.gn\")"如果 gn 命令找不到,需要先把 depot_tools 加到 PATH 里。depot_tools 是 Chromium 的构建工具集,Electron 的编译离不开它。3.3 Ninja 编译与常见报错处理配置好之后就可以开始编译了:ninja -C out/Release electron这一步是整个过程中最耗时的,龙芯机器上可能要跑 6 到 12 个小时。建议用screen或者tmux挂着跑,避免 SSH 断线导致编译中断。编译过程中最常见的报错有几类。第一类是龙芯特有的指令集问题,比如某些 SIMD 指令在龙芯上不支持,需要改源码或者加编译宏屏蔽。第二类是链接错误,通常是某个库找不到,需要手动指定库路径。第三类是内存不足,Chromium 编译很吃内存,建议机器至少 16GB 内存,不够的话加 swap。注意:编译过程中如果遇到某个文件反复报错,可以单独编译那个文件来定位问题,命令是ninja -C out/Release obj/path/to/file.o。这样比每次全量编译快得多。3.4 编译产物的打包与运行时准备编译成功后,产物在out/Release目录下。核心文件是electron这个可执行文件,以及一堆.so和资源文件。要把它打包成可分发的东西,可以用 Electron 提供的create-dist脚本:./script/create-dist.py这个脚本会把需要的文件收集到dist目录下。然后你可以把dist目录拷贝到目标机器上,设置好ELECTRON_HOME环境变量就能用了。如果你是要在项目里用,可以把编译好的 Electron 放到 npm 的缓存目录里,或者直接用electron的path配置指向你的编译产物。具体做法是在项目根目录建一个.npmrc,加上:electron_mirror=file:///path/to/your/electron/dist这样npm install electron的时候就会用你本地的包,而不是去下载预编译的。4. 常见问题排查与避坑经验实录这一部分是我在实际操作中积累的问题排查经验,很多都是官方文档里不会写的。龙芯 + 麒麟这个组合本身就比较小众,遇到问题往往搜不到现成答案,只能自己一点点试。4.1 编译阶段典型报错速查下面这个表格整理了我遇到过的典型报错和对应的解决方法:报错信息可能原因解决方法internal compiler errorGCC 优化 bug降低优化级别,加-O2或换 GCC 版本undefined reference to xxx链接库缺失检查-l参数,手动指定库路径cannot find -lgbmlibgbm 未安装安装 libgbm-dev 或对应龙芯包snapshot blob errorsnapshot 生成失败加--without-snapshot重新编译out of memory内存不足加 swap 或减少并行编译任务数gn: command not founddepot_tools 未配置把 depot_tools 加到 PATHpython not foundPython 版本问题指定--python=python3这个表里的每一条我都是实际踩过的。比如internal compiler error那个,当时卡了我整整一天,后来发现是 GCC 9 在编译 V8 的某个文件时触发了优化 bug,换成 GCC 8 就好了。4.2 运行时问题的排查思路编译成功只是第一步,跑起来可能还有问题。最常见的运行时问题是启动就崩溃,或者界面显示异常。启动崩溃的话,先用ldd检查一下electron可执行文件的动态库依赖:ldd out/Release/electron | grep "not found"如果有not found的库,说明运行时缺少依赖,需要把对应的库装上或者把库路径加到LD_LIBRARY_PATH里。界面显示异常通常是 GPU 加速的问题。龙芯的显卡驱动支持比较有限,可以尝试禁用 GPU 加速:./electron --disable-gpu如果禁用 GPU 后能正常显示,那就说明是驱动的问题,可以在应用启动参数里固定加上这个选项。还有一个常见问题是字体显示成方块。这是因为系统缺少中文字体,装一下fonts-noto-cjk或者把 Windows 的字体拷过来就行。4.3 性能优化与实用技巧龙芯机器上跑 Electron,性能肯定不如 x86,但通过一些优化可以让体验好很多。第一,编译时开启-O2优化,不要用-O0。虽然编译慢一点,但运行速度快很多。第二,Electron 的启动参数里加上--disable-dev-shm-usage,避免共享内存不足导致的问题。第三,如果应用不需要 GPU 渲染,直接禁用 GPU 可以省不少资源。第四,打包的时候把不必要的 locale 文件和资源删掉,减小体积,也能加快启动速度。提示:龙芯的磁盘 IO 相对较慢,Electron 启动时加载大量小文件会比较慢。可以考虑把应用打包成 asar 归档,减少文件数量,提升加载速度。4.4 版本兼容性的一些经验Electron 版本和 Node.js 版本之间有对应关系,不能随便配。比如 Electron 24 对应的是 Node.js 16,Electron 28 对应的是 Node.js 18。编译之前一定要查一下对应关系,用错版本会有一堆莫名其妙的错误。麒麟 V10 的 SP 版本也有影响。SP1 和 SP2 的系统库版本不一样,编译时可能需要不同的配置。我建议在 SP2 以上版本上做,兼容性好一些。龙芯的架构版本也要注意。早期的龙芯是 MIPS 系,后来是 LoongArch。这两个架构的编译配置不一样,target_cpu要设对。LoongArch 的话设loongarch64,MIPS 的话设mips64el。5. 从编译到部署的完整链路梳理把 Electron 编译出来只是完成了第一步,真正要把它用在实际项目里,还需要考虑部署和分发的问题。这一部分聊聊怎么把编译产物集成到实际项目中,以及一些工程化的实践。5.1 将编译产物集成到 npm 项目最直接的方式是在项目里配置electron的路径。在package.json里加上:{ "config": { "electron_path": "/opt/electron-loongarch64/electron" } }然后在代码里用process.env.ELECTRON_PATH或者直接引用这个路径。不过更规范的做法是用electron包的path.txt机制。Electron 的 npm 包在安装后会生成一个path.txt,里面记录了可执行文件的路径。你可以手动创建这个文件,指向你编译好的 electron:echo "/opt/electron-loongarch64/electron" > node_modules/electron/path.txt这样require('electron')就能找到正确的可执行文件了。5.2 制作可分发的安装包如果要把应用分发给其他人用,最好做成安装包。麒麟 V10 支持 deb 和 rpm 两种格式,可以用electron-builder来打包。不过electron-builder默认会去下载预编译的 Electron,需要配置一下让它用本地的:{ "build": { "electronDist": "/opt/electron-loongarch64/dist", "linux": { "target": ["deb"], "category": "Utility" } } }electronDist指向你编译好的 dist 目录,这样打包时就不会去下载了。打包出来的 deb 包在麒麟 V10 上用dpkg -i安装就行。注意依赖关系要写清楚,把 Electron 需要的系统库都列上,避免装完了跑不起来。5.3 持续集成与自动化构建的思路如果项目需要频繁更新 Electron 版本,手动编译太痛苦了。可以考虑搭一个简单的 CI 流程,在龙芯机器上跑自动化编译。基本的思路是用 Jenkins 或者 GitLab CI,配置一个龙芯的 runner,每次 tag 推送时自动拉源码、编译、打包。编译脚本可以写成一个 shell 脚本,把前面说的步骤串起来:#!/bin/bash set -e # 更新源码 cd /opt/electron-src git fetch --all git checkout $1 git submodule update --init --recursive # 配置 gn gen out/Release --args="import(\"//build/args/loongarch64.gn\")" # 编译 ninja -C out/Release electron # 打包 ./script/create-dist.py # 拷贝产物 cp -r dist /opt/electron-$1这个脚本可以根据实际需求调整。关键是set -e要加上,任何一步失败就中断,避免产出不完整的包。5.4 一些工程化的小建议在实际项目中,我建议把 Electron 的编译产物单独管理,不要和业务代码混在一起。可以建一个专门的仓库或者目录来存放编译好的 Electron,业务项目通过环境变量或者配置文件来引用。另外,编译产物最好做版本标记,比如electron-24.8.5-loongarch64这样的命名,方便区分不同版本和架构。如果同时维护多个架构的版本,这个习惯能省很多事。还有一点是文档。龙芯 + 麒麟这个组合的坑太多了,每次踩完坑一定要记下来,形成团队内部的文档。不然换个人来又要重新踩一遍。6. 实际项目中的性能调优与体验优化编译能跑起来只是及格线,要让 Electron 应用在龙芯上真正好用,还需要做一些针对性的优化。这一部分分享一些我在实际项目中验证过的调优手段。6.1 启动速度优化Electron 应用在龙芯上的启动速度是个大问题,冷启动可能要十几秒甚至更久。优化启动速度可以从几个方面入手。首先是减少主进程的初始化工作。很多应用在app.on('ready')之前做了大量同步操作,这些都会拖慢启动。能异步的都改成异步,能延迟的都延迟到窗口显示之后再做。其次是 V8 的 snapshot。前面编译 Node.js 时用了--without-snapshot,这会让启动时重新解析 JavaScript,影响速度。如果稳定性允许,可以尝试开启 snapshot,能明显提升启动速度。开启的方法是在编译 Node.js 时去掉--without-snapshot,然后重新编译 Electron。第三是减少渲染进程的负担。首屏只加载必要的资源,其他模块按需加载。可以用webpack的代码分割功能,把首屏不需要的代码拆出去。6.2 内存占用控制Chromium 的内存占用本来就高,在龙芯这种内存相对紧张的平台上更要注意。几个实用的手段:一是限制渲染进程的数量。Electron 默认每个窗口一个渲染进程,如果开了很多窗口,内存会飙升。可以用app.commandLine.appendSwitch('renderer-process-limit', '2')来限制。二是及时释放不用的资源。窗口关闭后要确保相关的渲染进程被回收,避免内存泄漏。三是用--js-flags="--max-old-space-size=512"限制 V8 的堆大小,避免单个进程占用过多内存。6.3 图形渲染的取舍龙芯的 GPU 驱动支持有限,很多时候只能用软件渲染。软件渲染的性能肯定不如硬件加速,但胜在稳定。如果应用对图形性能要求不高,直接用软件渲染反而更省心。禁用 GPU 加速的方法是在启动参数里加--disable-gpu。如果只是部分场景有问题,可以用--disable-gpu-compositing只禁用合成加速,保留其他 GPU 功能。对于需要图形性能的场景,可以尝试用--use-gl=swiftshader走软件 OpenGL 渲染,比纯 CPU 渲染快一些。6.4 实际体验的一些观察我在龙芯 3A5000 的机器上跑过一个基于 Electron 24 的应用,冷启动大概 8 秒,热启动 3 秒左右。内存占用在 300MB 到 500MB 之间,取决于打开的窗口数量。这个表现相比 x86 确实有差距,但日常使用是够的。界面流畅度方面,简单的表单和列表操作基本没问题,复杂的动画和滚动会有轻微卡顿。如果应用以数据处理为主,对动画要求不高,体验是可以接受的。一个比较明显的瓶颈是文件 IO。龙芯机器的磁盘读写速度相对较慢,Electron 启动时加载大量小文件会比较耗时。把应用打包成 asar 之后,启动速度能提升 20% 到 30%。最后再分享一个小技巧:如果应用需要频繁读写本地文件,可以考虑用内存缓存减少磁盘操作。比如把配置文件加载到内存里,定期同步回磁盘,而不是每次都读写文件。这个改动虽然简单,但对体验的提升很明显。
1. 龙芯架构下 Electron 安装的整体思路拆解在国产化替代的大背景下,越来越多的项目需要跑在银河麒麟 V10 这类国产操作系统上,而硬件平台也从常见的 x86 转向了龙芯(LoongArch/MIPS 系)。Electron 作为一个基于 Chromium 和 Node.js 的桌面应用框架,官方预编译包几乎清一色是 x86_64 和 arm64,龙芯架构的二进制包基本找不到现成的。这就意味着,想在麒麟 V10 + 龙芯的机器上跑 Electron,不能指望npm install electron一把梭,必须走源码编译或者寻找社区移植版本的路子。我自己在这个组合上折腾了相当长一段时间,踩过的坑从 Node.js 编译不过、到 Chromium 依赖缺失、再到 Electron 链接阶段报错,几乎每个环节都卡过。这篇文章就是把这些经验完整地梳理出来,让后来的人少走弯路。核心思路其实就一句话:先搞定龙芯原生的 Node.js,再基于它去编译 Electron 的源码,最后把编译产物打包成可用的运行时。听起来简单,但每一步都有大量细节。为什么不能直接用 npm 上的 electron 包?因为那个包在安装时会根据当前平台去下载对应的预编译二进制。龙芯架构不在官方支持列表里,下载脚本要么直接报错,要么下载到一个不匹配的 x86 包,运行时报“无法执行二进制文件”。所以必须绕开预编译,走源码编译。整体方案我把它拆成四个阶段:环境准备、Node.js 原生编译、Electron 源码编译、运行时验证与打包。下面逐个展开。1.1 为什么选择源码编译而不是交叉编译交叉编译听起来很美好——在 x86 机器上编译出龙芯的二进制。但 Electron 的构建体系(基于 GN + Ninja)对交叉编译的支持非常有限,尤其是涉及 V8 引擎的 JIT 部分,交叉编译出来的产物在目标机上经常出现指令集不兼容或者运行时崩溃。我试过在 x86 上配 cross toolchain 去编,光是 GN 的 toolchain 配置就折腾了两天,最后编出来的东西跑不起来。所以更稳妥的做法是在龙芯机器上直接编译。虽然龙芯机器的性能相比 x86 有差距,编译一次 Electron 可能要几个小时甚至更久,但胜在可靠。麒麟 V10 自带的 GCC 版本通常够用,如果不够就自己升一个。1.2 麒麟 V10 自带的工具链够不够用麒麟 V10 默认的 GCC 版本一般在 7.x 到 9.x 之间,具体看你的 SP 版本。Electron 较新的版本(比如 20 以上)对 GCC 要求比较高,可能需要 GCC 9 以上。你可以先用gcc --version看一下。如果版本偏低,建议通过系统包管理器升级,或者自己编译一个高版本 GCC 放到/opt下,通过环境变量切换。另外要注意的是,龙芯的 GCC 和 x86 的 GCC 在行为上有一些差异,比如某些优化选项的支持、内联汇编的写法等。编译 Chromium 这种大型项目时,偶尔会遇到龙芯特有的编译错误,需要打补丁。这部分后面会详细说。2. 环境准备与依赖安装的实操要点环境准备这一步看起来是体力活,但实际上最容易出问题。麒麟 V10 的软件源里有些包版本比较老,有些包干脆没有,需要自己找龙芯版本的 rpm 或者 deb 来装。我建议在开始之前先做一次完整的系统更新,把能升的都升到最新,减少后面因为版本不匹配导致的诡异问题。2.1 系统更新与基础开发工具安装先执行系统更新:sudo apt update sudo apt upgrade -y如果你的麒麟 V10 用的是 yum/dnf 系,对应换成sudo yum update -y。更新完之后安装基础开发工具:sudo apt install -y build-essential git python3 python3-pip \ pkg-config libssl-dev libffi-dev libncurses-dev \ libx11-dev libxext-dev libxrandr-dev libxcomposite-dev \ libxcursor-dev libxi-dev libxtst-dev libnss3-dev \ libasound2-dev libcups2-dev libdrm-dev libgbm-dev \ libpango1.0-dev libcairo2-dev libatk1.0-dev libatk-bridge2.0-dev这些包是编译 Chromium 和 Node.js 的基础依赖。注意libgbm-dev和libdrm-dev在部分麒麟版本里可能名字不一样,如果装不上,用apt search找一下对应的包名。提示:麒麟 V10 的源里如果缺少某些包,可以去龙芯社区或者相关开源镜像站找对应的 rpm/deb 手动安装。装的时候注意架构要是 loongarch64 或者 mips64el,别下成 x86 的。2.2 Node.js 原生编译的关键步骤Electron 的编译依赖 Node.js,而且必须是龙芯原生的 Node.js。官方 Node.js 不提供龙芯的预编译包,所以得自己编。我选的是 Node.js 16.x 这个 LTS 版本,兼容性比较好,太新的版本在龙芯上编译容易出问题。下载源码:wget https://nodejs.org/dist/v16.20.2/node-v16.20.2.tar.gz tar -xzf node-v16.20.2.tar.gz cd node-v16.20.2配置编译选项。这里有个关键点:龙芯架构下要确保 V8 的 JIT 能正常工作,所以不能禁用 JIT。配置命令:./configure --prefix=/usr/local/node16 \ --without-snapshot \ --dest-cpu=loongarch64如果你的机器是 mips64el 而不是 loongarch64,把--dest-cpu换成mips64el。--without-snapshot是为了避免在龙芯上生成 snapshot 时出现兼容性问题,虽然会稍微影响启动速度,但稳定性优先。然后开始编译:make -j$(nproc) sudo make install编译过程大概需要 1 到 3 个小时,取决于机器性能。编完之后把 Node.js 加到 PATH:export PATH=/usr/local/node16/bin:$PATH node -v npm -v能正常输出版本号就说明 Node.js 搞定了。2.3 编译过程中常见的依赖缺失处理编译 Node.js 时最常见的报错是缺少libssl或者libcrypto。麒麟 V10 自带的 OpenSSL 版本可能是 1.1.1,Node.js 16 需要的就是这个版本,一般没问题。如果报错说找不到openssl/ssl.h,装一下libssl-dev就行。另一个常见问题是 Python 版本。Node.js 的构建脚本依赖 Python 3,但有些麒麟版本默认python指向 Python 2。这时候要么改软链接,要么在 configure 时指定--python=python3。还有一个坑是龙芯的 GCC 在编译 V8 时可能报“internal compiler error”。这种情况通常是 GCC 的某个优化选项触发了 bug,可以在编译时加上CXXFLAGS="-O2"降低优化级别,或者换一个 GCC 版本。3. Electron 源码编译的完整流程Node.js 搞定之后,就可以开始编 Electron 了。Electron 的编译比 Node.js 复杂得多,因为它包含了 Chromium 这个庞然大物。整个编译流程大致是:拉取源码、安装构建依赖、配置 GN、执行 Ninja 编译、打包产物。3.1 拉取 Electron 源码与版本选择Electron 的版本选择很重要。太新的版本对工具链要求高,太老的版本可能不支持龙芯的某些指令集。我建议选 Electron 22 或者 24 这两个 LTS 版本,相对稳定,社区里龙芯相关的补丁也比较多。拉源码:git clone https://github.com/electron/electron.git cd electron git checkout v24.8.5Electron 的源码里包含了很多子模块,需要同步下来:git submodule update --init --recursive这一步会拉取 Chromium 的源码,体积非常大,网络不好的话可能要很久。建议配置好 git 的代理或者用国内镜像。3.2 构建依赖安装与 GN 配置Electron 提供了一个脚本用来安装构建依赖:./build/install-build-deps.sh但这个脚本主要是针对 x86 的 Ubuntu 写的,在麒麟 V10 + 龙芯上跑会有一堆问题。我的做法是手动安装它需要的包,跳过脚本。前面环境准备里装的那些依赖基本够用,如果编译过程中报缺什么再补。接下来配置 GN。Electron 的构建配置在build/args目录下,可以创建一个loongarch64.gn文件:is_debug = false target_cpu = "loongarch64" is_component_build = false enable_nacl = false use_custom_libcxx = false use_sysroot = false treat_warnings_as_errors = false几个关键参数说明一下。target_cpu指定龙芯架构,use_sysroot = false是因为麒麟 V10 的 sysroot 和 Chromium 默认的不一样,用系统的就行。treat_warnings_as_errors = false是为了避免龙芯 GCC 的一些警告导致编译中断。然后生成构建文件:gn gen out/Release --args="import(\"//build/args/loongarch64.gn\")"如果 gn 命令找不到,需要先把 depot_tools 加到 PATH 里。depot_tools 是 Chromium 的构建工具集,Electron 的编译离不开它。3.3 Ninja 编译与常见报错处理配置好之后就可以开始编译了:ninja -C out/Release electron这一步是整个过程中最耗时的,龙芯机器上可能要跑 6 到 12 个小时。建议用screen或者tmux挂着跑,避免 SSH 断线导致编译中断。编译过程中最常见的报错有几类。第一类是龙芯特有的指令集问题,比如某些 SIMD 指令在龙芯上不支持,需要改源码或者加编译宏屏蔽。第二类是链接错误,通常是某个库找不到,需要手动指定库路径。第三类是内存不足,Chromium 编译很吃内存,建议机器至少 16GB 内存,不够的话加 swap。注意:编译过程中如果遇到某个文件反复报错,可以单独编译那个文件来定位问题,命令是ninja -C out/Release obj/path/to/file.o。这样比每次全量编译快得多。3.4 编译产物的打包与运行时准备编译成功后,产物在out/Release目录下。核心文件是electron这个可执行文件,以及一堆.so和资源文件。要把它打包成可分发的东西,可以用 Electron 提供的create-dist脚本:./script/create-dist.py这个脚本会把需要的文件收集到dist目录下。然后你可以把dist目录拷贝到目标机器上,设置好ELECTRON_HOME环境变量就能用了。如果你是要在项目里用,可以把编译好的 Electron 放到 npm 的缓存目录里,或者直接用electron的path配置指向你的编译产物。具体做法是在项目根目录建一个.npmrc,加上:electron_mirror=file:///path/to/your/electron/dist这样npm install electron的时候就会用你本地的包,而不是去下载预编译的。4. 常见问题排查与避坑经验实录这一部分是我在实际操作中积累的问题排查经验,很多都是官方文档里不会写的。龙芯 + 麒麟这个组合本身就比较小众,遇到问题往往搜不到现成答案,只能自己一点点试。4.1 编译阶段典型报错速查下面这个表格整理了我遇到过的典型报错和对应的解决方法:报错信息可能原因解决方法internal compiler errorGCC 优化 bug降低优化级别,加-O2或换 GCC 版本undefined reference to xxx链接库缺失检查-l参数,手动指定库路径cannot find -lgbmlibgbm 未安装安装 libgbm-dev 或对应龙芯包snapshot blob errorsnapshot 生成失败加--without-snapshot重新编译out of memory内存不足加 swap 或减少并行编译任务数gn: command not founddepot_tools 未配置把 depot_tools 加到 PATHpython not foundPython 版本问题指定--python=python3这个表里的每一条我都是实际踩过的。比如internal compiler error那个,当时卡了我整整一天,后来发现是 GCC 9 在编译 V8 的某个文件时触发了优化 bug,换成 GCC 8 就好了。4.2 运行时问题的排查思路编译成功只是第一步,跑起来可能还有问题。最常见的运行时问题是启动就崩溃,或者界面显示异常。启动崩溃的话,先用ldd检查一下electron可执行文件的动态库依赖:ldd out/Release/electron | grep "not found"如果有not found的库,说明运行时缺少依赖,需要把对应的库装上或者把库路径加到LD_LIBRARY_PATH里。界面显示异常通常是 GPU 加速的问题。龙芯的显卡驱动支持比较有限,可以尝试禁用 GPU 加速:./electron --disable-gpu如果禁用 GPU 后能正常显示,那就说明是驱动的问题,可以在应用启动参数里固定加上这个选项。还有一个常见问题是字体显示成方块。这是因为系统缺少中文字体,装一下fonts-noto-cjk或者把 Windows 的字体拷过来就行。4.3 性能优化与实用技巧龙芯机器上跑 Electron,性能肯定不如 x86,但通过一些优化可以让体验好很多。第一,编译时开启-O2优化,不要用-O0。虽然编译慢一点,但运行速度快很多。第二,Electron 的启动参数里加上--disable-dev-shm-usage,避免共享内存不足导致的问题。第三,如果应用不需要 GPU 渲染,直接禁用 GPU 可以省不少资源。第四,打包的时候把不必要的 locale 文件和资源删掉,减小体积,也能加快启动速度。提示:龙芯的磁盘 IO 相对较慢,Electron 启动时加载大量小文件会比较慢。可以考虑把应用打包成 asar 归档,减少文件数量,提升加载速度。4.4 版本兼容性的一些经验Electron 版本和 Node.js 版本之间有对应关系,不能随便配。比如 Electron 24 对应的是 Node.js 16,Electron 28 对应的是 Node.js 18。编译之前一定要查一下对应关系,用错版本会有一堆莫名其妙的错误。麒麟 V10 的 SP 版本也有影响。SP1 和 SP2 的系统库版本不一样,编译时可能需要不同的配置。我建议在 SP2 以上版本上做,兼容性好一些。龙芯的架构版本也要注意。早期的龙芯是 MIPS 系,后来是 LoongArch。这两个架构的编译配置不一样,target_cpu要设对。LoongArch 的话设loongarch64,MIPS 的话设mips64el。5. 从编译到部署的完整链路梳理把 Electron 编译出来只是完成了第一步,真正要把它用在实际项目里,还需要考虑部署和分发的问题。这一部分聊聊怎么把编译产物集成到实际项目中,以及一些工程化的实践。5.1 将编译产物集成到 npm 项目最直接的方式是在项目里配置electron的路径。在package.json里加上:{ "config": { "electron_path": "/opt/electron-loongarch64/electron" } }然后在代码里用process.env.ELECTRON_PATH或者直接引用这个路径。不过更规范的做法是用electron包的path.txt机制。Electron 的 npm 包在安装后会生成一个path.txt,里面记录了可执行文件的路径。你可以手动创建这个文件,指向你编译好的 electron:echo "/opt/electron-loongarch64/electron" > node_modules/electron/path.txt这样require('electron')就能找到正确的可执行文件了。5.2 制作可分发的安装包如果要把应用分发给其他人用,最好做成安装包。麒麟 V10 支持 deb 和 rpm 两种格式,可以用electron-builder来打包。不过electron-builder默认会去下载预编译的 Electron,需要配置一下让它用本地的:{ "build": { "electronDist": "/opt/electron-loongarch64/dist", "linux": { "target": ["deb"], "category": "Utility" } } }electronDist指向你编译好的 dist 目录,这样打包时就不会去下载了。打包出来的 deb 包在麒麟 V10 上用dpkg -i安装就行。注意依赖关系要写清楚,把 Electron 需要的系统库都列上,避免装完了跑不起来。5.3 持续集成与自动化构建的思路如果项目需要频繁更新 Electron 版本,手动编译太痛苦了。可以考虑搭一个简单的 CI 流程,在龙芯机器上跑自动化编译。基本的思路是用 Jenkins 或者 GitLab CI,配置一个龙芯的 runner,每次 tag 推送时自动拉源码、编译、打包。编译脚本可以写成一个 shell 脚本,把前面说的步骤串起来:#!/bin/bash set -e # 更新源码 cd /opt/electron-src git fetch --all git checkout $1 git submodule update --init --recursive # 配置 gn gen out/Release --args="import(\"//build/args/loongarch64.gn\")" # 编译 ninja -C out/Release electron # 打包 ./script/create-dist.py # 拷贝产物 cp -r dist /opt/electron-$1这个脚本可以根据实际需求调整。关键是set -e要加上,任何一步失败就中断,避免产出不完整的包。5.4 一些工程化的小建议在实际项目中,我建议把 Electron 的编译产物单独管理,不要和业务代码混在一起。可以建一个专门的仓库或者目录来存放编译好的 Electron,业务项目通过环境变量或者配置文件来引用。另外,编译产物最好做版本标记,比如electron-24.8.5-loongarch64这样的命名,方便区分不同版本和架构。如果同时维护多个架构的版本,这个习惯能省很多事。还有一点是文档。龙芯 + 麒麟这个组合的坑太多了,每次踩完坑一定要记下来,形成团队内部的文档。不然换个人来又要重新踩一遍。6. 实际项目中的性能调优与体验优化编译能跑起来只是及格线,要让 Electron 应用在龙芯上真正好用,还需要做一些针对性的优化。这一部分分享一些我在实际项目中验证过的调优手段。6.1 启动速度优化Electron 应用在龙芯上的启动速度是个大问题,冷启动可能要十几秒甚至更久。优化启动速度可以从几个方面入手。首先是减少主进程的初始化工作。很多应用在app.on('ready')之前做了大量同步操作,这些都会拖慢启动。能异步的都改成异步,能延迟的都延迟到窗口显示之后再做。其次是 V8 的 snapshot。前面编译 Node.js 时用了--without-snapshot,这会让启动时重新解析 JavaScript,影响速度。如果稳定性允许,可以尝试开启 snapshot,能明显提升启动速度。开启的方法是在编译 Node.js 时去掉--without-snapshot,然后重新编译 Electron。第三是减少渲染进程的负担。首屏只加载必要的资源,其他模块按需加载。可以用webpack的代码分割功能,把首屏不需要的代码拆出去。6.2 内存占用控制Chromium 的内存占用本来就高,在龙芯这种内存相对紧张的平台上更要注意。几个实用的手段:一是限制渲染进程的数量。Electron 默认每个窗口一个渲染进程,如果开了很多窗口,内存会飙升。可以用app.commandLine.appendSwitch('renderer-process-limit', '2')来限制。二是及时释放不用的资源。窗口关闭后要确保相关的渲染进程被回收,避免内存泄漏。三是用--js-flags="--max-old-space-size=512"限制 V8 的堆大小,避免单个进程占用过多内存。6.3 图形渲染的取舍龙芯的 GPU 驱动支持有限,很多时候只能用软件渲染。软件渲染的性能肯定不如硬件加速,但胜在稳定。如果应用对图形性能要求不高,直接用软件渲染反而更省心。禁用 GPU 加速的方法是在启动参数里加--disable-gpu。如果只是部分场景有问题,可以用--disable-gpu-compositing只禁用合成加速,保留其他 GPU 功能。对于需要图形性能的场景,可以尝试用--use-gl=swiftshader走软件 OpenGL 渲染,比纯 CPU 渲染快一些。6.4 实际体验的一些观察我在龙芯 3A5000 的机器上跑过一个基于 Electron 24 的应用,冷启动大概 8 秒,热启动 3 秒左右。内存占用在 300MB 到 500MB 之间,取决于打开的窗口数量。这个表现相比 x86 确实有差距,但日常使用是够的。界面流畅度方面,简单的表单和列表操作基本没问题,复杂的动画和滚动会有轻微卡顿。如果应用以数据处理为主,对动画要求不高,体验是可以接受的。一个比较明显的瓶颈是文件 IO。龙芯机器的磁盘读写速度相对较慢,Electron 启动时加载大量小文件会比较耗时。把应用打包成 asar 之后,启动速度能提升 20% 到 30%。最后再分享一个小技巧:如果应用需要频繁读写本地文件,可以考虑用内存缓存减少磁盘操作。比如把配置文件加载到内存里,定期同步回磁盘,而不是每次都读写文件。这个改动虽然简单,但对体验的提升很明显。