Files
LocalAI/backend/cpp/audio-cpp/run.sh
Ettore Di Giacinto 234371c027 backend(audio-cpp): exempt the driver libraries from the packaging gate
package.sh already left libcuda.so* and libnvidia-* to the host when copying,
because the driver has to match the kernel module on whatever host runs the
image, but the validation gate had no matching exemption. With BUILD_TYPE=cublas
ggml is static and links CUDA::cuda_driver, so grpc-server carries DT_NEEDED
libcuda.so.1 and the gate would have rejected the very absence the copy loop
created, failing every cublas build in CI. One regex now feeds both.

Building a control for that found a second defect: ld.so --list refuses to trace
an object with an unresolvable dependency at all, exiting 127 without emitting a
per-library line, so the "=> not found" rule was dead code and no exemption could
have applied to it. The gate now traces with LD_TRACE_LOADED_OBJECTS and
LD_LIBRARY_PATH, which reports the missing name and exits 0, and which is also
what run.sh does at run time.

Adds a layout assertion so a future move of the loader into lib/ fails the build
instead of shipping a package that resolves bundled: models into lib/assets and
finds no ggml CPU backend, and records for Task 16 that the Darwin script must
not be a straight copy of privacy-filter-darwin.sh, which never calls package.sh
and would silently drop assets/.

Assisted-by: Claude:claude-opus-5 [Claude Code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2026-07-29 19:03:33 +00:00

59 lines
3.0 KiB
Bash
Executable File

#!/bin/bash
# Entry point for the audio-cpp backend image and for BACKEND_BINARY mode.
#
# The image's final stage is FROM scratch, so the package root is / and there is
# no system loader, no system libc and no fallback library path. Everything the
# process opens has to be inside the package, and it has to be findable by the
# two mechanisms that actually do the finding: the dynamic linker, and
# audio.cpp's own directory scans.
set -e
CURDIR=$(dirname "$(realpath "$0")")
if [ "$(uname -s)" = "Darwin" ]; then
export DYLD_LIBRARY_PATH="$CURDIR/lib:$CURDIR:$DYLD_LIBRARY_PATH"
exec "$CURDIR/grpc-server" "$@"
fi
# $CURDIR is on the path as well as $CURDIR/lib: the ggml shared objects the
# CPU-all-variants build produces sit in the package root, next to the binary,
# not in lib/. See the comment below for why they cannot live in lib/.
export LD_LIBRARY_PATH="$CURDIR/lib:$CURDIR:$LD_LIBRARY_PATH"
# THE BUNDLED LOADER IS AT THE PACKAGE ROOT, NOT AT lib/ld.so. DO NOT MOVE IT.
#
# Exec'ing the loader is what pins the bundled glibc to the matching ld.so, and
# every other C++ backend here does it. The cost is that /proc/self/exe then
# names the LOADER rather than grpc-server, and this backend has two consumers
# of /proc/self/exe that both have to land on the package root:
#
# - ggml's backend registry DISCOVERS the per-microarch libggml-cpu-*.so by
# scanning dirname(/proc/self/exe) and the current directory. Those files
# are dlopened, never linked, so no library path and no RUNPATH reaches
# them: they have to be in a directory ggml scans.
# - resolve_model_path() turns "bundled:<name>" into
# dirname(/proc/self/exe)/assets/<name>, which is how the bundled
# silero_vad and marblenet_vad models resolve with nothing downloaded.
#
# backend/cpp/llama-cpp/package.sh answers the first of these by keeping
# lib/ld.so and moving the ggml objects INTO lib/. That does not generalise
# here, because it would also drag assets/ into lib/ to keep the second
# consumer working. Putting the loader in the package root instead makes
# dirname(/proc/self/exe) the package root, so the binary, the ggml objects and
# assets/ all sit in the one directory that all three mechanisms agree on.
#
# The ggml half has a second chance that the bundled: half does not: LocalAI
# sets the backend process cwd to the directory holding run.sh
# (pkg/model/process.go), so ggml's fs::current_path() fallback would find the
# objects in normal operation whatever the loader's placement. That fallback is
# worth little here. It holds only for the launcher that sets that cwd, it is
# gone the moment anyone runs the binary by hand or through a wrapper that
# chdirs, and resolve_model_path has no equivalent, which would leave the only
# zero-download path in this backend resting on it. Rooting the loader is the
# one layout where all three mechanisms agree without depending on the cwd.
if [ -f "$CURDIR/ld.so" ]; then
exec "$CURDIR/ld.so" "$CURDIR/grpc-server" "$@"
fi
exec "$CURDIR/grpc-server" "$@"