mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-20 06:39:01 -04:00
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>
59 lines
1.9 KiB
Go
59 lines
1.9 KiB
Go
package model
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("vulkanICDEnv", func() {
|
|
It("returns nil when the backend ships no vulkan/icd.d (CPU/CUDA/SYCL builds)", func() {
|
|
Expect(vulkanICDEnv(GinkgoT().TempDir())).To(BeNil())
|
|
})
|
|
|
|
It("returns nil when icd.d exists but holds no .json manifests", func() {
|
|
work := GinkgoT().TempDir()
|
|
icdDir := filepath.Join(work, "vulkan", "icd.d")
|
|
Expect(os.MkdirAll(icdDir, 0o755)).To(Succeed())
|
|
Expect(os.WriteFile(filepath.Join(icdDir, "README.txt"), []byte("not a manifest"), 0o644)).To(Succeed())
|
|
// A directory whose name ends in .json must be ignored.
|
|
Expect(os.MkdirAll(filepath.Join(icdDir, "nested.json"), 0o755)).To(Succeed())
|
|
|
|
Expect(vulkanICDEnv(work)).To(BeNil())
|
|
})
|
|
|
|
It("points VK_DRIVER_FILES/VK_ICD_FILENAMES at the bundled manifests", func() {
|
|
work := GinkgoT().TempDir()
|
|
icdDir := filepath.Join(work, "vulkan", "icd.d")
|
|
Expect(os.MkdirAll(icdDir, 0o755)).To(Succeed())
|
|
for _, name := range []string{"intel_icd.json", "lvp_icd.json"} {
|
|
Expect(os.WriteFile(filepath.Join(icdDir, name), []byte("{}"), 0o644)).To(Succeed())
|
|
}
|
|
|
|
env := vulkanICDEnv(work)
|
|
Expect(env).To(HaveLen(2))
|
|
|
|
got := map[string]string{}
|
|
for _, kv := range env {
|
|
k, v, ok := strings.Cut(kv, "=")
|
|
Expect(ok).To(BeTrue(), "malformed env entry %q", kv)
|
|
got[k] = v
|
|
}
|
|
|
|
for _, key := range []string{"VK_DRIVER_FILES", "VK_ICD_FILENAMES"} {
|
|
Expect(got).To(HaveKey(key))
|
|
// Both manifests must be listed as absolute paths, joined by the
|
|
// OS path-list separator the Vulkan loader expects.
|
|
parts := strings.Split(got[key], string(os.PathListSeparator))
|
|
Expect(parts).To(HaveLen(2))
|
|
for _, p := range parts {
|
|
Expect(filepath.IsAbs(p)).To(BeTrue(), "%s entry %q must be absolute", key, p)
|
|
Expect(p).To(HaveSuffix(".json"))
|
|
}
|
|
}
|
|
})
|
|
})
|