Skip to content

Commit 55bf786

Browse files
authored
feat(tmachine): build local RPM artifacts (#4651)
* fix(tmachine): link libstdc++ statically and verify static musl binaries On macOS hosts, the aarch64 musl openshell-prover that build-artifacts-binaries produced was not static. z3-sys asks for a dynamic libstdc++ (-Wl,-Bdynamic -lstdc++), and the musl cross compiler wrapper resolved libstdc++.so. The result was a static executable with a DT_NEEDED entry for libstdc++.so.6 and no interpreter, which crashed during C++ static initialization. The local Debian package from #4598 ships this prover without running it. Build the musl binaries with CXXSTDLIB=static:-bundle=stdc++ so z3-sys requests a static libstdc++. CXXSTDLIB applies to every target and Darwin has no libstdc++, so set it only on this musl build rather than in the shared toolchain environment. The bundled form, static=stdc++, fails because rustc cannot find libstdc++.a on its own search path. Run tasks/scripts/verify-static-binary.sh on the musl CLI, sandbox and prover, as the release does, so a binary that is not fully static fails the local build. Signed-off-by: Evan Lezar <elezar@nvidia.com> * feat(tmachine): build local RPM artifacts Add build-artifacts-rpm, which builds the CLI and gateway RPMs that tmachine's rpm installer expects at artifacts/packages/rpm/openshell.rpm and artifacts/packages/rpm/openshell-gateway.rpm. It runs `packit build locally` with openshell.spec in the Fedora 44 image that build-rpm.yml uses, for the host's Linux architecture, and packages the binaries staged by build-artifacts-binaries. The package version defaults to the development version that branch E2E CI computes. The aggregate build-artifacts app runs the RPM step after the DEB step. Signed-off-by: Evan Lezar <elezar@nvidia.com> --------- Signed-off-by: Evan Lezar <elezar@nvidia.com>
1 parent b58e24c commit 55bf786

3 files changed

Lines changed: 123 additions & 1 deletion

File tree

‎TESTING.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,21 @@ mise run e2e:podman
335335
host's Linux architecture (`arm64` or `amd64`). Set `OPENSHELL_DEB_VERSION` to
336336
override the default package version, `0.0.0-local`.
337337

338+
It also builds `artifacts/packages/rpm/openshell.rpm` and
339+
`artifacts/packages/rpm/openshell-gateway.rpm` for tmachine's `rpm` installer.
340+
The RPM step runs `packit build locally` with `openshell.spec` in the Fedora
341+
container that CI uses, so it needs a Docker daemon that runs Linux containers
342+
for the host's architecture (`aarch64` or `x86_64`), such as Docker Desktop on
343+
macOS. The package version defaults to the development version that branch CI
344+
computes; set `OPENSHELL_RPM_VERSION` and `OPENSHELL_RPM_RELEASE` to override
345+
it. After `nix run .#build-artifacts-binaries`, `nix run .#build-artifacts-rpm`
346+
rebuilds only the RPMs. Run conformance against the installed RPMs:
347+
348+
```shell
349+
nix run .#build-artifacts
350+
nix run .#tmachine -- test fedora-podman-rootful rpm conformance
351+
```
352+
338353
Run the portable subset in a disposable rootless Podman guest:
339354

340355
```shell

‎flake.nix‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@
165165
type = "app";
166166
program = "${artifacts.deb}/bin/build-artifacts-deb";
167167
};
168+
build-artifacts-rpm = {
169+
type = "app";
170+
program = "${artifacts.rpm}/bin/build-artifacts-rpm";
171+
};
168172
build-artifacts-test-archives = {
169173
type = "app";
170174
program = "${artifacts.testArchives}/bin/build-artifacts-test-archives";

‎tests/artifacts.nix‎

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,20 +214,34 @@ rec {
214214
binaries = pkgs.writeShellApplication {
215215
name = "build-artifacts-binaries";
216216
runtimeInputs = [
217+
pkgs.binutils-unwrapped
217218
pkgs.coreutils
219+
pkgs.file
220+
pkgs.gawk
218221
pkgs.git
222+
pkgs.gnugrep
223+
pkgs.gnused
219224
rustToolchain
220225
];
221226
runtimeEnv = toolchainEnv;
222227
text = ''
223228
root=$(git rev-parse --show-toplevel)
224229
cd "$root"
225230
226-
cargo build --target ${muslToolchain.target} \
231+
# z3-sys links libstdc++ dynamically unless CXXSTDLIB says otherwise, and
232+
# the musl binaries must be fully static. CXXSTDLIB applies to every
233+
# target, so set it only for the musl build: Darwin has no libstdc++.
234+
CXXSTDLIB=static:-bundle=stdc++ cargo build --target ${muslToolchain.target} \
227235
-p openshell-cli \
228236
-p openshell-sandbox \
229237
-p openshell-prover-cli
230238
239+
# Fail as the release does if a musl binary is not fully static.
240+
tasks/scripts/verify-static-binary.sh \
241+
target/${muslToolchain.target}/debug/openshell \
242+
target/${muslToolchain.target}/debug/openshell-sandbox \
243+
target/${muslToolchain.target}/debug/openshell-prover
244+
231245
cargo build --target ${gnuToolchain.target} \
232246
-p openshell-gateway \
233247
-p openshell-supervisor
@@ -431,6 +445,93 @@ rec {
431445
'';
432446
};
433447

448+
# Build the CLI and gateway RPMs the way .github/workflows/build-rpm.yml does:
449+
# `packit build locally` with openshell.spec in the same Fedora image, packaging
450+
# the binaries staged by build-artifacts-binaries. The container runs on the
451+
# host's Linux architecture, so the RPMs match the tmachine guest.
452+
rpm = pkgs.writeShellApplication {
453+
name = "build-artifacts-rpm";
454+
runtimeInputs = [
455+
pkgs.coreutils
456+
pkgs.docker-client
457+
pkgs.git
458+
pkgs.python3
459+
];
460+
text = ''
461+
root=$(git rev-parse --show-toplevel)
462+
cd "$root"
463+
464+
# Keep in sync with the container image in .github/workflows/build-rpm.yml.
465+
image=docker.io/library/fedora:44@sha256:43b29f65a41eb9c35e1cd5323e3bdf3b655c2357a9f4f1ff2f9c2798e5045d80
466+
output_dir="$root/artifacts/packages/rpm"
467+
# Default to the development version that branch E2E CI computes.
468+
rpm_version="''${OPENSHELL_RPM_VERSION:-$(python3 tasks/scripts/release.py get-version --dev --rpm-version)}"
469+
rpm_release="''${OPENSHELL_RPM_RELEASE:-$(python3 tasks/scripts/release.py get-version --dev --rpm-release)}"
470+
471+
for binary in \
472+
artifacts/binaries/${muslToolchain.target}/openshell \
473+
artifacts/binaries/${gnuToolchain.target}/openshell-gateway \
474+
artifacts/binaries/${muslToolchain.target}/openshell-prover; do
475+
if [[ ! -x "$binary" ]]; then
476+
echo "missing $binary; run build-artifacts-binaries first" >&2
477+
exit 1
478+
fi
479+
done
480+
481+
mkdir -p "$output_dir"
482+
rm -f "$output_dir"/*.rpm
483+
484+
# Packit archives the files git tracks, so build from a fresh repository
485+
# holding the checkout's tracked and untracked, non-ignored files.
486+
git ls-files -z --cached --others --exclude-standard \
487+
| docker run --rm -i \
488+
--platform linux/${dockerArch} \
489+
--volume "$root:/repo:ro" \
490+
--volume "$root/artifacts/binaries/${muslToolchain.target}/openshell:/binaries/openshell:ro" \
491+
--volume "$root/artifacts/binaries/${gnuToolchain.target}/openshell-gateway:/binaries/openshell-gateway:ro" \
492+
--volume "$root/artifacts/binaries/${muslToolchain.target}/openshell-prover:/binaries/openshell-prover:ro" \
493+
--volume "$output_dir:/out" \
494+
--volume openshell-rpm-cargo:/root/.cargo/registry \
495+
--volume openshell-rpm-dnf:/var/cache/libdnf5 \
496+
--env OPENSHELL_RPM_VERSION="$rpm_version" \
497+
--env OPENSHELL_RPM_RELEASE="$rpm_release" \
498+
--env OPENSHELL_PREBUILT_BINARIES_DIR=/binaries \
499+
--env HOST_UID="$(id -u)" \
500+
--env HOST_GID="$(id -g)" \
501+
"$image" \
502+
bash -euo pipefail -c '
503+
dnf install -y --setopt=keepcache=1 \
504+
packit rpm-build \
505+
cargo cargo-rpm-macros git-core \
506+
pandoc python3-devel systemd-rpm-macros tar
507+
508+
mkdir /build
509+
tar -C /repo --null --files-from=- --ignore-failed-read -cf - \
510+
| tar -C /build -xf -
511+
cd /build
512+
git init -q
513+
git add -A
514+
git -c user.name=local -c user.email=local@localhost \
515+
commit -q -m "Local OpenShell RPM build"
516+
517+
packit build locally
518+
519+
cli_rpms=(/build/*/openshell-[0-9]*.rpm)
520+
gateway_rpms=(/build/*/openshell-gateway-[0-9]*.rpm)
521+
if [[ ''${#cli_rpms[@]} -ne 1 || ''${#gateway_rpms[@]} -ne 1 ]]; then
522+
echo "expected exactly one CLI and one gateway RPM" >&2
523+
exit 1
524+
fi
525+
install -m 0644 "''${cli_rpms[0]}" "''${gateway_rpms[0]}" /out/
526+
install -m 0644 "''${cli_rpms[0]}" /out/openshell.rpm
527+
install -m 0644 "''${gateway_rpms[0]}" /out/openshell-gateway.rpm
528+
chown "$HOST_UID:$HOST_GID" /out/*.rpm
529+
'
530+
531+
ls -l "$output_dir"
532+
'';
533+
};
534+
434535
helm = pkgs.writeShellApplication {
435536
name = "build-artifacts-helm";
436537
runtimeInputs = [
@@ -452,6 +553,7 @@ rec {
452553
binaries
453554
vmDriver
454555
deb
556+
rpm
455557
testArchives
456558
images
457559
helm
@@ -460,6 +562,7 @@ rec {
460562
build-artifacts-binaries
461563
build-artifacts-vm-driver
462564
build-artifacts-deb
565+
build-artifacts-rpm
463566
build-artifacts-test-archives
464567
build-artifacts-images
465568
build-artifacts-helm

0 commit comments

Comments
 (0)