From b9e7f44ed7bc57653e2ba43bdb2fdca15bc23161 Mon Sep 17 00:00:00 2001 From: bong-water-water-bong Date: Sat, 24 Oct 2026 10:25:21 -0300 Subject: [PATCH 1/2] package: every shipped program must resolve its NEEDED libraries the way a user runs it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-10-23 rc shipped `hrx/llama/bin/llama-perplexity` without `libllama-perplexity-impl.so`: the tool never started, and anything that used it failed at launch rather than at build time. Two things in the stage made that possible, and both are fixed here. - **The implementation library is built.** `cmake/hrx.cmake`'s HRX build targeted `llama-server llama-bench` only, so the impl library for `llama-perplexity` did not exist to be packed. `llama-perplexity` joins the target list, so the next package carries both halves. - **The stage now refuses to ship a program it cannot load.** `pack_prune_unloadable()` drops a program whose NEEDED libraries do not resolve from the package and the system, with a line saying so, instead of shipping a binary that fails at first use; `pack_artifact_hygiene()` reports any that remain, so a package cannot quietly pass with one. The resolve check runs the way a user launches the binary: **plain `ldd` with no `LD_LIBRARY_PATH`**, so only the ELF's own RUNPATH and the system are consulted. A library path inherited from the build shell resolves against the build tree and would hide exactly this defect. Proof on a copy of the rc (no program run): ``` # as shipped, on this box: it resolves *through a RUNPATH into the build cache*, which no user has libllama-perplexity-impl.so => /home/bcloud/.cache/hw-gate/build-685489b587/bin/libllama-perplexity-impl.so RUNPATH starts at: /home/bcloud/.cache/hw-gate/build-685489b587/bin # with that RUNPATH removed β€” the shape the next package ships in, $ORIGIN only libllama-perplexity-impl.so => not found libllama-common.so.0 => not found # the gate catches it 1bit/hrx/llama/bin/llama-perplexity: libllama-perplexity-impl.so 1bit/hrx/llama/bin/llama-perplexity: libllama-common.so.0 (…) # and the stage drops the program rather than shipping it broken drop 1bit/hrx/llama/bin/llama-perplexity: needs a library the package does not carry 1 program(s) dropped as unloadable β†’ gate on the pruned tree: clean ``` This is for the next package, not the rc: the rc keeps the defect it was cut with. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) --- cmake/hrx.cmake | 2 +- scripts/pack-elf.sh | 31 +++++++++++++++++++++++++++++++ scripts/package-linux.sh | 3 +++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/cmake/hrx.cmake b/cmake/hrx.cmake index 3e559d68..fbe882d5 100644 --- a/cmake/hrx.cmake +++ b/cmake/hrx.cmake @@ -143,7 +143,7 @@ ExternalProject_Add(llama_hrx "-DCMAKE_C_FLAGS=${ONEBIT_HRX_PATH_MAP_FLAGS}" "-DCMAKE_CXX_FLAGS=${ONEBIT_HRX_PATH_MAP_FLAGS}" ${_hrx_gpu_private_args} - BUILD_COMMAND ${CMAKE_COMMAND} --build --target llama-server llama-bench + BUILD_COMMAND ${CMAKE_COMMAND} --build --target llama-server llama-bench llama-perplexity INSTALL_COMMAND "" BUILD_ALWAYS ON USES_TERMINAL_BUILD ON) diff --git a/scripts/pack-elf.sh b/scripts/pack-elf.sh index f067212e..4e34445b 100644 --- a/scripts/pack-elf.sh +++ b/scripts/pack-elf.sh @@ -86,6 +86,34 @@ pack_localize() { done } +# A program or library ships only if every library it NEEDs resolves the way it will on a user's machine: +# plain ldd, with **no** LD_LIBRARY_PATH, so only the ELF's own RUNPATH and the system are consulted. A +# library path inherited from the build shell resolves against the build tree and hides exactly the defect +# this check exists for. Prints ": " for each NEEDED that cannot be found. +pack_unresolved_needed() { + local stage=$1 f + while IFS= read -r -d '' f; do + pack_is_dynelf "$f" || continue + env -u LD_LIBRARY_PATH ROCR_VISIBLE_DEVICES=-1 ldd "$f" 2>/dev/null | + awk -v f="$f" '$2 == "=>" && $3 == "not" {print f": "$1}' + done < <(find "$stage" -type f -print0) +} + +# A thin binary whose implementation library was not built has to leave the package rather than ship broken +# (the 2026-10-23 rc shipped llama-perplexity without libllama-perplexity-impl.so). Removing the binary is +# the safe direction: the tool is then absent instead of failing at first use. +pack_prune_unloadable() { + local stage=$1 bad dropped=0 + while IFS= read -r line; do + bad=${line%%:*} + [ -f "$bad" ] || continue + echo " drop $(echo "$bad" | sed "s|^$stage/||"): needs a library the package does not carry" + rm -f "$bad" + dropped=$((dropped+1)) + done < <(pack_unresolved_needed "$stage") + [ "$dropped" = 0 ] || echo " $dropped program(s) dropped as unloadable" +} + pack_strip() { local f while IFS= read -r -d '' f; do @@ -116,6 +144,9 @@ $f: embedded build-machine path" grep -E "^/" | grep -vE "^(${ONEBIT_TOOLCHAIN_ROOT:-/opt/rocm-therock})/" | grep -q . && out="$out\n$f: absolute RUNPATH outside the toolchain root" done < <(find "$1" -type f -print0) + # every shipped program and library must resolve what it links against + while IFS= read -r line; do out="$out\n$line: a NEEDED library is not in the package or on the machine"; done \ + < <(pack_unresolved_needed "$1") [ -z "$out" ] || printf "%b\n" "$out" } diff --git a/scripts/package-linux.sh b/scripts/package-linux.sh index d66923cb..f095e490 100755 --- a/scripts/package-linux.sh +++ b/scripts/package-linux.sh @@ -97,6 +97,9 @@ pack_localize "$stage" "$build" # engine binary at the top of the tree is the one it does not visit (depth 1), so drop its rpath here. patchelf --remove-rpath "$stage/1bit" +# a program whose implementation library was not built leaves the package instead of shipping broken +pack_prune_unloadable "$stage" + # symbol tables and debug info out of every program and library: the release ships compiled code # only (docs/releases.md, "Private components"); the dynamic symbols they link by stay pack_strip "$stage" From e6f2333da4fffb0f7e2ea28eba9d42e912f5bfdc Mon Sep 17 00:00:00 2001 From: bong-water-water-bong Date: Sat, 24 Oct 2026 11:00:19 -0300 Subject: [PATCH 2/2] package: take every tool from the build being packaged, and fail when one cannot load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-10-23 rc shipped `hrx/llama/bin/llama-perplexity` with RUNPATH entries into `/home/bcloud/.cache/hw-gate/build-685489b587/…` and without `libllama-perplexity-impl.so`: the binary came from a hardware-gate build, not from the build being packaged, so it carries that build's paths and is missing the part that build never produced. It failed at first use, and the KLD rows that used it failed with it. Four checks, each catching one step of that: - **`pack_require_provenance `** β€” every ELF in the stage must exist at the same relative path under the build being packaged and be byte-identical to it. A tool copied in from another tree fails here, before anything else looks at it. - **`pack_require_tools `** β€” the programs the release promises (`llama-server`, `llama-bench`, `llama-perplexity`, the three ds4 binaries) must be in the package and must resolve; otherwise the package stops instead of quietly losing a tool. - **`pack_unresolved_needed `** β€” plain `ldd`, **no** `LD_LIBRARY_PATH`, so only the ELF's own RUNPATH and the system count, which is how a user launches it. - **`pack_artifact_hygiene`** β€” additionally fails on an absolute RUNPATH outside the toolchain root (that is what points into a build machine), and `pack_prune_unloadable` drops any incidental ELF that cannot load. And the tool now exists in the package build: `cmake/hrx.cmake` builds `llama-perplexity` alongside `llama-server` and `llama-bench`, so its implementation library is produced and ships beside it with `$ORIGIN`. Measured against the rc (copy, no program run): ``` # provenance, with the rc build tree as the build being packaged hrx/llama/bin/llama-perplexity is not in the build being packaged ← the defect, named # the promised tools, once the build-machine RUNPATH is gone (the next package's shape) libllama-perplexity-impl.so => not found 1bit/hrx/llama/bin/llama-perplexity: libllama-perplexity-impl.so ← gate drop 1bit/hrx/llama/bin/llama-perplexity: needs a library the package does not carry ``` This is for the next package; the rc keeps the defect it was cut with. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) --- scripts/pack-elf.sh | 64 ++++++++++++++++++++++++++++++++++++++++ scripts/package-linux.sh | 13 +++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/scripts/pack-elf.sh b/scripts/pack-elf.sh index 4e34445b..7e3b3c6e 100644 --- a/scripts/pack-elf.sh +++ b/scripts/pack-elf.sh @@ -99,6 +99,70 @@ pack_unresolved_needed() { done < <(find "$stage" -type f -print0) } +# Everything in the package has to come from the build being packaged. A binary copied in from another tree +# (a hardware-gate cache, a drop) carries that tree's RUNPATH and its build's missing parts: in the 2026-10-23 +# rc, `llama-perplexity` came from a hardware-gate build and pointed at that build's directory. Compares each +# staged file with the same relative path under the build and reports what has no counterpart there. +pack_require_provenance() { # + local stage=$1 build=$2 f rel bad=0 + while IFS= read -r -d '' f; do + pack_is_elf "$f" || continue + rel=${f#"$stage"/} + if [ ! -f "$build/$rel" ]; then + echo " $rel is not in the build being packaged" + bad=1 + elif ! cmp -s "$f" "$build/$rel"; then + echo " $rel differs from the build being packaged" + bad=1 + fi + done < <(find "$stage" -type f -print0) + return $bad +} + +# The programs `put` was asked for are the ones the release promises: if one of them cannot resolve, that is a +# build problem (the tool came from another tree, or its implementation library was not built) and the package +# has to fail rather than quietly lose the tool. Call once per directory group: pack_require_tools +# . +pack_require_tools() { + local stage=$1 rel=$2 f bad=0 + shift 2 + for f in "$@"; do + if [ ! -f "$stage/$rel/$f" ]; then + echo " missing from the package: $rel/$f" + bad=1 + continue + fi + while IFS= read -r line; do + echo " $rel/$f cannot load: ${line##*: }" + bad=1 + done < <(pack_unresolved_needed "$stage" | grep -F "$stage/$rel/$f:") + done + return $bad +} + +# Everything in the package has to come from the build being packaged. A binary copied in from another tree +# (a hardware-gate cache, a drop) carries that tree's RUNPATH and its build's missing parts: in the 2026-10-23 +# rc, `llama-perplexity` came from a hardware-gate build and pointed at that build's directory. Compares each +# staged file with the same relative path under the build and reports what has no counterpart there. +pack_require_provenance() { # + local stage=$1 build=$2 f rel bad=0 + while IFS= read -r -d '' f; do + pack_is_elf "$f" || continue + rel=${f#"$stage"/} + if [ ! -f "$build/$rel" ]; then + echo " $rel is not in the build being packaged" + bad=1 + elif ! cmp -s "$f" "$build/$rel"; then + echo " $rel differs from the build being packaged" + bad=1 + fi + done < <(find "$stage" -type f -print0) + return $bad +} + +# The programs `put` was asked for are the ones the release promises: if one of them cannot resolve, that is a +# build problem (the tool came from another tree, or its implementation library was not built) and the package +# has to fail rather than quietly lose the tool. Prints the offending programs. # A thin binary whose implementation library was not built has to leave the package rather than ship broken # (the 2026-10-23 rc shipped llama-perplexity without libllama-perplexity-impl.so). Removing the binary is # the safe direction: the tool is then absent instead of failing at first use. diff --git a/scripts/package-linux.sh b/scripts/package-linux.sh index f095e490..4c2d5963 100755 --- a/scripts/package-linux.sh +++ b/scripts/package-linux.sh @@ -97,7 +97,18 @@ pack_localize "$stage" "$build" # engine binary at the top of the tree is the one it does not visit (depth 1), so drop its rpath here. patchelf --remove-rpath "$stage/1bit" -# a program whose implementation library was not built leaves the package instead of shipping broken +# every program the release promises has to load from the package; one that does not is a build problem, not +# something to drop silently (the 2026-10-23 rc shipped llama-perplexity without its implementation library) +tools_bad="" +tools_bad+=$(pack_require_tools "$stage" hrx/llama/bin llama-server llama-bench llama-perplexity || true) +tools_bad+=$(pack_require_tools "$stage" ds4/hip ds4-server ds4 ds4-bench || true) +[ -z "$tools_bad" ] || { echo "shipped tools that cannot load:"; echo "$tools_bad"; exit 1; } + +# everything shipped has to come from the build being packaged +provenance_bad=$(pack_require_provenance "$stage" "$build" || true) +[ -z "$provenance_bad" ] || { echo "files that did not come from this build:"; echo "$provenance_bad"; exit 1; } + +# anything else that cannot load leaves the package rather than shipping broken pack_prune_unloadable "$stage" # symbol tables and debug info out of every program and library: the release ships compiled code