# =============================================================================
# RunAnywhere SDKs — Root CMake project
# =============================================================================
#
# This is the SINGLE entry point for native builds across the monorepo.
# Subdirectories:
#   - core/ — the C++ runtime library (rac_commons)
#   - idl/                     — protobuf IDL schemas + codegen (no CMake
#                                target; see idl/codegen/)
#   - engines/                 — engine plugins (llamacpp, onnx, sherpa,
#                                qhexrt, neurt). Each publishes
#                                a `rac_engine_vtable_t` at
#                                `RAC_PLUGIN_API_VERSION=11u` via
#                                `RAC_STATIC_PLUGIN_REGISTER` or a dlopen'd
#                                `rac_plugin_entry` symbol.
#   - tools/plugin-loader-smoke/ — CLI smoke test for the plugin loader
#
# Common builds:
#   cmake --preset macos-release && cmake --build --preset macos-release
#   cmake --preset linux-asan       && cmake --build --preset linux-asan
#   cmake --preset android-arm64    && cmake --build --preset android-arm64
#   cmake --preset ios-device       && cmake --build --preset ios-device
#   cmake --preset wasm             && cmake --build --preset wasm
#
# Per-language SDKs (Swift / Kotlin / Flutter / RN / Web) consume the artifacts
# this build produces — they do NOT call this CMake directly. The wrapper
# scripts under scripts/build/build-core-{android,xcframework,wasm}.sh wire the
# preset output into the right SDK directory layout.
# =============================================================================

# Must match core/VERSIONS::MIN_CMAKE_VERSION (3.24).
# Required for FetchContent's FIND_PACKAGE_ARGS and DOWNLOAD_EXTRACT_TIMESTAMP
# (both added in CMake 3.24) used by the protobuf and ONNX Runtime fetches.
cmake_minimum_required(VERSION 3.24)

# Read version from the canonical VERSION file (kept under commons for
# historical reasons; treat as monorepo-wide).
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/core/VERSION" _RAC_VERSION_RAW)
string(STRIP "${_RAC_VERSION_RAW}" RAC_VERSION)

project(runanywhere
    VERSION ${RAC_VERSION}
    LANGUAGES CXX C
    DESCRIPTION "RunAnywhere SDKs — on-device AI runtime + per-language frontends"
    HOMEPAGE_URL "https://github.com/RunanywhereAI/runanywhere-sdks"
)

# Enable Objective-C AND Objective-C++ at the root project level.
#   - OBJCXX: engines/neurt/*.mm and any Apple-framework bridge TU.
#   - OBJC:   vendored llama.cpp ggml-metal *.m. These are plain Objective-C
#             (C-style implicit void*->T* conversions, e.g. `calloc`). Without
#             OBJC enabled, the Makefiles/Ninja generators have no Objective-C
#             language and fall back to compiling .m as Objective-C++ (clang++
#             -std=c++17), which rejects those conversions and breaks the Metal
#             build. (The Xcode generator used for the iOS presets maps .m->OBJC
#             natively, which is why device builds were unaffected.)
# `enable_language` inside a subdirectory doesn't populate the CMAKE_OBJC*_*
# toolchain variables the generator needs — it must run before subdirectories.
if(APPLE)
    enable_language(OBJC)
    enable_language(OBJCXX)
endif()

# =============================================================================
# Top-level options
#
# These are the *single source of truth* for build switches. Subdirectories
# (commons, engines/*, idl) inherit them via cache vars + the helper macros
# in cmake/plugins.cmake.
# =============================================================================

# Build mode
option(RAC_BUILD_SHARED       "Build rac_commons + plugins as shared libraries" OFF)
option(RAC_BUILD_TESTS        "Build CTest binaries" OFF)
option(RAC_BUILD_SERVER       "Build the OpenAI-compatible HTTP server (runanywhere-server)" OFF)
option(RAC_BUILD_PLATFORM     "Build the platform backend (Apple Foundation Models, System TTS) on Apple hosts" ON)
option(RAC_BUILD_JNI          "Build the JNI bridge for Android / JVM hosts" OFF)
option(RAC_BUILD_PLUGIN_SMOKE "Build tools/plugin-loader-smoke" OFF)
option(RAC_BUILD_CLI          "Retired: in-tree rcli was moved to RunanywhereAI/RCLI. Leaving ON is a hard error." OFF)
option(RAC_BUILD_ELECTRON_HARNESS "Build the runanywhere-electron M0 Win32 inference harness" OFF)
option(RAC_BUILD_ELECTRON_ADDON "Build the runanywhere-electron N-API .node addon" OFF)
option(RAC_BUILD_PYTHON_MODULE "Build the runanywhere-python pybind11 _core module" OFF)
option(RAC_DESKTOP_ADAPTER    "Build the desktop (macOS/Linux/Windows) platform adapter + libcurl HTTP transport" OFF)
option(RAC_GPU_CUDA           "Build llama.cpp with the CUDA GPU backend (NVIDIA; requires the CUDA toolkit + MSVC)" OFF)
# Windows/Linux only, and independent of RAC_GPU_CUDA. Enabling it is a request,
# not a guarantee: engines/llamacpp probes for the Vulkan SDK and silently falls
# back to CPU when it is absent, so a host without the SDK still configures.
option(RAC_GPU_VULKAN         "Build llama.cpp with the Vulkan GPU backend on Windows/Linux (AMD/Intel/NVIDIA)" ON)

# Protobuf is a private implementation detail of the serialized-byte C ABI.
# Keep its C++ namespace private too: static ML runtimes such as ONNX Runtime
# may carry a different unshaded protobuf runtime in the same final app.
option(RAC_ISOLATE_PROTOBUF_NAMESPACE
       "Build the private protobuf runtime in a RunAnywhere-owned C++ namespace"
       ON)

