mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-20 06:39:01 -04:00
feat(vulkan): make Vulkan backends self-contained on the GPU (#10404)
Vulkan backends bundled their own loader and ICD manifests but neither the Mesa driver the manifests point at nor a way to make the loader find them, so on a runtime base image without Mesa the loader enumerated zero devices and the GPU silently fell back to CPU (only NVIDIA worked, since its ICD is injected by the container toolkit). - scripts/build/package-gpu-libs.sh: for each installed ICD manifest, bundle the driver .so its library_path names — no hard-coded, platform-dependent soname list — plus that driver's ldd dependencies, skipping manifests whose driver isn't installed. Rewrite each library_path to a bare soname so the bundled driver resolves via the LD_LIBRARY_PATH run.sh already sets. - .docker/install-base-deps.sh, backend/Dockerfile.golang, backend/Dockerfile.python: install mesa-vulkan-drivers in every Vulkan builder so the driver + manifests exist to be packaged (the LunarG SDK ships only the loader and shader tooling). - pkg/model/process.go: when a backend ships vulkan/icd.d/, point the loader at it via VK_DRIVER_FILES/VK_ICD_FILENAMES at launch (no-op otherwise). Covered by pkg/model/process_vulkan_test.go. - backend/go/parakeet-cpp/package.sh: complete the L0 stub (was missing the libc-family ldd walk + GPU-lib packaging) by mirroring whisper, so the vulkan-parakeet image actually bundles its GPU runtime. Assisted-by: Claude Code:claude-opus-4-8 Signed-off-by: Richard Palethorpe <io@richiejp.com>
This commit is contained in:
committed by
GitHub
parent
59c7ad5153
commit
606128e4e9
@@ -109,6 +109,38 @@ copy_libs_glob() {
|
||||
done
|
||||
}
|
||||
|
||||
# Returns success for the core runtime libs the base image and package.sh
|
||||
# already provide. We must NOT bundle our own copies of these — a second libc
|
||||
# or libstdc++ on LD_LIBRARY_PATH clashes with the loader and the rest of the
|
||||
# process — so they're skipped when pulling in a driver's transitive deps.
|
||||
is_core_lib() {
|
||||
case "$1" in
|
||||
ld-linux*|ld.so|libc.so.*|libm.so.*|libdl.so.*|libpthread.so.*|librt.so.*|\
|
||||
libgcc_s.so.*|libstdc++.so.*|libresolv.so.*|libutil.so.*|linux-vdso.so.*)
|
||||
return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# Copy the shared-library dependencies of an ELF file into TARGET_LIB_DIR.
|
||||
# Used to make a bundled GPU driver self-contained: e.g. the Mesa Vulkan ICDs
|
||||
# pull in libdrm, libexpat and (for RADV/lavapipe) libLLVM, none of which the
|
||||
# runtime base image is guaranteed to have. Core libc-family deps are skipped.
|
||||
copy_elf_deps() {
|
||||
local elf="$1"
|
||||
[ -e "$elf" ] || return 0
|
||||
command -v ldd >/dev/null 2>&1 || return 0
|
||||
|
||||
# ldd lines look like: "<TAB>libfoo.so.1 => /path/to/libfoo.so.1 (0x..)".
|
||||
# Take the resolved absolute path (field 3) and skip vdso/static entries.
|
||||
while read -r dep; do
|
||||
if is_core_lib "$(basename "$dep")"; then
|
||||
continue
|
||||
fi
|
||||
copy_lib "$dep"
|
||||
done < <(ldd "$elf" 2>/dev/null | awk '/=>/ && $3 ~ /^\// {print $3}')
|
||||
}
|
||||
|
||||
# Package NVIDIA CUDA libraries
|
||||
package_cuda_libs() {
|
||||
echo "Packaging CUDA libraries for BUILD_TYPE=${BUILD_TYPE}..."
|
||||
@@ -284,7 +316,7 @@ package_vulkan_libs() {
|
||||
"/usr/local/lib"
|
||||
)
|
||||
|
||||
# Core Vulkan runtime libraries
|
||||
# Core Vulkan runtime: the loader plus the shader tooling shipped by the SDK.
|
||||
local vulkan_libs=(
|
||||
"libvulkan.so*"
|
||||
"libshaderc_shared.so*"
|
||||
@@ -301,10 +333,63 @@ package_vulkan_libs() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Copy Vulkan ICD files
|
||||
# Bundle the ICD drivers. Rather than hard-code Mesa's (platform- and
|
||||
# version-dependent) driver sonames, treat each installed ICD manifest as
|
||||
# the source of truth: every /usr/share/vulkan/icd.d/*.json names the exact
|
||||
# driver .so it needs in its "library_path". So we copy whatever drivers
|
||||
# the manifests reference (libvulkan_intel/radeon/lvp/... on amd64, the SoC
|
||||
# drivers on arm64, ...) plus each driver's transitive deps, and skip any
|
||||
# manifest whose driver isn't actually installed. The loader picks the
|
||||
# right driver for the GPU at runtime.
|
||||
if [ -d "/usr/share/vulkan/icd.d" ]; then
|
||||
mkdir -p "$TARGET_LIB_DIR/../vulkan/icd.d"
|
||||
cp -arfL /usr/share/vulkan/icd.d/* "$TARGET_LIB_DIR/../vulkan/icd.d/" 2>/dev/null || true
|
||||
local icd_dest="$TARGET_LIB_DIR/../vulkan/icd.d"
|
||||
mkdir -p "$icd_dest"
|
||||
|
||||
local manifest driver driver_base resolved lib_path
|
||||
for manifest in /usr/share/vulkan/icd.d/*.json; do
|
||||
[ -e "$manifest" ] || continue
|
||||
|
||||
# Pull the driver path out of "library_path": "<path-or-soname>".
|
||||
driver=$(sed -nE 's/.*"library_path"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/p' "$manifest" | head -n1)
|
||||
[ -n "$driver" ] || continue
|
||||
driver_base=$(basename "$driver")
|
||||
|
||||
# Resolve to an absolute path: honour an absolute library_path,
|
||||
# else look in the standard lib dirs, else fall back to ldconfig.
|
||||
resolved=""
|
||||
case "$driver" in
|
||||
/*) [ -e "$driver" ] && resolved="$driver" ;;
|
||||
esac
|
||||
if [ -z "$resolved" ]; then
|
||||
for lib_path in "${vulkan_lib_paths[@]}"; do
|
||||
if [ -e "${lib_path}/${driver_base}" ]; then
|
||||
resolved="${lib_path}/${driver_base}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ -z "$resolved" ] && command -v ldconfig >/dev/null 2>&1; then
|
||||
resolved=$(ldconfig -p | awk -v n="$driver_base" '$1 == n { print $NF; exit }')
|
||||
fi
|
||||
|
||||
if [ -z "$resolved" ] || [ ! -e "$resolved" ]; then
|
||||
echo "Vulkan ICD: driver '$driver_base' for $(basename "$manifest") not installed; skipping its manifest" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# Bundle the driver + its transitive deps (libdrm, libexpat, and
|
||||
# libLLVM for RADV/lavapipe, ...) so the backend is self-contained
|
||||
# on a runtime base image without Mesa.
|
||||
copy_lib "$resolved"
|
||||
copy_elf_deps "$resolved"
|
||||
|
||||
# Copy the manifest and rewrite its library_path to a bare soname
|
||||
# so the loader resolves our bundled driver via LD_LIBRARY_PATH
|
||||
# (run.sh adds lib/ to it) instead of a host path that won't exist
|
||||
# on the runtime image.
|
||||
cp -arfL "$manifest" "$icd_dest/" 2>/dev/null || true
|
||||
sed -i -E 's#("library_path"[[:space:]]*:[[:space:]]*")[^"]*/#\1#' "$icd_dest/$(basename "$manifest")"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Vulkan libraries packaged successfully"
|
||||
@@ -345,6 +430,8 @@ package_gpu_libs() {
|
||||
export -f package_gpu_libs
|
||||
export -f copy_lib
|
||||
export -f copy_libs_glob
|
||||
export -f is_core_lib
|
||||
export -f copy_elf_deps
|
||||
export -f package_cuda_libs
|
||||
export -f package_rocm_libs
|
||||
export -f package_intel_libs
|
||||
|
||||
Reference in New Issue
Block a user