#!/usr/bin/env bash # Build a "thin" PeerSpeak AppImage that also bundles the pixelpass screen-share # helper. # # PeerSpeak is an iced/wgpu GUI app; pixelpass is the separate screen-share # orchestrator peerspeak shells out to (never a Cargo dependency). Both link # almost nothing — the graphics stack (libGL, libvulkan, wayland, xkbcommon, # X11) is dlopen'd at runtime and is on the AppImage excludelist because it must # match the host driver, and pixelpass's capture/encode tools (gst-launch-1.0, # pactl, mpv) are expected on the host PATH. So the AppImage carries just the two # binaries plus their handful of non-excludelisted libs. The custom AppRun # prepends usr/bin to PATH so peerspeak's own $PATH lookup finds the bundled # pixelpass, while the host's tools stay reachable. # # All runtime assets (notification WAVs, avatar presets, window icon, fonts) are # include_bytes!-embedded in the peerspeak binary, so nothing else is bundled. # # Usage: packaging/appimage/build-appimage.sh # Output: packaging/appimage/peerspeak--x86_64.AppImage # # Build inside an Ubuntu 24.04 distrobox (glibc 2.39, PipeWire 1.0.5) for broad # reach — pixelpass's `pipewire` crate needs PipeWire >= 1.0 headers, so the # older peerspeak-bookworm box (PW 0.3.65) cannot build it. The 2.39 baseline # covers Debian 13+, Fedora 40+, and all current rolling distros. See README.md. set -euo pipefail here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo="$(cd "$here/../.." && pwd)" tools="$here/.tools" appdir="$here/AppDir" mkdir -p "$tools" # linuxdeploy is itself an AppImage; run it without FUSE so this works in a # container / on CI without libfuse2. export APPIMAGE_EXTRACT_AND_RUN=1 VERSION="$(grep -m1 '^version' "$repo/Cargo.toml" | sed -E 's/.*"(.*)".*/\1/')" export VERSION # Isolated target dirs so an old-glibc box build never clobbers the host target/. cache="${PEERSPEAK_APPIMAGE_CACHE:-$HOME/.cache/peerspeak-appimage}" ps_target="$cache/peerspeak-target" pp_target="$cache/pixelpass-target" # The pixelpass screen-share helper we bundle. Sibling checkout by default. pixelpass_repo="${PIXELPASS_REPO:-$repo/../pixelpass}" if [ ! -d "$pixelpass_repo" ]; then echo "!! pixelpass repo not found at $pixelpass_repo (set PIXELPASS_REPO)" >&2 exit 1 fi echo ">> building peerspeak (release)" ( cd "$repo" && CARGO_TARGET_DIR="$ps_target" cargo build --release ) ps_bin="$ps_target/release/peerspeak" # Headless pixelpass: peerspeak drives it via `--host`/viewer + `--output json`, # never its GUI, so the default (no `gui` feature) keeps the GL toolkit out. echo ">> building pixelpass (release, headless) from $pixelpass_repo" ( cd "$pixelpass_repo" && CARGO_TARGET_DIR="$pp_target" cargo build --release ) pp_bin="$pp_target/release/pixelpass" echo ">> fetching linuxdeploy" ld="$tools/linuxdeploy-x86_64.AppImage" if [ ! -x "$ld" ]; then curl -fL --retry 3 -o "$ld" \ "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage" chmod +x "$ld" fi echo ">> assembling AppDir" rm -rf "$appdir" mkdir -p "$appdir/usr/bin" install -m755 "$ps_bin" "$appdir/usr/bin/peerspeak" install -m755 "$pp_bin" "$appdir/usr/bin/pixelpass" echo ">> running linuxdeploy (bundles libs, builds the AppImage)" # -e (repeated): analyse both binaries for libraries to bundle; excludelisted # graphics/glibc libs are skipped. -d/-i: desktop entry + icon. # --custom-apprun: our launcher that puts the bundled pixelpass on PATH. ( cd "$here" && OUTPUT="peerspeak-${VERSION}-x86_64.AppImage" "$ld" \ --appdir "$appdir" \ -e "$appdir/usr/bin/peerspeak" \ -e "$appdir/usr/bin/pixelpass" \ -d "$repo/packaging/peerspeak.desktop" \ -i "$repo/assets/icons/peerspeak-256.png" \ --icon-filename peerspeak \ --custom-apprun "$here/AppRun" \ --output appimage ) echo ">> done: $here/peerspeak-${VERSION}-x86_64.AppImage"