# Plugin loading mode
# RAC_STATIC_PLUGINS:
#   ON  → engine TUs are linked into rac_commons; iOS/WASM force this.
#   OFF → engines build as standalone librunanywhere_<name>.so/.dylib/.dll
#         and the host loads them via rac_registry_load_plugin().
# Forcing for iOS/Emscripten happens inside core/CMakeLists.txt
# so subdirectory consumers see the final value.
option(RAC_STATIC_PLUGINS "Link engine plugins statically into rac_commons (forced ON on iOS/WASM)" OFF)

# Sanitizers
set(RAC_SANITIZER "" CACHE STRING "Enable a sanitizer: '', 'asan', 'tsan', 'ubsan'")
set_property(CACHE RAC_SANITIZER PROPERTY STRINGS "" asan tsan ubsan)

# WebAssembly knobs must be cached at the root so commons/engines see the
# final values before their CMakeLists run. The wasm wrapper target itself
# lives under bindings/web/wasm and is added after the engine targets.
if(EMSCRIPTEN)
    option(RAC_WASM_PTHREADS    "Enable pthreads in the WebAssembly target" OFF)
    option(RAC_WASM_DEBUG       "Enable debug assertions/logging in the WebAssembly target" OFF)
    option(RAC_WASM_BUILD_CORE  "Build the commons-only Web SDK WASM target" OFF)
    option(RAC_WASM_LLAMACPP    "Build the WebAssembly target with llama.cpp (LLM + VLM)" OFF)
    option(RAC_WASM_ONNX        "Build the WebAssembly target with ONNX/sherpa support" OFF)
    option(RAC_WASM_WEBGPU      "Enable WebGPU acceleration for the WebAssembly target" OFF)
    option(RAC_WASM_WEBGPU_JSPI "Use experimental JSPI instead of Asyncify for WebGPU" OFF)

    set(RAC_BUILD_JNI OFF CACHE BOOL "" FORCE)
    set(RAC_BUILD_TESTS OFF CACHE BOOL "" FORCE)
    set(RAC_BUILD_SHARED OFF CACHE BOOL "" FORCE)
    set(RAC_BUILD_PLATFORM OFF CACHE BOOL "" FORCE)

    # Backends follow the union of requested WASM targets. The core-only target
    # never links backend archives, but a configure that ONLY requests core
    # still leaves backends off (commons compiles standalone).
    if(RAC_WASM_LLAMACPP OR RAC_WASM_ONNX)
        set(RAC_BUILD_BACKENDS ON CACHE BOOL "" FORCE)
    else()
        set(RAC_BUILD_BACKENDS OFF CACHE BOOL "" FORCE)
    endif()

    set(RAC_BACKEND_LLAMACPP ${RAC_WASM_LLAMACPP} CACHE BOOL "" FORCE)
    set(RAC_BACKEND_ONNX ${RAC_WASM_ONNX} CACHE BOOL "" FORCE)

    if(RAC_WASM_LLAMACPP)
        set(GGML_METAL OFF CACHE BOOL "" FORCE)
        set(GGML_VULKAN OFF CACHE BOOL "" FORCE)
        set(GGML_CUDA OFF CACHE BOOL "" FORCE)
        set(GGML_OPENCL OFF CACHE BOOL "" FORCE)
        set(GGML_HIPBLAS OFF CACHE BOOL "" FORCE)
        set(GGML_SYCL OFF CACHE BOOL "" FORCE)
        set(GGML_KOMPUTE OFF CACHE BOOL "" FORCE)
        set(GGML_RPC OFF CACHE BOOL "" FORCE)
        set(GGML_ACCELERATE OFF CACHE BOOL "" FORCE)
        set(GGML_NEON OFF CACHE BOOL "" FORCE)
        set(GGML_NATIVE OFF CACHE BOOL "" FORCE)
        set(GGML_LLAMAFILE OFF CACHE BOOL "" FORCE)
        set(GGML_OPENMP OFF CACHE BOOL "" FORCE)
        set(GGML_CPU_HBM OFF CACHE BOOL "" FORCE)
    endif()

    if(RAC_WASM_LLAMACPP)
        if(RAC_WASM_WEBGPU)
            set(GGML_WEBGPU ON CACHE BOOL "" FORCE)
            set(GGML_WEBGPU_JSPI ${RAC_WASM_WEBGPU_JSPI} CACHE BOOL "" FORCE)
        else()
            set(GGML_WEBGPU OFF CACHE BOOL "" FORCE)
            set(GGML_WEBGPU_JSPI OFF CACHE BOOL "" FORCE)
        endif()
        set(LLAMA_WASM_MEM64 OFF CACHE BOOL "" FORCE)
        set(LLAMA_BUILD_HTML OFF CACHE BOOL "" FORCE)
        set(LLAMA_WASM_SINGLE_FILE OFF CACHE BOOL "" FORCE)
    endif()

    if(RAC_WASM_ONNX)
        set(ORT_USE_COREML OFF CACHE BOOL "" FORCE)
        set(ORT_USE_NNAPI OFF CACHE BOOL "" FORCE)
    endif()
endif()

# =============================================================================
# Shared cmake/ helpers
# =============================================================================

# Where this repository's own tree starts.
#
# CMAKE_SOURCE_DIR is the TOP-LEVEL project, which is this repo only when it is
# built directly. Embedded with add_subdirectory or FetchContent — the rcli
# repo, the Electron addon, anything that consumes commons as a subproject —
# it points at the consumer, and every path built from it resolves into their
# tree instead of ours. Sub-CMakeLists use this variable instead.
set(RAC_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "runanywhere-sdks source root")

