From b89ee385b3a21e655540afab64cd8885afd8deba Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Tue, 30 Jun 2026 15:26:37 -0600 Subject: [PATCH] build: aarch64 Linux build script (foundation for the Slint ARM workflow) Native (on an ARM runner: apt deps + cargo build -p qbz) and cross (from x86-64 via cross + Cross.toml arm64 sysroot) paths, auto-selected by host arch. Documents the ~30 GB qbz_ui RAM wall (8 GB Macs / 4 GB Pis cannot build natively). Cross path is best-effort/untested pending a first run. cc --- crates/Cross.toml | 24 ++++++++++ scripts/build-aarch64-linux.sh | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 crates/Cross.toml create mode 100755 scripts/build-aarch64-linux.sh diff --git a/crates/Cross.toml b/crates/Cross.toml new file mode 100644 index 000000000..1bbed59fb --- /dev/null +++ b/crates/Cross.toml @@ -0,0 +1,24 @@ +# cross (https://github.com/cross-rs/cross) config for cross-compiling the +# aarch64 `qbz` binary from an x86-64 Linux host. Used by +# scripts/build-aarch64-linux.sh (CROSS mode). +# +# The default cross image ships the aarch64 toolchain but NOT the native dev +# libs qbz links against, so we add the arm64 multiarch packages in pre-build. +# PKG_CONFIG_* is set so the build scripts resolve the :arm64 .pc files. +# +# NOTE: each pre-build entry is a single-line TOML string (no backslash +# continuations — those are only valid in TOML """multi-line""" strings). + +[target.aarch64-unknown-linux-gnu] +pre-build = [ + "dpkg --add-architecture arm64", + "apt-get update", + "apt-get install -y --no-install-recommends pkg-config cmake clang libclang-dev nasm libasound2-dev:arm64 libjack-jackd2-dev:arm64 libfontconfig1-dev:arm64 libfreetype-dev:arm64 libxkbcommon-dev:arm64 libwayland-dev:arm64 libxcb1-dev:arm64 libgl1-mesa-dev:arm64 libegl1-mesa-dev:arm64 libdbus-1-dev:arm64 libssl-dev:arm64", +] + +[target.aarch64-unknown-linux-gnu.env] +passthrough = [ + "PKG_CONFIG_ALLOW_CROSS=1", + "PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig", + "PKG_CONFIG_SYSROOT_DIR=/", +] diff --git a/scripts/build-aarch64-linux.sh b/scripts/build-aarch64-linux.sh new file mode 100755 index 000000000..584979bf9 --- /dev/null +++ b/scripts/build-aarch64-linux.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# +# build-aarch64-linux.sh — build the Linux aarch64 (ARM64) `qbz` binary, e.g. +# for a Raspberry Pi 4 / other ARM single-board boxes. +# +# ── READ FIRST: where can this run? ────────────────────────────────────────── +# The generated Slint crate `qbz_ui` compiles as ONE ~1.6M-line module whose +# single `rustc` needs ~30 GB RAM (RSS+swap). Consequences: +# • An 8 GB Mac or a 4 GB Pi CANNOT build it natively — it OOMs. Don't try. +# • Build on a box with >= ~16 GB RAM + swap (the wall is survivable at +# ~14 GB RAM + swap, proven on the dev box). +# +# This script has two modes, auto-selected by the host arch: +# +# 1. NATIVE (running ON aarch64 Linux: an ARM runner, an ARM VM, etc.) +# -> apt-installs the build deps and runs `cargo build --release -p qbz`. +# This is exactly what a future Slint aarch64 CI job runs — treat the +# dep list + build line below as the workflow's source of truth. +# +# 2. CROSS (running on x86-64 Linux with Docker, e.g. the dev box, 30 GB) +# -> uses `cross` (https://github.com/cross-rs/cross): a container with +# the aarch64 sysroot + the arm64 dev libs (see crates/Cross.toml) does +# the compile. Needs Docker running and ~30 GB RAM available to it. +# +# macOS is intentionally NOT a build host here: cross from macOS to +# linux-gnu means re-creating a full Linux sysroot for every native dep +# (ALSA, dbus, fontconfig, …). Run the CROSS mode on a Linux box instead. +# +# Output: dist/qbz-aarch64-linux (an aarch64 ELF — verify with `file`). +# ───────────────────────────────────────────────────────────────────────────── +set -euo pipefail + +cd "$(dirname "$0")/.." # repo root (qbz-nix) +REPO="$(pwd)" +TARGET="aarch64-unknown-linux-gnu" +OUT="$REPO/dist/qbz-aarch64-linux" + +# The Linux build deps for the Slint `qbz` binary (kept in sync with the CI +# workflows). PipeWire is reached through its ALSA/JACK compat shims, so only +# libasound2-dev + libjack-jackd2-dev are needed. +DEPS=( + build-essential pkg-config cmake clang libclang-dev mold nasm + libasound2-dev libjack-jackd2-dev + libfontconfig1-dev libfreetype-dev + libxkbcommon-dev libwayland-dev libxcb1-dev + libgl1-mesa-dev libegl1-mesa-dev + libdbus-1-dev libssl-dev +) + +arch="$(uname -m)" +case "$arch" in + aarch64 | arm64) + echo "[aarch64-build] NATIVE build on $arch" + if command -v apt-get >/dev/null; then + sudo apt-get update + sudo apt-get install -y --no-install-recommends "${DEPS[@]}" + else + echo "[aarch64-build] non-apt distro: install the equivalents of: ${DEPS[*]}" >&2 + fi + ( cd crates && cargo build --release -p qbz ) + install -Dm755 "crates/target/release/qbz" "$OUT" + ;; + x86_64 | amd64) + echo "[aarch64-build] CROSS-compile from $arch via cross (Docker)" + if ! docker info >/dev/null 2>&1; then + echo "[aarch64-build] ERROR: Docker is not running. cross needs it." >&2 + exit 1 + fi + command -v cross >/dev/null || cargo install cross --locked + # Cap the container's RAM so a runaway qbz_ui rustc gets OOM-killed + # (losing the build) instead of swap-thrashing the host into a hard freeze + # — the dev box has no hibernation and dies under memory pressure. Override + # via CROSS_CONTAINER_OPTS if your box has more headroom. + export CROSS_CONTAINER_OPTS="${CROSS_CONTAINER_OPTS:---memory=18g --memory-swap=26g}" + # Cross.toml (workspace root) injects the arm64 dev libs into the image. + ( cd crates && cross build --release --target "$TARGET" -p qbz ) + install -Dm755 "crates/target/$TARGET/release/qbz" "$OUT" + ;; + *) + echo "[aarch64-build] ERROR: unsupported build host arch: $arch" >&2 + exit 1 + ;; +esac + +echo "[aarch64-build] done -> $OUT" +file "$OUT" || true