Skip to content

fix(gpu-libs): bundle transitive deps of GPU runtime libs (#10537)#10539

Merged
mudler merged 1 commit into
masterfrom
fix/rocm-transitive-libs-10537
Jun 26, 2026
Merged

fix(gpu-libs): bundle transitive deps of GPU runtime libs (#10537)#10539
mudler merged 1 commit into
masterfrom
fix/rocm-transitive-libs-10537

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

What

Fixes #10537 — the ROCm llama-cpp backend (and every other GPU backend) fails to load with:

librocprofiler-register.so.0: cannot open shared object file: No such file or directory

Root cause

scripts/build/package-gpu-libs.sh is the shared GPU-lib packager used by all GPU backends. Its per-vendor packagers (package_rocm_libs, package_cuda_libs, package_intel_libs) copy a fixed allowlist of top-level runtime libs (libamdhip64, libhipblas, librocblas, ...) but never resolved their transitive dependencies.

Backends run through the bundled lib/ld.so with LD_LIBRARY_PATH=lib (see run.sh), so the binary only sees what's in lib/. On recent ROCm (base image rocm 7.2.1) the runtime libs link against librocprofiler-register.so.0, which is not in the allowlist, so it's never bundled — a hard load failure. libhipblas.so itself loads fine (it is allowlisted), which matches the issue report.

This is not related to the llama.cpp shared-libs change.

The Vulkan path already solved this class of problem with copy_elf_deps (ldd-based transitive resolution), but that sweep was only wired into the Vulkan ICD path.

Fix

  • Add a generic sweep_transitive_deps that runs the existing copy_elf_deps (ldd) over everything the allowlist already bundled. ldd returns the full recursive closure, so one pass suffices.
  • Wire it into the ROCm, CUDA and Intel packagers (Vulkan already had it).
  • Core libc-family deps are skipped via is_core_lib, so we never shadow the loader's own libc/libstdc++.

Because the script is shared, this fixes the missing-transitive-dep class for llama-cpp, whisper, stablediffusion-ggml, turboquant, ds4, and the rest in one place.

Testing

  • Added scripts/build/package-gpu-libs_test.sh: a self-contained regression test (gcc + ldd) that fabricates a primary lib linking a transitive lib, simulates the allowlist step, and asserts the sweep bundles the transitive dep. Red before the fix, green after.
  • Smoke-tested the cpu and hipblas-without-/opt/rocm paths (graceful no-op / warning).

Note: the mechanism is verified locally with synthetic libs; full end-to-end validation runs in the ROCm build image in CI, using the same ldd resolution the Vulkan path already uses in production.

🤖 Generated with Claude Code

The per-vendor packagers in package-gpu-libs.sh copy an explicit allowlist
of top-level GPU runtime libraries (libamdhip64, libhipblas, librocblas, the
CUDA/Intel equivalents, ...) but never resolved their transitive
dependencies. Backends run through the bundled lib/ld.so with
LD_LIBRARY_PATH=lib, so any transitive dep not in the allowlist is a fatal
"cannot open shared object file" at load time.

On recent ROCm (base image rocm 7.2.1) the runtime libs link against
librocprofiler-register.so.0, which is not in the allowlist, so the rocm
llama-cpp backend (and every other GPU backend sharing this script) failed
to load with:

  librocprofiler-register.so.0: cannot open shared object file

The Vulkan path already solved this class of problem with copy_elf_deps
(ldd-based transitive resolution), but that sweep was only wired into the
Vulkan ICD path. This adds a generic sweep_transitive_deps that runs the
same ldd resolution over everything the allowlist already bundled, and wires
it into the ROCm, CUDA and Intel packagers. ldd returns the full recursive
closure, so one pass suffices; core libc-family deps are skipped via
is_core_lib so we never shadow the loader's own libc/libstdc++.

Adds a self-contained regression test (gcc + ldd) that fabricates a primary
lib linking a transitive lib and asserts the sweep bundles the dependency.

Fixes #10537

Assisted-by: Claude:opus-4.8 [Claude Code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
@localai-bot

Copy link
Copy Markdown
Collaborator Author

Validation against the real released image

Reproduced and verified against quay.io/go-skynet/local-ai-backends:latest-gpu-rocm-hipblas-llama-cpp (the image a v4.5.2 user runs).

Bug reproduced: the image bundles libhipblas.so.3, librocblas.so.5, libamdhip64.so.7 but librocprofiler-register.so.0 is absent from the entire image.

Confirmed it's a NEEDED dep, not dlopen (so ldd catches it and the sweep works):

$ readelf -d lib/libamdhip64.so.7
 (NEEDED)  Shared library: [librocprofiler-register.so.0]
 (NEEDED)  Shared library: [libhsa-runtime64.so.1]

Full audit of every bundled lib's NEEDED entries vs what's actually in lib/ (excluding core libc-family) shows librocprofiler-register is just the first of 8 missing transitive deps:

MISSING: libdrm_amdgpu.so.1
MISSING: libdrm.so.2
MISSING: libelf.so.1
MISSING: libnuma.so.1
MISSING: librocprofiler-register.so.0
MISSING: librocroller.so.1
MISSING: libz.so.1
MISSING: libzstd.so.1

A naive "add librocprofiler-register to the allowlist" fix would just move the failure to the next missing lib. The generic sweep_transitive_deps in this PR catches all 8 in one ldd pass (none are in the is_core_lib skip list), and the same applies to the CUDA/Intel packagers.

Residual note: this was validated by static readelf/ldd analysis of the released artifact. The sweep copies these from /opt/rocm + system libs at build time; final end-to-end confirmation happens when the ROCm backend is rebuilt in CI with this change.

@mudler
mudler merged commit f98b0f1 into master Jun 26, 2026
59 checks passed
@mudler
mudler deleted the fix/rocm-transitive-libs-10537 branch June 26, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

librocprofiler-register.so.0 missing

2 participants