list(APPEND CMAKE_MODULE_PATH
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
    "${CMAKE_CURRENT_SOURCE_DIR}/core/cmake"  # LoadVersions, FetchONNXRuntime, ... — kept for engine subdirs
)

# Shared cmake/ helper modules. The includes are OPTIONAL so a missing
# helper degrades gracefully rather than failing configure.
include(platform   OPTIONAL)   # rac_detect_platform()
include(sanitizers OPTIONAL)   # rac_apply_sanitizer()
include(plugins    OPTIONAL)   # rac_add_engine_plugin() / rac_force_load()
include(protobuf   OPTIONAL)   # RAC_HAVE_PROTOBUF / RAC_ABSL_LIBS

if(COMMAND rac_detect_platform)
    rac_detect_platform()
endif()

# =============================================================================
# Compiler defaults
# =============================================================================

# C++20 is required because parts of the codebase use designated initializers
# (struct vtable registration) that MSVC doesn't accept under C++17.
set(CMAKE_CXX_STANDARD          20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS        OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# M_PI and friends are POSIX/GNU math extensions, not standard C++. With
# CMAKE_CXX_EXTENSIONS OFF (strict -std=c++20), MinGW/MSVC hide them unless
# _USE_MATH_DEFINES is defined before <cmath>. llama.cpp's mtmd audio code uses
# M_PI, so define it globally on Windows (harmless elsewhere; POSIX exposes it).
# Set at the root so it reaches every subdirectory, including the llama.cpp
# FetchContent tree under engines/.
if(WIN32)
    add_compile_definitions(_USE_MATH_DEFINES)
endif()

# =============================================================================
# Subdirectories
# =============================================================================

# Commons — always built. Owns its own backend-toggle option block.
add_subdirectory(core)

# IDL — no CMake target. The C++ proto bindings the commons build consumes are
# committed under core/src/generated/proto/ and compiled by
# rac_commons directly; Swift/Kotlin/Dart/TS bindings are generated by the
# helper scripts in idl/codegen/, not via CMake.

# runtimes/ — L1 compute-runtime plugins. Mirrors engines/ but scoped
# to compute targets (CPU, ONNX Runtime, CoreML, CUDA, …). The built-in CPU runtime
# is always folded into rac_commons; adapter runtimes are linked by their
# owning engines.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/runtimes/CMakeLists.txt")
    add_subdirectory(runtimes)
endif()

# engines/ — top-level engine plugin directory. LlamaCPP owns GGUF LLM/VLM,
# Sherpa owns speech primitives and legacy ONNX-named speech compatibility,
# ONNX owns embeddings and ONNXRT-backed generic services, QHexRT owns
# Qualcomm Hexagon NPU bundles, and CoreML owns Apple diffusion models.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/engines/CMakeLists.txt")
    add_subdirectory(engines)
endif()

# Fold the built-in CPU runtime's OBJECTs into rac_commons so there is no
# separate librac_runtime_cpu to ship.
if(TARGET rac_runtime_cpu)
    target_sources(rac_commons PRIVATE $<TARGET_OBJECTS:rac_runtime_cpu>)
endif()

# WASM wrapper target — composes rac_commons + any enabled engine plugins into
# the JavaScript/WebAssembly artifacts consumed by bindings/web.
if(EMSCRIPTEN
   AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bindings/web/wasm/CMakeLists.txt")
    add_subdirectory(bindings/web/wasm)
endif()

# Smoke test for the plugin loader. Only built when explicitly
# requested so headless CI nodes don't pay the build cost.
if(RAC_BUILD_PLUGIN_SMOKE
   AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/plugin-loader-smoke/CMakeLists.txt")
    add_subdirectory(tools/plugin-loader-smoke)
endif()

# Enable CTest before SDK subdirectories that register their own tests.
if(RAC_BUILD_TESTS)
    enable_testing()
endif()

# In-tree rcli is retired. The product lives in RunanywhereAI/RCLI and
# consumes the C++ desktop kit (find_package(RunAnywhere)).
if(RAC_BUILD_CLI)
    message(FATAL_ERROR
        "RAC_BUILD_CLI is retired. Build EXTERNAL/RCLI (RunanywhereAI/RCLI) against "
        "the C++ desktop kit:\n"
        "  cmake --preset cpp-desktop-macos-arm64 && cmake --build --preset cpp-desktop-macos-arm64\n"
        "  cmake -S EXTERNAL/RCLI -B EXTERNAL/RCLI/build -DCMAKE_PREFIX_PATH=<kit>")
endif()

# runanywhere-electron M0 inference harness. Added after engines/ because it
# links rac_backend_llamacpp, which only exists once the engine subdir configured.
if((RAC_BUILD_ELECTRON_HARNESS OR RAC_BUILD_ELECTRON_ADDON)
   AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bindings/electron/native/CMakeLists.txt")
    add_subdirectory(bindings/electron/native)
endif()

# runanywhere-python pybind11 _core module. Added after engines/ because it
# links rac_backend_llamacpp, which only exists once the engine subdir configured.
if(RAC_BUILD_PYTHON_MODULE
   AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bindings/python/native/CMakeLists.txt")
    add_subdirectory(bindings/python/native)
endif()

# Tests — wired through commons/tests for now. RAC_BUILD_TESTS is forwarded
# from this root option to the commons cache slot of the same name.
if(RAC_BUILD_TESTS)
    enable_testing()
    if(TARGET test_mlx_cancellation)
        add_test(NAME mlx_cancellation_tests COMMAND test_mlx_cancellation)
    endif()
    # Pure request-latch regression: cancellation in the reset/setup window
    # must reach the active request without poisoning its successor. This test
    # deliberately has no dependency on QHexRT's private C ABI.
    if(NOT TARGET test_qhexrt_request_cancellation)
        find_package(Threads REQUIRED)
        add_executable(test_qhexrt_request_cancellation
            engines/qhexrt/tests/test_qhexrt_request_cancellation.cpp)
        target_include_directories(test_qhexrt_request_cancellation PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/engines/qhexrt)
        target_link_libraries(test_qhexrt_request_cancellation PRIVATE Threads::Threads)
        target_compile_features(test_qhexrt_request_cancellation PRIVATE cxx_std_17)
        add_test(NAME qhexrt_request_cancellation_tests
                 COMMAND test_qhexrt_request_cancellation)
    endif()
    # The llama.cpp engine is configured after commons/tests, so its plugin
    # contract test must be wired here once the backend target exists.
    if(RAC_BACKEND_LLAMACPP AND TARGET rac_backend_llamacpp AND
       NOT TARGET test_plugin_entry_llamacpp)
        add_executable(test_plugin_entry_llamacpp
            core/tests/test_plugin_entry_llamacpp.cpp)
        target_include_directories(test_plugin_entry_llamacpp PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_plugin_entry_llamacpp PRIVATE
            rac_commons
            rac_backend_llamacpp
        )
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_plugin_entry_llamacpp)
        endif()
        target_compile_features(test_plugin_entry_llamacpp PRIVATE cxx_std_17)
        add_test(NAME plugin_entry_llamacpp_tests COMMAND test_plugin_entry_llamacpp)
    endif()
    # Reranking primitive (RAC_PRIMITIVE_RERANK, ABI v8) contract test. Backend-
    # neutral: it registers an in-test fake rerank engine, so it needs only
    # rac_commons + the protobuf runtime (no llama.cpp / ONNX linkage).
    if(RAC_PROTOBUF_RUNTIME_ENABLED AND TARGET rac_commons AND NOT TARGET test_rerank)
        add_executable(test_rerank
            core/tests/test_rerank.cpp)
        target_include_directories(test_rerank PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src/generated/proto
            ${Protobuf_INCLUDE_DIRS}
        )
        target_compile_definitions(test_rerank PRIVATE RAC_HAVE_PROTOBUF=1)
        target_link_libraries(test_rerank PRIVATE rac_commons)
        if(TARGET protobuf::libprotobuf)
            target_link_libraries(test_rerank PRIVATE protobuf::libprotobuf)
        elseif(Protobuf_LIBRARIES)
            target_link_libraries(test_rerank PRIVATE ${Protobuf_LIBRARIES})
        endif()
        if(RAC_ABSL_LIBS)
            target_link_libraries(test_rerank PRIVATE ${RAC_ABSL_LIBS})
        endif()
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_rerank)
        endif()
        target_compile_features(test_rerank PRIVATE cxx_std_20)
        add_test(NAME rerank_tests COMMAND test_rerank)
        set_tests_properties(rerank_tests PROPERTIES LABELS "native;rerank")
    endif()
    # Decision primitive (RAC_PRIMITIVE_DECIDE, ABI v13) contract test. Same shape
    # as test_rerank: an in-test fake decision engine, no backend linkage.
    if(RAC_PROTOBUF_RUNTIME_ENABLED AND TARGET rac_commons AND NOT TARGET test_decision)
        add_executable(test_decision
            core/tests/test_decision.cpp)
        target_include_directories(test_decision PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src/generated/proto
            ${Protobuf_INCLUDE_DIRS}
        )
        target_compile_definitions(test_decision PRIVATE RAC_HAVE_PROTOBUF=1)
        target_link_libraries(test_decision PRIVATE rac_commons)
        if(TARGET protobuf::libprotobuf)
            target_link_libraries(test_decision PRIVATE protobuf::libprotobuf)
        elseif(Protobuf_LIBRARIES)
            target_link_libraries(test_decision PRIVATE ${Protobuf_LIBRARIES})
        endif()
        if(RAC_ABSL_LIBS)
            target_link_libraries(test_decision PRIVATE ${RAC_ABSL_LIBS})
        endif()
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_decision)
        endif()
        target_compile_features(test_decision PRIVATE cxx_std_20)
        add_test(NAME decision_tests COMMAND test_decision)
        set_tests_properties(decision_tests PROPERTIES LABELS "native;decision")
    endif()
    # The ONNX engine is configured after commons/tests. Keep this plugin-entry
    # contract gate alive in both RAG modes: segmentation is unconditional,
    # while embeddings are intentionally compiled only when RAG is enabled.
    if(RAC_BACKEND_ONNX AND TARGET rac_backend_onnx AND
       NOT TARGET test_plugin_entry_onnx)
        add_executable(test_plugin_entry_onnx
            core/tests/test_plugin_entry_onnx.cpp)
        target_include_directories(test_plugin_entry_onnx PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_plugin_entry_onnx PRIVATE
            rac_commons
            rac_backend_onnx
        )
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_plugin_entry_onnx)
        endif()
        target_compile_features(test_plugin_entry_onnx PRIVATE cxx_std_20)
        add_test(NAME plugin_entry_onnx_tests COMMAND test_plugin_entry_onnx)
        set_tests_properties(plugin_entry_onnx_tests PROPERTIES
            LABELS "native;onnx;segmentation")
    endif()
    # Native semantic-segmentation gate. The fixture target compiles the
    # production provider against a real tiny SegFormer-architecture ONNX graph
    # to exercise the generic resize/normalize/argmax inference path.
    if(RAC_BACKEND_ONNX AND TARGET rac_backend_onnx AND
       TARGET rac_runtime_onnxrt AND RAC_PROTOBUF_RUNTIME_ENABLED)
        add_executable(test_segmentation_onnx
            core/tests/test_segmentation_onnx.cpp
            engines/onnx/onnx_segmentation_provider.cpp
            engines/onnx/rac_onnx_segmentation_register.cpp
        )
        target_include_directories(test_segmentation_onnx PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/engines/onnx
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src/generated/proto
            ${Protobuf_INCLUDE_DIRS}
        )
        target_compile_definitions(test_segmentation_onnx PRIVATE
            RAC_HAVE_PROTOBUF=1
            RAC_SEGMENTATION_TEST_FIXTURE_BUNDLE=1
            "RAC_SEGMENTATION_FIXTURE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/core/tests/fixtures/segformer_tiny\""
        )
        target_link_libraries(test_segmentation_onnx PRIVATE
            rac_commons
            rac_runtime_onnxrt
            nlohmann_json::nlohmann_json
        )
        if(TARGET protobuf::libprotobuf)
            target_link_libraries(test_segmentation_onnx PRIVATE protobuf::libprotobuf)
        elseif(Protobuf_LIBRARIES)
            target_link_libraries(test_segmentation_onnx PRIVATE ${Protobuf_LIBRARIES})
        endif()
        if(RAC_ABSL_LIBS)
            target_link_libraries(test_segmentation_onnx PRIVATE ${RAC_ABSL_LIBS})
        endif()
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_segmentation_onnx)
        endif()
        target_compile_features(test_segmentation_onnx PRIVATE cxx_std_20)
        add_test(NAME segmentation_onnx_tests COMMAND test_segmentation_onnx)
        set_tests_properties(segmentation_onnx_tests PROPERTIES
            LABELS "native;onnx;segmentation;real-fixture")

        # Streaming-Sortformer diarization: op-table wiring, the self-contained
        # DSP math (FFT / mel filterbank / median / binarization) vs independent
        # scalar oracles, and null/missing-model graceful failure. Needs no ORT
        # weights and no Sortformer bundle. The test TU #includes the provider
        # .cpp to reach its file-local math helpers; the service-vtable adapter
        # is compiled alongside to expose g_onnx_diarization_ops. Neither links
        # rac_backend_onnx, so the provider symbols are defined exactly once.
        add_executable(test_diarization_onnx
            core/tests/test_diarization_onnx.cpp
            engines/onnx/rac_onnx_diarization_register.cpp
        )
        target_include_directories(test_diarization_onnx PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/engines/onnx
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src
        )
        target_link_libraries(test_diarization_onnx PRIVATE
            rac_commons
            rac_runtime_onnxrt
        )
        if(COMMAND rac_link_archive_deps)
            rac_link_archive_deps(test_diarization_onnx)
        endif()
        target_compile_features(test_diarization_onnx PRIVATE cxx_std_20)
        add_test(NAME diarization_onnx_tests COMMAND test_diarization_onnx)
        set_tests_properties(diarization_onnx_tests PROPERTIES
            LABELS "native;onnx;diarization")

        # Generic-derivation gate. Proves the provider derives class count, input
        # size, mean/std/rescale, do_normalize/do_rescale, and labels from the
        # bundle sidecars + the model output tensor -- every value here DIFFERS
        # from the file-local SegFormer defaults, so a regression that falls back
        # to a hardcoded default is observable. The test TU #includes
        # onnx_segmentation_provider.cpp (white-box helpers) and compiles
        # rac_onnx_segmentation_register.cpp alongside for g_onnx_segmentation_ops;
        # neither links rac_backend_onnx, so the provider symbols are defined
        # exactly once. The N=4 / 256-input / 64x64-logits ONNX fixture is
        # generated at build time (no binary checked in) by the committed python
        # generator; the test is added only when python + onnx are available.
        find_package(Python3 COMPONENTS Interpreter QUIET)
        set(_seg_generic_py_ok FALSE)
        if(Python3_Interpreter_FOUND)
            execute_process(
                COMMAND ${Python3_EXECUTABLE} -c "import onnx, numpy"
                RESULT_VARIABLE _seg_generic_py_check
                OUTPUT_QUIET ERROR_QUIET)
            if(_seg_generic_py_check EQUAL 0)
                set(_seg_generic_py_ok TRUE)
            endif()
        endif()
        # CI opt-in: a lane that enables the ONNX segmentation tests can require the
        # generic-segmentation derivation proof to actually build, so a missing
        # python onnx/numpy fixture generator FAILS LOUDLY here instead of silently
        # dropping the only test that distinguishes derived-from-sidecar values from
        # SegFormer defaults. Default OFF preserves every other lane's silent skip.
        option(RAC_REQUIRE_ONNX_SEGMENTATION_TESTS
            "Fail configuration if the generic-segmentation ONNX derivation test cannot be built (CI opt-in against silent skips)"
            OFF)
        if(NOT _seg_generic_py_ok AND RAC_REQUIRE_ONNX_SEGMENTATION_TESTS)
            message(FATAL_ERROR
                "RAC_REQUIRE_ONNX_SEGMENTATION_TESTS=ON but the generic-segmentation "
                "derivation test cannot be built: python3 with 'import onnx, numpy' is "
                "unavailable to generate the ONNX fixture. Install onnx + numpy in this "
                "lane (e.g. pip install onnx numpy) so the derivation proof runs instead "
                "of being silently skipped.")
        endif()
        if(_seg_generic_py_ok AND NOT TARGET test_segmentation_generic)
            set(_seg_generic_fixture_dir
                "${CMAKE_CURRENT_BINARY_DIR}/fixtures/segmentation_generic")
            add_custom_command(
                OUTPUT "${_seg_generic_fixture_dir}/model.onnx"
                       "${_seg_generic_fixture_dir}/config.json"
                       "${_seg_generic_fixture_dir}/preprocessor_config.json"
                COMMAND ${Python3_EXECUTABLE}
                        "${CMAKE_CURRENT_SOURCE_DIR}/core/tests/fixtures/generate_segmentation_generic_fixture.py"
                        "${_seg_generic_fixture_dir}"
                DEPENDS
                        "${CMAKE_CURRENT_SOURCE_DIR}/core/tests/fixtures/generate_segmentation_generic_fixture.py"
                COMMENT "Generating generic semantic-segmentation ONNX fixture (N=4, 256->64)"
                VERBATIM)
            add_custom_target(segmentation_generic_fixture
                DEPENDS "${_seg_generic_fixture_dir}/model.onnx")

            add_executable(test_segmentation_generic
                core/tests/test_segmentation_generic.cpp
                engines/onnx/rac_onnx_segmentation_register.cpp
            )
            add_dependencies(test_segmentation_generic segmentation_generic_fixture)
            target_include_directories(test_segmentation_generic PRIVATE
                ${CMAKE_CURRENT_SOURCE_DIR}/engines/onnx
                ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
                ${CMAKE_CURRENT_SOURCE_DIR}/core/include
                ${CMAKE_CURRENT_SOURCE_DIR}/core/src
            )
            target_compile_definitions(test_segmentation_generic PRIVATE
                "RAC_SEGMENTATION_GENERIC_FIXTURE_DIR=\"${_seg_generic_fixture_dir}\""
                "RAC_SEGMENTATION_SEGFORMER_FIXTURE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/core/tests/fixtures/segformer_tiny\""
            )
            target_link_libraries(test_segmentation_generic PRIVATE
                rac_commons
                rac_runtime_onnxrt
                nlohmann_json::nlohmann_json
            )
            if(COMMAND rac_link_archive_deps)
                rac_link_archive_deps(test_segmentation_generic)
            endif()
            target_compile_features(test_segmentation_generic PRIVATE cxx_std_20)
            add_test(NAME segmentation_generic_tests COMMAND test_segmentation_generic)
            set_tests_properties(segmentation_generic_tests PROPERTIES
                LABELS "native;onnx;segmentation;generic")
        endif()
    endif()
    # commons-010: sherpa plugin-entry smoke test. Wired here because
    # rac_backend_sherpa is built by engines/, which is configured after
    # core/. This is also an intentional final-link gate:
    # rac_commons contributes RunAnywhere's private protobuf runtime while the
    # static macOS ONNX Runtime inventory contributes its own protobuf. A
    # namespace-isolation regression therefore fails this target at link time.
    if(RAC_BACKEND_SHERPA AND TARGET rac_backend_sherpa AND NOT TARGET test_plugin_entry_sherpa)
        add_executable(test_plugin_entry_sherpa
            core/tests/test_plugin_entry_sherpa.cpp)
        target_include_directories(test_plugin_entry_sherpa PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_plugin_entry_sherpa PRIVATE
            rac_commons
            rac_backend_sherpa
        )
        if(TARGET archive_static)
            target_link_libraries(test_plugin_entry_sherpa PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_plugin_entry_sherpa PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_plugin_entry_sherpa PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_plugin_entry_sherpa PRIVATE cxx_std_17)
        add_test(NAME plugin_entry_sherpa_tests COMMAND test_plugin_entry_sherpa)
        set_tests_properties(plugin_entry_sherpa_tests PROPERTIES
            LABELS "native;protobuf-isolation;sherpa")
    endif()
    # Sherpa STT language policy: the unset-language fallback (Canary) and the
    # refusal of an override a build-time-pinned recognizer cannot honor. Wired
    # here rather than in engines/sherpa/CMakeLists.txt because enable_testing()
    # runs after add_subdirectory(engines), so add_test() there is a no-op.
    # Header-only policy — needs neither Sherpa-ONNX nor sherpa_backend.cpp.
    if(RAC_BACKEND_SHERPA AND NOT TARGET test_sherpa_language_policy)
        add_executable(test_sherpa_language_policy
            engines/sherpa/tests/test_sherpa_language_policy.cpp)
        target_include_directories(test_sherpa_language_policy PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/engines/sherpa
            ${CMAKE_CURRENT_SOURCE_DIR}/engines
        )
        target_compile_definitions(test_sherpa_language_policy PRIVATE SHERPA_ONNX_AVAILABLE=0)
        target_link_libraries(test_sherpa_language_policy PRIVATE nlohmann_json::nlohmann_json)
        target_compile_features(test_sherpa_language_policy PRIVATE cxx_std_20)
        add_test(NAME sherpa_language_policy_tests COMMAND test_sherpa_language_policy)
        set_tests_properties(sherpa_language_policy_tests PROPERTIES
            LABELS "native;sherpa;stt")
    endif()
    # The speech backend and its availability flag are configured after
    # commons/tests. Wire the real Sherpa STT test here so optional NVIDIA
    # transducer/Canary fixtures can exercise the shipped backend instead of
    # being silently omitted by configuration order.
    if(RAC_BACKEND_ONNX AND RAC_BACKEND_SHERPA AND RAC_SHERPA_ONNX_AVAILABLE AND
       TARGET rac_backend_onnx AND TARGET rac_backend_sherpa AND NOT TARGET test_stt)
        add_executable(test_stt core/tests/test_stt.cpp)
        target_include_directories(test_stt PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/engines/sherpa
        )
        target_link_libraries(test_stt PRIVATE
            rac_commons
            rac_backend_onnx
            rac_backend_sherpa
        )
        target_compile_features(test_stt PRIVATE cxx_std_20)
        add_test(NAME stt_tests COMMAND test_stt --run-all)
        set_tests_properties(stt_tests PROPERTIES LABELS "native;sherpa;stt")
    endif()

    # RAC_NEURT_ENGINE_AVAILABLE, not just the target: without a prebuilt slice the engine
    # builds as a non-routable shell, so the target exists but rac_diffusion_coreml.h is on no
    # include path and this test cannot compile.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND RAC_NEURT_ENGINE_AVAILABLE
       AND NOT TARGET test_diffusion_coreml_generate)
        add_executable(test_diffusion_coreml_generate
            core/tests/test_diffusion_coreml_generate.cpp)
        # rac_diffusion_coreml.h ships in the prebuilt include dir and reaches
        # this target transitively: rac_add_engine_plugin exports the engine's
        # INCLUDE_DIRECTORIES as PUBLIC on rac_backend_neurt, linked below.
        target_include_directories(test_diffusion_coreml_generate PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_diffusion_coreml_generate PRIVATE
            rac_commons
            rac_backend_neurt
        )
        if(TARGET archive_static)
            target_link_libraries(test_diffusion_coreml_generate PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_diffusion_coreml_generate PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_diffusion_coreml_generate PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_diffusion_coreml_generate PRIVATE cxx_std_17)
        add_test(NAME diffusion_coreml_generate_tests COMMAND test_diffusion_coreml_generate)
    endif()

    # EMBED_IMAGE end to end through the PUBLIC C API (rac_image_embedding_create/_embed).
    # Wired HERE and not in core/tests/CMakeLists.txt for the reason that file already documents:
    # engines/ is configured after core/, so `TARGET rac_backend_neurt` is still false there.
    # Skips (exit 0) without RAC_TEST_NEURT_IMAGE_EMBED_BUNDLE.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND RAC_NEURT_ENGINE_AVAILABLE
       AND NOT TARGET test_image_embedding_neurt_e2e)
        add_executable(test_image_embedding_neurt_e2e
            core/tests/test_image_embedding_neurt_e2e.cpp)
        target_include_directories(test_image_embedding_neurt_e2e PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_image_embedding_neurt_e2e PRIVATE
            rac_commons
            rac_backend_neurt
        )
        if(TARGET archive_static)
            target_link_libraries(test_image_embedding_neurt_e2e PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_image_embedding_neurt_e2e PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_image_embedding_neurt_e2e PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_image_embedding_neurt_e2e PRIVATE cxx_std_17)
        add_test(NAME image_embedding_neurt_e2e_tests COMMAND test_image_embedding_neurt_e2e)
        # 77 = "no bundle configured". Without SKIP_RETURN_CODE the test's own SKIP path exits 0
        # and CTest reports a PASS, which is how test_stt_neurt_e2e went its whole life reported
        # green without ever running.
        set_tests_properties(image_embedding_neurt_e2e_tests PROPERTIES
            LABELS "neurt" SKIP_RETURN_CODE 77)
    endif()

    # OCR end to end through the LIFECYCLE PROTO ABI -- rac_model_lifecycle_load_proto by
    # category, then rac_ocr_read_page_lifecycle_proto. Deliberately NOT the handle API
    # (rac_ocr_create/_read_page): that path already worked in 0.20.35 while no platform SDK
    # could reach OCR at all, because none of them use it. Skips (77) without
    # RAC_TEST_NEURT_OCR_BUNDLE.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND RAC_NEURT_ENGINE_AVAILABLE
       AND RAC_ENABLE_PROTOBUF
       AND NOT TARGET test_ocr_neurt_e2e)
        add_executable(test_ocr_neurt_e2e
            core/tests/test_ocr_neurt_e2e.cpp)
        target_include_directories(test_ocr_neurt_e2e PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src
            # _RAC_PROTO_GEN_DIR is set inside core/CMakeLists.txt and does not
            # reach this scope; spell the same path out rather than leaking a
            # PARENT_SCOPE variable for one test.
            ${CMAKE_CURRENT_SOURCE_DIR}/core/src/generated/proto
        )
        target_link_libraries(test_ocr_neurt_e2e PRIVATE
            rac_commons
            rac_backend_neurt
        )
        # rac_commons keeps its proto headers and protobuf includes PRIVATE by
        # design (the C ABI exposes byte buffers, not runanywhere::v1:: types),
        # so a test that speaks the proto ABI has to bring protobuf itself.
        target_include_directories(test_ocr_neurt_e2e PRIVATE ${Protobuf_INCLUDE_DIRS})
        if(TARGET protobuf::libprotobuf)
            target_link_libraries(test_ocr_neurt_e2e PRIVATE protobuf::libprotobuf)
        else()
            target_link_libraries(test_ocr_neurt_e2e PRIVATE ${Protobuf_LIBRARIES})
        endif()
        if(TARGET archive_static)
            target_link_libraries(test_ocr_neurt_e2e PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_ocr_neurt_e2e PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_ocr_neurt_e2e PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_ocr_neurt_e2e PRIVATE cxx_std_17)
        add_test(NAME ocr_neurt_e2e_tests COMMAND test_ocr_neurt_e2e)
        set_tests_properties(ocr_neurt_e2e_tests PROPERTIES
            LABELS "neurt" SKIP_RETURN_CODE 77)
    endif()

    # SYNTHESIZE end to end through the PUBLIC C API (rac_tts_create/_synthesize). Wired here for
    # the same reason as the EMBED_IMAGE test above: engines/ is configured after core/.
    # Skips (77) without RAC_TEST_NEURT_TTS_BUNDLE.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND RAC_NEURT_ENGINE_AVAILABLE
       AND NOT TARGET test_tts_neurt_e2e)
        add_executable(test_tts_neurt_e2e
            core/tests/test_tts_neurt_e2e.cpp)
        target_include_directories(test_tts_neurt_e2e PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_tts_neurt_e2e PRIVATE
            rac_commons
            rac_backend_neurt
        )
        if(TARGET archive_static)
            target_link_libraries(test_tts_neurt_e2e PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_tts_neurt_e2e PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_tts_neurt_e2e PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_tts_neurt_e2e PRIVATE cxx_std_17)
        add_test(NAME tts_neurt_e2e_tests COMMAND test_tts_neurt_e2e)
        set_tests_properties(tts_neurt_e2e_tests PROPERTIES
            LABELS "neurt" SKIP_RETURN_CODE 77)
    endif()

    # NeuRT ASR end to end: a WAV in through the SDK's own stt_ops, a scored transcript out.
    # The seam neither of the other two neurt tests covers — the plugin test stops at the vtable
    # and neurun's own tools stop at the runtime. Skips (exit 0) without RAC_ASR_BUNDLE, because a
    # multi-gigabyte private bundle cannot be a hard requirement of the test suite.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND RAC_NEURT_ENGINE_AVAILABLE
       AND NOT TARGET test_stt_neurt_e2e)
        add_executable(test_stt_neurt_e2e core/tests/test_stt_neurt_e2e.cpp)
        target_include_directories(test_stt_neurt_e2e PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_stt_neurt_e2e PRIVATE rac_commons rac_backend_neurt)
        if(TARGET archive_static)
            target_link_libraries(test_stt_neurt_e2e PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_stt_neurt_e2e PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_stt_neurt_e2e PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_stt_neurt_e2e PRIVATE cxx_std_17)
        add_test(NAME stt_neurt_e2e_tests COMMAND test_stt_neurt_e2e)
        set_tests_properties(stt_neurt_e2e_tests PROPERTIES LABELS "native;neurt;stt")
    endif()

    # neurt engine plugin-entry smoke test. Same wiring rationale as sherpa:
    # rac_backend_neurt is built by engines/ which is configured after
    # core/. The neurt engine is the sole
    # RAC_PRIMITIVE_DIFFUSION provider, so this locks the manifest's COREML
    # runtime/format + the diffusion_ops AND llm_ops slots the router routes
    # against; test_diffusion_coreml_generate.cpp only exercises the backend
    # directly and bypasses the plugin-entry/vtable path. Apple-only because the
    # backend is.
    if(APPLE AND RAC_BACKEND_NEURT
       AND TARGET rac_backend_neurt
       AND NOT TARGET test_plugin_entry_neurt)
        add_executable(test_plugin_entry_neurt
            core/tests/test_plugin_entry_neurt.cpp)
        target_include_directories(test_plugin_entry_neurt PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/core/tests
            ${CMAKE_CURRENT_SOURCE_DIR}/core/include
        )
        target_link_libraries(test_plugin_entry_neurt PRIVATE
            rac_commons
            rac_backend_neurt
        )
        if(TARGET archive_static)
            target_link_libraries(test_plugin_entry_neurt PRIVATE archive_static)
        endif()
        if(TARGET zlibstatic)
            target_link_libraries(test_plugin_entry_neurt PRIVATE zlibstatic)
        endif()
        if(TARGET bz2_bundled)
            target_link_libraries(test_plugin_entry_neurt PRIVATE bz2_bundled)
        endif()
        target_compile_features(test_plugin_entry_neurt PRIVATE cxx_std_17)
        add_test(NAME plugin_entry_neurt_tests
                 COMMAND test_plugin_entry_neurt)
    endif()

    # Cross-SDK parity test harness.
    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/streaming/CMakeLists.txt")
        add_subdirectory(tests/streaming)
    endif()
