diff options
| -rw-r--r-- | .gitignore | 4 | ||||
| -rwxr-xr-x | packaging/build-remote.sh | 33 | ||||
| -rw-r--r-- | packaging/remote.local.example | 31 | ||||
| -rwxr-xr-x | packaging/setup-distcc.sh | 114 | ||||
| -rwxr-xr-x | packaging/start-unbox | 9 |
5 files changed, 177 insertions, 14 deletions
@@ -7,6 +7,10 @@ compile_commands.json prompts/ reports/ +# machine/network specifics for the remote-build helpers (template is committed: +# packaging/remote.local.example). Never commit real hosts/IPs. +packaging/remote.local + # meson subprojects: keep wraps + our patch files, ignore downloaded sources subprojects/* !subprojects/*.wrap diff --git a/packaging/build-remote.sh b/packaging/build-remote.sh index b522284..3c55bcc 100755 --- a/packaging/build-remote.sh +++ b/packaging/build-remote.sh @@ -1,39 +1,44 @@ #!/usr/bin/env bash -# build-on-builder.sh — build the unbox pacman package on the fast box (builder) -# and install it here on the slow CF-AX3. +# build-remote.sh — build the unbox pacman package on a fast remote builder and +# install it here on the slow target. # -# 1. rsync the working tree to builder:~/unbox -# 2. makepkg -s there (installs build deps via sudo ON builder — you'll be +# 1. rsync the working tree to $REMOTE_HOST:~/$REMOTE_DIR +# 2. makepkg -s there (installs build deps via sudo ON the builder — you'll be # prompted for that machine's sudo password) -# 3. scp the built .pkg.tar.zst back to /tmp here +# 3. scp the built .pkg.tar.zst back to $PKGOUT here # 4. pacman -U here (you'll be prompted for THIS machine's sudo password) # -# Re-runnable: edit code, run again. Safe to Ctrl-C. +# Builder details come from the gitignored packaging/remote.local (template: +# remote.local.example). Re-runnable; safe to Ctrl-C. set -euo pipefail -REMOTE="${REMOTE:-builder}" -REMOTE_DIR="${REMOTE_DIR:-unbox}" # ~/unbox on builder -LOCAL_REPO="${LOCAL_REPO:-/home/user/projects/unbox}" +HERE="$(cd "$(dirname "$0")" && pwd)" +LOCAL_REPO="$(cd "$HERE/.." && pwd)" # repo root (this script lives in packaging/) +# shellcheck disable=SC1091 +[ -f "$HERE/remote.local" ] && . "$HERE/remote.local" +: "${REMOTE_HOST:?set REMOTE_HOST (see packaging/remote.local.example)}" +REMOTE_DIR="${REMOTE_DIR:-unbox}" PKGOUT="${PKGOUT:-/tmp/unbox-pkg}" -echo "==> [1/4] Sync source -> $REMOTE:$REMOTE_DIR" +echo "==> [1/4] Sync source -> $REMOTE_HOST:$REMOTE_DIR" rsync -az --info=progress2 \ --exclude 'build*/' \ --exclude '.git/' \ --exclude '.cache/' \ + --exclude 'packaging/remote.local' \ --exclude 'packaging/src/' \ --exclude 'packaging/pkg/' \ --exclude 'packaging/*.pkg.tar.zst' \ - "$LOCAL_REPO/" "$REMOTE:$REMOTE_DIR/" + "$LOCAL_REPO/" "$REMOTE_HOST:$REMOTE_DIR/" -echo "==> [2/4] Build package on $REMOTE (installs makedeps via its sudo)" +echo "==> [2/4] Build package on $REMOTE_HOST (installs makedeps via its sudo)" # -t: give makepkg a tty so the remote sudo password prompt works. # -Cf: -C cleans $srcdir first (no stale build dir -> subproject options like # toml++ default_library=static always apply), -f overwrites the package. # Then verify the packaged binary links NO shared toml (extract to a real file; # readelf cannot read a non-seekable pipe). Abort loudly if it still does. -ssh -t "$REMOTE" " +ssh -t "$REMOTE_HOST" " set -e cd '$REMOTE_DIR/packaging' makepkg -sCf --noconfirm @@ -49,7 +54,7 @@ ssh -t "$REMOTE" " echo "==> [3/4] Ferry the built package back -> $PKGOUT" mkdir -p "$PKGOUT" -scp "$REMOTE:$REMOTE_DIR/packaging/unbox-*.pkg.tar.zst" "$PKGOUT/" +scp "$REMOTE_HOST:$REMOTE_DIR/packaging/unbox-*.pkg.tar.zst" "$PKGOUT/" PKG="$(ls -t "$PKGOUT"/unbox-*.pkg.tar.zst | head -1)" if [ -z "$PKG" ]; then diff --git a/packaging/remote.local.example b/packaging/remote.local.example new file mode 100644 index 0000000..9505a55 --- /dev/null +++ b/packaging/remote.local.example @@ -0,0 +1,31 @@ +# remote.local.example — template for the remote-builder settings. +# +# These are machine/network specifics and are deliberately NOT committed. To use +# the remote-build helpers (setup-distcc.sh, build-remote.sh), copy this file and +# fill in your own values: +# +# cp packaging/remote.local.example packaging/remote.local +# $EDITOR packaging/remote.local # packaging/remote.local is gitignored +# +# Prerequisites on a NEW set of systems: +# * A fast "builder" box reachable over a private network (Tailscale/WireGuard/ +# LAN), with the SAME gcc version as this machine (distcc plain mode requires +# matching compilers), passwordless SSH from here, and sudo on the builder. +# * `distcc` (and `ccache`) installed on BOTH machines. +# Then run: packaging/setup-distcc.sh + +# SSH host/alias of the fast remote builder. +REMOTE_HOST=builder.example.ts.net + +# Private IP of the remote builder (Tailscale/WireGuard/LAN). distccd binds +# (--listen) ONLY to this address, so it is never exposed on public interfaces. +REMOTE_TS=100.64.0.2 + +# Private IP of THIS machine. distccd will --allow ONLY this address. +LOCAL_TS=100.64.0.1 + +# Parallel compile slots the remote offers (roughly its CPU core count). +REMOTE_JOBS=16 + +# (Optional) working dir name created in the builder's home for build-remote.sh. +REMOTE_DIR=unbox diff --git a/packaging/setup-distcc.sh b/packaging/setup-distcc.sh new file mode 100755 index 0000000..e22ed54 --- /dev/null +++ b/packaging/setup-distcc.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# setup-distcc.sh — make C/C++ compilation transparently offload to a fast remote +# builder, so a plain `ninja`/`meson test` (and any tool/agent that builds) farms +# compile jobs out automatically, falling back to local when the remote is down. +# +# It works by: +# * LOCAL : ccache prefix_command=distcc (~/.config/ccache/ccache.conf) + +# distcc host list (~/.distcc/hosts). These are read by ccache/distcc +# regardless of shell, so the offload needs NO env vars and is fully +# transparent (no shell-init, no per-build flags). +# * REMOTE: a locked-down distccd (systemd) bound to the private interface, +# accepting ONLY this machine. +# ccache hits stay local/instant; only real compiles go remote; preprocessing and +# linking always run locally. +# +# ---- Setup on a NEW network / set of systems -------------------------------- +# 1. On BOTH machines: install distcc (+ ccache) and ensure the SAME gcc +# version (distcc plain mode requires matching compilers). +# 2. Ensure passwordless SSH from here to the builder, and sudo on the builder. +# 3. cp packaging/remote.local.example packaging/remote.local # fill in IPs +# 4. packaging/setup-distcc.sh +# Re-runnable and idempotent. Output is tee'd to $LOG. +# ----------------------------------------------------------------------------- + +set -uo pipefail + +HERE="$(cd "$(dirname "$0")" && pwd)" +# Machine/network specifics live in the gitignored packaging/remote.local +# (template: remote.local.example). Env vars override the file. +# shellcheck disable=SC1091 +[ -f "$HERE/remote.local" ] && . "$HERE/remote.local" +: "${REMOTE_HOST:?set REMOTE_HOST (see packaging/remote.local.example)}" +: "${REMOTE_TS:?set REMOTE_TS — remote builder private IP}" +: "${LOCAL_TS:?set LOCAL_TS — this machine's private IP}" +: "${REMOTE_JOBS:=16}" +PORT="${PORT:-3632}" + +LOG=/tmp/distcc-setup.log +: > "$LOG" +exec > >(tee -a "$LOG") 2>&1 + +echo "######## distcc setup $(date -Is) ########" +echo "remote_host=$REMOTE_HOST remote_ip=$REMOTE_TS local_ip=$LOCAL_TS jobs=$REMOTE_JOBS port=$PORT" +echo + +# ---- 1. local config: transparent for every build tool ---------------------- +echo "==> [1/4] local ccache + distcc config" +mkdir -p "$HOME/.config/ccache" "$HOME/.distcc" +cat > "$HOME/.config/ccache/ccache.conf" <<EOF +# On a cache MISS, ccache compiles through distcc (hosts in ~/.distcc/hosts). +# Read for every ccache invocation regardless of shell, so distributed builds +# are transparent. Falls back to local if the remote is unreachable. +prefix_command = distcc +EOF +cat > "$HOME/.distcc/hosts" <<EOF +# Remote builder (private network), then local fallback/overflow. Read when the +# DISTCC_HOSTS env var is unset (so non-login/automated builds use it too). +${REMOTE_TS}/${REMOTE_JOBS},lzo +localhost/4 +EOF +echo " wrote ~/.config/ccache/ccache.conf and ~/.distcc/hosts" +echo + +# ---- 2. push the locked-down daemon config to the builder -------------------- +echo "==> [2/4] copy distccd config to $REMOTE_HOST:/tmp" +tmpconf="$(mktemp)"; tmpoverride="$(mktemp)" +cat > "$tmpconf" <<EOF +# Managed by packaging/setup-distcc.sh +DISTCC_ARGS="--allow ${LOCAL_TS}/32 --listen ${REMOTE_TS} --port ${PORT} --jobs ${REMOTE_JOBS} --nice 5 --log-level warning" +EOF +cat > "$tmpoverride" <<'EOF' +[Unit] +After=tailscaled.service +[Service] +Restart=on-failure +RestartSec=2 +EOF +scp -q "$tmpconf" "$REMOTE_HOST:/tmp/distccd.conf" && echo " ok: distccd.conf" || { echo " SCP FAILED"; exit 1; } +scp -q "$tmpoverride" "$REMOTE_HOST:/tmp/distccd-override.conf" && echo " ok: override.conf" || { echo " SCP FAILED"; exit 1; } +rm -f "$tmpconf" "$tmpoverride" +echo + +# ---- 3. install + enable distccd on the builder (sudo there) ----------------- +echo "==> [3/4] install + enable distccd on $REMOTE_HOST (sudo prompt on the builder)" +ssh -t "$REMOTE_HOST" ' + set -e + sudo install -m644 /tmp/distccd.conf /etc/conf.d/distccd + sudo mkdir -p /etc/systemd/system/distccd.service.d + sudo install -m644 /tmp/distccd-override.conf /etc/systemd/system/distccd.service.d/override.conf + rm -f /tmp/distccd.conf /tmp/distccd-override.conf + sudo systemctl daemon-reload + sudo systemctl enable --now distccd + sudo systemctl restart distccd + sleep 1 + echo "----- systemctl status -----"; systemctl --no-pager --full status distccd | head -6 + echo "----- listening socket -----"; sudo ss -tlnp | grep ":'"$PORT"'" || echo "NOT LISTENING (FAIL)" +' +echo + +# ---- 4. verify offload from this box ---------------------------------------- +echo "==> [4/4] verify offload" +echo "--- ccache prefix_command ---"; ccache -p 2>/dev/null | grep -i prefix_command +echo "--- distcc hosts (from file, env unset) ---"; env -u DISTCC_HOSTS distcc --show-hosts 2>&1 +td="$(mktemp -d)" +printf '#include <vector>\nint main(){std::vector<int> v(8); return (int)v.size()-8;}\n' > "$td/probe.cpp" +DISTCC_VERBOSE=1 distcc g++ -O2 -std=c++23 -c "$td/probe.cpp" -o "$td/probe.o" 2>"$td/v.txt"; rc=$? +grep -iE "compiled on|exec on|locally|failed to distribute" "$td/v.txt" | head +if [ $rc -eq 0 ] && [ -f "$td/probe.o" ] && ! grep -qiE "running locally|failed to distribute" "$td/v.txt"; then + echo "RESULT: OK — probe compiled on the remote builder." +else + echo "RESULT: probe did NOT offload (built locally) — check the daemon/network." +fi +rm -rf "$td" +echo "######## done — full log: $LOG ########" diff --git a/packaging/start-unbox b/packaging/start-unbox index d90a2f6..eb0c235 100755 --- a/packaging/start-unbox +++ b/packaging/start-unbox @@ -7,4 +7,13 @@ # makes PipeWire spam RTKit "ServiceUnknown" warnings. # # Usage: from a TTY, run start-unbox +# +# Wallpaper: unbox has no built-in wallpaper, so we draw one with swaybg (a +# wlr-layer-shell client on the background layer) via unbox's -s startup hook. +# It runs only if the image exists; put your image at the path below (a real file +# or a symlink), or override with UNBOX_WALLPAPER=/path/to/image. +WALLPAPER="${UNBOX_WALLPAPER:-$HOME/.config/unbox/wallpaper}" +if [ -f "$WALLPAPER" ]; then + exec dbus-run-session -- unbox -s "swaybg -i '$WALLPAPER' -m fill" +fi exec dbus-run-session -- unbox |
