desktop AppImage: de-bundle host-coupled graphics libs (fixes black window)
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m14s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m14s
Tauri's AppImage bundles the build host's graphics/display stack (libEGL/libGL/libdrm/libgbm/libwayland-* + Mesa dri drivers) into usr/lib. On many end-user systems (Arch/CachyOS, NVIDIA, Wayland) those clash with the running kernel driver + Mesa and abort with EGL_BAD_PARAMETER -> a black window (issue 2021). They load before any renderer choice, so the runtime env fallbacks can't rescue it; per the AppImage excludelist they must come from the host. Add a CI-only post-build step (desktop/packaging/appimage/debundle-graphics.sh) that extracts the built AppImage, strips exactly that graphics/display subset (keeping webkit/gtk bundled for portability), and repackages in place so the app falls through to the system's graphics libs. Wired into desktop.yml between the Tauri build and the artifact upload. Task 2023. Makes the AppImage the zero-install taste-test vehicle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
+118
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# De-bundle host-coupled graphics/display libraries from the built Tauri AppImage.
|
||||
#
|
||||
# WHY: Tauri's AppImage bundles the BUILD host's libEGL/libGL/libdrm/libgbm/
|
||||
# libwayland-* into usr/lib. On many end-user systems (Arch/CachyOS, NVIDIA,
|
||||
# Wayland) those bundled copies clash with the running kernel driver + Mesa and
|
||||
# abort with "Could not create default EGL display: EGL_BAD_PARAMETER" -> a black
|
||||
# window (issue 2021). They load before any renderer choice, so the runtime env
|
||||
# fallbacks (WEBKIT_DISABLE_DMABUF_RENDERER etc.) cannot rescue it. Per the
|
||||
# AppImage excludelist these libraries MUST come from the host. We strip exactly
|
||||
# that graphics/display subset -- keeping webkit/gtk/javascriptcore bundled for
|
||||
# portability -- so the dynamic loader falls through to the system copies (the
|
||||
# AppRun keeps usr/lib first on LD_LIBRARY_PATH, then system paths).
|
||||
#
|
||||
# CI-only post-build step: extract -> remove libs -> repackage, overwriting the
|
||||
# original AppImage in place so the desktop.yml artifact glob emits the
|
||||
# de-bundled one.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
BUNDLE_DIR="$REPO_ROOT/desktop/src-tauri/target/release/bundle/appimage"
|
||||
|
||||
# appimagetool is published only under the rolling "continuous" tag (the project
|
||||
# cuts no semver releases), so this URL is the pinned distribution channel.
|
||||
# Preferred source is Tauri's own already-downloaded copy (see below); this is
|
||||
# the network fallback.
|
||||
APPIMAGETOOL_URL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
|
||||
# Graphics/display libraries that must come from the host, per the AppImage
|
||||
# excludelist (github.com/AppImage/pkg2appimage/blob/master/excludelist), plus
|
||||
# the libwayland-* family that slips in through the GTK/WebKit dependency chain.
|
||||
# Globs (.so*) catch every versioned variant. Only the GPU/driver stack is
|
||||
# stripped; webkit/gtk stay bundled.
|
||||
REMOVE_GLOBS=(
|
||||
'libGL.so*' 'libEGL.so*' 'libGLdispatch.so*' 'libGLX.so*' 'libOpenGL.so*'
|
||||
'libglapi.so*' 'libgbm.so*' 'libdrm.so*'
|
||||
'libxcb.so*' 'libxcb-dri2.so*' 'libxcb-dri3.so*'
|
||||
'libX11.so*' 'libX11-xcb.so*'
|
||||
'libwayland-client.so*' 'libwayland-cursor.so*'
|
||||
'libwayland-egl.so*' 'libwayland-server.so*'
|
||||
)
|
||||
|
||||
echo "==> Locating built AppImage under $BUNDLE_DIR"
|
||||
shopt -s nullglob
|
||||
appimages=("$BUNDLE_DIR"/*.AppImage)
|
||||
if [ ${#appimages[@]} -eq 0 ]; then
|
||||
echo "ERROR: no .AppImage in $BUNDLE_DIR (did the tauri build run?)" >&2
|
||||
exit 1
|
||||
fi
|
||||
APPIMAGE="${appimages[0]}"
|
||||
echo " $APPIMAGE"
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
|
||||
echo "==> Extracting AppImage (FUSE-free)"
|
||||
cp "$APPIMAGE" "$WORK/app.AppImage"
|
||||
chmod +x "$WORK/app.AppImage"
|
||||
(cd "$WORK" && ./app.AppImage --appimage-extract >/dev/null)
|
||||
LIBDIR="$WORK/squashfs-root/usr/lib"
|
||||
[ -d "$LIBDIR" ] || {
|
||||
echo "ERROR: no usr/lib in the extracted AppImage" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "==> Removing host-coupled graphics/display libraries"
|
||||
before=$(find "$LIBDIR" -maxdepth 1 -type f -name '*.so*' | wc -l)
|
||||
removed=0
|
||||
for pat in "${REMOVE_GLOBS[@]}"; do
|
||||
for f in "$LIBDIR"/$pat; do
|
||||
echo " - $(basename "$f")"
|
||||
rm -f "$f"
|
||||
removed=$((removed + 1))
|
||||
done
|
||||
done
|
||||
if [ -d "$LIBDIR/dri" ]; then
|
||||
n=$(find "$LIBDIR/dri" -type f | wc -l)
|
||||
echo " - dri/ (${n} Mesa GPU drivers)"
|
||||
rm -rf "$LIBDIR/dri"
|
||||
removed=$((removed + 1))
|
||||
fi
|
||||
after=$(find "$LIBDIR" -maxdepth 1 -type f -name '*.so*' | wc -l)
|
||||
echo " removed ${removed} entries (usr/lib .so files: ${before} -> ${after})"
|
||||
if [ "$removed" -eq 0 ]; then
|
||||
echo "WARNING: nothing removed -- excludelist libs were not bundled here." >&2
|
||||
fi
|
||||
|
||||
echo "==> Locating appimagetool"
|
||||
# Prefer the copy Tauri already downloaded during the build (no network, and
|
||||
# version-matched to the toolchain that produced the AppImage).
|
||||
APPIMAGETOOL="$(find "$REPO_ROOT/desktop/src-tauri/target" -name 'appimagetool-*.AppImage' -type f 2>/dev/null | head -n1 || true)"
|
||||
if [ -z "${APPIMAGETOOL:-}" ]; then
|
||||
echo " not cached by Tauri; downloading from continuous channel"
|
||||
APPIMAGETOOL="$WORK/appimagetool"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL -o "$APPIMAGETOOL" "$APPIMAGETOOL_URL"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$APPIMAGETOOL" "$APPIMAGETOOL_URL"
|
||||
else
|
||||
echo "ERROR: need curl or wget to fetch appimagetool" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " reusing Tauri's copy: $APPIMAGETOOL"
|
||||
fi
|
||||
chmod +x "$APPIMAGETOOL"
|
||||
|
||||
echo "==> Repackaging AppImage (overwriting original)"
|
||||
rm -f "$APPIMAGE"
|
||||
# APPIMAGE_EXTRACT_AND_RUN lets appimagetool (itself an AppImage) run without
|
||||
# FUSE in the CI container; ARCH is required by the embedded runtime.
|
||||
export APPIMAGE_EXTRACT_AND_RUN=1
|
||||
ARCH=x86_64 "$APPIMAGETOOL" "$WORK/squashfs-root" "$APPIMAGE"
|
||||
|
||||
echo "==> Done: de-bundled AppImage at"
|
||||
ls -lh "$APPIMAGE"
|
||||
Reference in New Issue
Block a user