cmake_minimum_required(VERSION 3.21 FATAL_ERROR)

project(devXlib
    VERSION 0.2
    DESCRIPTION "Library wrapping device-oriented routines and utilities"
    LANGUAGES Fortran C)

###########################################################
# Options
###########################################################
set(DEVXLIB_ENABLE_ACC "CUDAF" CACHE STRING "Enable a specific acceleration")
set_property(CACHE DEVXLIB_ENABLE_ACC PROPERTY STRINGS "CUDAF" "OPENACC" "OPENMPGPU")

set(DEVXLIB_ENABLE_GPU_BLAS "CUBLAS" CACHE STRING "Enable a specific BLAS offload")
set_property(CACHE DEVXLIB_ENABLE_GPU_BLAS PROPERTY STRINGS "CUBLAS" "MKLGPU" "ROCBLAS")

###########################################################
# Dependencies
###########################################################
# Option dependencies
get_property(OPT_STRINGS CACHE DEVXLIB_ENABLE_ACC PROPERTY STRINGS)
if(NOT DEVXLIB_ENABLE_ACC IN_LIST OPT_STRINGS)
    message(FATAL_ERROR "Wrong value of the parameter 'DEVXLIB_ENABLE_ACC'")
endif()

get_property(OPT_STRINGS CACHE DEVXLIB_ENABLE_GPU_BLAS PROPERTY STRINGS)
if(NOT DEVXLIB_ENABLE_GPU_BLAS IN_LIST OPT_STRINGS)
    message(FATAL_ERROR "Wrong value of the parameter 'DEVXLIB_ENABLE_GPU_BLAS'")
endif()

# Compiler dependencies
if(DEVXLIB_ENABLE_ACC STREQUAL "CUDAF")
    if(NOT(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI"))
	    message(FATAL_ERROR "CUDA Fortran is supported only from the Nvidia Fortran compiler")
    endif()
elseif(DEVXLIB_ENABLE_ACC STREQUAL "OPENACC")
    if(NOT(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU"))
        message(FATAL_ERROR "OPENACC is supported only from Nvidia and GNU Fortran compilers")
    endif()
elseif(DEVXLIB_ENABLE_ACC STREQUAL "OPENMPGPU")
    if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
        message(FATAL_ERROR "OpenMP GPU offload is supported only from the Intel OneAPI compiler")
    endif()
endif()

# BLAS offload dependencies
if(DEVXLIB_ENABLE_GPU_BLAS STREQUAL "CUBLAS")
    if(NOT(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR CMAKE_Fortran_COMPILER_ID STREQUAL "PGI" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU"))
        message(FATAL_ERROR "Nvidia CUBLAS is supported only from Nvidia and GNU Fortran compilers")
    endif()
elseif(DEVXLIB_ENABLE_GPU_BLAS STREQUAL "MKLGPU")
    if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
        message(FATAL_ERROR "Intel MKLGPU BLAS is supported only from Intel OneAPI compiler")
    endif()
endif()

###########################################################
# Build Type
###########################################################
set(default_build_type "RelWithDebInfo")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
    set(CMAKE_BUILD_TYPE "${default_build_type}"
        CACHE STRING "Choose the type of build." FORCE)
    # Set the possible values of build type for cmake-gui
    set_property(CACHE CMAKE_BUILD_TYPE
        PROPERTY
            STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

###########################################################
# Build helpers
###########################################################
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

if (NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_INSTALL_PREFIX}/mod")
endif()

############################################################
# Compiler vendor specific options and bug checks
############################################################
if(CMAKE_Fortran_COMPILER_ID MATCHES "NVHPC")
    include(NVFortranCompiler)
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
    include(GNUFortranCompiler)
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "IntelLLVM")
    include(IntelOneAPIFortranCompiler)
endif()

###########################################################
# OpenACC
###########################################################
if(DEVXLIB_ENABLE_ACC STREQUAL "OPENACC")
    find_package(OpenACC REQUIRED)
endif()

###########################################################
# OpenMP
###########################################################
find_package(OpenMP REQUIRED)

###########################################################
# BLAS offloading
###########################################################
if(DEVXLIB_ENABLE_GPU_BLAS STREQUAL "CUBLAS")
    find_package(CUDAToolkit REQUIRED)
elseif(DEVXLIB_ENABLE_GPU_BLAS STREQUAL "MKLGPU")
    find_package(MKL CONFIG REQUIRED)
elseif(DEVXLIB_ENABLE_GPU_BLAS STREQUAL "ROCBLAS")
    find_package(rocblas REQUIRED)
endif()

###########################################################
# LAPACK
###########################################################
find_package(LAPACK REQUIRED)

###########################################################
# Add directories
###########################################################
add_subdirectory(src)
