# NetDesk — Linux build & packaging Build the native `netdesk-viewer` for Linux and bundle the two distributions **NetDesk by Akronlogic** ships on Linux: | Edition | Artifact | Install? | |--------------|-----------------------------------|----------------------------------------| | **AppImage** | `NetDesk--x86_64.AppImage` | No — `chmod +x` and run anywhere | | **.deb** | `netdesk__amd64.deb` | Yes — `apt install ./…` (launcher + icon) | Both are produced by [`packaging/build-linux.sh`](../packaging/build-linux.sh). Everything it writes lands in **`packaging/dist/linux/`** (git-ignored). This is the Linux counterpart of the Windows [`packaging/README.md`](../packaging/README.md). > This target must be **built on Linux** (x86_64). The viewer links the system > FFmpeg/VAAPI libraries for the Linux hardware-decode path > (`core/src/decode_vaapi.rs`), which are not present when cross-building from > Windows or macOS. --- ## 1. Build dependencies The Linux decode backend pulls in FFmpeg through the `ffmpeg-next` crate, whose build script (`ffmpeg-sys-next`) locates `libav*` with **pkg-config** and generates bindings with **libclang**. The GUI (eframe/egui on winit + glow) needs OpenGL at runtime. Install the toolchain + dev libraries first. ### Debian / Ubuntu ```bash sudo apt update sudo apt install -y build-essential clang pkg-config nasm \ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \ libavfilter-dev libavdevice-dev libswresample-dev \ libva-dev \ libgl1-mesa-dev ``` - `build-essential` → the C/C++ linker (`cc`/`g++`) Rust and `openh264-sys2` need. - `clang` → libclang for `ffmpeg-sys-next`'s bindgen. - `pkg-config` → locates the FFmpeg and VAAPI libraries. - `nasm` → assembler for the bundled `openh264` software-decode fallback. - `libav*-dev` → FFmpeg ≥ 4 development libraries (the full set matches the default features of `ffmpeg-next`). - `libva-dev` → VAAPI headers for the hardware-decode path. - `libgl1-mesa-dev` → OpenGL for the glow renderer. ### Fedora (FFmpeg dev libs come from RPM Fusion) ```bash sudo dnf install -y gcc gcc-c++ clang pkgconf-pkg-config nasm \ ffmpeg-devel libva-devel mesa-libGL-devel ``` ### Optional — native file-picker The viewer's **File transfer → Upload…** button uses `rfd`, which is compiled with **no Linux backend** in `viewer/Cargo.toml` (`default-features = false`). The build and the app run fine without it, but the picker is a no-op on Linux until `rfd` is given a backend feature: - **GTK 3** backend → add `features = ["gtk3"]` to `rfd`, then install `libgtk-3-dev` (build) / `libgtk-3-0` (runtime). - **XDG portal** backend (no GTK) → add `features = ["xdg-portal", "tokio"]`; needs a running `xdg-desktop-portal` at runtime, nothing extra at build. This is the only reason `libgtk` is ever involved on Linux — it is **not** required to build or run NetDesk as shipped. --- ## 2. The one command ```bash export PATH="$HOME/.cargo/bin:$PATH" # ensure cargo/rustup are reachable packaging/build-linux.sh ``` That runs `cargo build --release -p netdesk-viewer` (target `x86_64-unknown-linux-gnu`) and then produces **both** the `.deb` and the AppImage in `packaging/dist/linux/`: ``` packaging/dist/linux/ ├── netdesk_0.1.0_amd64.deb ← dpkg package (launcher + hicolor icons) ├── NetDesk-0.1.0-x86_64.AppImage ← portable single file ├── com.akronlogic.netdesk.desktop (generated launcher, shared by both) ├── AppDir/ (AppImage staging) └── deb/ (.deb staging tree) ``` > The underlying build command on its own: > ```bash > cargo build --release -p netdesk-viewer --target x86_64-unknown-linux-gnu > ``` ### Flags | Flag | Effect | |-----------------------|----------------------------------------------------| | `--skip-build` | reuse an existing `target/.../release/netdesk-viewer` | | `--no-appimage` | build the `.deb` only | | `--no-deb` | build the AppImage only | | `--target ` | override the Rust target (default `x86_64-unknown-linux-gnu`) | | `LINUXDEPLOY=/path` | env: use a local `linuxdeploy` instead of downloading it | The AppImage step downloads **linuxdeploy** once (cached in `packaging/dist/.tools/`) and runs it with `APPIMAGE_EXTRACT_AND_RUN=1`, so it works in containers/CI without FUSE. linuxdeploy `ldd`-scans the binary and bundles its shared libraries (`libavcodec`, `libavutil`, `libswscale`, …) into the AppImage; `libGL`, `libX11`/`xcb`, Wayland and `libva` are intentionally **not** bundled — they are `dlopen()`ed and must come from the host graphics stack. The `.deb` instead declares those as package `Depends:`. --- ## 3. VAAPI hardware-decode note NetDesk hardware-decodes the host's H.264 stream on Linux through **VAAPI via FFmpeg/libavcodec** (`core/src/decode_vaapi.rs`): it opens the libavcodec H.264 decoder with a VAAPI `hw_device_ctx` on the default DRI render node (`/dev/dri/renderD128`), decodes on the GPU, pulls the surface to system memory (NV12), crops to the true display size, and swscales to the packed RGB8 `Frame` the viewer paints — see [`cross-platform-decode.md`](cross-platform-decode.md) for the full backend matrix. **Hardware decode is optional at runtime.** `best_decoder()` tries VAAPI first and **falls back to the openh264 software decoder** if no usable VAAPI device is present, so headless / GPU-less boxes still work. VAAPI is a build dependency (the libraries must link) but not a runtime requirement. To get the hardware path at runtime on the target machine: 1. **Install a VAAPI driver** (the `.deb` lists these as `Recommends`): - Intel (Broadwell+): `intel-media-va-driver` (iHD) - Intel (older): `i965-va-driver` - AMD / others (Mesa): `mesa-va-drivers` (radeonsi) 2. **Verify it:** `vainfo` should list an `H264` decode profile (e.g. `VAProfileH264High : VAEntrypointVLD`). Install `vainfo` from `libva-utils`. 3. **Render-node access:** the user must be able to read `/dev/dri/renderD128` — typically by membership of the `render` (or `video`) group. 4. **Driver override (if needed):** `export LIBVA_DRIVER_NAME=iHD` (or `i965`, `radeonsi`) when autodetection picks the wrong driver. Confirm which path is live from the viewer's log: ``` decode: VAAPI H.264 (FFmpeg hardware) ← hardware path selected VAAPI init failed (...); using openh264 ... ← fell back to software ``` If it fell back, check `vainfo`, the `/dev/dri/renderD128` permissions, and `LIBVA_DRIVER_NAME`. --- ## 4. Troubleshooting - **`libavcodec` not found via pkg-config / bindgen errors** — the FFmpeg dev libraries or `clang` are missing. Re-run the install command in §1. For FFmpeg in a non-standard prefix, set `PKG_CONFIG_PATH`. - **`openh264` build fails for want of an assembler** — install `nasm`. - **AppImage not produced** (linuxdeploy download/FUSE error) — the script warns and still writes the `.deb`. Supply a local tool with `LINUXDEPLOY=/path`, or run with `--no-appimage`. `APPIMAGE_EXTRACT_AND_RUN=1` is already exported for FUSE-less hosts. - **`.deb` won't install — unmet FFmpeg dependency** — soname package names differ per release; the control file lists `libavcodec60 | 59 | 58 | ffmpeg` (and likewise for `libavutil`/`libswscale`). On an unusual release, installing the distro `ffmpeg` package satisfies the catch-all. - **Wrong window/taskbar icon on GNOME/Wayland** — the launcher file name and its `Icon=` key both use the app-id `com.akronlogic.netdesk`, matching the viewer's `with_app_id(...)`; for the `.deb`, `gtk-update-icon-cache` runs in `postinst`. Log out/in if the shell cached the old icon. --- ## 5. Test ```bash vainfo # confirm a VAAPI driver + H264 profile (optional) cargo test -p netdesk-core # core decode/transport tests ./packaging/dist/linux/NetDesk-*.AppImage # smoke-test the viewer ``` Smoke-test end to end against a live host; the log line `decode: VAAPI H.264 (FFmpeg hardware)` confirms the hardware path was selected.