cmake_minimum_required(VERSION 3.18)
project(SpectralMM VERSION 0.2.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
option(SPECTRALMM_FETCH_EIGEN "Fetch pinned Eigen headers automatically" OFF)
if(SPECTRALMM_FETCH_EIGEN AND NOT EIGEN3_INCLUDE_DIR)
  include(FetchContent)
  FetchContent_Declare(spectralmm_eigen
    URL https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
    URL_HASH SHA256=8586084f71f9bde545ee7fa6d00288b264a2b7ac3607b974e54d13e7162c1c72
    SOURCE_SUBDIR spectralmm-headers-only)
  FetchContent_MakeAvailable(spectralmm_eigen)
  set(EIGEN3_INCLUDE_DIR "${spectralmm_eigen_SOURCE_DIR}")
else()
  find_path(EIGEN3_INCLUDE_DIR Eigen/Core PATH_SUFFIXES eigen3 REQUIRED)
endif()
set(SPECTRALMM_NATIVE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/native")
add_library(spectralmm SHARED ${SPECTRALMM_NATIVE_DIR}/core.cpp ${SPECTRALMM_NATIVE_DIR}/c_api.cpp)
target_include_directories(spectralmm PUBLIC ${SPECTRALMM_NATIVE_DIR}/include)
target_include_directories(spectralmm SYSTEM PRIVATE ${EIGEN3_INCLUDE_DIR})
if(MSVC)
  target_compile_options(spectralmm PRIVATE /W4)
else()
  target_compile_options(spectralmm PRIVATE -Wall -Wextra -Wpedantic)
endif()
set(SPECTRALMM_USE_BLAS "OFF" CACHE STRING "Dense BLAS: ON, OFF or AUTO")
set_property(CACHE SPECTRALMM_USE_BLAS PROPERTY STRINGS ON OFF AUTO)
if(SPECTRALMM_USE_BLAS STREQUAL "AUTO")
  if(APPLE AND NOT BLA_VENDOR)
    set(BLA_VENDOR Apple)
  endif()
  find_package(BLAS QUIET)
elseif(SPECTRALMM_USE_BLAS)
  find_package(BLAS REQUIRED)
endif()
if(BLAS_FOUND AND BLAS_LIBRARIES MATCHES "blastrampoline")
  if(SPECTRALMM_USE_BLAS STREQUAL "AUTO")
    message(STATUS "Ignoring libblastrampoline: SpectralMM requires a configured LP64 BLAS; using Eigen")
    set(BLAS_FOUND FALSE)
  elseif(SPECTRALMM_USE_BLAS)
    message(FATAL_ERROR "SpectralMM requires a direct LP64 BLAS provider, not libblastrampoline")
  endif()
endif()
if(SPECTRALMM_USE_BLAS AND BLAS_FOUND)
  target_compile_definitions(spectralmm PRIVATE EIGEN_USE_BLAS)
  target_link_libraries(spectralmm PRIVATE BLAS::BLAS)
  message(STATUS "SpectralMM dense backend: BLAS (${BLAS_LIBRARIES})")
else()
  message(STATUS "SpectralMM dense backend: Eigen")
endif()
set_target_properties(spectralmm PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
option(SPECTRALMM_CHECK_PCG_ALLOCATIONS "Assert no Eigen heap allocations in iterative inner solvers" OFF)
if(SPECTRALMM_CHECK_PCG_ALLOCATIONS)
  target_compile_definitions(spectralmm PRIVATE EIGEN_RUNTIME_NO_MALLOC)
  target_compile_options(spectralmm PRIVATE -UNDEBUG)
endif()
option(SPECTRALMM_PROFILE "Enable diagnostic phase profiling" OFF)
if(SPECTRALMM_PROFILE)
  target_compile_definitions(spectralmm PRIVATE SPECTRALMM_PROFILE)
endif()
if(SKBUILD)
  install(TARGETS spectralmm LIBRARY DESTINATION spectralmm/_lib RUNTIME DESTINATION spectralmm/_lib)
  install(FILES THIRD_PARTY_NOTICES.md DESTINATION spectralmm)
else()
  install(TARGETS spectralmm LIBRARY DESTINATION lib RUNTIME DESTINATION bin ARCHIVE DESTINATION lib)
  install(DIRECTORY ${SPECTRALMM_NATIVE_DIR}/include/ DESTINATION include)
  install(FILES THIRD_PARTY_NOTICES.md DESTINATION share/doc/spectralmm)
endif()
