From 7652f328ac5f1220220894ff21b32b0c83aa5f3a Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Thu, 25 Jun 2026 20:52:41 +0000 Subject: [PATCH] fix(privacy-filter): macOS proto include + bundle ggml dylibs Validated natively on an M4 (the build/package/load chain now works with Metal): - CMakeLists.txt: hw_grpc_proto compiles the generated proto/grpc sources but only linked the binary dir, so on macOS it could not find protobuf's headers (runtime_version.h) - Homebrew puts them under /opt/homebrew, not /usr/include. Link protobuf::libprotobuf + gRPC::grpc++ so their include dirs propagate. No-op on Linux (apt headers are already on the default search path). - privacy-filter-darwin.sh: bundle the ggml shared libs the binary @rpath-links (libggml{,-base,-cpu,-blas,-metal}); the otool -L walk only catches on-disk absolute deps and missed them. Resolved at runtime by run.sh's DYLD_LIBRARY_PATH. M4 check: arm64 grpc-server links @rpath/libggml-metal.0.dylib; with the 15 ggml dylibs + grpc/protobuf bundled, it loads clean (no dyld errors) and prints usage. Signed-off-by: Ettore Di Giacinto Assisted-by: Claude:opus-4.8 [Claude Code] --- backend/cpp/privacy-filter/CMakeLists.txt | 8 ++++++++ scripts/build/privacy-filter-darwin.sh | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/backend/cpp/privacy-filter/CMakeLists.txt b/backend/cpp/privacy-filter/CMakeLists.txt index b8580d1d4..f9ee78328 100644 --- a/backend/cpp/privacy-filter/CMakeLists.txt +++ b/backend/cpp/privacy-filter/CMakeLists.txt @@ -51,6 +51,14 @@ add_library(hw_grpc_proto STATIC ${HW_GRPC_SRCS} ${HW_GRPC_HDRS} ${HW_PROTO_SRCS} ${HW_PROTO_HDRS}) target_include_directories(hw_grpc_proto PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +# The generated proto/grpc sources include protobuf and grpc++ headers, so this +# library must see their include dirs. Linking the imported targets propagates +# them. On Linux the apt headers live in /usr/include (default search path) so +# this was a no-op; on macOS the Homebrew headers are under /opt/homebrew and +# would otherwise be missed (runtime_version.h not found). +target_link_libraries(hw_grpc_proto PUBLIC + protobuf::libprotobuf + gRPC::grpc++) # Build only the pf static lib (+ ggml) from the engine tree — no CLI/bench/tests. # PF_VULKAN is honored when passed on the cmake command line (it lands in the diff --git a/scripts/build/privacy-filter-darwin.sh b/scripts/build/privacy-filter-darwin.sh index 47b8d053b..aca901822 100644 --- a/scripts/build/privacy-filter-darwin.sh +++ b/scripts/build/privacy-filter-darwin.sh @@ -32,6 +32,14 @@ for file in $ADDITIONAL_LIBS; do cp -rfv "$file" build/darwin/lib done +# Bundle the ggml shared libs the binary @rpath-links (libggml, -cpu, -blas, +# -metal). The engine builds ggml shared, scattered under the build tree; flatten +# them (with their version symlinks) into lib/, resolved at runtime by leaf name +# via run.sh's DYLD_LIBRARY_PATH=lib. Without this the packaged binary can't find +# libggml*.dylib once the build dir is gone. +GGML_SRC="backend/cpp/privacy-filter/build/privacy-filter.cpp/ggml/src" +find "$GGML_SRC" -name 'libggml*.dylib' -exec cp -a {} build/darwin/lib/ \; + # Walk dylibs via otool -L and bundle anything that isn't a system framework. for file in build/darwin/grpc-server; do LIBS="$(otool -L "$file" | awk 'NR > 1 { system("echo " $1) } ' | xargs echo)"