cmake_minimum_required(VERSION 3.24)

# must be on the same line so that pyproject.toml can correctly identify the version
project(musica-distribution VERSION 0.14.2)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE ${PROJECT_SOURCE_DIR}/cmake/SetDefaults.cmake)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING
      "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
      FORCE)
endif(NOT CMAKE_BUILD_TYPE)

include(GNUInstallDirs)

################################################################################
# Library options to build
include(CMakeDependentOption)

option(MUSICA_BUILD_C_CXX_INTERFACE "Use MUSICA" ON)
option(MUSICA_BUILD_FORTRAN_INTERFACE "Use MUSICA-Fortran interface" OFF)
option(MUSICA_ENABLE_INSTALL "Install the musica library" ON)
option(MUSICA_ENABLE_TESTS "Builds tests that ensures each enabled MUSICA component can be used" ON)
option(MUSICA_ENABLE_MPI "Enable MPI parallel support" OFF)
option(MUSICA_ENABLE_OPENMP "Enable OpemMP support" OFF)
option(MUSICA_ENABLE_MEMCHECK "Enable memory checking" OFF)
option(MUSICA_BUILD_DOCS "Build the documentation" OFF)
option(MUSICA_ENABLE_MICM "Enable MICM" ON)
option(MUSICA_ENABLE_TUVX "Enable TUV-x" ON)
option(MUSICA_ENABLE_CARMA "Enable CARMA" ON)
option(MUSICA_ENABLE_PIC "Build the library with position independent code" OFF)
option(MUSICA_ENABLE_COVERAGE "Enable code coverage output" OFF)
option(MUSICA_BUNDLE_DEPENDENCIES "Bundle dependencies with the library" ON)
option(MUSICA_ENABLE_JAVASCRIPT "Build the JavaScript addon" OFF)
option(MUSICA_CREATE_ENVIRONMENT_MODULE "Create an Lmod environment module file" OFF)

set(MUSICA_GPU_TYPE "None" CACHE STRING "The GPU type being targeted")

set(MUSICA_SET_MICM_DEFAULT_VECTOR_SIZE "4" CACHE STRING "Set MICM vector-ordered matrix dimension")

cmake_dependent_option(
  MUSICA_ENABLE_PYTHON_LIBRARY "Adds pybind11, a lightweight header-only library that exposes C++ types in Python and vice versa" OFF "MUSICA_BUILD_C_CXX_INTERFACE" OFF)

cmake_dependent_option(
  MUSICA_ONLY_PYTHON "Build only the Python bindings. This option is used when building Python wheels primarily" OFF "MUSICA_ENABLE_PYTHON_LIBRARY" OFF)

################################################################################
# Projet wide setup variables 
set(MUSICA_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(MUSICA_LIB_DIR ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(MUSICA_PROJECT_SRC_DIR ${PROJECT_SOURCE_DIR})

set(MUSICA_MOD_DIR ${PROJECT_BINARY_DIR}/mod_fortran)
set(MUSICA_INSTALL_MOD_DIR ${CMAKE_INSTALL_INCLUDEDIR}/musica/fortran)

set(musica_compile_definitions "")

# Add flags for various compilers
if(${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel")
  list(APPEND musica_compile_definitions MUSICA_USING_INTEL)
elseif(${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU")
  list(APPEND musica_compile_definitions MUSICA_USING_GNU)
elseif(${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI")
  list(APPEND musica_compile_definitions MUSICA_USING_PGI)
endif()

# since sources are collected so that python libraries can target them directly,
# we need to know if we are targeting Fortran before we collect the sources
# otherwise cmake freaks out, and I don't know why, but this fixes it
if(MUSICA_ENABLE_TUVX OR MUSICA_ENABLE_CARMA)
    enable_language(Fortran)
endif()

# Add flags when using the ClangCL toolset
if(CMAKE_GENERATOR_TOOLSET STREQUAL "ClangCL")
  list(APPEND musica_compile_definitions MUSICA_USING_CLANGCL)
endif()

# Set the Valgrind suppressions file for tests
set(MEMCHECK_SUPPRESS "--suppressions=${PROJECT_SOURCE_DIR}/valgrind.supp")

################################################################################
# Dependencies

if(MUSICA_BUNDLE_DEPENDENCIES)
  include(${PROJECT_SOURCE_DIR}/cmake/dependencies.cmake)
endif()

################################################################################
# Tests
if(MUSICA_ENABLE_TESTS)
  if(MUSICA_ENABLE_COVERAGE)
    include(CodeCoverage)
    append_coverage_compiler_flags()
    setup_target_for_coverage_lcov(
        NAME coverage
        EXECUTABLE "ctest"
        EXCLUDE "${PROJECT_SOURCE_DIR}/src/test/*"
        BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
        LCOV_ARGS "--ignore-errors" "mismatch")
    
  endif()
  
  enable_testing()
endif()


# disable CMake module scanning on macOS
if (APPLE)
  set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
endif()

################################################################################
# MUSICA
if(MUSICA_BUILD_C_CXX_INTERFACE)
  add_subdirectory(src)
endif()

if(MUSICA_BUILD_DOCS)
  add_subdirectory(docs)
endif()

################################################################################
# MUSICA-Fortran
if(MUSICA_BUILD_FORTRAN_INTERFACE)
  add_subdirectory(fortran)
endif()

################################################################################
# Musica python
if(MUSICA_ENABLE_PYTHON_LIBRARY)
  add_subdirectory(python)
endif()

################################################################################

# Musica JavaScript Addon
if(MUSICA_ENABLE_JAVASCRIPT)
  add_subdirectory(javascript)
endif()

################################################################################
###
# Configure and display a summary file for how musica was built.
###
include(${PROJECT_SOURCE_DIR}/cmake/summary.cmake)
