cmake_minimum_required(VERSION 3.20) project( SpectraREML VERSION 0.1.0 DESCRIPTION "Reusable batched spectral AI-REML engine" LANGUAGES CXX ) include(GNUInstallDirs) include(CTest) list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(REML_BLAS "MKL" CACHE STRING "BLAS/LAPACKE backend: MKL or OPENBLAS") set_property(CACHE REML_BLAS PROPERTY STRINGS MKL OPENBLAS) string(TOUPPER "${REML_BLAS}" REML_BLAS) option(REML_ENABLE_OPENMP "Parallelize independent REML tasks with OpenMP" ON) option(REML_ENABLE_NATIVE_ARCH "Enable compiler tuning for the build host" OFF) add_library(reml_blas_lapacke INTERFACE) add_library(REML::BLAS_LAPACKE ALIAS reml_blas_lapacke) if(REML_BLAS STREQUAL "MKL") # These variables are consumed by Intel's MKLConfig.cmake. Sequential is # deliberately the portable default because tasks are parallelized with # OpenMP; a threaded BLAS can otherwise create nested thread pools. set(MKL_INTERFACE "lp64" CACHE STRING "oneMKL integer interface") set(MKL_LINK "dynamic" CACHE STRING "oneMKL link type") set(MKL_THREADING "sequential" CACHE STRING "oneMKL threading layer") set_property(CACHE MKL_INTERFACE PROPERTY STRINGS lp64 ilp64) set_property(CACHE MKL_LINK PROPERTY STRINGS dynamic static) set_property(CACHE MKL_THREADING PROPERTY STRINGS sequential intel_thread gnu_thread tbb_thread) find_package(MKL CONFIG REQUIRED) if(NOT TARGET MKL::MKL) message(FATAL_ERROR "MKL was found, but its MKL::MKL CMake target is missing") endif() target_link_libraries(reml_blas_lapacke INTERFACE MKL::MKL) target_compile_definitions(reml_blas_lapacke INTERFACE REML_BLAS_MKL=1) elseif(REML_BLAS STREQUAL "OPENBLAS") find_package(REML_OpenBLAS REQUIRED) target_link_libraries(reml_blas_lapacke INTERFACE REML::OpenBLASLAPACKE) target_compile_definitions(reml_blas_lapacke INTERFACE REML_BLAS_OPENBLAS=1) else() message(FATAL_ERROR "Unsupported REML_BLAS='${REML_BLAS}'. Choose MKL or OPENBLAS.") endif() if(REML_ENABLE_OPENMP) find_package(OpenMP REQUIRED COMPONENTS CXX) endif() add_library(spectra_reml_core STATIC src/linalg.cpp src/grm.cpp src/distributions.cpp src/reml_core.cpp src/fixed_effects.cpp src/batch_io.cpp ) add_library(SpectraREML::core ALIAS spectra_reml_core) target_compile_features(spectra_reml_core PUBLIC cxx_std_17) target_include_directories(spectra_reml_core PUBLIC $ $ ) target_link_libraries(spectra_reml_core PUBLIC REML::BLAS_LAPACKE) if(REML_ENABLE_OPENMP) target_link_libraries(spectra_reml_core PUBLIC OpenMP::OpenMP_CXX) target_compile_definitions(spectra_reml_core PUBLIC REML_USE_OPENMP=1) endif() if(MSVC) target_compile_options(spectra_reml_core PRIVATE /W4 /permissive- /EHsc) else() target_compile_options(spectra_reml_core PRIVATE -Wall -Wextra -Wpedantic) target_compile_definitions(spectra_reml_core PUBLIC _FILE_OFFSET_BITS=64) if(REML_ENABLE_NATIVE_ARCH) target_compile_options(spectra_reml_core PRIVATE -march=native) endif() endif() add_executable(spectra_reml src/main.cpp) target_link_libraries(spectra_reml PRIVATE SpectraREML::core) target_compile_features(spectra_reml PRIVATE cxx_std_17) if(MSVC) target_compile_options(spectra_reml PRIVATE /W4 /permissive- /EHsc) else() target_compile_options(spectra_reml PRIVATE -Wall -Wextra -Wpedantic) if(REML_ENABLE_NATIVE_ARCH) target_compile_options(spectra_reml PRIVATE -march=native) endif() endif() if(BUILD_TESTING) add_executable(test_reml_synthetic tests/cpp/test_reml_synthetic.cpp) target_link_libraries(test_reml_synthetic PRIVATE SpectraREML::core) add_test(NAME reml_synthetic COMMAND test_reml_synthetic) add_executable(test_grm_io tests/cpp/test_grm_io.cpp) target_link_libraries(test_grm_io PRIVATE SpectraREML::core) add_test(NAME grm_io COMMAND test_grm_io) endif() install(TARGETS spectra_reml_core spectra_reml RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) message(STATUS "SpectraREML ${PROJECT_VERSION}") message(STATUS " BLAS/LAPACKE backend : ${REML_BLAS}") message(STATUS " OpenMP : ${REML_ENABLE_OPENMP}") message(STATUS " Native architecture : ${REML_ENABLE_NATIVE_ARCH}")