endif()

# =============================================================================
# Configuration summary (matches the commons summary block for consistency)
# =============================================================================

# Resolve genex-free strings: message() runs at configure time and prints
# generator expressions literally, so compute the mode labels with if().
if(RAC_BUILD_SHARED)
    set(_rac_build_mode "SHARED")
else()
    set(_rac_build_mode "STATIC")
endif()
if(RAC_STATIC_PLUGINS)
    set(_rac_plugin_mode "STATIC (linked into commons)")
else()
    set(_rac_plugin_mode "SHARED (dlopen-loaded)")
endif()

# C++ desktop kit (find_package(RunAnywhere) prefix for RCLI). After engines
# so rac_backend_* targets exist for the kit's optional-engine flags.
include(CppDesktopKit)

message(STATUS "")
message(STATUS "============================================")
message(STATUS "RunAnywhere SDKs — root CMake configured")
message(STATUS "============================================")
message(STATUS "Version          : ${RAC_VERSION}")
message(STATUS "Build mode       : ${_rac_build_mode}")
message(STATUS "Plugin mode      : ${_rac_plugin_mode}")
message(STATUS "Sanitizer        : ${RAC_SANITIZER}")
message(STATUS "Tests            : ${RAC_BUILD_TESTS}")
message(STATUS "Server (HTTP)    : ${RAC_BUILD_SERVER}")
message(STATUS "Platform backend : ${RAC_BUILD_PLATFORM}")
message(STATUS "JNI bridge       : ${RAC_BUILD_JNI}")
message(STATUS "Plugin smoke CLI : ${RAC_BUILD_PLUGIN_SMOKE}")
message(STATUS "CLI (in-tree)    : retired (RunanywhereAI/RCLI)")
message(STATUS "C++ desktop kit  : ${RAC_PACKAGE_CPP_DESKTOP}")
message(STATUS "Desktop adapter  : ${RAC_DESKTOP_ADAPTER}")
message(STATUS "============================================")
message(STATUS "")
