cmake_minimum_required(VERSION 3.12)
project(
  MCL
  VERSION 3.0.0
  DESCRIPTION "MCL: MiMiC Communication Library"
  HOMEPAGE_URL "https://mimic-project.org/"
  LANGUAGES CXX C
)

option(BUILD_TESTS "Build tests" OFF)
option(ENABLE_COVERAGE "Enable code coverage report" OFF)
option(BUILD_FORTRAN_API "Build Fortran API module" ON)
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
option(DISABLE_MPI_F08 "Disable MPI F08 Fortran module (even if it is available)" OFF)
if(BUILD_FORTRAN_API)
  enable_language(Fortran)
endif()

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(MPI 2.1 REQUIRED)
find_package(Python 3.6 REQUIRED)

if(BUILD_FORTRAN_API)
  if (MPI_Fortran_HAVE_F08_MODULE AND NOT DISABLE_MPI_F08)
    add_compile_definitions(USE_MPIF08)
  else()
    message(WARNING "MPI F08 module not found. Fortran API is limited to MPI F90 module.")
  endif()
  if(NOT MPI_Fortran_HAVE_F08_MODULE AND NOT MPI_Fortran_HAVE_F90_MODULE)
    message(FATAL_ERROR "MPI Fortran module was not found")
  endif()
endif()

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release"
    CACHE STRING "Choose the type of build." FORCE
  )
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "System processor: ${CMAKE_SYSTEM_PROCESSOR}")

if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
  if(ENABLE_COVERAGE)
    message(FATAL_ERROR "Code coverage compilation requires GCC compiler.")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
  if(ENABLE_COVERAGE)
    message(FATAL_ERROR "Code coverage compilation requires GCC compiler.")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
  if(ENABLE_COVERAGE)
    message(FATAL_ERROR "Code coverage compilation requires GCC compiler.")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
  if(ENABLE_COVERAGE)
    message(FATAL_ERROR "Code coverage compilation requires GCC compiler.")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  if(ENABLE_COVERAGE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
  endif()
  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pedantic -Wall")
  set(CMAKE_CXX_FLAGS_RELEASE "-O3")
else()
  message(WARNING "${CMAKE_CXX_COMPILER_ID} C++ compiler has not been explicitly configured")
endif()

if(BUILD_FORTRAN_API)
  if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O3")
  elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O3")
  elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O3")
  elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
    if(CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER 10.0.0)
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fallow-argument-mismatch")
    endif()
    if(ENABLE_COVERAGE)
      set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} --coverage")
    endif()
    set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -pedantic -Wall")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O3")
  elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Cray")
    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ef")
    set(CMAKE_Fortran_FLAGS_RELEASE "-O3")
  else()
    message(
      WARNING
      "'${CMAKE_Fortran_COMPILER_ID}' Fortran compiler has not been explicitly configured"
    )
  endif()
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Release")
  message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}")
  message(STATUS "Fortran flags: ${CMAKE_Fortran_FLAGS} ${CMAKE_Fortran_FLAGS_RELEASE}")
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
  message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}")
  message(STATUS "Fortran flags: ${CMAKE_Fortran_FLAGS} ${CMAKE_Fortran_FLAGS_DEBUG}")
else()
  message(STATUS "C++ flags: ${CMAKE_CXX_FLAGS}")
  message(STATUS "Fortran flags: ${CMAKE_Fortran_FLAGS}")
endif()

include(GNUInstallDirs)
if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
endif()
if(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
endif()
if(NOT DEFINED CMAKE_Fortran_MODULE_DIRECTORY)
  set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR})
endif()

add_subdirectory(src)

if(BUILD_TESTS)
  message(STATUS "Building test suite")
  include(CTest)
  enable_testing()
  include_directories(
    ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}
    ${CMAKE_BINARY_DIR}/src
  )
  add_subdirectory(tests)
endif(BUILD_TESTS)
