mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-25 09:09:07 -04:00
ggml emits its loadable backends (per-microarch CPU variants, metal, blas) with a .so suffix even on darwin, while the core libraries (ggml-base/ggml/llama/ llama-common/mtmd) use .dylib. Split the distribution by suffix: .so DL backends go in the package root for ggml's executable-directory scan, .dylib core libs go in lib/ for DYLD_LIBRARY_PATH. The previous .dylib name-pattern matched none of the variants. Verified on an M4: ggml loads the apple_m4 CPU variant (SME=1) and Metal, model loads and generates correct tokens. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Assisted-by: Claude:claude-opus-4-8 [Claude Code]
84 lines
2.8 KiB
Bash
84 lines
2.8 KiB
Bash
#!/bin/bash
|
|
|
|
set -ex
|
|
|
|
IMAGE_NAME="${IMAGE_NAME:-localai/llama-cpp-darwin}"
|
|
|
|
pushd backend/cpp/llama-cpp
|
|
|
|
# Single build via ggml CPU_ALL_VARIANTS: one binary plus the per-microarch Apple/arm
|
|
# dylibs (apple_m1/m2_m3/m4, armv8.x) that ggml selects at runtime. GGML_METAL stays ON
|
|
# and --target ggml also builds ggml-metal (via add_dependencies), so the Metal GPU
|
|
# backend is still produced as a loadable libggml-metal.dylib.
|
|
make llama-cpp-cpu-all && \
|
|
make llama-cpp-grpc && \
|
|
make llama-cpp-rpc-server
|
|
|
|
popd
|
|
|
|
mkdir -p build/darwin
|
|
mkdir -p backend-images
|
|
mkdir -p build/darwin/lib
|
|
|
|
cp -rf backend/cpp/llama-cpp/llama-cpp-cpu-all build/darwin/
|
|
cp -rf backend/cpp/llama-cpp/llama-cpp-grpc build/darwin/
|
|
cp -rf backend/cpp/llama-cpp/llama-cpp-rpc-server build/darwin/
|
|
|
|
# Distribute the shared ggml/llama libraries from the CPU_ALL_VARIANTS build. Unlike the
|
|
# old fully-static fallback build, these have @rpath install names, so the otool loop below
|
|
# (which only copies deps that exist on disk) will not pick them up. The split is by suffix:
|
|
# - ggml emits its loadable backends (per-microarch CPU variants, metal, blas) with a .so
|
|
# suffix EVEN ON DARWIN. These go in the package ROOT next to the binary, because darwin
|
|
# run.sh execs the binary directly (no bundled ld.so) so ggml's executable-directory
|
|
# scan looks there.
|
|
# - the core libraries (libggml-base/libggml/libllama/libllama-common/libmtmd) use the
|
|
# platform .dylib suffix and are NEEDED deps; they go in lib/, resolved at load time via
|
|
# the DYLD_LIBRARY_PATH=lib that run.sh exports. -a preserves the version symlinks.
|
|
SHLIBS=backend/cpp/llama-cpp/ggml-shared-libs
|
|
cp -a $SHLIBS/*.so build/darwin/
|
|
cp -a $SHLIBS/*.dylib build/darwin/lib/
|
|
|
|
# Set default additional libs only for Darwin on M chips (arm64)
|
|
if [[ "$(uname -s)" == "Darwin" && "$(uname -m)" == "arm64" ]]; then
|
|
ADDITIONAL_LIBS=${ADDITIONAL_LIBS:-$(ls /opt/homebrew/Cellar/protobuf/**/lib/libutf8_validity*.dylib 2>/dev/null)}
|
|
else
|
|
ADDITIONAL_LIBS=${ADDITIONAL_LIBS:-""}
|
|
fi
|
|
|
|
for file in $ADDITIONAL_LIBS; do
|
|
cp -rfv $file build/darwin/lib
|
|
done
|
|
|
|
for file in build/darwin/*; do
|
|
LIBS="$(otool -L $file | awk 'NR > 1 { system("echo " $1) } ' | xargs echo)"
|
|
for lib in $LIBS; do
|
|
# only libraries ending in dylib
|
|
if [[ "$lib" == *.dylib ]]; then
|
|
if [ -e "$lib" ]; then
|
|
cp -rvf "$lib" build/darwin/lib
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "--------------------------------"
|
|
echo "ADDITIONAL_LIBS: $ADDITIONAL_LIBS"
|
|
echo "--------------------------------"
|
|
|
|
echo "Bundled libraries:"
|
|
ls -la build/darwin/lib
|
|
|
|
|
|
cp -rf backend/cpp/llama-cpp/run.sh build/darwin/
|
|
|
|
PLATFORMARCH="${PLATFORMARCH:-darwin/arm64}"
|
|
|
|
./local-ai util create-oci-image \
|
|
build/darwin/. \
|
|
--output ./backend-images/llama-cpp.tar \
|
|
--image-name $IMAGE_NAME \
|
|
--platform $PLATFORMARCH
|
|
|
|
rm -rf build/darwin
|
|
|