cmake_minimum_required(VERSION 3.28) project(raid VERSION 0.1.0 LANGUAGES CXX) # --------------------------------------------------------------------------- # RAID — Research Architecture for Intraday Data (UQO WP 40) # C++20 core + CPU backend (portable) + optional Metal backend (macOS arm64). # --------------------------------------------------------------------------- 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) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() option(RAID_ENABLE_METAL "Build the Metal backend (macOS only)" ${APPLE}) option(RAID_WITH_ARROW "Build the Arrow/Parquet reader (requires Apache Arrow C++)" ON) option(RAID_WITH_ACCELERATE "Use Apple Accelerate BLAS/LAPACK through Eigen (macOS only)" ${APPLE}) option(RAID_BUILD_TESTS "Build Catch2 tests" ON) option(RAID_BUILD_BENCH "Build benchmark executables" ON) option(RAID_BUILD_CLI "Build the raid command-line tool" ON) option(RAID_BUILD_PYTHON "Build the nanobind Python extension" OFF) option(RAID_NATIVE_ARCH "Tune for the host CPU (-mcpu=native)" ON) option(RAID_WERROR "Treat warnings as errors" OFF) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(GNUInstallDirs) # ---- dependencies ---------------------------------------------------------- find_package(Eigen3 REQUIRED CONFIG) find_package(nlohmann_json 3.11 REQUIRED CONFIG) find_package(CURL REQUIRED) # system libcurl (macOS SDK / Linux) find_package(Threads REQUIRED) if(RAID_WITH_ARROW) find_package(Arrow CONFIG QUIET) find_package(Parquet CONFIG QUIET) if(NOT Arrow_FOUND OR NOT Parquet_FOUND) message(WARNING "RAID_WITH_ARROW=ON but Arrow/Parquet not found; building without Arrow") set(RAID_WITH_ARROW OFF) endif() endif() # ---- compile options ------------------------------------------------------- add_library(raid_options INTERFACE) target_compile_options(raid_options INTERFACE $<$:-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wno-sign-conversion> $<$,$>:-Werror> $<$,$>:-O3> ) if(RAID_NATIVE_ARCH AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") target_compile_options(raid_options INTERFACE -mcpu=native) endif() # Floating-point semantics: strict IEEE (no -ffast-math) so that CPU FP64 is a true reference. target_compile_options(raid_options INTERFACE $<$:-ffp-model=precise>) # ---- core library ---------------------------------------------------------- file(GLOB_RECURSE RAID_CORE_SOURCES CONFIGURE_DEPENDS src/core/*.cpp src/data/*.cpp src/statistics/*.cpp src/estimators/*.cpp src/models/*.cpp backends/cpu/*.cpp) if(NOT RAID_WITH_ARROW) list(FILTER RAID_CORE_SOURCES EXCLUDE REGEX ".*parquet_arrow\\.cpp$") endif() add_library(raid ${RAID_CORE_SOURCES}) add_library(raid::raid ALIAS raid) target_include_directories(raid PUBLIC $ $) target_link_libraries(raid PUBLIC Eigen3::Eigen nlohmann_json::nlohmann_json Threads::Threads CURL::libcurl raid_options) target_compile_definitions(raid PUBLIC RAID_VERSION="${PROJECT_VERSION}" RAID_WITH_FINDATA=1) if(RAID_WITH_ARROW) target_link_libraries(raid PUBLIC Arrow::arrow_shared Parquet::parquet_shared) target_compile_definitions(raid PUBLIC RAID_WITH_ARROW=1) endif() if(APPLE AND RAID_WITH_ACCELERATE) target_compile_definitions(raid PUBLIC RAID_WITH_ACCELERATE=1 EIGEN_USE_BLAS=1 ACCELERATE_NEW_LAPACK=1 ACCELERATE_LAPACK_ILP64=0) target_link_libraries(raid PUBLIC "-framework Accelerate") endif() # ---- Metal backend --------------------------------------------------------- if(RAID_ENABLE_METAL) if(NOT APPLE) message(FATAL_ERROR "RAID_ENABLE_METAL requires macOS") endif() file(GLOB _raid_metal_probe CONFIGURE_DEPENDS backends/metal/host/*.mm) if(NOT _raid_metal_probe) message(STATUS "Metal backend sources not present yet (Phase 3): building without Metal") set(RAID_ENABLE_METAL OFF) endif() endif() if(RAID_ENABLE_METAL) enable_language(OBJCXX) set(CMAKE_OBJCXX_STANDARD 20) file(GLOB RAID_METAL_HOST CONFIGURE_DEPENDS backends/metal/host/*.mm backends/metal/host/*.cpp) file(GLOB RAID_METAL_SHADERS CONFIGURE_DEPENDS backends/metal/shaders/*.metal) add_library(raid_metal ${RAID_METAL_HOST}) target_link_libraries(raid_metal PUBLIC raid "-framework Metal" "-framework Foundation") target_compile_options(raid_metal PRIVATE -fobjc-arc) target_compile_definitions(raid PUBLIC RAID_ENABLE_METAL=1) # Embed the MSL sources as a string (runtime compilation fallback / cold-compile benchmark) set(RAID_MSL_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/raid_msl_bundle.cpp") add_custom_command(OUTPUT ${RAID_MSL_BUNDLE} COMMAND ${CMAKE_COMMAND} -DOUT=${RAID_MSL_BUNDLE} "-DSHADERS=${RAID_METAL_SHADERS}" -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EmbedMSL.cmake DEPENDS ${RAID_METAL_SHADERS} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EmbedMSL.cmake COMMENT "Embedding MSL sources") target_sources(raid_metal PRIVATE ${RAID_MSL_BUNDLE}) # Optional offline metallib (requires the Metal Toolchain). Missing toolchain => runtime compile only. find_program(RAID_XCRUN xcrun) if(RAID_XCRUN AND RAID_METAL_SHADERS) execute_process(COMMAND ${RAID_XCRUN} -sdk macosx metal --version RESULT_VARIABLE _mt_rc OUTPUT_QUIET ERROR_QUIET) if(_mt_rc EQUAL 0) set(RAID_METALLIB "${CMAKE_CURRENT_BINARY_DIR}/raid.metallib") set(_airs) foreach(s ${RAID_METAL_SHADERS}) get_filename_component(n ${s} NAME_WE) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${n}.air COMMAND ${RAID_XCRUN} -sdk macosx metal -O2 -fno-fast-math -c ${s} -o ${CMAKE_CURRENT_BINARY_DIR}/${n}.air DEPENDS ${s} COMMENT "metal ${n}") list(APPEND _airs ${CMAKE_CURRENT_BINARY_DIR}/${n}.air) endforeach() add_custom_command(OUTPUT ${RAID_METALLIB} COMMAND ${RAID_XCRUN} -sdk macosx metallib ${_airs} -o ${RAID_METALLIB} DEPENDS ${_airs} COMMENT "metallib") add_custom_target(raid_metallib ALL DEPENDS ${RAID_METALLIB}) add_dependencies(raid_metal raid_metallib) target_compile_definitions(raid_metal PRIVATE RAID_METALLIB_PATH="${RAID_METALLIB}") message(STATUS "Metal toolchain found: building raid.metallib") else() message(STATUS "Metal toolchain not found: runtime MSL compilation only") endif() endif() endif() # ---- CLI -------------------------------------------------------------------- if(RAID_BUILD_CLI) add_executable(raid_cli cli/raid.cpp) set_target_properties(raid_cli PROPERTIES OUTPUT_NAME raid) target_link_libraries(raid_cli PRIVATE raid) if(RAID_ENABLE_METAL) target_link_libraries(raid_cli PRIVATE raid_metal) endif() endif() # ---- examples ----------------------------------------------------------------- add_executable(example_minimal examples/cpp/minimal.cpp) target_link_libraries(example_minimal PRIVATE raid) if(RAID_ENABLE_METAL) target_link_libraries(example_minimal PRIVATE raid_metal) endif() # ---- tests ------------------------------------------------------------------ if(RAID_BUILD_TESTS) find_package(Catch2 3 CONFIG REQUIRED) include(CTest) include(Catch) file(GLOB_RECURSE RAID_TEST_SOURCES CONFIGURE_DEPENDS tests/unit/*.cpp tests/property/*.cpp tests/reference/*.cpp tests/simulation/*.cpp tests/stress/*.cpp tests/integration/*.cpp) add_executable(raid_tests ${RAID_TEST_SOURCES}) target_link_libraries(raid_tests PRIVATE raid Catch2::Catch2WithMain) target_compile_definitions(raid_tests PRIVATE RAID_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") if(RAID_ENABLE_METAL) target_link_libraries(raid_tests PRIVATE raid_metal) endif() catch_discover_tests(raid_tests) endif() # ---- benchmarks --------------------------------------------------------------- if(RAID_BUILD_BENCH) file(GLOB RAID_BENCH_SOURCES CONFIGURE_DEPENDS benchmarks/micro/*.cpp benchmarks/end_to_end/*.cpp benchmarks/accuracy/*.cpp benchmarks/scalability/*.cpp) foreach(b ${RAID_BENCH_SOURCES}) get_filename_component(n ${b} NAME_WE) add_executable(bench_${n} ${b}) target_link_libraries(bench_${n} PRIVATE raid) if(RAID_ENABLE_METAL) target_link_libraries(bench_${n} PRIVATE raid_metal) endif() endforeach() endif() # ---- Python ------------------------------------------------------------------- if(RAID_BUILD_PYTHON) add_subdirectory(bindings/python) endif() # ---- install ----------------------------------------------------------------- install(TARGETS raid raid_options EXPORT raidTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if(RAID_ENABLE_METAL) install(TARGETS raid_metal EXPORT raidTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() if(RAID_BUILD_CLI) install(TARGETS raid_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(EXPORT raidTargets NAMESPACE raid:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/raid)