#!/bin/bash # Unified build script for YAMS # # Usage: ./setup.sh [Debug|Release|Profiling|Fuzzing] [--coverage] [--tsan] [--no-tsan] [--asan] [--no-asan] # ./setup.sh Release --with-tests [--with-onnx] [--offline] [--system-deps] # --with-onnx: Build the deprecated ONNX Runtime integration (off by default) # build_type: Release (default), Debug, Profiling, or Fuzzing (TODO) # --coverage: Enable code coverage instrumentation (Debug builds only) # --tsan: Enable ThreadSanitizer for race detection (default for Debug builds) # --no-tsan: Disable ThreadSanitizer (overrides default) # --asan: Enable AddressSanitizer for memory error detection # --no-asan: Disable AddressSanitizer (overrides default) # # Environment variables (for CI/advanced use): # YAMS_OFFLINE - Disable network access for dependency resolution # (Conan cache only, no wrap downloads) # YAMS_USE_SYSTEM_DEPS - Skip Conan entirely and resolve dependencies via # pkg-config/CMake/system prefixes # YAMS_CONAN_HOST_PROFILE - Path to Conan host profile (bypasses auto-detection) # YAMS_CONAN_ARCH - Target architecture (x86_64, armv8, etc.) # YAMS_BUILD_DIR - Override the Meson/Conan build directory # YAMS_EXTRA_MESON_FLAGS - Additional Meson setup flags # YAMS_PKG_CONFIG_PATH - Extra host pkg-config search path passed to Meson # YAMS_BUILD_PKG_CONFIG_PATH - Extra build-machine pkg-config path for Meson # YAMS_CMAKE_PREFIX_PATH - Extra host CMake prefix path passed to Meson # YAMS_BUILD_CMAKE_PREFIX_PATH - Extra build-machine CMake prefix path for Meson # YAMS_MESON_NATIVE_FILE - Use this Meson native file instead of Conan output # YAMS_MESON_CROSS_FILE - Use this Meson cross file instead of Conan output # YAMS_MESON_WRAP_MODE - Override Meson wrap mode (default, nofallback, # nodownload, forcefallback, nopromote) # YAMS_ENABLE_MOBILE_BINDINGS - Build mobile C ABI shared library (true/false) # YAMS_DISABLE_RE2 - Disable RE2 dependency and use std::regex fallback (true/false) # YAMS_COMPILER - Force compiler (clang or gcc) # YAMS_CPPSTD - C++ standard (17, 20, 23) # YAMS_ENABLE_MODULES - Enable C++20 modules (true/false, auto-detected if not set) # YAMS_LIBCXX_HARDENING - libc++ hardening mode (none, fast, extensive, debug) # YAMS_INSTALL_PREFIX - Installation prefix (default: /usr/local or Homebrew) # YAMS_ONNX_GPU - GPU provider for ONNX (auto|cuda|coreml|migraphx|none, default: auto) # auto: macOS=coreml, Linux+NVIDIA=cuda, Linux+ROCm=migraphx, otherwise=none # migraphx: AMD ROCm GPU acceleration (builds ONNX Runtime from source) # YAMS_USE_SYSTEM_ONNX - Use system-installed onnxruntime (auto|true|false, default: auto) # auto: detect system onnxruntime and use it if found # true: require system onnxruntime (fail if not found) # false: always download/build via Conan recipe # YAMS_ONNX_PREFIX - Override prefix path for system onnxruntime # (e.g., /opt/homebrew/opt/onnxruntime) # YAMS_ROCM_PATH - ROCm installation path for MIGraphX builds (default: /opt/rocm) # YAMS_ROCM_GPU_TARGETS - Semicolon-separated AMD GPU architectures for MIGraphX builds # (default: gfx900;gfx906;gfx908;gfx90a;gfx1030;gfx1100) # Common targets: # gfx900 = Vega 10 (MI25, Vega 56/64) # gfx906 = Vega 20 (MI50/60, Radeon VII) # gfx908 = CDNA (MI100) # gfx90a = CDNA2 (MI200 series: MI210, MI250, MI250X) # gfx942 = CDNA3 (MI300 series: MI300A, MI300X, MI325X) # gfx1030 = RDNA2 (RX 6800/6900 series) # gfx1100 = RDNA3 (RX 7900 series) # gfx1101 = RDNA3 (RX 7700/7800 series) # gfx1200 = RDNA4 (RX 9070 series) # # The script prefers Clang when available, falling back to GCC otherwise. It # ensures Conan is given a concrete C++ standard so dependencies resolve cleanly # and keeps Meson in sync with the generated toolchain file. set -euo pipefail is_true() { case "${1:-}" in 1 | true | TRUE | yes | YES | on | ON) return 0 ;; *) return 1 ;; esac } command_path_or_empty() { command -v "$1" 2>/dev/null || true } ENABLE_OFFLINE=false USE_SYSTEM_DEPS=false ENABLE_COVERAGE=false ENABLE_TSAN="${ENABLE_TSAN:-}" # Preserve environment variable if set ENABLE_ASAN="${ENABLE_ASAN:-}" # Preserve environment variable if set BUILD_TYPE_INPUT="" ENABLE_RELEASE_TESTS=false ENABLE_ONNX=false TSAN_EXPLICIT=false ASAN_EXPLICIT=false if is_true "${YAMS_OFFLINE:-false}"; then ENABLE_OFFLINE=true fi if is_true "${YAMS_USE_SYSTEM_DEPS:-false}"; then USE_SYSTEM_DEPS=true fi INITIAL_MESON_BIN="$(command_path_or_empty meson)" INITIAL_NINJA_BIN="$(command_path_or_empty ninja)" while [[ $# -gt 0 ]]; do case "$1" in --coverage) ENABLE_COVERAGE=true shift ;; --tsan) ENABLE_TSAN=true TSAN_EXPLICIT=true shift ;; --no-tsan) ENABLE_TSAN=false TSAN_EXPLICIT=true shift ;; --asan) ENABLE_ASAN=true ASAN_EXPLICIT=true shift ;; --no-asan) ENABLE_ASAN=false ASAN_EXPLICIT=true shift ;; --with-tests) # Force building tests/benchmarks even in Release builds. ENABLE_RELEASE_TESTS=true shift ;; --with-onnx) # ONNX Runtime is deprecated and opt-in: it adds a heavy onnxruntime # dependency (built from source for some GPU providers). ENABLE_ONNX=true shift ;; --offline) ENABLE_OFFLINE=true shift ;; --system-deps) USE_SYSTEM_DEPS=true shift ;; Debug | Release | Profiling | Fuzzing | debug | release | profiling | fuzzing) if [[ -n "${BUILD_TYPE_INPUT}" ]]; then echo "Error: Build type specified multiple times" >&2 exit 1 fi BUILD_TYPE_INPUT="$1" shift ;; *) echo "Usage: $0 [Debug|Release|Profiling|Fuzzing] [--coverage] [--tsan] [--no-tsan] [--asan] [--no-asan] [--with-tests] [--with-onnx] [--offline] [--system-deps]" >&2 exit 1 ;; esac done BUILD_TYPE_INPUT=${BUILD_TYPE_INPUT:-Release} # ONNX Runtime is deprecated and opt-in (--with-onnx). YAMS_DISABLE_ONNX=true still # forces it off for older scripts. if [[ "${YAMS_DISABLE_ONNX:-}" == "true" ]]; then ENABLE_ONNX=false fi BUILD_TYPE_INPUT_LOWER=$(echo "${BUILD_TYPE_INPUT}" | tr '[:upper:]' '[:lower:]') case "${BUILD_TYPE_INPUT_LOWER}" in debug) BUILD_TYPE="Debug" ;; release) BUILD_TYPE="Release" ;; profiling) # Profile what ships: Release Conan dependencies and the Release Meson # configuration (-O3 -g, NDEBUG), plus Tracy and frame pointers. No sanitizers. BUILD_TYPE="Release" ENABLE_PROFILING=true ;; fuzzing) BUILD_TYPE="Debug" # Use Debug as base for Conan/Meson ENABLE_FUZZING=true echo "Fuzzing build: AFL++/libFuzzer instrumentation enabled" ;; *) echo "Unknown build type: ${BUILD_TYPE_INPUT}. Expected Debug, Release, Profiling, or Fuzzing." >&2 exit 1 ;; esac if [[ "${ENABLE_COVERAGE}" == "true" ]] && [[ "${BUILD_TYPE}" != "Debug" ]]; then echo "Error: --coverage flag requires Debug build type" >&2 exit 1 fi # Select desired C++ standard. # Override with YAMS_CPPSTD=20/23. # macOS defaults to C++20 to stay aligned with the repo's supported Conan host # profiles and current CI dependency graph. Other platforms prefer C++23 when # the compiler supports constexpr containers. if [[ -z "${YAMS_CPPSTD:-}" ]]; then if [[ "$(uname -s)" == "Darwin" ]]; then CPPSTD_INPUT="20" echo "macOS defaulting to C++20 for Conan/Meson compatibility" else # Test if compiler supports C++23 with constexpr containers if echo '#include #if __cplusplus >= 202302L && defined(__cpp_lib_constexpr_vector) && __cpp_lib_constexpr_vector >= 201907L #define HAS_CPP23_CONTAINERS 1 #else #define HAS_CPP23_CONTAINERS 0 #endif #if !HAS_CPP23_CONTAINERS #error "No C++23 constexpr containers" #endif' | "${CXX:-c++}" -std=c++23 -fsyntax-only -x c++ - >/dev/null 2>&1; then CPPSTD_INPUT="23" echo "Auto-detected C++23 compiler support (constexpr containers available)" else CPPSTD_INPUT="20" echo "C++23 not fully supported, using C++20" fi fi else CPPSTD_INPUT="${YAMS_CPPSTD}" fi case "${CPPSTD_INPUT}" in 17 | 20 | 23) CPPSTD="${CPPSTD_INPUT}" ;; c++17 | c++20 | c++23) CPPSTD="${CPPSTD_INPUT#c++}" ;; *) echo "Unknown C++ standard: ${CPPSTD_INPUT}. Expected 17|20|23 or c++17|c++20|c++23." >&2 exit 1 ;; esac # Value for Meson project option MESON_CPPSTD="c++${CPPSTD}" if [[ -z "${YAMS_ENABLE_MODULES:-}" ]]; then ENABLE_MODULES=false if echo 'export module test; export int foo() { return 42; }' | "${CXX:-c++}" -std=c++20 -fmodules -fsyntax-only -x c++ - >/dev/null 2>&1; then ENABLE_MODULES=true echo "Auto-detected C++20 module support (Clang -fmodules)" elif echo 'export module test; export int foo() { return 42; }' | "${CXX:-c++}" -std=c++20 -fmodules-ts -fsyntax-only -x c++ - >/dev/null 2>&1; then ENABLE_MODULES=true echo "Auto-detected C++20 module support (GCC -fmodules-ts)" else echo "C++20 modules not fully supported by compiler, disabled" fi else if [[ "${YAMS_ENABLE_MODULES}" == "true" ]]; then ENABLE_MODULES=true echo "C++20 modules enabled via YAMS_ENABLE_MODULES=true" else ENABLE_MODULES=false echo "C++20 modules disabled via YAMS_ENABLE_MODULES=false" fi fi # libc++ hardening mode (only applies when using libc++) # Options: none, fast, extensive, debug # Override with YAMS_LIBCXX_HARDENING=fast|extensive|debug|none LIBCXX_HARDENING=${YAMS_LIBCXX_HARDENING:-none} # Check if using explicit Conan profile (CI mode) CONAN_HOST_PROFILE=${YAMS_CONAN_HOST_PROFILE:-} CONAN_ARCH=${YAMS_CONAN_ARCH:-} # Conan names 64-bit ARM "armv8"; callers often pass uname/pacman labels. case "${CONAN_ARCH}" in aarch64 | arm64) CONAN_ARCH="armv8" ;; esac CONAN_EXTRA_OPTIONS=${YAMS_CONAN_EXTRA_OPTIONS:-} USE_PROFILE=false if [[ -z "${CONAN_HOST_PROFILE}" ]] && [[ "$(uname -s)" == "Darwin" ]]; then uname_machine=$(uname -m) if [[ "${uname_machine}" == "x86_64" ]]; then CONAN_HOST_PROFILE="./conan/profiles/host-macos-apple-clang-x86" else CONAN_HOST_PROFILE="./conan/profiles/host-macos-apple-clang" fi fi if [[ -n "${CONAN_HOST_PROFILE}" ]]; then if [[ ! -f "${CONAN_HOST_PROFILE}" ]]; then echo "ERROR: Conan host profile not found: ${CONAN_HOST_PROFILE}" >&2 exit 1 fi USE_PROFILE=true echo "Using explicit Conan host profile: ${CONAN_HOST_PROFILE}" fi CONAN_ARGS=(-s "build_type=${BUILD_TYPE}") if [[ "${ENABLE_OFFLINE}" == "true" ]]; then CONAN_ARGS+=(-nr --build=never) else CONAN_ARGS+=(--update --build=missing) fi # Add common Conan options (sqlite3 with FTS5, etc.) CONAN_ARGS+=(-o "sqlite3/*:fts5=True") # Fuzzing builds: disable programs in zstd to avoid symlink issues in Docker if [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then CONAN_ARGS+=(-o "zstd/*:build_programs=False") fi # Add extra Conan options from environment (for CI) if [[ -n "${CONAN_EXTRA_OPTIONS}" ]]; then # shellcheck disable=SC2086 read -ra EXTRA_OPTS <<<"${CONAN_EXTRA_OPTIONS}" CONAN_ARGS+=("${EXTRA_OPTS[@]}") echo "Extra Conan options: ${CONAN_EXTRA_OPTIONS}" fi detect_version() { local bin="$1" if command -v "${bin}" >/dev/null 2>&1; then if "${bin}" -dumpfullversion >/dev/null 2>&1; then "${bin}" -dumpfullversion elif "${bin}" -dumpversion >/dev/null 2>&1; then "${bin}" -dumpversion else "${bin}" --version | head -n1 | grep -oE '[0-9]+(\.[0-9]+)*' | head -n1 fi fi } COERCE_MAJOR() { echo "$1" | cut -d. -f1 } COMPILER_OVERRIDE=${YAMS_COMPILER:-} # When using explicit profile, skip auto-detection of compiler settings if [[ "${USE_PROFILE}" == "true" ]]; then echo "Skipping compiler auto-detection (using profile: ${CONAN_HOST_PROFILE})" # Still set CC/CXX for Meson if not already set if [[ -z "${CC:-}" ]] && command -v clang >/dev/null 2>&1; then export CC="clang" export CXX="clang++" elif [[ -z "${CC:-}" ]] && command -v gcc >/dev/null 2>&1; then export CC="gcc" export CXX="g++" fi # Add profile to Conan args CONAN_ARGS+=(-pr:h "${CONAN_HOST_PROFILE}" -pr:b default) CONAN_ARGS+=(-s:h "build_type=${BUILD_TYPE}") CONAN_ARGS+=(-s:h "compiler.cppstd=${CPPSTD}") # Add architecture if specified if [[ -n "${CONAN_ARCH}" ]]; then CONAN_ARGS+=(-s:h "arch=${CONAN_ARCH}") echo "Target architecture: ${CONAN_ARCH}" fi else # Auto-detection mode (original behavior) if [[ "${COMPILER_OVERRIDE}" == clang ]] || { [[ -z "${COMPILER_OVERRIDE}" ]] && command -v clang >/dev/null 2>&1 && command -v clang++ >/dev/null 2>&1; }; then echo "--- Using Clang toolchain ---" export CC="clang" export CXX="clang++" # macOS requires libc++, Linux can use libstdc++11 if [[ "$(uname -s)" == "Darwin" ]]; then LIBCXX="libc++" else LIBCXX="libstdc++11" fi CLANG_VERSION=$(detect_version clang++) CLANG_MAJOR=$(COERCE_MAJOR "${CLANG_VERSION:-0}") if [[ -z "${CLANG_MAJOR}" || "${CLANG_MAJOR}" == 0 ]]; then echo "Unable to detect clang version." >&2 exit 1 fi if [[ "$(uname -s)" == "Darwin" ]]; then # On macOS use Conan's apple-clang compiler model CONAN_ARGS+=( -s "compiler=apple-clang" -s "compiler.version=${CLANG_MAJOR}" -s "compiler.libcxx=${LIBCXX}" -s "compiler.cppstd=${CPPSTD}" ) else CONAN_ARGS+=( -s "compiler=clang" -s "compiler.version=${CLANG_MAJOR}" -s "compiler.libcxx=${LIBCXX}" -s "compiler.cppstd=${CPPSTD}" ) fi else echo "--- Using GCC toolchain ---" export CC="gcc" export CXX="g++" if ! command -v g++ >/dev/null 2>&1; then echo "g++ not found in PATH." >&2 exit 1 fi GCC_VERSION=$(detect_version g++) GCC_MAJOR=$(COERCE_MAJOR "${GCC_VERSION:-0}") if [[ -z "${GCC_MAJOR}" || "${GCC_MAJOR}" == 0 ]]; then echo "Unable to detect gcc version." >&2 exit 1 fi CONAN_ARGS+=( -s "compiler=gcc" -s "compiler.version=${GCC_MAJOR}" -s "compiler.libcxx=libstdc++11" -s "compiler.cppstd=${CPPSTD}" ) fi fi # Wrap CC/CXX with ccache if available for faster incremental builds. # Skip ccache environment wrapping when YAMS_SKIP_CCACHE=1 is set — # useful for CI environments where ccache interferes with Conan # dependency builds (e.g. OpenBLAS ASM compilation via CMake). if [[ "${YAMS_SKIP_CCACHE:-}" == "1" ]]; then echo "--- Skipping ccache wrapper (YAMS_SKIP_CCACHE=1) ---" elif command -v ccache >/dev/null 2>&1; then echo "--- Enabling ccache for faster incremental builds ---" # Only wrap if not already wrapped if [[ "${CC:-}" != ccache* ]]; then export CC="ccache ${CC:-cc}" export CXX="ccache ${CXX:-c++}" fi # Show ccache stats if verbose ccache -s 2>/dev/null | head -5 || true fi if [[ "${ENABLE_PROFILING:-false}" == "true" ]]; then BUILD_DIR="build/profiling" CONAN_SUBDIR="build-profiling" # Conan writes the Release-based profiling toolchain under a nested build-release directory CONAN_ALT_SUBDIR="build-release" # Profile optimized code: -O0 zone timings do not predict release hot spots. BUILD_TYPE_MESON_LOWER="release" elif [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then BUILD_DIR="build/fuzzing" CONAN_SUBDIR="build-fuzzing" # Fuzzing uses Debug as the Conan build type, so Conan writes its toolchain under # build-debug (same as Profiling). CONAN_ALT_SUBDIR="build-debug" BUILD_TYPE_MESON_LOWER="debug" elif [[ "${BUILD_TYPE}" == "Debug" ]]; then BUILD_DIR="build/debug" CONAN_SUBDIR="build-debug" BUILD_TYPE_MESON_LOWER="debug" else BUILD_DIR="build/${BUILD_TYPE_INPUT_LOWER}" CONAN_SUBDIR="build-${BUILD_TYPE_INPUT_LOWER}" BUILD_TYPE_MESON_LOWER="release" fi if [[ -n "${YAMS_BUILD_DIR:-}" ]]; then BUILD_DIR="${YAMS_BUILD_DIR}" fi # Some Conan generators ignore --output-folder and always emit to build-. # Remember locations to probe for toolchains and Meson cache files. CONAN_GENERATED_DIR="${BUILD_DIR}/build-${BUILD_TYPE_INPUT_LOWER}" CONAN_ALT_DIR="${BUILD_DIR}/${CONAN_ALT_SUBDIR:-}" # Detect install prefix based on platform if [[ "$(uname -s)" == "Darwin" ]]; then # macOS: check for Homebrew installation if command -v brew >/dev/null 2>&1; then BREW_PREFIX=$(brew --prefix 2>/dev/null || echo "/usr/local") INSTALL_PREFIX="${BREW_PREFIX}" else INSTALL_PREFIX="/usr/local" fi else # Linux: use standard prefix INSTALL_PREFIX="/usr/local" fi # Allow override via environment INSTALL_PREFIX="${YAMS_INSTALL_PREFIX:-${INSTALL_PREFIX}}" echo "Build Type: ${BUILD_TYPE_INPUT}" if [[ "${ENABLE_PROFILING:-false}" == "true" ]]; then echo "Profiling: Tracy enabled" fi if [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then echo "Fuzzing: AFL++/libFuzzer enabled" fi echo "Build Dir: ${BUILD_DIR}" echo "Install Prefix: ${INSTALL_PREFIX}" echo "C++ Std: ${MESON_CPPSTD} (Conan: ${CPPSTD})" echo "Offline Mode: ${ENABLE_OFFLINE}" echo "System Deps: ${USE_SYSTEM_DEPS}" if [[ "${LIBCXX_HARDENING}" != "none" ]]; then echo "libc++ Hardening: ${LIBCXX_HARDENING}" fi if [[ "${ENABLE_RELEASE_TESTS}" == "true" ]]; then echo "Release Tests: enabled (--with-tests)" fi if [[ "${USE_SYSTEM_DEPS}" != "true" ]]; then echo "--- Exporting custom Conan recipes... ---" # Export custom onnxruntime recipe if it exists if [[ "${ENABLE_ONNX}" != "true" ]]; then echo "Skipping onnxruntime recipe export (ONNX disabled)" elif [[ -f "conan/onnxruntime/conanfile.py" ]]; then # Avoid sporadic Conan cache race/collision errors by retrying export once. echo "Exporting onnxruntime/1.23.0 from conan/onnxruntime/" if ! conan export conan/onnxruntime --name=onnxruntime --version=1.23.0; then echo "Retrying conan export onnxruntime/1.23.0..." conan export conan/onnxruntime --name=onnxruntime --version=1.23.0 fi fi echo "--- Running conan install... ---" # Add policy toolchain for legacy recipes if in Docker or CI POLICY_TC="" if [[ -n "${DOCKERFILE_CONF_REV:-}" ]] || [[ -n "${CI:-}" ]]; then POLICY_TC="/tmp/yams_policy_toolchain.cmake" echo 'cmake_policy(VERSION 3.5)' >"$POLICY_TC" CONAN_ARGS+=(-c "tools.cmake.cmaketoolchain:user_toolchain+=${POLICY_TC}") fi fi # Enable tests for Debug builds in Conan (needed for Catch2/gtest dependencies) if [[ "${BUILD_TYPE}" == "Debug" ]] || [[ "${ENABLE_PROFILING:-false}" == "true" ]] || [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then CONAN_ARGS+=(-o "&:build_tests=True") fi # Optionally enable tests in Conan for Release builds. if [[ "${BUILD_TYPE}" == "Release" ]] && [[ "${ENABLE_RELEASE_TESTS}" == "true" ]]; then CONAN_ARGS+=(-o "&:build_tests=True") fi # Enable Tracy profiling for profiling builds if [[ "${ENABLE_PROFILING:-false}" == "true" ]]; then echo "Tracy profiling enabled" CONAN_ARGS+=(-o "yams/*:enable_profiling=True") CONAN_ARGS+=(-o "tracy/*:enable=True") fi if [[ "${ENABLE_ONNX}" != "true" ]]; then echo "ONNX support disabled (deprecated; pass --with-onnx to build it)" CONAN_ARGS+=(-o "yams/*:enable_onnx=False") else CONAN_ARGS+=(-o "yams/*:enable_onnx=True") # --- Detect system-installed onnxruntime --- # Override with YAMS_USE_SYSTEM_ONNX=true|false|auto (default: auto) # When auto, we detect system onnxruntime and use it if found. # Set YAMS_ONNX_PREFIX to override the detected prefix path. USE_SYSTEM_ONNX="${YAMS_USE_SYSTEM_ONNX:-auto}" SYSTEM_ONNX_PREFIX="${YAMS_ONNX_PREFIX:-}" if [[ "${USE_SYSTEM_ONNX}" == "auto" ]]; then # Auto-detect: check pkg-config, Homebrew, common paths DETECTED_ONNX_PREFIX="" # 1) pkg-config if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists onnxruntime 2>/dev/null; then DETECTED_ONNX_PREFIX=$(pkg-config --variable=prefix onnxruntime 2>/dev/null || true) if [[ -n "${DETECTED_ONNX_PREFIX}" && -d "${DETECTED_ONNX_PREFIX}" ]]; then echo "System onnxruntime detected via pkg-config: ${DETECTED_ONNX_PREFIX}" else DETECTED_ONNX_PREFIX="" fi fi # 2) Homebrew (macOS) if [[ -z "${DETECTED_ONNX_PREFIX}" && "$(uname -s)" == "Darwin" ]]; then if command -v brew >/dev/null 2>&1; then BREW_ONNX_PREFIX=$(brew --prefix onnxruntime 2>/dev/null || true) if [[ -n "${BREW_ONNX_PREFIX}" && -d "${BREW_ONNX_PREFIX}/lib" && -d "${BREW_ONNX_PREFIX}/include" ]]; then # Verify it's actually installed (brew --prefix returns cellar path even if not installed) if ls "${BREW_ONNX_PREFIX}"/lib/libonnxruntime* >/dev/null 2>&1; then DETECTED_ONNX_PREFIX="${BREW_ONNX_PREFIX}" echo "System onnxruntime detected via Homebrew: ${DETECTED_ONNX_PREFIX}" fi fi fi fi # 3) Common system paths if [[ -z "${DETECTED_ONNX_PREFIX}" ]]; then for candidate_prefix in /opt/homebrew /usr/local /usr; do if ls "${candidate_prefix}"/lib/libonnxruntime* >/dev/null 2>&1; then # Check all known header layouts: # Flat: include/onnxruntime_c_api.h (prebuilt archives) # Homebrew: include/onnxruntime/onnxruntime_c_api.h (brew) # Source: include/onnxruntime/core/session/onnxruntime_c_api.h (apt/manual) if [[ -f "${candidate_prefix}/include/onnxruntime_c_api.h" ]] || [[ -f "${candidate_prefix}/include/onnxruntime/onnxruntime_c_api.h" ]] || [[ -f "${candidate_prefix}/include/onnxruntime/core/session/onnxruntime_c_api.h" ]]; then DETECTED_ONNX_PREFIX="${candidate_prefix}" echo "System onnxruntime detected at: ${DETECTED_ONNX_PREFIX}" break fi fi done fi if [[ -n "${DETECTED_ONNX_PREFIX}" ]]; then USE_SYSTEM_ONNX="true" SYSTEM_ONNX_PREFIX="${SYSTEM_ONNX_PREFIX:-${DETECTED_ONNX_PREFIX}}" else USE_SYSTEM_ONNX="false" fi fi if [[ "${USE_SYSTEM_ONNX}" == "true" ]]; then echo "Using system onnxruntime from: ${SYSTEM_ONNX_PREFIX}" CONAN_ARGS+=(-o "onnxruntime/*:use_system=True") if [[ -n "${SYSTEM_ONNX_PREFIX}" ]]; then CONAN_ARGS+=(-o "onnxruntime/*:system_prefix=${SYSTEM_ONNX_PREFIX}") fi # Detect system onnxruntime version for informational purposes if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists onnxruntime 2>/dev/null; then SYS_ONNX_VERSION=$(pkg-config --modversion onnxruntime 2>/dev/null || true) if [[ -n "${SYS_ONNX_VERSION}" ]]; then echo "System onnxruntime version: ${SYS_ONNX_VERSION}" fi fi fi # Auto-detect GPU for ONNX acceleration (skip when using system onnxruntime) # Override with YAMS_ONNX_GPU=cuda|coreml|migraphx|none if [[ "${USE_SYSTEM_ONNX}" == "true" ]]; then echo "Skipping GPU auto-detection (using system onnxruntime)" ONNX_GPU="none" # System build has its own GPU support baked in else ONNX_GPU="${YAMS_ONNX_GPU:-auto}" if [[ "${ONNX_GPU}" == "auto" ]]; then if [[ "$(uname -s)" == "Darwin" ]]; then # macOS: CoreML is included in standard ONNX Runtime builds ONNX_GPU="coreml" echo "macOS detected: enabling CoreML GPU acceleration (Neural Engine + GPU)" elif command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi >/dev/null 2>&1; then # NVIDIA GPU detected - now validate CUDA toolkit is actually available # nvidia-smi presence alone doesn't guarantee CUDA runtime is usable if command -v nvcc >/dev/null 2>&1; then # nvcc is available (CUDA toolkit installed via package manager or CUDA SDK) ONNX_GPU="cuda" echo "NVIDIA GPU + CUDA toolkit (nvcc) detected: enabling CUDA acceleration" elif [[ -f /usr/local/cuda/lib64/libcudart.so ]] || [[ -f /usr/local/cuda/lib/libcudart.so ]] || ldconfig -p 2>/dev/null | grep -q libcudart; then # CUDA runtime library found (sufficient for inference, even without nvcc) ONNX_GPU="cuda" echo "NVIDIA GPU + CUDA runtime (libcudart) detected: enabling CUDA acceleration" else # GPU present but CUDA toolkit/runtime missing - use CPU to avoid runtime failures ONNX_GPU="none" echo "NVIDIA GPU detected but CUDA toolkit missing: using CPU-only ONNX Runtime" echo " Install CUDA toolkit for GPU acceleration: https://developer.nvidia.com/cuda-downloads" fi elif [[ -d /opt/rocm ]] || command -v rocm-smi >/dev/null 2>&1; then # ROCm detected - use MIGraphX (builds ONNX Runtime from source) # Detect ROCm path if [[ -d /opt/rocm ]]; then ROCM_PATH="/opt/rocm" elif command -v rocm-smi >/dev/null 2>&1; then ROCM_PATH="$(dirname "$(dirname "$(command -v rocm-smi)")")" fi # Check if MIGraphX is installed (ROCm 7.x uses lib/migraphx/lib/) if [[ -f "${ROCM_PATH}/lib/libmigraphx.so" ]] || [[ -f "${ROCM_PATH}/lib/migraphx/lib/libmigraphx.so" ]] || [[ -f "${ROCM_PATH}/lib/libmigraphx_c.so" ]]; then ONNX_GPU="migraphx" echo "ROCm + MIGraphX detected at ${ROCM_PATH}: enabling AMD GPU acceleration" echo " Note: ONNX Runtime will be built from source (takes ~20-30 minutes)" # Auto-detect GPU architecture using rocminfo (with timeout in case of permission issues) if [[ -z "${YAMS_ROCM_GPU_TARGETS:-}" ]] && command -v rocminfo >/dev/null 2>&1; then DETECTED_TARGETS=$(timeout 5 rocminfo 2>/dev/null | grep -oP 'gfx[0-9a-z]+' | sort -u | tr '\n' ';' | sed 's/;$//' || true) if [[ -n "${DETECTED_TARGETS}" ]]; then export YAMS_ROCM_GPU_TARGETS="${DETECTED_TARGETS}" echo " Auto-detected GPU target(s): ${DETECTED_TARGETS}" else echo " Could not auto-detect GPU targets (rocminfo failed or no permission)" echo " Set YAMS_ROCM_GPU_TARGETS manually if needed (e.g., gfx1100 for RX 7900)" fi fi else ONNX_GPU="none" echo "ROCm detected at ${ROCM_PATH} but MIGraphX not found" echo " Using CPU-only ONNX Runtime" echo " Install MIGraphX for GPU acceleration: https://github.com/ROCm/AMDMIGraphX" fi else ONNX_GPU="none" echo "No GPU detected: using CPU-only ONNX Runtime" fi fi fi # end: skip GPU detection for system onnxruntime # Handle MIGraphX-specific options (only for non-system builds) if [[ "${USE_SYSTEM_ONNX}" != "true" ]] && [[ "${ONNX_GPU}" == "migraphx" ]]; then # Set ROCm path for conan (use detected path or environment override) ROCM_PATH="${YAMS_ROCM_PATH:-${ROCM_PATH:-/opt/rocm}}" if [[ ! -d "${ROCM_PATH}" ]]; then echo "ERROR: ROCm not found at ${ROCM_PATH}" >&2 echo " Set YAMS_ROCM_PATH to your ROCm installation path" >&2 exit 1 fi CONAN_ARGS+=(-o "onnxruntime/*:rocm_path=${ROCM_PATH}") echo "ROCm path: ${ROCM_PATH}" # Pass GPU targets if specified if [[ -n "${YAMS_ROCM_GPU_TARGETS:-}" ]]; then echo "ROCm GPU targets: ${YAMS_ROCM_GPU_TARGETS}" fi fi if [[ "${USE_SYSTEM_ONNX}" != "true" ]] && [[ "${ONNX_GPU}" != "none" ]]; then CONAN_ARGS+=(-o "onnxruntime/*:with_gpu=${ONNX_GPU}") echo "ONNX GPU provider: ${ONNX_GPU}" fi fi if [[ "${YAMS_DISABLE_RE2:-}" == "true" ]]; then echo "RE2 disabled (YAMS_DISABLE_RE2=true)" CONAN_ARGS+=(-o "yams/*:enable_re2=False") fi MESON_TOOLCHAIN_ARG="" MESON_TOOLCHAIN_FILE="" MESON_NATIVE_FILE_OVERRIDE="${YAMS_MESON_NATIVE_FILE:-}" MESON_CROSS_FILE_OVERRIDE="${YAMS_MESON_CROSS_FILE:-}" MESON_EXTRA_NATIVE_FILES=() if [[ -n "${YAMS_EXTRA_MESON_NATIVE_FILES:-}" ]]; then IFS=':' read -r -a RAW_EXTRA_NATIVE_FILES <<<"${YAMS_EXTRA_MESON_NATIVE_FILES}" for extra_native_file in "${RAW_EXTRA_NATIVE_FILES[@]}"; do [[ -z "${extra_native_file}" ]] && continue if [[ ! -f "${extra_native_file}" ]]; then echo "Error: Extra Meson native file not found: ${extra_native_file}" >&2 exit 1 fi MESON_EXTRA_NATIVE_FILES+=("${extra_native_file}") done fi if [[ -n "${MESON_NATIVE_FILE_OVERRIDE}" && -n "${MESON_CROSS_FILE_OVERRIDE}" ]]; then echo "Error: Set only one of YAMS_MESON_NATIVE_FILE or YAMS_MESON_CROSS_FILE." >&2 exit 1 fi if [[ -n "${MESON_NATIVE_FILE_OVERRIDE}" ]]; then if [[ ! -f "${MESON_NATIVE_FILE_OVERRIDE}" ]]; then echo "Error: Meson native file not found: ${MESON_NATIVE_FILE_OVERRIDE}" >&2 exit 1 fi MESON_TOOLCHAIN_ARG="--native-file" MESON_TOOLCHAIN_FILE="${MESON_NATIVE_FILE_OVERRIDE}" elif [[ -n "${MESON_CROSS_FILE_OVERRIDE}" ]]; then if [[ ! -f "${MESON_CROSS_FILE_OVERRIDE}" ]]; then echo "Error: Meson cross file not found: ${MESON_CROSS_FILE_OVERRIDE}" >&2 exit 1 fi MESON_TOOLCHAIN_ARG="--cross-file" MESON_TOOLCHAIN_FILE="${MESON_CROSS_FILE_OVERRIDE}" fi if [[ "${USE_SYSTEM_DEPS}" == "true" ]]; then echo "--- Skipping Conan install (system dependency mode) ---" else # Use runtime_deploy to copy shared libraries next to executables (mainly for Windows, no-op on Unix with RPATH) conan install . -of "${BUILD_DIR}" "${CONAN_ARGS[@]}" --deployer=runtime_deploy --deployer-folder="${BUILD_DIR}" -c tools.deployer:symlinks=False # Check for either native or cross file (Conan generates cross file for cross-compilation) # Conan 2.x sometimes nests generator output under build-/conan even when -of points at # ${BUILD_DIR}. Probe primary, then CONAN_GENERATED_DIR, then the legacy root, then CONAN_ALT_DIR. NATIVE_FILE_PRIMARY="${BUILD_DIR}/${CONAN_SUBDIR}/conan/conan_meson_native.ini" CROSS_FILE_PRIMARY="${BUILD_DIR}/${CONAN_SUBDIR}/conan/conan_meson_cross.ini" NATIVE_FILE_SECONDARY="${CONAN_GENERATED_DIR}/conan/conan_meson_native.ini" CROSS_FILE_SECONDARY="${CONAN_GENERATED_DIR}/conan/conan_meson_cross.ini" NATIVE_FILE_TERTIARY="${BUILD_DIR}/conan/conan_meson_native.ini" CROSS_FILE_TERTIARY="${BUILD_DIR}/conan/conan_meson_cross.ini" NATIVE_FILE_QUAT="${CONAN_ALT_DIR}/conan/conan_meson_native.ini" CROSS_FILE_QUAT="${CONAN_ALT_DIR}/conan/conan_meson_cross.ini" if [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${NATIVE_FILE_PRIMARY}" ]]; then MESON_TOOLCHAIN_ARG="--native-file" MESON_TOOLCHAIN_FILE="${NATIVE_FILE_PRIMARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${CROSS_FILE_PRIMARY}" ]]; then MESON_TOOLCHAIN_ARG="--cross-file" MESON_TOOLCHAIN_FILE="${CROSS_FILE_PRIMARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${NATIVE_FILE_SECONDARY}" ]]; then MESON_TOOLCHAIN_ARG="--native-file" MESON_TOOLCHAIN_FILE="${NATIVE_FILE_SECONDARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${CROSS_FILE_SECONDARY}" ]]; then MESON_TOOLCHAIN_ARG="--cross-file" MESON_TOOLCHAIN_FILE="${CROSS_FILE_SECONDARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${NATIVE_FILE_TERTIARY}" ]]; then MESON_TOOLCHAIN_ARG="--native-file" MESON_TOOLCHAIN_FILE="${NATIVE_FILE_TERTIARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -f "${CROSS_FILE_TERTIARY}" ]]; then MESON_TOOLCHAIN_ARG="--cross-file" MESON_TOOLCHAIN_FILE="${CROSS_FILE_TERTIARY}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -n "${CONAN_ALT_DIR}" && -f "${NATIVE_FILE_QUAT}" ]]; then MESON_TOOLCHAIN_ARG="--native-file" MESON_TOOLCHAIN_FILE="${NATIVE_FILE_QUAT}" elif [[ -z "${MESON_TOOLCHAIN_ARG}" && -n "${CONAN_ALT_DIR}" && -f "${CROSS_FILE_QUAT}" ]]; then MESON_TOOLCHAIN_ARG="--cross-file" MESON_TOOLCHAIN_FILE="${CROSS_FILE_QUAT}" fi if [[ -z "${MESON_TOOLCHAIN_ARG}" ]]; then echo "Error: Conan meson toolchain file not found" >&2 echo "Checked: ${NATIVE_FILE_PRIMARY}" >&2 echo " and: ${CROSS_FILE_PRIMARY}" >&2 echo " and: ${NATIVE_FILE_SECONDARY}" >&2 echo " and: ${CROSS_FILE_SECONDARY}" >&2 echo " and: ${NATIVE_FILE_TERTIARY}" >&2 echo " and: ${CROSS_FILE_TERTIARY}" >&2 if [[ -n "${CONAN_ALT_DIR}" ]]; then echo " and: ${NATIVE_FILE_QUAT}" >&2 echo " and: ${CROSS_FILE_QUAT}" >&2 fi echo "Please check the output path from 'conan install'." >&2 exit 1 fi CONAN_TOOLCHAIN_DIR="$(cd "$(dirname "${MESON_TOOLCHAIN_FILE}")" && pwd)" CONAN_BUILD_ENV="${CONAN_TOOLCHAIN_DIR}/conanbuild.sh" if [[ -f "${CONAN_BUILD_ENV}" ]]; then # Activate Conan's build-machine tools before Meson configure so cross-build # generators resolve native utilities like protoc from the Conan graph. # Conan-generated env scripts may reference variables (e.g. ACLOCAL_PATH) # that are unset in minimal environments like Docker; disable nounset temporarily. for maybe_unset_var in ACLOCAL_PATH PKG_CONFIG_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH \ DYLD_FALLBACK_LIBRARY_PATH LIBRARY_PATH CMAKE_PREFIX_PATH MANPATH; do if [[ -z "${!maybe_unset_var+x}" ]]; then export "${maybe_unset_var}=" fi done # shellcheck disable=SC1090 set +u source "${CONAN_BUILD_ENV}" set -u fi # Export BOOST_ROOT so meson's auto-detect Boost dep finds the Conan-installed # Boost on platforms with no system Boost (Windows). Read prefix= directly # from Conan's boost.pc — that file's location is the same dir holding # CONAN_BUILD_ENV. if [[ -z "${BOOST_ROOT:-}" ]]; then BOOST_PC="${CONAN_TOOLCHAIN_DIR:-}/boost.pc" if [[ -f "${BOOST_PC}" ]]; then BOOST_ROOT_CANDIDATE=$(awk -F= '/^prefix[[:space:]]*=/ { print $2; exit }' "${BOOST_PC}") if [[ -n "${BOOST_ROOT_CANDIDATE}" && -d "${BOOST_ROOT_CANDIDATE}/include/boost" ]]; then export BOOST_ROOT="${BOOST_ROOT_CANDIDATE}" echo "BOOST_ROOT set to: ${BOOST_ROOT}" fi fi fi fi YAMS_PROTOC_PATH="${YAMS_PROTOC_PATH:-}" MESON_WRAPPER_PATH="" ACTIVE_MESON_BIN="$(command_path_or_empty meson)" ACTIVE_NINJA_BIN="$(command_path_or_empty ninja)" CONAN_TOOLS_OVERRIDE=false if [[ -f "${CONAN_BUILD_ENV:-}" ]]; then MESON_WRAPPER_PATH="${BUILD_DIR}/mesonw" CONAN_BUILD_ENV_ESCAPED=$(printf '%q' "${CONAN_BUILD_ENV}") cat >"${MESON_WRAPPER_PATH}" <&2 exit 1 fi if [[ "${LIBSQL_BACKEND_LOWER}" == "libsql" && "${USE_SYSTEM_DEPS}" == "true" ]]; then LIBSQL_PKG_FOUND=false if command -v pkg-config >/dev/null 2>&1; then if pkg-config --exists libsql || pkg-config --exists libsql-sqlite3; then LIBSQL_PKG_FOUND=true fi fi if [[ "${LIBSQL_PKG_FOUND}" != "true" ]]; then echo "System dependency mode: libSQL not found via pkg-config; falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" fi elif [[ "${LIBSQL_BACKEND_LOWER}" == "libsql" && "$(uname -s)" != "Darwin" ]]; then LIBSQL_PKG_FOUND=false if command -v pkg-config >/dev/null 2>&1; then if pkg-config --exists libsql || pkg-config --exists libsql-sqlite3; then LIBSQL_PKG_FOUND=true fi fi if [[ "${LIBSQL_PKG_FOUND}" != "true" ]]; then if [[ -d "subprojects/libsql" ]]; then echo "libSQL subproject detected at subprojects/libsql; keeping libsql backend" elif ! command -v cargo >/dev/null 2>&1; then echo "libSQL not detected on Linux (pkg-config/cargo missing); falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" fi fi fi if [[ "${LIBSQL_BACKEND_LOWER}" == "libsql" ]]; then echo "Database backend: libsql" if [[ -f "subprojects/libsql.wrap" && ! -d "subprojects/libsql" ]]; then if [[ "${USE_SYSTEM_DEPS}" == "true" ]]; then echo "libSQL not found via system dependencies; falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" elif [[ "${ENABLE_OFFLINE}" == "true" ]]; then echo "Offline mode: not fetching libSQL subproject; falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" elif command -v meson >/dev/null 2>&1; then echo "Fetching libSQL subproject (meson wrap)..." if ! meson subprojects download libsql; then echo "Failed to fetch libSQL subproject; falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" fi else echo "Meson not found; cannot fetch libSQL subproject. Falling back to sqlite" >&2 LIBSQL_BACKEND_LOWER="sqlite" fi fi else echo "Database backend: sqlite" fi MESON_OPTIONS+=("-Ddatabase-backend=${LIBSQL_BACKEND_LOWER}") # Mobile bindings are off by default; allow CI/users to opt-in. if [[ "${YAMS_ENABLE_MOBILE_BINDINGS:-}" == "true" ]]; then MESON_OPTIONS+=("-Denable-mobile-bindings=true") echo "Mobile bindings enabled (YAMS_ENABLE_MOBILE_BINDINGS=true)" elif [[ "${YAMS_ENABLE_MOBILE_BINDINGS:-}" == "false" ]]; then MESON_OPTIONS+=("-Denable-mobile-bindings=false") echo "Mobile bindings disabled (YAMS_ENABLE_MOBILE_BINDINGS=false)" fi # ThreadSanitizer: default enabled for Debug builds, can be overridden with --tsan/--no-tsan if [[ -z "${ENABLE_TSAN}" ]]; then # Profiling stays uninstrumented so Tracy timings are not TSAN-distorted (opt in with --tsan). # Fuzzing stays uninstrumented too: the fuzz harnesses link -fsanitize=fuzzer,address,undefined # and ASan cannot share a process with TSan. if [[ "${ENABLE_PROFILING:-false}" == "true" ]] || [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then ENABLE_TSAN=false elif [[ "${BUILD_TYPE}" == "Debug" ]]; then ENABLE_TSAN=true else ENABLE_TSAN=false fi fi # AddressSanitizer: default disabled; enable with --asan or ENABLE_ASAN=true if [[ -z "${ENABLE_ASAN}" ]]; then ENABLE_ASAN=false fi # If ASAN was explicitly requested and TSAN wasn't explicitly chosen, prefer ASAN for this build. if [[ "${ENABLE_ASAN}" == "true" ]] && [[ "${ASAN_EXPLICIT}" == "true" ]] && [[ "${TSAN_EXPLICIT}" == "false" ]]; then ENABLE_TSAN=false fi if [[ "${ENABLE_TSAN}" == "true" ]] && [[ "${ENABLE_ASAN}" == "true" ]]; then echo "Error: TSAN and ASAN cannot be enabled in the same build directory." >&2 echo "Use separate invocations, e.g.:" >&2 echo " ./setup.sh Debug --tsan --no-asan" >&2 echo " ./setup.sh Debug --asan --no-tsan" >&2 exit 1 fi # Fuzz harnesses link -fsanitize=fuzzer,address,undefined, so TSan cannot share the binary. if [[ "${ENABLE_FUZZING:-false}" == "true" ]] && [[ "${ENABLE_TSAN}" == "true" ]]; then echo "Error: Fuzzing builds link ASan/UBSan via the fuzz harnesses and cannot use TSAN." >&2 echo "Drop --tsan, or configure a separate directory without -Dbuild-fuzzers=true." >&2 exit 1 fi if [[ "${BUILD_TYPE}" == "Debug" ]] || [[ "${ENABLE_PROFILING:-false}" == "true" ]] || [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then MESON_OPTIONS+=( "-Dbuild-tests=true" "-Denable-bench-tests=true" "-Denable-vector-tests=true" "-Dbuild-benchmarks=true" ) echo "Vector/embedding tests and benchmarks enabled for ${BUILD_TYPE} build" fi # Optionally enable tests in Release builds for benchmark executables. if [[ "${BUILD_TYPE}" == "Release" ]] && [[ "${ENABLE_RELEASE_TESTS}" == "true" ]]; then MESON_OPTIONS+=( "-Dbuild-tests=true" ) echo "Tests enabled for Release build (benchmarks under tests/benchmarks will be built)" fi # Sanitizers are selected through Meson's b_sanitize; enable-tsan/enable-asan only # mirror that choice for third_party/symspell. MESON_OPTIONS+=("-Denable-tsan=${ENABLE_TSAN}") MESON_OPTIONS+=("-Denable-asan=${ENABLE_ASAN}") if [[ "${ENABLE_TSAN}" == "true" ]]; then MESON_OPTIONS+=("-Db_sanitize=thread") cc_tool="${CC##* }" cxx_tool="${CXX##* }" if [[ "${cc_tool}" == clang* ]] || [[ "${cxx_tool}" == clang++* ]]; then MESON_OPTIONS+=("-Db_lundef=false") echo "ThreadSanitizer on Clang: forcing b_lundef=false to avoid Meson link warnings" fi echo "ThreadSanitizer enabled (race detection)" elif [[ "${ENABLE_ASAN}" == "true" ]]; then MESON_OPTIONS+=("-Db_sanitize=address,undefined") echo "AddressSanitizer enabled (memory safety checks)" else # Ensure any previous sanitizer setting doesn't persist across reconfigure. # Users can override via YAMS_EXTRA_MESON_FLAGS. Only reset explicit sanitizer # state when reconfiguring an existing builddir; clean builds do not need it. if [[ -f "${INTRO_OPTS_JSON}" ]]; then MESON_OPTIONS+=("-Db_sanitize=none") fi fi if [[ "${ENABLE_PROFILING:-false}" == "true" ]]; then MESON_OPTIONS+=( "-Denable-profiling=true" ) echo "Tracy profiling enabled for Meson build" fi if [[ "${ENABLE_FUZZING:-false}" == "true" ]]; then MESON_OPTIONS+=( "-Dbuild-fuzzers=true" # Sanitizer and SanitizerCoverage symbols in shared libraries resolve against the # fuzzer executable, so shared objects must not be linked with --no-undefined. "-Db_lundef=false" ) echo "Fuzzing targets enabled for Meson build" fi if [[ "${ENABLE_COVERAGE}" == "true" ]]; then MESON_OPTIONS+=("-Db_coverage=true") echo "Coverage instrumentation enabled" fi # Add extra Meson flags from environment (for CI) if [[ -n "${YAMS_EXTRA_MESON_FLAGS:-}" ]]; then # shellcheck disable=SC2086 read -ra EXTRA_FLAGS <<<"${YAMS_EXTRA_MESON_FLAGS}" MESON_OPTIONS+=("${EXTRA_FLAGS[@]}") echo "Extra Meson flags: ${YAMS_EXTRA_MESON_FLAGS}" fi # Auto-enable zyp plugin if Zig 0.15.2+ is installed if command -v zig >/dev/null 2>&1; then ZIG_VERSION=$(zig version 2>/dev/null || echo "0.0.0") # Parse major.minor.patch ZIG_MAJOR=$(echo "${ZIG_VERSION}" | cut -d. -f1) ZIG_MINOR=$(echo "${ZIG_VERSION}" | cut -d. -f2) ZIG_PATCH=$(echo "${ZIG_VERSION}" | cut -d. -f3 | cut -d- -f1) # Handle -dev suffix # Check if >= 0.15.2 if [[ "${ZIG_MAJOR:-0}" -gt 0 ]] || { [[ "${ZIG_MAJOR:-0}" -eq 0 ]] && [[ "${ZIG_MINOR:-0}" -gt 15 ]]; } || { [[ "${ZIG_MAJOR:-0}" -eq 0 ]] && [[ "${ZIG_MINOR:-0}" -eq 15 ]] && [[ "${ZIG_PATCH:-0}" -ge 2 ]]; }; then echo "Zig ${ZIG_VERSION} detected, enabling zyp PDF plugin" MESON_OPTIONS+=("-Dplugin-zyp=true") else echo "Zig ${ZIG_VERSION} found but requires 0.15.2+ for zyp plugin" fi fi # Glint NL entity extractor plugin (GLiNER-based) requires ONNX Runtime. if [[ "${ENABLE_ONNX}" == "true" ]]; then echo "Enabling Glint NL entity extractor plugin" MESON_OPTIONS+=("-Dplugin-glint=true") fi echo "--- Running meson setup... ---" if [[ -n "${PREV_CPPSTD}" ]]; then if [[ "${PREV_CPPSTD}" != "${MESON_CPPSTD}" ]]; then echo "cpp_std changed (${PREV_CPPSTD} -> ${MESON_CPPSTD}); wiping build directory configuration..." meson setup "${MESON_ARGS[@]}" "${MESON_OPTIONS[@]}" --wipe else meson setup "${MESON_ARGS[@]}" "${MESON_OPTIONS[@]}" --reconfigure fi else meson setup "${MESON_ARGS[@]}" "${MESON_OPTIONS[@]}" fi echo echo "--- Setup complete! ---" if [[ "${CONAN_TOOLS_OVERRIDE}" == "true" ]]; then echo "Conan provided Meson/Ninja for this build directory." echo "To compile, run: ${MESON_WRAPPER_PATH} compile -C ${BUILD_DIR}" echo "To install, run: ${MESON_WRAPPER_PATH} install -C ${BUILD_DIR}" elif [[ -n "${MESON_WRAPPER_PATH}" ]]; then echo "To compile, run: meson compile -C ${BUILD_DIR}" echo "To install, run: meson install -C ${BUILD_DIR}" echo "Fallback wrapper (replays Conan build env if needed): ${MESON_WRAPPER_PATH}" else echo "To compile, run: meson compile -C ${BUILD_DIR}" echo "To install, run: meson install -C ${BUILD_DIR}" fi