1600 字
8 分钟

LWE AppImage 图标断链与 ABI 验收

LWE 的 AppImage 在 CI 中构建成功,提交到 AppImage 目录后却没通过检查。最先暴露的是图标断链;继续检查安装包,又发现旧包的 glibc 要求高于目录测试主机。修复时还需要兼顾 Arch 包使用的 libmpv.so.2,最后把 AppImage 和原生包拆成了两条构建基线。

本文根据 2026 年 10 月 8 日的排障和发布记录整理。当天完成了 LWE v0.9.11 发布,并补齐了最终安装包的检查。

图标存在,链接却留在构建机上#

LWE 是一个使用 Tauri 2、SvelteKit 和 Rust 的 Linux 桌面应用,已验证的壁纸运行目标是 Wayland + niri 上的视频壁纸。这次问题发生在发布包,先不用怀疑壁纸引擎。

目录检查器认为 .DirIcon 缺失,但解开包后能找到 lwe.png。原因是 .DirIcon 使用了绝对软链接,目标落在 GitHub runner 的工作目录里。包离开 runner 后,这条路径就失效了。

下面是缩写后的结构示意,省略了构建目录中间的层级:

AppDir/
├── lwe.png
└── .DirIcon -> /home/runner/.../lwe.png

文件存在和入口能访问到文件,是两个检查。相对链接可以随 AppDir 一起移动;指向构建机的绝对链接只在那台机器上碰巧可用。AppDir 规范要求根目录包含 AppRun、desktop 文件和图标等入口,并允许图标链接到包内文件。

这也是 Tauri 打包器已经修复过的问题:tauri-cli 2.11.4 的发布说明明确记录了将 desktop 和 .DirIcon 的绝对软链接改为相对软链接。LWE 当次选用并固定了 CLI 2.12.1。这里需要更新的是执行打包的 CLI;应用的 Rust 依赖升级了,缓存里的 cargo-tauri 仍可能是旧版本。

因此,发布流程除了读统一的 .tauri-cli-version,还把版本放进缓存键,恢复缓存后再次核验 CLI。缓存命中只说明拿到了文件,版本核验才说明拿到了本次要用的工具。

修完图标,继续检查 ELF 依赖#

图标问题有明确修复,但旧包还存在另一个启动门槛:主程序要求 GLIBC 2.39,包内部分 WebKit、JavaScriptCore 和 mpv 库要求 2.38。目录测试主机使用 Ubuntu 22.04,提供的是 glibc 2.35。

AppImage 会携带许多依赖,但不能因此假定它与宿主机 ABI 无关。AppImage 官方建议是使用足够旧的构建基线,并在目标基础系统上实际测试。高版本系统上编出来的二进制,如果引用了旧系统没有的符号版本,复制更多业务文件也不能解决启动失败。

对已解包的 ELF,可以先做只读检查。下面的文件路径是示例,应替换为包内的实际主程序和动态库:

Terminal window
readelf --version-info AppDir/usr/bin/lwe
readelf -d AppDir/usr/bin/lwe

前一项用于查看所需符号版本,后一项里的 NEEDED 用于查看动态库依赖。只查主程序还不够,捆绑库也可能提高最低要求。这次修复后的公开包检查了 298 个 ELF 文件,观察到的最高 GLIBC 要求降到了 2.35。

这个结果确认了包内符号版本的基线,也限定了它能证明的范围:图形会话、驱动、窗口系统和外部依赖仍需要启动验收。

AppImage 与 deb/rpm 分开构建#

把所有产物一律改在 Ubuntu 22.04 上构建,又会碰到原生包的依赖选择。LWE 的 Arch 软件包使用 libmpv.so.2;原生 deb/rpm 需要保留对应的链接 ABI。

最终的分工是:

产物构建环境本次处理的约束
AppImageUbuntu 22.04控制包内 glibc 符号版本要求
deb、rpmUbuntu 24.04保留原生包使用的 libmpv.so.2 ABI

两条任务的 Rust 和 CLI 缓存也按发行版隔离,避免旧环境的产物进入另一条构建路径。实际配置可以看 v0.9.11 的稳定发布 workflow。这是一组针对 LWE 依赖组合的选择,换成其他桌面框架或媒体库时,还需要重新核对目标系统与链接依赖。

在上传前挡住坏包#

只升级打包工具,下次工具链变动仍可能重新带入同类问题。我给发布链增加了独立的 AppImage 校验脚本,直接检查最终准备上传的包。

它解开文件系统后,检查 AppRun 是否可执行、根目录是否只有一个有效 desktop 文件、desktop 引用的图标和 .DirIcon 是否可读取。解析软链接时逐跳检查,拒绝绝对路径、断链、越界和循环。普通图标文件也可以通过,不强制一定使用链接。

检查不会启动应用,也不会把坏包临时修好后继续上传。失败应回到源码或构建流程修复,否则发布出来的包就偏离了可追溯的构建结果。回归夹具覆盖了正常文件、相对链接,以及这次遇到的构建机绝对路径等失败情况。

在 LWE 仓库中,对已经下载到本地的发布包可这样调用:

Terminal window
python3 scripts/validate-appimage.py lwe_0.9.11_amd64.AppImage

脚本需要 Python 3、unsquashfs、file 和 desktop-file-validate。发布 workflow 在上传前执行相同检查,检查对象限定为本次版本,避免把工作目录里残留的旧包一起发布。

再验证用户下载到的那一份#

上传前通过,只覆盖了构建阶段。当天发布后又下载了公开的 v0.9.11 AppImage,核对 SHA-256 与 GitHub asset digest 一致,并重新执行静态校验。这一步把验收对象落到了下载入口里的文件上。

当时还完成了空 HOME/X11 启动验收,以及真实 niri 会话里的三轮应用、清除和重启恢复。前者能暴露对已有用户配置的隐含依赖,后者才覆盖壁纸运行路径。单元测试、构建成功和图标校验各有作用,不能相互替代。

AppImage 目录的技术检查后来通过,并获得了 screenshot-ok。当天记录尚未确认上游维护者完成收录合并;多显示器也没有实测。本次交付完成了 v0.9.11 发布、公开包复验和单显示器 niri 验收,后续扩大支持范围时仍需要新增验收证据。

LWE AppImage 图标断链与 ABI 验收
https://blog.yangyus8.top/posts/lwe-appimage-icon-linux-abi-validation/
作者
杨与S8
发布于
2026-10-08
许可协议
CC BY-NC-SA 4.0

评论