From d4d5c3c2726fb529797be56e29f6030d9e5214d6 Mon Sep 17 00:00:00 2001 From: bong-water-water-bong Date: Sat, 24 Oct 2026 04:06:10 -0300 Subject: [PATCH 1/3] build: rewrite build-machine paths out of the binaries and gate the shipped artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three related packaging properties, all enforced rather than assumed: - **Path mapping.** `ONEBIT_PATH_MAP_FLAGS` (`-ffile-prefix-map` for the source tree and the build tree) is applied to every engine target and handed to the HRX llama.cpp build through `cmake/hrx.cmake`, so a string an assert or a log bakes in reads `.` / `build` instead of the machine that produced it. With `-DONEBIT_GPU_PRIVATE` the add-on checkout is mapped as well. - **Artifact hygiene gate.** `pack_artifact_hygiene()` (scripts/pack-elf.sh) reports any shipped program or library that still carries a compiler identification section, a path into a build machine, or an absolute RUNPATH; `scripts/package-linux.sh` fails the package when it reports anything. `pack_strip()` now also drops `.comment` (and the gold-version note) after `strip --strip-unneeded`. - **Relative RUNPATH.** Every shipped ELF gets `$ORIGIN` instead of whatever the build left, so a program loads its libraries from beside itself and from the system only — `ds4-server` included, which used to keep an SDK path. Verified on this box with a Release build of the `onebit` target: ``` $ strings -a 1bit | grep -cE '^/(home|Users|root)/' -> 0 $ readelf -p .comment 1bit -> GCC: (Ubuntu 16-…) $ source scripts/pack-elf.sh; pack_artifact_hygiene … -> 1bit: .comment names the compiler $ pack_strip …; patchelf --set-rpath '$ORIGIN' … -> gate: clean $ readelf -p .comment 1bit -> (no .comment) $ readelf -d 1bit | grep RUNPATH -> Library runpath: [$ORIGIN] ``` The HRX and NPU binaries take the same flags through the same two CMake entry points but were not built here (they need the toolchain), so they are covered by the gate on the next package run, not by this transcript. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- CMakeLists.txt | 10 ++++++++++ cmake/hrx.cmake | 10 ++++++++++ scripts/pack-elf.sh | 23 ++++++++++++++++++++++- scripts/package-linux.sh | 12 ++++++++++-- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1310d09c..8576f663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,16 @@ endif() set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Every string the build bakes in (asserts, log prefixes, __FILE__) has to name a path that exists in +# the package, not on the machine that built it: the shipped binaries are gated on it +# (scripts/pack-elf.sh, pack_artifact_hygiene). -ffile-prefix-map covers -fmacro-prefix-map and +# -fdebug-prefix-map on GCC and clang alike; ONEBIT_PATH_MAPS is also handed to the externals below. +set(ONEBIT_PATH_MAP_FLAGS + "-ffile-prefix-map=${CMAKE_SOURCE_DIR}=." + "-ffile-prefix-map=${CMAKE_BINARY_DIR}=build" + CACHE STRING "Compiler flags that rewrite build-machine paths out of embedded strings") +add_compile_options(${ONEBIT_PATH_MAP_FLAGS}) + # The public binary drop (docs/releases.md): prebuilt proprietary parts for a source build outside # the org. Sets ONEBIT_BINARY_DROP_* and verifies the drop; a no-op when ONEBIT_BINARY_DROP is unset. include(cmake/binary_drop.cmake) diff --git a/cmake/hrx.cmake b/cmake/hrx.cmake index 3d399bf6..3e559d68 100644 --- a/cmake/hrx.cmake +++ b/cmake/hrx.cmake @@ -34,6 +34,14 @@ include(ExternalProject) set(ONEBIT_HRX_TOOLCHAIN "/opt/rocm-therock" CACHE PATH "ROCm/TheRock root: its amdclang builds llama.cpp and HRX") +# The HRX binaries carry strings from this tree and, with -DONEBIT_GPU_PRIVATE, from the add-on +# checkout; both are rewritten so the shipped libraries name no build-machine path. +set(ONEBIT_HRX_PATH_MAP_FLAGS "-ffile-prefix-map=${CMAKE_SOURCE_DIR}=." + CACHE STRING "Path mapping for the HRX llama.cpp build") +if(ONEBIT_GPU_PRIVATE) + string(APPEND ONEBIT_HRX_PATH_MAP_FLAGS " -ffile-prefix-map=${ONEBIT_GPU_PRIVATE}=addon") +endif() + # A source build outside the org has no private HIP kernels to compile, so it links the prebuilt # HRX tree from the public binary drop instead (docs/releases.md, "The public binary drop"): the # pinned llama-server and its libraries, libggml-hrx.so with those kernels compiled in. Nothing is @@ -132,6 +140,8 @@ ExternalProject_Add(llama_hrx -DHRX_SOURCE_DIR=${CMAKE_SOURCE_DIR}/third_party/hrx-system -DGGML_HRX=ON -DGGML_VULKAN=OFF -DGGML_CUDA=OFF -DGGML_HIP=OFF -DGGML_NATIVE=ON -DGGML_CPU=ON -DLLAMA_BUILD_SERVER=ON -DLLAMA_CURL=OFF + "-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 INSTALL_COMMAND "" diff --git a/scripts/pack-elf.sh b/scripts/pack-elf.sh index 0a0ceab0..6867a26c 100644 --- a/scripts/pack-elf.sh +++ b/scripts/pack-elf.sh @@ -89,10 +89,31 @@ pack_localize() { pack_strip() { local f while IFS= read -r -d '' f; do - if pack_is_elf "$f"; then strip --strip-unneeded "$f"; fi + if pack_is_elf "$f"; then + strip --strip-unneeded "$f" + # .comment names the compiler and its version; it is not needed to load or link + objcopy --remove-section=.comment --remove-section=.note.gnu.gold-version "$f" 2>/dev/null || true + fi done < <(find "$1" -type f -print0) } +# Everything a shipped program and library may not carry: a compiler identification section, a path +# into a build machine, or an absolute RUNPATH. Prints one line per violation, empty when clean. +pack_artifact_hygiene() { + local f out="" + while IFS= read -r -d '' f; do + pack_is_elf "$f" || continue + readelf -p .comment "$f" 2>/dev/null | grep -qE "clang version|GCC:" && out="$out +$f: .comment names the compiler" + strings -a "$f" 2>/dev/null | grep -qE "^/(home|Users|root)/[A-Za-z0-9_./-]+" && + out="$out +$f: embedded build-machine path" + readelf -d "$f" 2>/dev/null | grep -E 'R(UN)?PATH' | grep -qE "Library (runpath|rpath): \[/" && + out="$out\n$f: absolute RUNPATH" + done < <(find "$1" -type f -print0) + [ -z "$out" ] || printf "%b\n" "$out" +} + pack_build_rpaths() { local f find "$1" -type f -print0 | while IFS= read -r -d '' f; do diff --git a/scripts/package-linux.sh b/scripts/package-linux.sh index 0279ecbb..d06a6813 100755 --- a/scripts/package-linux.sh +++ b/scripts/package-linux.sh @@ -93,15 +93,23 @@ fi # (libomp.so, which ggml's CPU code links when TheRock's amdclang builds llama.cpp) is copied beside # it; RUNPATH entries outside the build tree (TheRock in /opt) stay, since HRX needs TheRock anyway. pack_localize "$stage" "$build" -patchelf --remove-rpath "$stage/1bit" +# Every shipped program and library finds its libraries beside itself and nowhere else: replace whatever +# RUNPATH the build left (the build tree, an SDK under /opt) with $ORIGIN. +while IFS= read -r -d '' f; do + pack_is_elf "$f" || continue + patchelf --set-rpath '\$ORIGIN' "$f" 2>/dev/null || patchelf --remove-rpath "$f" 2>/dev/null || true +done < <(find "$stage" -type f -print0) # 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" -# nothing may still point into the build machine's home +# nothing may still point into the build machine's home, carry the compiler's identification, or load +# through an absolute RUNPATH bad=$(pack_build_rpaths "$stage" "$build") [ -z "$bad" ] || { echo "RPATH into the build machine left:"; echo "$bad"; exit 1; } +hygiene=$(pack_artifact_hygiene "$stage") +[ -z "$hygiene" ] || { echo "artifact hygiene:"; echo "$hygiene"; exit 1; } cp "$src/LICENSE" "$src/NOTICE" "$src/LICENSE-BINARY" "$src/NOTICE-BINARY" "$stage/" # the stock Lemonade PPA's lemond (Ubuntu 26.04) runs our HRX llama-server through lemonade-hrx From 8ab5fba1bf787b0821ddc9c741679eb585244733 Mon Sep 17 00:00:00 2001 From: bong-water-water-bong Date: Sat, 24 Oct 2026 07:49:52 -0300 Subject: [PATCH 2/3] package: keep the SDK runpath where the link needs it, and allow it in the gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured on the packed candidate: a blanket `$ORIGIN` leaves four programs unloadable — `ds4-server`, `ds4`, `ds4-bench` need `libhipblaslt.so.1`/`libhipblas.so.3`/`librocblas.so.5`/ `libamdhip64.so.7` from the toolchain, and the transitive closure of those is **905 MB**, so bundling them beside the binary is not an option. `pack_localize` already resolves this correctly: it gives every program `$ORIGIN` *plus* whatever SDK entries its link needed, and only the top-level engine binary (which it does not visit) needed its rpath dropped. So: revert the blanket override, keep `patchelf --remove-rpath` on `1bit` alone, and teach the hygiene gate to accept an absolute RUNPATH **only** under the toolchain root while still failing on one that points anywhere else (a build tree, a home directory). Also found while checking the packed tree (pre-existing, not touched here): `1bit/hrx/llama/bin/llama-perplexity` is shipped without `libllama-perplexity-impl.so` — it cannot load. It is the only unresolved ELF out of 21 in the candidate; the other 20 resolve, including `ds4-server` through the SDK entry this commit keeps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- scripts/pack-elf.sh | 9 +++++++-- scripts/package-linux.sh | 9 +++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/pack-elf.sh b/scripts/pack-elf.sh index 6867a26c..12db6f5c 100644 --- a/scripts/pack-elf.sh +++ b/scripts/pack-elf.sh @@ -108,8 +108,13 @@ $f: .comment names the compiler" strings -a "$f" 2>/dev/null | grep -qE "^/(home|Users|root)/[A-Za-z0-9_./-]+" && out="$out $f: embedded build-machine path" - readelf -d "$f" 2>/dev/null | grep -E 'R(UN)?PATH' | grep -qE "Library (runpath|rpath): \[/" && - out="$out\n$f: absolute RUNPATH" + # An absolute RUNPATH is only acceptable under the toolchain root: some shipped programs link the + # SDK's own libraries (whose closure is far larger than the package), and the release needs that + # toolchain to run anyway. + readelf -d "$f" 2>/dev/null | grep -E 'R(UN)?PATH' | + sed -n 's/.*Library \(runpath\|rpath\): \[\(.*\)\]/\2/p' | tr ':' '\n' | + grep -E "^/" | grep -vE "^(/opt/rocm-therock|$ONEBIT_TOOLCHAIN_ROOT)/" | grep -q . && + out="$out\n$f: absolute RUNPATH outside the toolchain root" done < <(find "$1" -type f -print0) [ -z "$out" ] || printf "%b\n" "$out" } diff --git a/scripts/package-linux.sh b/scripts/package-linux.sh index d06a6813..d66923cb 100755 --- a/scripts/package-linux.sh +++ b/scripts/package-linux.sh @@ -93,12 +93,9 @@ fi # (libomp.so, which ggml's CPU code links when TheRock's amdclang builds llama.cpp) is copied beside # it; RUNPATH entries outside the build tree (TheRock in /opt) stay, since HRX needs TheRock anyway. pack_localize "$stage" "$build" -# Every shipped program and library finds its libraries beside itself and nowhere else: replace whatever -# RUNPATH the build left (the build tree, an SDK under /opt) with $ORIGIN. -while IFS= read -r -d '' f; do - pack_is_elf "$f" || continue - patchelf --set-rpath '\$ORIGIN' "$f" 2>/dev/null || patchelf --remove-rpath "$f" 2>/dev/null || true -done < <(find "$stage" -type f -print0) +# pack_localize gives every program and library $ORIGIN plus whatever SDK entries its link needed; the +# 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" # 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 From a18657469bc707a712f756825b4d955c8d96994d Mon Sep 17 00:00:00 2001 From: bong-water-water-bong Date: Sat, 24 Oct 2026 08:14:00 -0300 Subject: [PATCH 3/3] package: default the toolchain-root allowance in the gate The gate read $ONEBIT_TOOLCHAIN_ROOT, which only weekly.sh sets; under 'set -u' the RUNPATH rule then errored out silently instead of checking. Default it to /opt/rocm-therock. Co-Authored-By: Claude Fable 5.1 --- scripts/pack-elf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pack-elf.sh b/scripts/pack-elf.sh index 12db6f5c..f067212e 100644 --- a/scripts/pack-elf.sh +++ b/scripts/pack-elf.sh @@ -113,7 +113,7 @@ $f: embedded build-machine path" # toolchain to run anyway. readelf -d "$f" 2>/dev/null | grep -E 'R(UN)?PATH' | sed -n 's/.*Library \(runpath\|rpath\): \[\(.*\)\]/\2/p' | tr ':' '\n' | - grep -E "^/" | grep -vE "^(/opt/rocm-therock|$ONEBIT_TOOLCHAIN_ROOT)/" | grep -q . && + 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) [ -z "$out" ] || printf "%b\n" "$out"