在 Linux 下做一款压缩工具的跨架构适配,听起来像是个简单的编译任务。其实标题这句话已经把事情说透了:PeaZip 11 在 Linux 上要同时交付 amd64、arm64 和龙芯(loongarch64)三个可用版本。做之前我以为只是把构建参数改一改,真正跑起来才发现,光是让三个架构的依赖库对齐,就已经花掉大半个周末。这篇文章是这次适配过程的全记录,把我踩过的坑、验证过的方法、最终采用的打包方案都写出来,给正好也在折腾跨架构 Linux GUI 工具的朋友做个参考。
1. 为什么 PeaZip 11 值得做 Linux 多架构适配
1.1 PeaZip 在 Linux 生态里的定位
PeaZip 是一款开源的图形化压缩工具,界面用 Lazarus/FreePascal 开发,核心压缩能力通过调用 7-Zip、p7zip、bsdtar 等后端引擎实现。它的看家本领是格式覆盖广:7z、zip、tar、gz、bz2、xz、zstd、rar 解压,以及自解压、分卷、加密、校验等高级功能。Linux 桌面自带的归档管理器,比如 GNOME 的 File Roller 和 KDE 的 Ark,日常解压 zip/tar 完全够用,但碰到冷门格式或者需要分卷加密的场景,就力不从心了。PeaZip 正好把这块补上,这也是它在 Linux 用户里一直有固定受众的原因。
不过 PeaZip 官方对 Linux 的架构支持一直偏向 x86 体系。早期只有 amd64 和 i386 包,后来慢慢有了 arm64 版本。真正把龙芯 loongarch64 纳入构建目标,是最近社区里呼声很高的一件事。原因也不难理解:使用 ARM 设备的 Linux 用户越来越多,树莓派、RK3588 盒子、鲲鹏服务器、苹果 M 系列跑 Linux 虚拟机,都需要 arm64 原生包;龙芯的 loongarch64 设备在国产化办公环境里大批量铺开,但应用生态相对薄弱,用户想装个顺手的压缩工具,经常只能找源码自己折腾。
1.2 amd64、arm64、loongarch64 到底有什么差别
很多用户对这几个架构名是懵的。amd64 就是平时说的 x86_64,几乎所有家用 PC 和主流服务器都在用,指令集成熟,软件生态最全。arm64 也叫 AArch64,是 ARM 公司的 64 位指令集,手机处理器、苹果 M 系列、树莓派、大量云厂商的 ARM 实例都是这个架构,特点是功耗低、核心数多,能效比好。loongarch64 是龙芯的自主 64 位指令集,跟前面两者完全不兼容,既不能直接运行 x86 程序,也不能运行 ARM 程序。
操作系统层面的区别同样关键。Debian/Ubuntu 的包架构名里,amd64 对应 x86_64,arm64 对应 AArch64,loongarch64 在不少仓库里写作 loong64,也有叫 loongarch64 的。这意味着做软件分发时,不但二进制要重新编译,打包系统的架构字段、依赖声明、安装判断逻辑都得跟着改。用一句话总结就是:这三种架构之间的指令集、ABI、系统库都不通用,不能指望一个 amd64 的 deb 包在龙芯上还能跑,也不存在"拷贝个 arm64 二进制到龙芯就能用"这种好事。
| 架构 | 指令集 | 常见设备 | 包架构名(Debian 系) |
|---|---|---|---|
| amd64 | x86_64 | PC、主流服务器 | amd64 |
| arm64 | AArch64 | 树莓派、M 系列、ARM 云实例 | arm64 |
| loongarch64 | LoongArch64 | 龙芯 3A5000/3A6000 等 | loong64 / loongarch64 |
1.3 这次适配的真实动机
我最开始只是想在树莓派上装个 PeaZip,结果发现官方虽然放了 arm64 包,但版本经常比 amd64 落后,而且依赖处理得很粗糙。后来在龙芯设备上试跑,发现连像样的安装包都没有,只能找旧版源码手工编译,编译过程中还因为 FreePascal 编译器版本太老、Lazarus 组件包不匹配折腾了一整晚。做这个适配项目说白了就一个目标:让 amd64、arm64、loongarch64 三种架构的用户,都能拿到同一版本的 PeaZip 11 安装包,下载安装就能用,不需要自己编译,也不需要在 x86 模拟层里忍受性能损失。
2. 构建环境:不是所有架构都能"编译一时爽"
2.1 主工具链:Lazarus/FreePascal 的版本门槛
PeaZip 的图形界面是基于 Lazarus 的 LCL 组件库写的,所以构建它必须先有 Lazarus IDE 和 Free Pascal Compiler(FPC)。这里第一个坑就来了:FPC 对 loongarch64 的支持是很晚才加入的。如果你用的是发行版软件源里自带的 FPC 3.2.0,那基本可以放弃龙芯目标,因为编译器后端根本不认识 LoongArch 指令集。实测需要 FPC 3.2.2 以上的版本,或者直接用 FPC 主线快照。Lazarus 也要注意,2.2.6 及以后版本对 LCL 的跨平台编译支持才比较完整,建议直接上 Lazarus 3.x 配合最新稳定版 FPC。
另一个容易忽略的是 fpcsrc 源码路径。FPC 在编译 LCL 组件时,需要引用自身的 RTU 源码。不同发行版对 FPC 目录布局的约定不一样,Debian/Ubuntu 一般装在/usr/lib/fpc/src,龙芯的 Loongnix 系统里可能装在/usr/share/fpcsrc。如果路径不对,编译时会报找不到system单元之类的错,看起来像是编译器损坏,其实只是FPCDIR或fpc.cfg里的路径配置问题。建议在开始构建前,先手动跑一遍fpc -i确认默认路径,再用fpcdir=/usr/lib/fpc/src这样的参数强制指定,能省去很多无效排查。
2.2 交叉编译还是原生构建:怎么选
跨架构 GUI 应用,第一个要决策的是用交叉编译还是原生编译。我的经验是:核心原则是"能用原生就原生"。交叉编译要解决编译器之外的整套运行库问题,比如目标架构的 GTK2/Qt 库、D-Bus 库、X11 库,这些一旦缺了,编译期报错五花八门,排查成本高。amd64 没有任何悬念,直接在 x86_64 机器上原生构建;arm64 采用了一个折中方案:先用交叉编译把主程序编出来,再在一台真机 ARM 设备上做make install和运行验证;loongarch64 则直接找了个龙芯 3A5000 的真机做原生构建,虽然编译速度慢一点,但省掉了交叉工具链缺失带来的巨大麻烦。
这里要特别说下 FPC 的交叉编译方式。FPC 交叉编译不像 Go 那样设置两个环境变量就完事,它需要先安装目标平台的交叉 binutils 和交叉 FPC 单元库。以 arm64 为例:
# 安装 arm64 交叉工具链 sudo apt install binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu # 使用 fpcupdeluxe 安装 lazarus aarch64 交叉版本(推荐) # 选择 cross-* 前缀的组件即可用 fpcupdeluxe 的好处是它会自动拉对应架构的 LCL 单元,并处理好目标平台的 RTL 和 packages。如果嫌 GUI 工具麻烦,也可以在命令行执行:
make clean all OS_TARGET=linux CPU_TARGET=aarch64 CROSSBINDIR=/usr/aarch64-linux-gnu/bin不过这招对纯命令行程序可行,对需要 LCL 界面组件的程序,后面的路还长。
2.3 压缩引擎的架构二进制准备
很多人以为编译完 PeaZip 主程序就结束了,这是对 PeaZip 架构的一个常见误解。PeaZip 的 GUI 只是个管理壳,真正执行压缩解压动作的,是它调用的 7zz、7za、bsdtar 等外部引擎。所以一个完整可用的 PeaZip 包,必须同时包含这些引擎的可执行文件,而且它们必须和目标平台架构匹配。
对于 amd64,7-Zip 官方直接提供 linux-x64 的二进制,爽快。对于 arm64,7-Zip 同样有 aarch64 构建,或者从源码编译也能拿到。比较麻烦的是 loongarch64:官方发布渠道没有现成的 loongarch64 可执行文件,只能从 7-Zip 源码自己编。7-Zip 官方源码在CPP/7zip/Bundles/Format7zF目录下用 make 构建,编译倒是比较顺利,毕竟它是纯 C++ CLI 工具,不依赖图形库。交叉编译也行,但建议在龙芯真机上原生跑一版,能少踩很多编译器指令兼容的坑。
准备好引擎后,还有一个细节:PEAZIP 在运行时通过配置查找这些工具的位置,默认会优先找主程序同目录下的可执行文件。打包时一定要把7zz、7za、bsdtar、peazip放对位置,并设置好可执行权限,否则用户拿到手会发现界面正常,点"解压"却没反应。
3. 三架构构建实战与踩坑记录
3.1 amd64 基线包:先跑通默认流程
做多架构适配不能一开始就扑到最难的目标上,正确顺序是先拿 amd64 做基线。我从 PeaZip 官方源码包开始,在 Ubuntu 22.04 上安装 Lazarus 3.2,进入源码目录执行自带的构建脚本。脚本会依次编译各个子组件,最终生成peazip可执行文件。这个阶段基本顺利,唯一的坑是脚本依赖的gresource工具如果没有安装,资源编译会失败,需要补上libglib2.0-dev-bin。
基线跑通之后,手动运行一遍源码目录里的peazip,确认界面能弹出,然后压缩一个目录、解压一个 7z 包,功能链路通了,才说明 GUI 和后端引擎的调用关系正常。这个基线包的价值在于,后续 arm64 和 loongarch64 出现任何奇奇怪怪的问题,都可以拿 amd64 的行为做对比,判断是代码本身的问题还是架构移植引入的问题。
3.2 arm64 交叉编译:缺的不是编译器,是 GUI 依赖
arm64 交叉编译,我踩的最大的坑不在 FPC 本身,而在 LCL 组件依赖的系统库。LCL 在 GTK2 的 widgetset 下编译,需要找到 arm64 版本的 GTK2 开发头文件。可是宿主机装的是 x86_64 的系统库,直接交叉编译会报gtk/gtk.h: No such file or directory。这时候才意识到要用多架构支持:
sudo dpkg --add-architecture arm64 sudo apt update sudo apt install libgtk2.0-dev:arm64 libc6-dev:arm64这一步在 x86_64 的 Ubuntu 22.04 上是可以走通的,但某些 ARM 第三方源里的包版本可能不齐,需要手动添加 ports 源。相比之下,用带桌面环境的 arm64 真机做原生构建要省心很多:直接在树莓派或者 ARM 开发板上装好 Lazarus,跑同一套构建脚本,中间不涉及任何 cross 参数,出错概率低很多。实测下来,我最终推荐 arm64 也用原生构建,除非你要在 CI 流水线里批量生成,才值得把交叉编译的坑一次性踩平。
3.3 loongarch64 龙芯版:问题最集中
龙芯版是整个适配过程里问题最集中的一块。首先是工具链:在龙芯设备上安装 Lazarus 3.x 并不像 x86 那样apt install lazarus就能拿到对应版本,Loongnix 软件源里的 Lazarus 往往陈旧。解决方案要么自己下载 Lazarus 对 loongarch64 的预编译包,要么从源码逐步编译 FPC 再到 Lazarus。这里我强烈建议直接用预编译包,因为 FPC 的 bootstrap 链条比较长,源码来自举耗时太可观。
第二个坑是 Glibc 版本兼容。PeaZip 11 在较新发行版上编译,默认链接到较新的 Glibc,放到老版本的龙芯系统上运行时,会报:
version `GLIBC_2.34' not found这个问题在红帽系系统上尤其明显。我们后来统一在较老的兼容基础环境上编译,或者对二进制做 patch,保证最低满足 GLIBC_2.32 左右,这样龙芯设备上的大多数系统都能跑。
第三个坑是 Qt 和 GTK2 的选择。龙芯设备的桌面环境五花八门,有的基于 GTK,有的用 Qt。PeaZip 在 Linux 下可以用 GTK2 widgetset 也可以编译成 Qt5 版本。为了兼容性,我选择保留 GTK2 构建,因为这个依赖在老系统上更常见。但在部分只预装 Qt 库的精简系统上,就要额外装libgtk2.0-0和相应依赖,否则启动直接报缺库错误。
3.4 编译期摸黑排查的一个通用套路
遇到编译失败,我的经验是先分清是三类问题里的哪一类:第一类,FPC 编译器本身不支持目标 CPU,一般会报 illegal instruction 或 operand type mismatch,这时只能升级编译器;第二类,目标架构的系统库缺失,一般是找不到某个.h文件或.so文件,这时要回到包管理器解决依赖;第三类,源码里的汇编或内嵌汇编不是跨平台的,常见于一些深度优化的第三方库,这时要么换成纯 C 实现,要么用条件编译跳过。把问题归类后,至少不会被编译器的一长串输出绕晕。
4. 打包与分发:deb、rpm、AppImage 怎么选
4.1 包格式与发行版覆盖
三架构都编译出来后,分发方式又是一个需要仔细琢磨的问题。Linux 发行版各自为政,deb 适用于 Debian、Ubuntu、Deepin、UOS 这些系统,rpm 适用于 Fedora、RHEL、openEuler 这些系统,tar.gz 是最后兜底方案。考虑到 PeaZip 用户里 Debian 系和 Ubuntu 系占比最大,我把 deb 作为第一优先格式,每个架构独立打一个包。
| 发行版家族 | 包格式 | 安装方式 |
|---|---|---|
| Debian / Ubuntu / Deepin / UOS | deb | sudo dpkg -i |
| Fedora / openEuler / RHEL 系 | rpm | sudo rpm -Uvh |
| 所有 Linux | tar.gz | 解压后直接运行目录内可执行文件 |
| 所有 Linux | AppImage | chmod +x 后运行 |
做 deb 包时,控制文件里的Architecture字段要严格对应:amd64 写amd64,arm64 写arm64,龙芯在 Debian 系规范里通常写loong64,但有的仓库也接受loongarch64。如果这个字段写错,dpkg 会直接拒绝安装,提示架构不匹配。建议打好的包在每种架构的干净虚拟机里都试装一遍,不要只看包管理器提示成功。
4.2 文件命名、控制信息与校验
文件名最好遵循发行版的命名习惯,比如:
peazip_11.2.0-1_amd64.deb peazip_11.2.0-1_arm64.deb peazip_11.2.0-1_loong64.deb版本号里把上游版本和修订号分开,后续修复依赖问题时可以直接递增修订号。控制文件里除了Architecture,还要注意Depends字段。如果写的依赖过强,比如强制要求某个具体版本的 GTK2,用户系统上略微不同的版本就会导致安装失败;如果依赖过弱,缺少必要运行库,用户装完又跑不起来。这需要你在两种风险之间找一个平衡点。最后,每个包发布前必须对.deb和.rpm生成 SHA-256 校验和,放在下载页面上,省得用户下载时文件损坏还一头雾水。
4.3 AppImage 的取舍
如果目标是为不同发行版提供"免安装"体验,AppImage 是个好选择。它的原理是把应用运行时需要的库都打包在一起,用户下载后加个执行权限就能用,听起来很美好,实际做起来还是有几个地方要注意。
第一,AppImage 内的库版本如果跟宿主系统差异过大,依然可能遇到 Glibc 版本冲突,所以要在尽量老的兼容环境里制作。第二,AppImage 的图标和桌面集成需要额外的 AppStream 元数据,否则用户启动后看不到托盘图标。第三,PeaZip 调用外部 7zz 引擎时,引擎文件必须在 AppImage 的 mount 路径下可执行,这就意味着制作工具要正确配置AppRun脚本,处理好相对路径。建议仍然是先制作一个完整功能的 AppImage,手动在 3 个架构的系统上跑一遍解压压缩流程,再对外发布。
5. 三架构实测对比与用户避坑指南
5.1 功能与稳定性测试
三套包出来后,不能只看能不能打开界面。我的验证分三层:第一层是基础功能,创建 zip 和 7z 压缩包、解压 zip/7z/rar/tar.gz、设置密码、创建分卷、校验文件完整性,全部过一遍;第二层是异常场景,比如压缩一个包含只读文件的目录、解压一个路径带中文的包、密码输入错误时的提示是否正常;第三层是长时间运行稳定性,我用一个 2GB 左右的目录做了连续 10 次压缩解压循环,观察内存是否有明显泄漏。
这个过程里发现 arm64 版本在连续循环解压大文件时,偶尔会出现界面卡顿,后来定位是线程池里对 7zz 进程的回调处理在高并发时锁竞争导致。这个和架构本身关系不大,更像是通用逻辑问题,之后在 amd64 上也能复现,属于上游代码的一个 bug。这类问题对多架构适配者的启示是:不能只测"能跑不能跑",还要测"跑多久出问题",性能和稳定性往往比单次功能更早暴露架构移植隐患。
5.2 性能实测数据
性能方面,我用一个约 1.2GB 的混合目录(包含大文件、小文件、文本、二进制)做了压缩测试,选用默认的 7z 压缩等级,结果如下:
| 架构 | 压缩耗时 | 解压耗时 | CPU 占用 | 备注 |
|---|---|---|---|---|
| amd64 | 约 58 秒 | 约 21 秒 | 多核打满 | 基线性能 |
| arm64(RK3588) | 约 96 秒 | 约 35 秒 | 多核打满 | 能效比不错,温度控制好 |
| loongarch64 | 约 128 秒 | 约 46 秒 | 多核打满 | 可用性没问题,与架构代差相关 |
这个数据仅供参考,不同 CPU 型号差异很大。实际的意思是说,PeaZip 在三个架构上都能正常完成核心任务,性能差距主要体现在 CPU 本身的算力。至少在龙芯 3A5000 级别的设备上,日常压缩解压是完全可用的,不会再出现以前那种"装不上、打不开、一跑就崩"的情况。
5.3 常见安装与使用问题
最后集中说一下用户最容易踩的安装坑。
第一个问题是下错架构包。arm64 和 amd64 的 deb 包表面看起来差不多,但架构字段不同,dpkg 会拒绝安装。如果安装时提示package architecture (arm64) does not match system (amd64),那就说明下错包,直接换对应架构的下载链接,不要试图加--force-architecture强制安装,那样大概率跑起来直接段错误。
第二个问题是提示缺依赖库。错误信息类似:
libgtk-x11-2.0.so.0: cannot open shared object file这在精简版系统上比较常见。解法是:
sudo apt install libgtk2.0-0对于 Ubuntu 24.04 等较新的系统,GTK2 已经从主软件源移除了,这时建议优先使用 AppImage 版本,或者自己从旧仓库拉 GTK2 运行时。
第三个问题是文件关联没生效。部分桌面环境需要用户到"设置-默认应用"里手动把压缩文件关联到 PeaZip,或者运行 PeaZip 自带的"设置关联"功能。这是因为不同桌面环境对.desktop文件的 MimeType 处理方式不同,不是安装包做错了,只是需要一个手动确认步骤。
还有一个很多人问的场景:在苹果 M 系列芯片上跑 Linux 虚拟机,比如用 QEMU 或 Parallels 装 Ubuntu,这时虚拟机里的架构是 arm64,不是 amd64,下载 Windows 版或者 amd64 的 Linux 版都没有意义,要下载 arm64 的 Linux 包。很多人在这一步反复出错,以为"Linux 包都一样",实际上不同 CPU 架构的 Linux 包天差地别。
最后一个建议:在龙芯设备上安装完软件以后,打开终端执行lscpu,确认架构信息再下载。如果输出的 Architecture 是loongarch64或Loongson-3,那就认准 loongarch64 构建,不要碰 amd64 和 arm64 的包。这不是嫌麻烦,是架构移植项目的底线规则。
这次适配做完,我最大的体会是:跨架构工作里,编译器只是起点,真正的工程量在依赖库、打包规范、运行库兼容这些看不见的地方。PeaZip 11 能在三个架构上跑起来,靠的也不是某一条神奇的命令,而是把每个架构当成一个完整的产品来对待。后面如果再遇到类似的 Linux 桌面软件适配,照这个思路走,基本不会跑偏。