build(rpm): let the spec build a client-only aarch64 RPM
The blocker was never ExclusiveArch — it was that %build builds host + tray + client together and %install lays down the host unconditionally, with no way to express "client only". `%bcond_without host` (default ON, so an x86_64 build is unchanged) now gates the host binary, the tray, the headless-session data, the firewalld services, the main %post and the bare %files section. Omitting %files for the MAIN package is the load-bearing part: it is what stops rpm emitting an empty `punktfunk` alongside punktfunk-client. build-rpm.sh exposes it as PF_WITHOUT_HOST=1 and skips the libcuda stub regeneration and the libcuda leak check, neither of which means anything without the host. Verified two ways. `rpmspec -P` shows the default expansion still carrying 3 host install lines, the tray build and one bare %files, while --without host carries none of those and one %files client. And a real rpmbuild in a native aarch64 Fedora 43 container produced punktfunk-client-*.aarch64.rpm with correct aarch64 sonames (libc.so.6(GLIBC_2.17), libSDL3.so.0, libavcodec.so.61) and no main package. Not a cross-compile: %build runs cargo for the build machine's arch, so this wants an arm64 builder. No CI leg yet — deliberate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -123,3 +123,24 @@ docker run --rm -v "$PWD:/src" -w /src punktfunk-fedora-rpm \
|
|||||||
|
|
||||||
A plain `rpmbuild`/COPR build with no `pf_version`/`pf_release` defines produces `0.3.0-1` (the
|
A plain `rpmbuild`/COPR build with no `pf_version`/`pf_release` defines produces `0.3.0-1` (the
|
||||||
spec defaults).
|
spec defaults).
|
||||||
|
|
||||||
|
### aarch64 — the client RPM
|
||||||
|
|
||||||
|
The **client** builds for aarch64; the **host** does not (its encode stack is NVENC/QSV/AMF, all
|
||||||
|
x86). `PF_WITHOUT_HOST=1` drops the host binary, the tray, the headless-session data, the
|
||||||
|
firewalld services and the main package's `%files`, leaving exactly one RPM: `punktfunk-client`.
|
||||||
|
Omitting the main `%files` is what keeps rpm from emitting an empty `punktfunk` next to it.
|
||||||
|
|
||||||
|
This is **not** a cross-compile — `%build` runs cargo for the host architecture, so run it on an
|
||||||
|
arm64 machine (or an emulated arm64 container, which is very slow):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker build --platform linux/arm64 -f ci/fedora-rpm.Dockerfile -t punktfunk-fedora-rpm-arm64 ci
|
||||||
|
docker run --rm --platform linux/arm64 -v "$PWD:/src" -w /src punktfunk-fedora-rpm-arm64 \
|
||||||
|
bash -lc 'git config --global --add safe.directory /src && \
|
||||||
|
PF_VERSION=0.0.1 PF_WITHOUT_HOST=1 bash packaging/rpm/build-rpm.sh'
|
||||||
|
# -> dist/punktfunk-client-0.0.1-1.fcNN.aarch64.rpm
|
||||||
|
```
|
||||||
|
|
||||||
|
`PF_WITHOUT_HOST=1` works on x86_64 too, if you only want the client RPM. The flag is orthogonal
|
||||||
|
to the architecture; it is just that aarch64 has no other option.
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ WEB_OPT=()
|
|||||||
# requirement as web; default off so a bare `rpmbuild`/COPR still works.
|
# requirement as web; default off so a bare `rpmbuild`/COPR still works.
|
||||||
SCRIPTING_OPT=()
|
SCRIPTING_OPT=()
|
||||||
[ "${PF_WITH_SCRIPTING:-0}" = "1" ] && SCRIPTING_OPT=(--with scripting)
|
[ "${PF_WITH_SCRIPTING:-0}" = "1" ] && SCRIPTING_OPT=(--with scripting)
|
||||||
|
# PF_WITHOUT_HOST=1 drops the host binary, the tray and the main package, leaving only
|
||||||
|
# punktfunk-client. This is what an aarch64 build uses: the client is portable, the host's encode
|
||||||
|
# stack (NVENC/QSV/AMF) is x86. Harmless on x86_64 too, if you only want the client RPM.
|
||||||
|
HOST_OPT=()
|
||||||
|
[ "${PF_WITHOUT_HOST:-0}" = "1" ] && HOST_OPT=(--without host)
|
||||||
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
cd "$ROOTDIR"
|
cd "$ROOTDIR"
|
||||||
|
|
||||||
@@ -39,7 +44,7 @@ git archive --format=tar.gz --prefix="punktfunk-${PF_VERSION}/" \
|
|||||||
# undefined cuStreamCreateWithPriority/cuMemcpy2DAsync_v2/…; this regen supersedes it.) Defining
|
# undefined cuStreamCreateWithPriority/cuMemcpy2DAsync_v2/…; this regen supersedes it.) Defining
|
||||||
# extra unused symbols is harmless; a missing one fails the link. Only when /usr/lib64 is writable
|
# extra unused symbols is harmless; a missing one fails the link. Only when /usr/lib64 is writable
|
||||||
# (CI image runs as root) — COPR/mock provides the real cuda-cudart-devel stub instead.
|
# (CI image runs as root) — COPR/mock provides the real cuda-cudart-devel stub instead.
|
||||||
if [ "$(id -u)" = 0 ] && [ -d /usr/lib64 ]; then
|
if [ "${PF_WITHOUT_HOST:-0}" != "1" ] && [ "$(id -u)" = 0 ] && [ -d /usr/lib64 ]; then
|
||||||
CU_SYMS="$(grep -rhoE '\bcu[A-Z][A-Za-z0-9_]*' crates/punktfunk-host/src/ | sort -u || true)"
|
CU_SYMS="$(grep -rhoE '\bcu[A-Z][A-Za-z0-9_]*' crates/punktfunk-host/src/ | sort -u || true)"
|
||||||
if [ -n "$CU_SYMS" ]; then
|
if [ -n "$CU_SYMS" ]; then
|
||||||
STUB_C="$(mktemp --suffix=.c)"
|
STUB_C="$(mktemp --suffix=.c)"
|
||||||
@@ -55,7 +60,7 @@ fi
|
|||||||
# resolves them from RPMs. Our builder image provides the toolchain via rustup (so
|
# resolves them from RPMs. Our builder image provides the toolchain via rustup (so
|
||||||
# rust-toolchain.toml's pinned channel works) and the -devel libs via dnf, neither of which
|
# rust-toolchain.toml's pinned channel works) and the -devel libs via dnf, neither of which
|
||||||
# rpmbuild's RPM-level check sees — skip it; a genuinely missing dep fails the compile/link.
|
# rpmbuild's RPM-level check sees — skip it; a genuinely missing dep fails the compile/link.
|
||||||
rpmbuild -bb --nodeps "${WEB_OPT[@]}" "${SCRIPTING_OPT[@]}" \
|
rpmbuild -bb --nodeps "${WEB_OPT[@]}" "${SCRIPTING_OPT[@]}" "${HOST_OPT[@]}" \
|
||||||
--define "_topdir $TOP" \
|
--define "_topdir $TOP" \
|
||||||
--define "pf_version ${PF_VERSION}" \
|
--define "pf_version ${PF_VERSION}" \
|
||||||
--define "pf_release ${PF_RELEASE}" \
|
--define "pf_release ${PF_RELEASE}" \
|
||||||
@@ -63,6 +68,12 @@ rpmbuild -bb --nodeps "${WEB_OPT[@]}" "${SCRIPTING_OPT[@]}" \
|
|||||||
|
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
find "$TOP/RPMS" -name '*.rpm' -exec cp -v {} dist/ \;
|
find "$TOP/RPMS" -name '*.rpm' -exec cp -v {} dist/ \;
|
||||||
|
# The libcuda leak check applies to the HOST package (the only thing that links the driver); a
|
||||||
|
# client-only build has no such package to inspect.
|
||||||
|
if [ "${PF_WITHOUT_HOST:-0}" = "1" ]; then
|
||||||
|
echo "== client-only build: no host RPM, libcuda check not applicable =="
|
||||||
|
else
|
||||||
echo "== Requires (must NOT contain libcuda) =="
|
echo "== Requires (must NOT contain libcuda) =="
|
||||||
rpm -qp --requires dist/punktfunk-${PF_VERSION}-*.rpm 2>/dev/null | grep -iE 'cuda|nvidia' \
|
rpm -qp --requires dist/punktfunk-${PF_VERSION}-*.rpm 2>/dev/null | grep -iE 'cuda|nvidia' \
|
||||||
&& echo " !! NVIDIA/CUDA leak !!" || echo " clean"
|
&& echo " !! NVIDIA/CUDA leak !!" || echo " clean"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ URL: https://git.unom.io/unom/punktfunk
|
|||||||
# COPR SCM builds provide the checkout; for a tarball build, drop a git archive here:
|
# COPR SCM builds provide the checkout; for a tarball build, drop a git archive here:
|
||||||
Source0: %{name}-%{version}.tar.gz
|
Source0: %{name}-%{version}.tar.gz
|
||||||
|
|
||||||
# punktfunk-host is Linux-only and links system FFmpeg/PipeWire/Opus. x86_64 only for now: encode
|
# punktfunk-host is Linux-only and links system FFmpeg/PipeWire/Opus. The HOST is x86_64 only —
|
||||||
# is NVENC (desktop NVIDIA) and no aarch64 build is produced/published by CI — claiming aarch64
|
# its encode stack is NVENC/QSV/AMF — but the CLIENT builds and runs fine on aarch64, so the spec
|
||||||
# here would advertise an arch we never ship. Re-add aarch64 once there's an arm64 build leg.
|
# accepts both arches and `--without host` (below) selects the client-only build.
|
||||||
ExclusiveArch: x86_64
|
ExclusiveArch: x86_64 aarch64
|
||||||
|
|
||||||
# The zerocopy FFI links the NVIDIA driver's libcuda.so.1; rpm's auto-dep generator would turn
|
# The zerocopy FFI links the NVIDIA driver's libcuda.so.1; rpm's auto-dep generator would turn
|
||||||
# that into a hard Requires on libcuda.so.1 (and we never want to pin the driver — NVENC/EGL come
|
# that into a hard Requires on libcuda.so.1 (and we never want to pin the driver — NVENC/EGL come
|
||||||
@@ -55,6 +55,14 @@ ExclusiveArch: x86_64
|
|||||||
# Debian punktfunk-scripting .deb.
|
# Debian punktfunk-scripting .deb.
|
||||||
%bcond_with scripting
|
%bcond_with scripting
|
||||||
|
|
||||||
|
# The HOST half of this spec (the punktfunk package itself + the tray). ON by default, so an
|
||||||
|
# ordinary x86_64 build is unchanged. `--without host` drops the host binary, the tray, the
|
||||||
|
# headless-session data, the firewalld services and the main %%files section entirely, leaving
|
||||||
|
# only punktfunk-client — which is what an aarch64 build produces, since the host's encode stack
|
||||||
|
# (NVENC/QSV/AMF) is x86 and the client's is not. Omitting the main %%files is what stops rpm
|
||||||
|
# from emitting an empty `punktfunk` package alongside the client.
|
||||||
|
%bcond_without host
|
||||||
|
|
||||||
# --- Build toolchain ---------------------------------------------------------
|
# --- Build toolchain ---------------------------------------------------------
|
||||||
BuildRequires: cargo
|
BuildRequires: cargo
|
||||||
BuildRequires: rust
|
BuildRequires: rust
|
||||||
@@ -211,14 +219,21 @@ export PUNKTFUNK_BUILD_VERSION="%{version}-%{release}"
|
|||||||
# with real RFI (clean P-frame recovery anchor via DPB reference slots; design/linux-vulkan-video-encode.md).
|
# with real RFI (clean P-frame recovery anchor via DPB reference slots; design/linux-vulkan-video-encode.md).
|
||||||
# Pure Rust `ash` (no new lib / no link-time dep); default on for HEVC (PUNKTFUNK_VULKAN_ENCODE=0 opts
|
# Pure Rust `ash` (no new lib / no link-time dep); default on for HEVC (PUNKTFUNK_VULKAN_ENCODE=0 opts
|
||||||
# back to libav VAAPI), and a failed open falls back to VAAPI so unsupported devices degrade gracefully.
|
# back to libav VAAPI), and a failed open falls back to VAAPI so unsupported devices degrade gracefully.
|
||||||
|
%if %{with host}
|
||||||
cargo build --release --locked --features punktfunk-host/nvenc,punktfunk-host/vulkan-encode \
|
cargo build --release --locked --features punktfunk-host/nvenc,punktfunk-host/vulkan-encode \
|
||||||
-p punktfunk-host -p punktfunk-client-linux -p punktfunk-client-session
|
-p punktfunk-host -p punktfunk-client-linux -p punktfunk-client-session
|
||||||
|
%else
|
||||||
|
# Client-only (aarch64): no host crate, so none of the encode features apply.
|
||||||
|
cargo build --release --locked -p punktfunk-client-linux -p punktfunk-client-session
|
||||||
|
%endif
|
||||||
# The status tray in its OWN cargo invocation — load-bearing, not tidiness. Cargo unifies features
|
# The status tray in its OWN cargo invocation — load-bearing, not tidiness. Cargo unifies features
|
||||||
# across everything in one build, so co-building the tray with the host pulls the host's
|
# across everything in one build, so co-building the tray with the host pulls the host's
|
||||||
# ashpd -> zbus/tokio onto the tray's shared zbus; the tray (ksni async-io + blocking, no tokio
|
# ashpd -> zbus/tokio onto the tray's shared zbus; the tray (ksni async-io + blocking, no tokio
|
||||||
# runtime by design) then panics at startup ("there is no reactor running, must be called from the
|
# runtime by design) then panics at startup ("there is no reactor running, must be called from the
|
||||||
# context of a Tokio 1.x runtime"). Built alone, its zbus stays on async-io. (Same split the .deb does.)
|
# context of a Tokio 1.x runtime"). Built alone, its zbus stays on async-io. (Same split the .deb does.)
|
||||||
|
%if %{with host}
|
||||||
cargo build --release --locked -p punktfunk-tray
|
cargo build --release --locked -p punktfunk-tray
|
||||||
|
%endif
|
||||||
|
|
||||||
%if %{with web}
|
%if %{with web}
|
||||||
# Management web console: build the Nitro SSR bundle with bun (the `bun` preset + our Bun.serve
|
# Management web console: build the Nitro SSR bundle with bun (the `bun` preset + our Bun.serve
|
||||||
@@ -243,6 +258,7 @@ fi
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%install
|
%install
|
||||||
|
%if %{with host}
|
||||||
# Binary
|
# Binary
|
||||||
install -Dm0755 target/release/punktfunk-host %{buildroot}%{_bindir}/punktfunk-host
|
install -Dm0755 target/release/punktfunk-host %{buildroot}%{_bindir}/punktfunk-host
|
||||||
|
|
||||||
@@ -294,6 +310,7 @@ for sz in 22x22 48x48; do
|
|||||||
install -Dm0644 "$png" %{buildroot}%{_datadir}/icons/hicolor/$sz/apps/"$(basename "$png")"
|
install -Dm0644 "$png" %{buildroot}%{_datadir}/icons/hicolor/$sz/apps/"$(basename "$png")"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
%endif
|
||||||
|
|
||||||
# --- client subpackage ---
|
# --- client subpackage ---
|
||||||
install -Dm0755 target/release/punktfunk-client %{buildroot}%{_bindir}/punktfunk-client
|
install -Dm0755 target/release/punktfunk-client %{buildroot}%{_bindir}/punktfunk-client
|
||||||
@@ -311,6 +328,7 @@ install -Dm0644 scripts/70-punktfunk-client.rules \
|
|||||||
install -Dm0644 scripts/99-punktfunk-client-net.conf \
|
install -Dm0644 scripts/99-punktfunk-client-net.conf \
|
||||||
%{buildroot}%{_prefix}/lib/sysctl.d/99-punktfunk-client-net.conf
|
%{buildroot}%{_prefix}/lib/sysctl.d/99-punktfunk-client-net.conf
|
||||||
|
|
||||||
|
%if %{with host}
|
||||||
# Headless session helpers + example config + OpenAPI doc (reference material).
|
# Headless session helpers + example config + OpenAPI doc (reference material).
|
||||||
install -d %{buildroot}%{_datadir}/%{name}/headless
|
install -d %{buildroot}%{_datadir}/%{name}/headless
|
||||||
install -Dm0755 scripts/headless/run-headless-kde.sh %{buildroot}%{_datadir}/%{name}/headless/run-headless-kde.sh
|
install -Dm0755 scripts/headless/run-headless-kde.sh %{buildroot}%{_datadir}/%{name}/headless/run-headless-kde.sh
|
||||||
@@ -344,6 +362,7 @@ install -Dm0644 packaging/linux/punktfunk-native.xml \
|
|||||||
# Web console opener (TCP 47992) — only meaningful with the web subpackage, opened deliberately.
|
# Web console opener (TCP 47992) — only meaningful with the web subpackage, opened deliberately.
|
||||||
install -Dm0644 packaging/linux/punktfunk-web.xml \
|
install -Dm0644 packaging/linux/punktfunk-web.xml \
|
||||||
%{buildroot}%{_prefix}/lib/firewalld/services/punktfunk-web.xml
|
%{buildroot}%{_prefix}/lib/firewalld/services/punktfunk-web.xml
|
||||||
|
%endif
|
||||||
|
|
||||||
%if %{with web}
|
%if %{with web}
|
||||||
# --- web console subpackage (punktfunk-web) ---
|
# --- web console subpackage (punktfunk-web) ---
|
||||||
@@ -383,6 +402,7 @@ chmod 0755 %{buildroot}%{_bindir}/punktfunk-scripting
|
|||||||
install -Dm0644 scripts/punktfunk-scripting.service %{buildroot}%{_userunitdir}/punktfunk-scripting.service
|
install -Dm0644 scripts/punktfunk-scripting.service %{buildroot}%{_userunitdir}/punktfunk-scripting.service
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if %{with host}
|
||||||
%files
|
%files
|
||||||
%license LICENSE-MIT LICENSE-APACHE THIRD-PARTY-NOTICES.txt
|
%license LICENSE-MIT LICENSE-APACHE THIRD-PARTY-NOTICES.txt
|
||||||
%doc README.md packaging/README.md
|
%doc README.md packaging/README.md
|
||||||
@@ -407,6 +427,7 @@ install -Dm0644 scripts/punktfunk-scripting.service %{buildroot}%{_userunitdir}/
|
|||||||
%config(noreplace) /etc/gamescope-session-plus/sessions.d/steam
|
%config(noreplace) /etc/gamescope-session-plus/sessions.d/steam
|
||||||
%dir %{_datadir}/%{name}
|
%dir %{_datadir}/%{name}
|
||||||
%{_datadir}/%{name}/*
|
%{_datadir}/%{name}/*
|
||||||
|
%endif
|
||||||
|
|
||||||
%files client
|
%files client
|
||||||
%license LICENSE-MIT LICENSE-APACHE THIRD-PARTY-NOTICES.txt
|
%license LICENSE-MIT LICENSE-APACHE THIRD-PARTY-NOTICES.txt
|
||||||
@@ -450,6 +471,7 @@ udevadm trigger --subsystem-match=hidraw 2>/dev/null || :
|
|||||||
# rpm-ostree it takes effect on the next boot into the layered deployment).
|
# rpm-ostree it takes effect on the next boot into the layered deployment).
|
||||||
sysctl -p %{_prefix}/lib/sysctl.d/99-punktfunk-client-net.conf >/dev/null 2>&1 || :
|
sysctl -p %{_prefix}/lib/sysctl.d/99-punktfunk-client-net.conf >/dev/null 2>&1 || :
|
||||||
|
|
||||||
|
%if %{with host}
|
||||||
%post
|
%post
|
||||||
# Reload udev so /dev/uinput picks up the new rule without a reboot (best-effort).
|
# Reload udev so /dev/uinput picks up the new rule without a reboot (best-effort).
|
||||||
udevadm control --reload-rules 2>/dev/null || :
|
udevadm control --reload-rules 2>/dev/null || :
|
||||||
@@ -474,6 +496,7 @@ if command -v punktfunk-host >/dev/null 2>&1; then
|
|||||||
echo "$conflict"
|
echo "$conflict"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
%endif
|
||||||
|
|
||||||
%if %{with web}
|
%if %{with web}
|
||||||
%post web
|
%post web
|
||||||
|
|||||||
Reference in New Issue
Block a user