From cac82d13dffd35e5e84b23b55693cb3a87e34163 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 25 Jul 2026 13:19:33 +0200 Subject: [PATCH] ci: check the client for aarch64 on every push Adds a `rust-arm64` job: clippy -D warnings for the client crates at --target aarch64-unknown-linux-gnu, plus a --no-default-features session build so the minimal embedded configuration keeps compiling in its own right rather than only as a subset of the default one. Runs in the cross image on the ordinary amd64 runner; client crates are listed explicitly because --workspace would drag in the x86-only host encode stack. This is a regression guard, not an artifact leg (deb.yml ships those). c_char signedness cuts both ways and neither direction is visible from an x86-only CI: hardcoding i8 fails to COMPILE on ARM, while casting to u8 fails the LINT on ARM. Two such defects were already found this way. Also documents the arm64 client .deb recipe in packaging/debian/README.md. Co-Authored-By: Claude Opus 5 (1M context) --- .gitea/workflows/ci.yml | 47 ++++++++++++++++++++++++++++++++++++++ packaging/debian/README.md | 22 ++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 87ff9baa..19af2119 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -108,6 +108,53 @@ jobs: git diff --exit-code include/punktfunk_core.h \ || (echo "include/punktfunk_core.h is stale — commit the regenerated header" && exit 1) + # The client stack cross-checked for aarch64. NOT an artifact job — deb.yml ships those — + # this exists so a portability defect fails here instead of surfacing in a release build or + # on a user's board. It earns its runtime: the bug that motivated it (a Vulkan extension + # array typed `*const i8`, where `c_char` is signed on x86_64 and UNSIGNED on aarch64) + # compiled cleanly on every target CI built at the time. + # + # Client crates only, listed explicitly: the host's encode stack is x86 (NVENC/QSV/AMF) and + # `--workspace` would drag it in. Runs in the cross image (amd64 toolchain + arm64 sysroot, + # ci/rust-ci-arm64cross.Dockerfile) on the ordinary runner — no arm64 runner involved. + rust-arm64: + runs-on: ubuntu-24.04 + container: + image: git.unom.io/unom/punktfunk-rust-ci-arm64cross:latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + + - name: Cache keys + run: echo "rustc=$(rustc --version | cut -d' ' -f2)" >> "$GITHUB_ENV" + - uses: actions/cache@v4 + with: + path: | + /usr/local/cargo/registry + /usr/local/cargo/git + key: cargo-home-${{ hashFiles('Cargo.lock') }} + restore-keys: cargo-home- + - uses: actions/cache@v4 + with: + path: target + # Its OWN prefix: aarch64 artifacts must never share the amd64 jobs' target cache. + key: cargo-target-arm64-v1-${{ env.rustc }}-${{ hashFiles('Cargo.lock') }} + restore-keys: cargo-target-arm64-v1-${{ env.rustc }}- + + - name: Clippy for aarch64 (deny warnings) + run: | + cargo clippy --target aarch64-unknown-linux-gnu --all-targets --locked \ + -p punktfunk-core -p pf-client-core -p pf-presenter -p pf-console-ui \ + -p punktfunk-client-session -p punktfunk-client-linux \ + -- -D warnings + + # The minimal embedded build — no Skia, no PyroWave — is what a small image installs, so + # it has to keep compiling on its own, not just as a subset of the default features. + - name: Build the session binary, minimal features + run: | + cargo build --release --target aarch64-unknown-linux-gnu --locked \ + -p punktfunk-client-session --no-default-features + web: runs-on: ubuntu-24.04 container: diff --git a/packaging/debian/README.md b/packaging/debian/README.md index ce0f495f..12ddae5b 100644 --- a/packaging/debian/README.md +++ b/packaging/debian/README.md @@ -171,3 +171,25 @@ docker run --rm -v "$PWD:/src" -w /src pf-noble \ `BUNDLE_FFMPEG=1` needs `patchelf` and an FFmpeg install at `FFMPEG_PREFIX` (default `/opt/ffmpeg`, which the noble image provides). + +### The arm64 client `.deb` + +The **client** also ships for arm64 (`punktfunk-client__arm64.deb`, published to the same +apt distribution — the registry keys pool entries by architecture, so an arm64 box needs no extra +configuration). There is no arm64 **host** package: the Linux host encodes with NVENC/QSV/AMF, all +x86. + +It is cross-compiled on an ordinary amd64 machine in `ci/rust-ci-arm64cross.Dockerfile` — the +rust-ci toolchain plus an Ubuntu ports arm64 multiarch sysroot. No arm64 runner is involved: + +```sh +docker build -f ci/rust-ci-arm64cross.Dockerfile -t pf-arm64cross . # repo-root context +docker run --rm -v "$PWD:/w" -w /w pf-arm64cross \ + bash -lc 'VERSION=0.0.1 ARCH=arm64 TARGET=aarch64-unknown-linux-gnu \ + bash packaging/debian/build-client-deb.sh' +``` + +`TARGET` moves the binaries to `target//release`; `ARCH` sets the package's +`Architecture:` field. Set both — one without the other builds an amd64 binary into a package +labelled arm64, or vice versa. `dpkg-shlibdeps` reads the arm64 sonames straight out of the +multiarch sysroot, so `Depends:` comes out right with no manual list.