diff --git a/backend/go/locate-anything-cpp/.gitignore b/backend/go/locate-anything-cpp/.gitignore new file mode 100644 index 000000000..b1d824c34 --- /dev/null +++ b/backend/go/locate-anything-cpp/.gitignore @@ -0,0 +1,7 @@ +sources/ +build*/ +package/ +liblocateanythingcpp*.so +locate-anything-cpp +test-models/ +test-data/ diff --git a/backend/go/locate-anything-cpp/CMakeLists.txt b/backend/go/locate-anything-cpp/CMakeLists.txt new file mode 100644 index 000000000..22d6232b8 --- /dev/null +++ b/backend/go/locate-anything-cpp/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.18) +project(liblocateanythingcpp LANGUAGES C CXX) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Static-link ggml + locate_anything so the resulting .so has no runtime +# dependency on extra ggml/locate_anything shared libraries — only on +# libc/libstdc++/libgomp, which the LocalAI package step bundles into the +# docker image. +set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries" FORCE) + +# locate-anything.cpp build switches: skip CLI/tests, keep static lib. +set(LA_BUILD_CLI OFF CACHE BOOL "Disable locate-anything CLI" FORCE) +set(LA_BUILD_TESTS OFF CACHE BOOL "Disable locate-anything tests" FORCE) +set(LA_SHARED OFF CACHE BOOL "Build locate_anything as static lib" FORCE) + +# Unlike rt-detr.cpp, locate-anything.cpp ships no in-tree ggml patches, so +# there is no apply_ggml_patches.sh hook to shim here. +add_subdirectory(./sources/locate-anything.cpp) + +# locate-anything.cpp's top-level CMakeLists points its own target's include +# dirs at ${CMAKE_SOURCE_DIR}/{include,src,third_party,...}. CMAKE_SOURCE_DIR +# is the *top-level* source dir of the whole CMake tree, so when we pull it in +# via add_subdirectory it resolves to OUR directory, not theirs, and the +# locate_anything target fails to find its own headers (la_capi.h, stb_image.h, +# la_gguf_keys.h). Re-add the correct, subdir-relative include paths to the +# already-defined target so it compiles regardless of where it's nested. +set(LA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sources/locate-anything.cpp) +target_include_directories(locate_anything PRIVATE + ${LA_SRC}/include + ${LA_SRC}/src + ${LA_SRC}/third_party + ${LA_SRC}/third_party/stb) + +# locate-anything.cpp's C-API symbols already live inside liblocate_anything +# (src/la_capi.cpp is compiled into the lib). We re-export them via a MODULE +# library that links locate_anything so the symbols are visible at dlopen time. +add_library(locateanythingcpp MODULE + sources/locate-anything.cpp/src/la_capi.cpp) + +target_include_directories(locateanythingcpp PRIVATE + sources/locate-anything.cpp/include + sources/locate-anything.cpp/src + sources/locate-anything.cpp/third_party + sources/locate-anything.cpp/third_party/stb +) + +target_link_libraries(locateanythingcpp PRIVATE locate_anything ggml) + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0) + target_link_libraries(locateanythingcpp PRIVATE stdc++fs) +endif() + +set_property(TARGET locateanythingcpp PROPERTY CXX_STANDARD 17) +set_target_properties(locateanythingcpp PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/backend/go/locate-anything-cpp/Makefile b/backend/go/locate-anything-cpp/Makefile new file mode 100644 index 000000000..822b664d6 --- /dev/null +++ b/backend/go/locate-anything-cpp/Makefile @@ -0,0 +1,126 @@ +CMAKE_ARGS?= +BUILD_TYPE?= +NATIVE?=false + +GOCMD?=go +GO_TAGS?= +JOBS?=$(shell nproc --ignore=1) + +# locate-anything.cpp. Pin to a specific commit for a stable build; leaving +# this on `master` always picks up the latest C-API surface (incl. the +# per-detection accessor functions used by golocateanythingcpp.go). +LOCATEANYTHING_REPO?=https://github.com/mudler/locate-anything.cpp.git +LOCATEANYTHING_VERSION?=60e450945476d5e97e0754a8c0e71a9ea81690e0 + +ifeq ($(NATIVE),false) + CMAKE_ARGS+=-DGGML_NATIVE=OFF +endif + +# Forward LocalAI's BUILD_TYPE to the matching ggml backend switch. +ifeq ($(BUILD_TYPE),cublas) + CMAKE_ARGS+=-DGGML_CUDA=ON -DLA_GGML_CUDA=ON +else ifeq ($(BUILD_TYPE),openblas) + CMAKE_ARGS+=-DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS +else ifeq ($(BUILD_TYPE),clblas) + CMAKE_ARGS+=-DGGML_CLBLAST=ON +else ifeq ($(BUILD_TYPE),hipblas) + ROCM_HOME ?= /opt/rocm + ROCM_PATH ?= /opt/rocm + export CXX=$(ROCM_HOME)/llvm/bin/clang++ + export CC=$(ROCM_HOME)/llvm/bin/clang + AMDGPU_TARGETS?=gfx908,gfx90a,gfx942,gfx950,gfx1030,gfx1100,gfx1101,gfx1102,gfx1200,gfx1201 + CMAKE_ARGS+=-DGGML_HIPBLAS=ON -DAMDGPU_TARGETS=$(AMDGPU_TARGETS) +else ifeq ($(BUILD_TYPE),vulkan) + CMAKE_ARGS+=-DGGML_VULKAN=ON -DLA_GGML_VULKAN=ON +else ifeq ($(OS),Darwin) + ifneq ($(BUILD_TYPE),metal) + CMAKE_ARGS+=-DGGML_METAL=OFF + else + CMAKE_ARGS+=-DGGML_METAL=ON + CMAKE_ARGS+=-DGGML_METAL_EMBED_LIBRARY=ON + CMAKE_ARGS+=-DLA_GGML_METAL=ON + endif +endif + +ifeq ($(BUILD_TYPE),sycl_f16) + CMAKE_ARGS+=-DGGML_SYCL=ON \ + -DCMAKE_C_COMPILER=icx \ + -DCMAKE_CXX_COMPILER=icpx \ + -DGGML_SYCL_F16=ON +endif + +ifeq ($(BUILD_TYPE),sycl_f32) + CMAKE_ARGS+=-DGGML_SYCL=ON \ + -DCMAKE_C_COMPILER=icx \ + -DCMAKE_CXX_COMPILER=icpx +endif + +sources/locate-anything.cpp: + mkdir -p sources && \ + git clone --recursive $(LOCATEANYTHING_REPO) sources/locate-anything.cpp && \ + cd sources/locate-anything.cpp && \ + git checkout $(LOCATEANYTHING_VERSION) && \ + git submodule update --init --recursive --depth 1 --single-branch + +# Detect OS +UNAME_S := $(shell uname -s) + +# Only build CPU variants on Linux +ifeq ($(UNAME_S),Linux) + VARIANT_TARGETS = liblocateanythingcpp-avx.so liblocateanythingcpp-avx2.so liblocateanythingcpp-avx512.so liblocateanythingcpp-fallback.so +else + # On non-Linux (e.g., Darwin), build only fallback variant + VARIANT_TARGETS = liblocateanythingcpp-fallback.so +endif + +locate-anything-cpp: main.go golocateanythingcpp.go $(VARIANT_TARGETS) + CGO_ENABLED=0 $(GOCMD) build -tags "$(GO_TAGS)" -o locate-anything-cpp ./ + +package: locate-anything-cpp + bash package.sh + +build: package + +clean: purge + rm -rf liblocateanythingcpp*.so locate-anything-cpp package sources + +purge: + rm -rf build* + +# Build all variants (Linux only) +ifeq ($(UNAME_S),Linux) +liblocateanythingcpp-avx.so: sources/locate-anything.cpp + rm -rfv build-$@ + $(info ${GREEN}I locate-anything-cpp build info:avx${RESET}) + SO_TARGET=$@ CMAKE_ARGS="$(CMAKE_ARGS) -DGGML_AVX=on -DGGML_AVX2=off -DGGML_AVX512=off -DGGML_FMA=off -DGGML_F16C=off -DGGML_BMI2=off" $(MAKE) liblocateanythingcpp-custom + rm -rfv build-$@ + +liblocateanythingcpp-avx2.so: sources/locate-anything.cpp + rm -rfv build-$@ + $(info ${GREEN}I locate-anything-cpp build info:avx2${RESET}) + SO_TARGET=$@ CMAKE_ARGS="$(CMAKE_ARGS) -DGGML_AVX=on -DGGML_AVX2=on -DGGML_AVX512=off -DGGML_FMA=on -DGGML_F16C=on -DGGML_BMI2=on" $(MAKE) liblocateanythingcpp-custom + rm -rfv build-$@ + +liblocateanythingcpp-avx512.so: sources/locate-anything.cpp + rm -rfv build-$@ + $(info ${GREEN}I locate-anything-cpp build info:avx512${RESET}) + SO_TARGET=$@ CMAKE_ARGS="$(CMAKE_ARGS) -DGGML_AVX=on -DGGML_AVX2=on -DGGML_AVX512=on -DGGML_FMA=on -DGGML_F16C=on -DGGML_BMI2=on" $(MAKE) liblocateanythingcpp-custom + rm -rfv build-$@ +endif + +# Build fallback variant (all platforms) +liblocateanythingcpp-fallback.so: sources/locate-anything.cpp + rm -rfv build-$@ + $(info ${GREEN}I locate-anything-cpp build info:fallback${RESET}) + SO_TARGET=$@ CMAKE_ARGS="$(CMAKE_ARGS) -DGGML_AVX=off -DGGML_AVX2=off -DGGML_AVX512=off -DGGML_FMA=off -DGGML_F16C=off -DGGML_BMI2=off" $(MAKE) liblocateanythingcpp-custom + rm -rfv build-$@ + +liblocateanythingcpp-custom: CMakeLists.txt + mkdir -p build-$(SO_TARGET) && \ + cd build-$(SO_TARGET) && \ + cmake .. $(CMAKE_ARGS) && \ + cmake --build . --config Release -j$(JOBS) && \ + cd .. && \ + mv build-$(SO_TARGET)/liblocateanythingcpp.so ./$(SO_TARGET) + +all: locate-anything-cpp package diff --git a/backend/go/locate-anything-cpp/golocateanythingcpp.go b/backend/go/locate-anything-cpp/golocateanythingcpp.go new file mode 100644 index 000000000..25c7b80c5 --- /dev/null +++ b/backend/go/locate-anything-cpp/golocateanythingcpp.go @@ -0,0 +1,174 @@ +package main + +// golocateanythingcpp.go - gRPC handlers (Load, Detect) for the +// locate-anything-cpp backend. +// +// Embeds base.SingleThread to default unimplemented RPCs to "not supported" +// while we only implement open-vocabulary object detection (Detect). + +import ( + "encoding/base64" + "fmt" + "os" + "path/filepath" + "unsafe" + + "github.com/mudler/LocalAI/pkg/grpc/base" + pb "github.com/mudler/LocalAI/pkg/grpc/proto" +) + +// la_ctx* is an opaque handle. la_capi_load returns it directly (0 == failure), +// unlike rfdetr's out-parameter convention. +var ( + // la_capi_load(const char* gguf_path, int n_threads) -> la_ctx* (0 = fail) + CapiLoad func(gguf string, nThreads int32) uintptr + // la_capi_free(la_ctx* ctx) + CapiFree func(handle uintptr) + // la_capi_locate_path(ctx, image_path, prompt, mode) -> char* json (0 = err) + CapiLocatePath func(handle uintptr, imagePath string, prompt string, mode int32) uintptr + // la_capi_locate_buffer(ctx, bytes, len, prompt, mode) -> char* json (0 = err) + CapiLocateBuffer func(handle uintptr, bytes uintptr, length uintptr, prompt string, mode int32) uintptr + // la_capi_get_n_detections(ctx) -> int + CapiGetNDetections func(handle uintptr) int32 + // la_capi_get_detection_box(ctx, i, out_xyxy[4]) -> int (0 on success) + CapiGetDetectionBox func(handle uintptr, i int32, outXYXY uintptr) int32 + // la_capi_get_detection_label(ctx, i, buf, buf_size) -> int (required size incl NUL; two-call sizing) + CapiGetDetectionLabel func(handle uintptr, i int32, buf uintptr, bufSize int32) int32 + // la_capi_free_string(char* s) + CapiFreeString func(s uintptr) + // la_capi_last_error(ctx) -> const char* (owned by ctx, "" if none / null ctx). + // purego marshals the returned C string into a Go string (a copy), so we + // never free it and avoid raw pointer arithmetic. + CapiLastError func(handle uintptr) string +) + +type LocateAnythingCpp struct { + base.SingleThread + handle uintptr +} + +// Load loads the GGUF model at opts.ModelFile (joined with opts.ModelPath if +// relative) and stores the la_ctx handle for later Detect calls. +func (r *LocateAnythingCpp) Load(opts *pb.ModelOptions) error { + modelFile := opts.ModelFile + if modelFile == "" { + modelFile = opts.Model + } + if modelFile == "" { + return fmt.Errorf("locate-anything-cpp: ModelFile is empty") + } + + var modelPath string + if filepath.IsAbs(modelFile) { + modelPath = modelFile + } else { + modelPath = filepath.Join(opts.ModelPath, modelFile) + } + + if _, err := os.Stat(modelPath); err != nil { + return fmt.Errorf("locate-anything-cpp: model file not found: %s: %w", modelPath, err) + } + + threads := opts.Threads + if threads <= 0 { + threads = 4 + } + + // Release previous model if any (re-Load). + if r.handle != 0 { + CapiFree(r.handle) + r.handle = 0 + } + + h := CapiLoad(modelPath, threads) + if h == 0 { + // la_capi_last_error needs a ctx; on a failed load we have none (it + // returns "" for a null ctx), so the text is best-effort. Surface it + // when present. + if msg := CapiLastError(0); msg != "" { + return fmt.Errorf("locate-anything-cpp: la_capi_load failed for %s: %s", modelPath, msg) + } + return fmt.Errorf("locate-anything-cpp: la_capi_load failed for %s", modelPath) + } + r.handle = h + return nil +} + +// Detect runs open-vocabulary detection on the base64-encoded image in opts.Src +// using the required text prompt in opts.Prompt, returning one pb.Detection per +// located object with its predicted label as ClassName. +func (r *LocateAnythingCpp) Detect(opts *pb.DetectOptions) (pb.DetectResponse, error) { + if r.handle == 0 { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: model not loaded") + } + + // Open-vocabulary detection is prompt-driven; without a prompt there is + // nothing to locate. + prompt := opts.Prompt + if prompt == "" { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: a text prompt is required (open-vocabulary detection)") + } + + // Decode base64 image and write to temp file. + imgData, err := base64.StdEncoding.DecodeString(opts.Src) + if err != nil { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: failed to decode base64 image: %w", err) + } + + tmpFile, err := os.CreateTemp("", "locate-anything-*.img") + if err != nil { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: failed to create temp file: %w", err) + } + defer func() { _ = os.Remove(tmpFile.Name()) }() + + if _, err := tmpFile.Write(imgData); err != nil { + _ = tmpFile.Close() + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: failed to write temp file: %w", err) + } + if err := tmpFile.Close(); err != nil { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: failed to close temp file: %w", err) + } + + // mode 0 = hybrid (Parallel Box Decoding). The JSON return value is unused: + // structured detections are read via the accessor functions. Still must + // free the returned string. + jsonPtr := CapiLocatePath(r.handle, tmpFile.Name(), prompt, 0) + if jsonPtr != 0 { + CapiFreeString(jsonPtr) + } + + n := CapiGetNDetections(r.handle) + if n < 0 { + return pb.DetectResponse{}, fmt.Errorf("locate-anything-cpp: invalid n_detections=%d", n) + } + + detections := make([]*pb.Detection, 0, n) + for i := int32(0); i < n; i++ { + var xyxy [4]float32 // x1, y1, x2, y2 + if CapiGetDetectionBox(r.handle, i, uintptr(unsafe.Pointer(&xyxy[0]))) != 0 { + continue + } + + // Two-call sizing for the label string. + label := "" + need := CapiGetDetectionLabel(r.handle, i, 0, 0) + if need > 0 { + buf := make([]byte, need) + CapiGetDetectionLabel(r.handle, i, uintptr(unsafe.Pointer(&buf[0])), need) + label = string(buf[:need-1]) + } + + detections = append(detections, &pb.Detection{ + X: xyxy[0], + Y: xyxy[1], + Width: xyxy[2] - xyxy[0], + Height: xyxy[3] - xyxy[1], + Confidence: 1.0, + ClassName: label, + }) + } + + return pb.DetectResponse{ + Detections: detections, + }, nil +} diff --git a/backend/go/locate-anything-cpp/main.go b/backend/go/locate-anything-cpp/main.go new file mode 100644 index 000000000..91ccaf38e --- /dev/null +++ b/backend/go/locate-anything-cpp/main.go @@ -0,0 +1,59 @@ +package main + +// main.go - entry point for the locate-anything-cpp gRPC backend. +// +// Dlopens liblocateanythingcpp-.so via purego at the path in +// LOCATEANYTHING_LIBRARY (set by run.sh based on /proc/cpuinfo), registers +// the la_capi_* C ABI symbols, then starts the gRPC server. + +import ( + "flag" + "os" + + "github.com/ebitengine/purego" + grpc "github.com/mudler/LocalAI/pkg/grpc" +) + +var ( + addr = flag.String("addr", "localhost:50051", "the address to connect to") +) + +type LibFuncs struct { + FuncPtr any + Name string +} + +func main() { + // Get library name from environment variable, default to fallback + libName := os.Getenv("LOCATEANYTHING_LIBRARY") + if libName == "" { + libName = "./liblocateanythingcpp-fallback.so" + } + + lib, err := purego.Dlopen(libName, purego.RTLD_NOW|purego.RTLD_GLOBAL) + if err != nil { + panic(err) + } + + libFuncs := []LibFuncs{ + {&CapiLoad, "la_capi_load"}, + {&CapiFree, "la_capi_free"}, + {&CapiLocatePath, "la_capi_locate_path"}, + {&CapiLocateBuffer, "la_capi_locate_buffer"}, + {&CapiGetNDetections, "la_capi_get_n_detections"}, + {&CapiGetDetectionBox, "la_capi_get_detection_box"}, + {&CapiGetDetectionLabel, "la_capi_get_detection_label"}, + {&CapiFreeString, "la_capi_free_string"}, + {&CapiLastError, "la_capi_last_error"}, + } + + for _, lf := range libFuncs { + purego.RegisterLibFunc(lf.FuncPtr, lib, lf.Name) + } + + flag.Parse() + + if err := grpc.StartServer(*addr, &LocateAnythingCpp{}); err != nil { + panic(err) + } +} diff --git a/backend/go/locate-anything-cpp/package.sh b/backend/go/locate-anything-cpp/package.sh new file mode 100755 index 000000000..3b1f13428 --- /dev/null +++ b/backend/go/locate-anything-cpp/package.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Script to copy the appropriate libraries based on architecture + +set -e + +CURDIR=$(dirname "$(realpath $0)") +REPO_ROOT="${CURDIR}/../../.." + +# Create lib directory +mkdir -p $CURDIR/package/lib + +cp -avf $CURDIR/liblocateanythingcpp-*.so $CURDIR/package/ +cp -avf $CURDIR/locate-anything-cpp $CURDIR/package/ +cp -fv $CURDIR/run.sh $CURDIR/package/ + +# Detect architecture and copy appropriate libraries +if [ -f "/lib64/ld-linux-x86-64.so.2" ]; then + # x86_64 architecture + echo "Detected x86_64 architecture, copying x86_64 libraries..." + cp -arfLv /lib64/ld-linux-x86-64.so.2 $CURDIR/package/lib/ld.so + cp -arfLv /lib/x86_64-linux-gnu/libc.so.6 $CURDIR/package/lib/libc.so.6 + cp -arfLv /lib/x86_64-linux-gnu/libgcc_s.so.1 $CURDIR/package/lib/libgcc_s.so.1 + cp -arfLv /lib/x86_64-linux-gnu/libstdc++.so.6 $CURDIR/package/lib/libstdc++.so.6 + cp -arfLv /lib/x86_64-linux-gnu/libm.so.6 $CURDIR/package/lib/libm.so.6 + cp -arfLv /lib/x86_64-linux-gnu/libgomp.so.1 $CURDIR/package/lib/libgomp.so.1 + cp -arfLv /lib/x86_64-linux-gnu/libdl.so.2 $CURDIR/package/lib/libdl.so.2 + cp -arfLv /lib/x86_64-linux-gnu/librt.so.1 $CURDIR/package/lib/librt.so.1 + cp -arfLv /lib/x86_64-linux-gnu/libpthread.so.0 $CURDIR/package/lib/libpthread.so.0 +elif [ -f "/lib/ld-linux-aarch64.so.1" ]; then + # ARM64 architecture + echo "Detected ARM64 architecture, copying ARM64 libraries..." + cp -arfLv /lib/ld-linux-aarch64.so.1 $CURDIR/package/lib/ld.so + cp -arfLv /lib/aarch64-linux-gnu/libc.so.6 $CURDIR/package/lib/libc.so.6 + cp -arfLv /lib/aarch64-linux-gnu/libgcc_s.so.1 $CURDIR/package/lib/libgcc_s.so.1 + cp -arfLv /lib/aarch64-linux-gnu/libstdc++.so.6 $CURDIR/package/lib/libstdc++.so.6 + cp -arfLv /lib/aarch64-linux-gnu/libm.so.6 $CURDIR/package/lib/libm.so.6 + cp -arfLv /lib/aarch64-linux-gnu/libgomp.so.1 $CURDIR/package/lib/libgomp.so.1 + cp -arfLv /lib/aarch64-linux-gnu/libdl.so.2 $CURDIR/package/lib/libdl.so.2 + cp -arfLv /lib/aarch64-linux-gnu/librt.so.1 $CURDIR/package/lib/librt.so.1 + cp -arfLv /lib/aarch64-linux-gnu/libpthread.so.0 $CURDIR/package/lib/libpthread.so.0 +elif [ $(uname -s) = "Darwin" ]; then + echo "Detected Darwin" +else + echo "Error: Could not detect architecture" + exit 1 +fi + +# Package GPU libraries based on BUILD_TYPE +GPU_LIB_SCRIPT="${REPO_ROOT}/scripts/build/package-gpu-libs.sh" +if [ -f "$GPU_LIB_SCRIPT" ]; then + echo "Packaging GPU libraries for BUILD_TYPE=${BUILD_TYPE:-cpu}..." + source "$GPU_LIB_SCRIPT" "$CURDIR/package/lib" + package_gpu_libs +fi + +echo "Packaging completed successfully" +ls -liah $CURDIR/package/ +ls -liah $CURDIR/package/lib/ diff --git a/backend/go/locate-anything-cpp/run.sh b/backend/go/locate-anything-cpp/run.sh new file mode 100755 index 000000000..cefbff629 --- /dev/null +++ b/backend/go/locate-anything-cpp/run.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -ex + +# Get the absolute current dir where the script is located +CURDIR=$(dirname "$(realpath $0)") + +cd / + +echo "CPU info:" +if [ "$(uname)" != "Darwin" ]; then + grep -e "model\sname" /proc/cpuinfo | head -1 + grep -e "flags" /proc/cpuinfo | head -1 +fi + +LIBRARY="$CURDIR/liblocateanythingcpp-fallback.so" + +if [ "$(uname)" != "Darwin" ]; then + if grep -q -e "\savx\s" /proc/cpuinfo ; then + echo "CPU: AVX found OK" + if [ -e $CURDIR/liblocateanythingcpp-avx.so ]; then + LIBRARY="$CURDIR/liblocateanythingcpp-avx.so" + fi + fi + + if grep -q -e "\savx2\s" /proc/cpuinfo ; then + echo "CPU: AVX2 found OK" + if [ -e $CURDIR/liblocateanythingcpp-avx2.so ]; then + LIBRARY="$CURDIR/liblocateanythingcpp-avx2.so" + fi + fi + + # Check avx 512 + if grep -q -e "\savx512f\s" /proc/cpuinfo ; then + echo "CPU: AVX512F found OK" + if [ -e $CURDIR/liblocateanythingcpp-avx512.so ]; then + LIBRARY="$CURDIR/liblocateanythingcpp-avx512.so" + fi + fi +fi + +export LD_LIBRARY_PATH=$CURDIR/lib:$LD_LIBRARY_PATH +export LOCATEANYTHING_LIBRARY=$LIBRARY + +# If there is a lib/ld.so, use it +if [ -f $CURDIR/lib/ld.so ]; then + echo "Using lib/ld.so" + echo "Using library: $LIBRARY" + exec $CURDIR/lib/ld.so $CURDIR/locate-anything-cpp "$@" +fi + +echo "Using library: $LIBRARY" +exec $CURDIR/locate-anything-cpp "$@"