Files
peerspeak/packaging/appimage/README.md
T
mollusk f46b2cacc7 build(appimage): harden thin bundle workflow
Keep host multimedia libraries out of the AppImage, document the exact Ubuntu build inputs, and resolve Rust 1.97 release-gate warnings.
2026-08-14 18:05:00 -04:00

4.4 KiB

PeerSpeak AppImage

A "thin" AppImage: the peerspeak binary, the bundled pixelpass screen-share helper, a launcher (AppRun), and the desktop entry + icon. Run ./build-appimage.sh to produce peerspeak-<version>-x86_64.AppImage.

Why thin, and why pixelpass is bundled

PeerSpeak owns voice; pixelpass owns pixels. They are never Cargo dependencies of each other — peerspeak shells out to the pixelpass binary over its CLI. The AppImage co-locates pixelpass in usr/bin, and AppRun prepends usr/bin to PATH, so peerspeak's normal $PATH lookup finds it with no code change. Joe gets one file, and screen-share works out of the box.

Almost nothing is bundled: peerspeak's own assets (notification WAVs, avatar presets, window icon, fonts) are include_bytes!-embedded, and the graphics stack (libGL, libvulkan, libwayland-*, libxkbcommon, X11) is dlopen'd at runtime and on the AppImage excludelist because it must match the host driver. So the image carries just the two binaries plus a handful of small libs.

Host requirements

The AppImage runs on any reasonably current glibc-based distro that has:

  • A Vulkan-capable GPU + driver (peerspeak's iced/wgpu renderer). Mesa/RADV on AMD/Intel or the NVIDIA driver all work.
  • PipeWire with the PulseAudio shim, pactl, and the host libpulse.so.0 client library. The Pulse client stack is deliberately not bundled because PixelPass launches host GStreamer tools that must keep using the host's matching multimedia libraries.
  • For screen-share only — pixelpass shells out to these on the host PATH; it prints the exact package names for your distro if any are missing:
    • GStreamer + plugins (gst-launch-1.0/gst-inspect-1.0, base, good/bad/ugly, libav, and the PipeWire plugin),
    • mpv (or vlc) for the viewer side,
    • on X11, xwininfo for single-window capture.

On Arch/Artix that is one pacman line, e.g.:

sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad \
  gst-plugins-ugly gst-libav gst-plugin-pipewire mpv xorg-xwininfo libpulse

(Add gstreamer-vaapi for hardware H.264 encode on AMD/Intel; the software x264 path always works. On XLibre / X11 the capture path uses ximagesrc and needs no XDG portal — no systemd required.)

Building for broad compatibility (glibc baseline)

An AppImage requires a host glibc at least as new as the build host's. Built on a rolling distro (glibc 2.43) it only runs on equally-new systems. Build inside Ubuntu 24.04 (glibc 2.39, PipeWire 1.0.5) for wide reach — pixelpass's pipewire crate binds the system PipeWire headers and needs PipeWire >= 1.0, so the older Debian 12 peerspeak-bookworm box (PW 0.3.65) cannot build it. 2.39 covers Debian 13+, Fedora 40+, and current rolling distros.

# One-time: an Ubuntu 24.04 distrobox that reuses the host rustup toolchain.
distrobox create --yes --image ubuntu:24.04 --name peerspeak-appimage
distrobox enter peerspeak-appimage -- sudo apt-get update
distrobox enter peerspeak-appimage -- sudo apt-get install -y \
  build-essential cmake clang libclang-dev pkg-config \
  libpipewire-0.3-dev libspa-0.2-dev libpulse-dev libasound2-dev libxcb1-dev \
  curl ca-certificates file patchelf git
rustup toolchain install 1.97.1 --profile default

# PeerSpeak's ownership validator needs the modern SPA-JSON parser headers it
# is tested against. Distrobox exposes the host's headers under /run/host;
# pkg-config still links Ubuntu's older ABI-compatible libraries, preserving
# the glibc baseline. This checkout's verified host-header version is 1.6.8:
test -f /run/host/usr/include/spa-0.2/spa/utils/json-core.h

# Build with the repository's pinned Rust version (the host's ~/.rustup
# toolchain is glibc-2.17-baseline, so it runs in the box; isolated
# CARGO_TARGET_DIRs keep it off the host target/):
distrobox enter peerspeak-appimage -- env \
  PATH="$HOME/.rustup/toolchains/1.97.1-x86_64-unknown-linux-gnu/bin:$PATH" \
  SYSTEM_DEPS_LIBSPA_INCLUDE="/run/host/usr/include/spa-0.2" \
  SYSTEM_DEPS_LIBPIPEWIRE_INCLUDE="/run/host/usr/include/pipewire-0.3:/run/host/usr/include/spa-0.2" \
  ./packaging/appimage/build-appimage.sh

Caveats

  • Hardware encode (VAAPI) uses the host GPU driver and can't be bundled; the software x264 path always works.
  • The bundled pixelpass is built headless (no gui feature) — it is only ever driven by peerspeak, never launched standalone from this image.