fix(desktop): make Linux AppImage GStreamer work on non-Debian distros#2176
fix(desktop): make Linux AppImage GStreamer work on non-Debian distros#2176dcadenas wants to merge 2 commits into
Conversation
…tros Signed-off-by: Daniel Cadenas <dcadenas@gmail.com>
93f5b2e to
480b5ee
Compare
wpfleger96
left a comment
There was a problem hiding this comment.
hey Daniel — the root-cause analysis here is right and well-evidenced (a set GST_PLUGIN_SYSTEM_PATH_1_0 replaces GStreamer's default search path, so the old Debian-multiarch symlink was a Debian-only accident), and the shim placement after AppRun.wrapped is the only spot that works. The Arch validation through the real AppRun → AppRun.wrapped → shim → app chain is exactly the right disproving test. The fail-loud guards are great too.
Requesting changes for two small hardenings (comments 1 and 2 inline — one flag and one character respectively). Comments 3 and 4 are nits, take or leave. None of this changes the approach.
| unset "$var" | ||
| fi | ||
| done | ||
| exec "$here/buzz-desktop.bin" "$@" |
There was a problem hiding this comment.
the bare exec makes argv[0] …/buzz-desktop.bin. GTK derives prgname → WM_CLASS from argv[0], so taskbar icon matching / window grouping against the .desktop file can break, and pidof/killall buzz-desktop stop working. One flag fixes it:
exec -a "buzz-desktop" "$here/buzz-desktop.bin" "$@"Separately, the kernel comm comes from the exec'd file's basename (not argv[0], so exec -a doesn't cover this leg): buzz-desktop.bin truncates to buzz-desktop.bi, which no longer matches DESKTOP_BINARY_NAMES in desktop_is_alive_for_instance (runtime.rs:761 / :955). I checked and this isn't a new regression — release Linux builds already fail that function's cmdline leg (the instance id only appears in /proc/pid/cmdline for tauri dev --config launches), so release desktops are already invisible to reap_dead_instance_agents on main. A companion line adding buzz-desktop.bi to DESKTOP_BINARY_NAMES would close the comm leg for whenever the cmdline leg gets fixed — fine as a fast-follow if you'd rather keep this PR tight.
There was a problem hiding this comment.
Addressed in 8f3003f. The shim now uses exec -a "buzz-desktop" to preserve argv[0], and I also added the Linux-truncated buzz-desktop.bi name to DESKTOP_BINARY_NAMES with a focused regression test.
| GST_PLUGIN_PATH_1_0 GST_PLUGIN_PATH \ | ||
| GST_PLUGIN_SCANNER GST_PLUGIN_SCANNER_1_0; do | ||
| val="${!var-}" | ||
| if [[ -n "$val" && "$val" == *"$appdir"* ]]; then |
There was a problem hiding this comment.
*"$appdir"* is a loose substring match — if someone runs the extracted AppDir from e.g. /opt/buzz, a user-set GST_PLUGIN_PATH=/opt/buzz-plugins would falsely match and get unset. *"$appdir/"* still matches the injected $APPDIR/usr/lib/gstreamer-1.0 and kills the false positive. One character.
There was a problem hiding this comment.
Addressed in 8f3003f. The match now requires $appdir/, so the injected in-AppImage paths are removed without falsely matching sibling paths such as /opt/buzz-plugins.
| # The real binary moves aside; buzz-desktop becomes a shim AppRun.wrapped execs. | ||
| mv "$APP_BIN" "$APP_BIN.bin" | ||
| cat > "$APP_BIN" <<'SHIM' | ||
| #!/usr/bin/env bash |
There was a problem hiding this comment.
nit (non-blocking): the shim adds a hard runtime dep on bash + readlink -f (coreutils). Both are universally present on the distros we target so I wouldn't hold anything on this, but a POSIX-sh shim would be marginally more portable if you feel like it.
There was a problem hiding this comment.
Keeping Bash intentionally here: the blocking process-name fix relies on Bash's exec -a, which POSIX sh does not provide portably. bash and readlink -f remain available on the Linux distributions we target.
| # silently ship — so fail loudly (mirrors the libwayland guard above). | ||
| APPRUN_WRAPPED="$WORKDIR/squashfs-root/AppRun.wrapped" | ||
| if ! grep -aq "GST_PLUGIN_SYSTEM_PATH_1_0" "$APPRUN_WRAPPED"; then | ||
| echo "Error: AppRun.wrapped no longer references GST_PLUGIN_SYSTEM_PATH_1_0 — GStreamer path injection changed; re-verify fix-appimage.sh" >&2 |
There was a problem hiding this comment.
nit (non-blocking): this guard also fires when AppRun.wrapped is missing entirely (grep's exit 2 under if ! — which is good, that's the right behavior), but then the message says the file "no longer references" the var when the file doesn't exist. Behavior's right, wording's slightly off — maybe cover both cases in the message.
There was a problem hiding this comment.
Addressed in 8f3003f. The guard now says AppRun.wrapped may be missing or may no longer reference the variable, covering both grep failure cases accurately.
Signed-off-by: Daniel Cadenas <dcadenas@gmail.com>
5297f9a to
8f3003f
Compare
Problem
The Linux AppImage opens a blank / fully transparent window on non-Debian
distros (Arch, Fedora, …): the transparent Tauri shell shows the desktop
through it because the WebKitWebProcess crashes (SIGABRT) during media-pipeline
init, logging:
The
.debis unaffected; only the AppImage is broken, and only offDebian/Ubuntu.
Root cause
Two things combine in
desktop/scripts/fix-appimage.sh(the CI post-buildstep):
AppRun.wrappedforce-setsGST_PLUGIN_SYSTEM_PATH_1_0=$APPDIR/usr/lib/gstreamer-1.0. A setGST_PLUGIN_SYSTEM_PATH_1_0replaces GStreamer's compiled-in defaultsearch path — it does not add to it.
fix-appimage.shpopulated$APPDIR/usr/lib/gstreamer-1.0as an absolutesymlink to the Debian multiarch path
/usr/lib/x86_64-linux-gnu/gstreamer-1.0,which only exists on Debian/Ubuntu — so on Arch/Fedora the symlink dangles.
Result on non-Debian: GStreamer searches only a nonexistent directory → zero
plugins →
appsink/appsrc/autoaudiosinkmissing → WebKit aborts → blankwindow. The old comment claimed a dangling symlink "safely falls back to
default discovery"; that is false — a set
GST_PLUGIN_SYSTEM_PATH_1_0disablesthe default.
(
fix-appimage.shalready strips the bundled GStreamer core libs so the appuses the host's GStreamer; the bug is purely that the plugin path was pinned
to a Debian-only location.)
Fix
Complete the script's existing "rely on the host's GStreamer" design. Instead
of pinning the plugin path to a hardcoded distro layout, install a small
launcher shim in front of the app binary that removes the bundle-pointing
GST_PLUGIN_*overrides afterAppRun.wrappedsets them, so the systemGStreamer resolves plugins via its own default path — correct on Debian, Arch,
and Fedora alike.
Why a shim and not just unsetting the var in
AppRun:AppRun.wrappedis acompiled binary that rewrites
GST_PLUGIN_SYSTEM_PATH_1_0after everyapprun-hook, discarding any value set before it (verified empirically — aruntime value passed in does not survive). The only place to neutralize the
override is between
AppRun.wrappedand the real binary, i.e. on the exectarget
usr/bin/buzz-desktop(moved aside tobuzz-desktop.bin).The shim only unsets values that point into the AppImage, so a user's own
GST_PLUGIN_*env is preserved. Fail-loud guards were added (verifyAppRun.wrappedstill injects the override; verify the app binary exists;refuse double-install) so a future tauri/linuxdeploy change is caught in CI,
not by users. Also removed a now-unused multiarch-detection block and renamed
the CI step.
Validation
Proven on Arch Linux (x86_64):
gst-inspect-1.0with the override pointed at the dangling Debian dir →appsink/appsrc/autoaudiosinkNOT FOUND; with it unset → all FOUND.(
AppRun → AppRun.wrapped → shim → app) against a fresh extract of theshipped AppImage: the forced override is stripped and the app process sees
all three elements.
bash -npasses on the script and the generated shim.Not yet tested (needs CI):
fix-appimage.shextract → repack → sign path locally (noappimagetoolon hand; the only local AppImage is already fix-processed,which the libwayland guard correctly refuses to re-process).
Files
desktop/scripts/fix-appimage.sh— shim replaces the dangling symlink;guards; corrected comments; removed unused multiarch block.
.github/workflows/release.yml— step name updated.