This workstation configures ONE Cargo target outside the checkouts for every worktree below the project directory. A build in any worktree therefore replaced the `qbz` another worktree had just built: a parallel session's release build in its own worktree replaced the binary under test in the main one. scripts/qt-target.py now decides where builds go. When the target Cargo resolves lies outside the worktree and nothing pins it (CARGO_TARGET_DIR or CARGO_BUILD_TARGET_DIR), the worktree builds in its own sibling directory, `<target>-worktrees/<worktree>`; rebuilding the same worktree still replaces its own binary. Cargo's default target inside the checkout (macOS, CI, Windows) and explicit overrides are untouched, and no machine path is committed. Two checkouts that share a directory name get a stable suffix instead of one target. qt-run.sh, the runtime gate and direct qt-cargo.py builds and tests all use it. qt-run.sh prints the target and the binary path, and re-points crates/target after each successful build, never over a real directory. The aarch64 scripts build into and install from the same target, and the qbzd acceptance script names the build command that lands its binary there. The first build of a profile in a new worktree target is seeded from the shared target with copy-on-write clones, skipping incremental caches: Cargo rewrites moved build-script paths through root-output (custom_build.rs, "rewrite paths if the target directory has been moved"), so unchanged crates are not compiled again and no data is duplicated. Without clone support nothing is copied and Cargo builds from scratch. The resolution and shortcut handling start from the uncommitted draft in the build-storage-layout worktree. Verified on the main worktree: seeded from the shared release target, Cargo found everything fresh in two seconds, and crates/target now points at the worktree's own target. 33 build-gate tests cover derivation, overrides, name collisions, linking, seeding and the runner end to end. cc
87 lines
4.0 KiB
Bash
Executable File
87 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# build-aarch64-qbzd.sh — build the Linux aarch64 (ARM64) `qbzd` daemon binary,
|
|
# e.g. for a Raspberry Pi 4 + HiFiBerry/USB DAC streamer.
|
|
#
|
|
# ── Why this is NOT build-aarch64-linux.sh ───────────────────────────────────
|
|
# That script builds the Qt desktop `qbz`, which needs a Qt >= 6.8 with private
|
|
# headers on the build host and cannot be cross-compiled with cross-rs (the
|
|
# target Qt's qmake has to run during the build). `qbzd` is the Qt-free and
|
|
# Slint-free column of the workspace: no UI crate, no fonts, no GPU libs. It
|
|
# builds in minutes on modest hardware and cross-compiles cleanly, so:
|
|
# • a 4 GB Pi CAN build it natively;
|
|
# • CROSS mode via cross-rs + crates/Cross.toml still works here;
|
|
# • the container caps are small.
|
|
#
|
|
# Two modes, auto-selected by host arch (same shape as the desktop script):
|
|
#
|
|
# 1. NATIVE (on aarch64 Linux: the Pi itself, an ARM VM/runner)
|
|
# 2. CROSS (on x86-64 Linux with Docker, via `cross`; crates/Cross.toml
|
|
# supplies the arm64 dev libs inside the image)
|
|
#
|
|
# Output: dist/qbzd-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/qbzd-aarch64-linux"
|
|
|
|
# Native deps for the DAEMON only. Audio (ALSA/JACK; PipeWire is reached through
|
|
# its ALSA shim), D-Bus for MPRIS, TLS, and the usual -sys toolchain. The GUI
|
|
# stack the desktop needs (fontconfig, freetype, xkbcommon, wayland, xcb, GL,
|
|
# EGL) is deliberately absent — qbzd links none of it.
|
|
DEPS=(
|
|
build-essential pkg-config cmake clang libclang-dev
|
|
libasound2-dev libjack-jackd2-dev
|
|
libdbus-1-dev libssl-dev
|
|
)
|
|
|
|
arch="$(uname -m)"
|
|
case "$arch" in
|
|
aarch64 | arm64)
|
|
echo "[qbzd-aarch64] 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 "[qbzd-aarch64] non-apt distro: install the equivalents of: ${DEPS[*]}" >&2
|
|
fi
|
|
# This worktree's own target (scripts/qt-target.py): Cargo's default in a
|
|
# plain checkout, a per-worktree sibling when the host shares one target.
|
|
CARGO_TARGET_DIR="$(python3 scripts/qt-target.py resolve)"
|
|
export CARGO_TARGET_DIR
|
|
( cd crates && cargo build --release -p qbzd )
|
|
install -Dm755 "$CARGO_TARGET_DIR/release/qbzd" "$OUT"
|
|
;;
|
|
x86_64 | amd64)
|
|
echo "[qbzd-aarch64] CROSS-compile from $arch via cross (Docker)"
|
|
if ! docker info >/dev/null 2>&1; then
|
|
echo "[qbzd-aarch64] ERROR: Docker is not running. cross needs it." >&2
|
|
exit 1
|
|
fi
|
|
command -v cross >/dev/null || cargo install cross --locked
|
|
# Modest caps: the heaviest qbzd rustc is a fraction of the desktop's, so
|
|
# this can be capped tightly and still never OOM. The point of the cap is
|
|
# the same as the desktop script's — a runaway gets killed instead of
|
|
# swap-thrashing this box (30 GB, no hibernation) into a hard freeze.
|
|
export CROSS_CONTAINER_OPTS="${CROSS_CONTAINER_OPTS:---memory=8g --memory-swap=12g}"
|
|
# crates/Cross.toml injects the arm64 dev libs into the image (the daemon's
|
|
# set; the Qt desktop is not cross-built, see build-aarch64-linux.sh).
|
|
# cross mounts CARGO_TARGET_DIR into the container: the worktree's own
|
|
# target here too, never one another worktree also builds into.
|
|
CARGO_TARGET_DIR="$(python3 scripts/qt-target.py resolve)"
|
|
export CARGO_TARGET_DIR
|
|
( cd crates && cross build --release --target "$TARGET" -p qbzd )
|
|
install -Dm755 "$CARGO_TARGET_DIR/$TARGET/release/qbzd" "$OUT"
|
|
;;
|
|
*)
|
|
echo "[qbzd-aarch64] ERROR: unsupported build host arch: $arch" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo "[qbzd-aarch64] done -> $OUT"
|
|
file "$OUT" || true
|