#!/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/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/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"