
cmake_minimum_required(VERSION 3.14)

list(APPEND
   CMAKE_MODULE_PATH
   ${CMAKE_CURRENT_SOURCE_DIR}/config/cmake
  )

include(utils)
ensure_out_of_source_build()

list(APPEND CMAKE_MESSAGE_CONTEXT "libgridxc")
project(
  libgridxc
  LANGUAGES Fortran
  VERSION "2.1.0"
  DESCRIPTION "Library for XC computation on grids"
)

# Follow GNU conventions for installing directories
include(GNUInstallDirs)


# Allow legacy names (e.g. WITH_LIBXC) for options
include(LibgridxcPrefixOptions)

#
option(LIBGRIDXC_WITH_MPI "Whether libgridxc should support MPI-parallelism" FALSE)
option(LIBGRIDXC_WITH_LIBXC "Whether libgridxc has a libxc interface" FALSE)
option(LIBGRIDXC_WITH_GRID_SP "Whether libgridxc has a single-precision (cellxc only) interface" FALSE)

option(LIBGRIDXC_BUILD_DOCS "Whether the libgridxc docs are built " FALSE)
option(LIBGRIDXC_TESTS "Whether the libgridxc tests are built " ${PROJECT_IS_TOP_LEVEL})
option(LIBGRIDXC_INSTALL "Whether to install the libgridxc binaries" TRUE)

# Allow this project to override the general setting
if(DEFINED LIBGRIDXC_SHARED_LIBS)
   set(BUILD_SHARED_LIBS ${LIBGRIDXC_SHARED_LIBS})
   message(STATUS "Setting BUILD_SHARED_LIBS to ${LIBGRIDXC_SHARED_LIBS}")
endif()

# General configuration information: Build_type, Config files...
add_subdirectory("config")

# Compiler flags
include(flags)

if(LIBGRIDXC_WITH_MPI)
  if (NOT TARGET MPI::MPI_Fortran)
    find_package(MPI REQUIRED)
  endif()
endif()

# Collect source of the project
set(srcs)
add_subdirectory("src")

add_library(
  "${PROJECT_NAME}-lib"
  "${srcs}"
)

#-------------
#  This is a record of a feature that can be checked programmatically when
#  configuring clients if libgridxc is used as a pre-compiled library, but
#  not if the libgridxc source is compiled by the client.
#
set(LIBGRIDXC_HAS_PROCEDURE_POINTERS TRUE CACHE BOOL "libgridxc uses procedure pointers")
#-------------

set_target_properties(
  "${PROJECT_NAME}-lib"
  PROPERTIES
  POSITION_INDEPENDENT_CODE TRUE
  OUTPUT_NAME "gridxc"
  VERSION "${PROJECT_VERSION}"
  SOVERSION "${PROJECT_VERSION_MAJOR}"
  Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include"
)
#
# It seems that CMake creates this directory at build time, but
# we might need it at configuration time in some cases (e.g when
# using FetchContent)
#
if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/include")
  make_directory("${CMAKE_CURRENT_BINARY_DIR}/include")
endif()

if(LIBGRIDXC_WITH_LIBXC)

 if (NOT TARGET Libxc::xc_Fortran)
  find_package(CustomLibxc)
  if (TARGET Libxc::xc_Fortran)
    message(VERBOSE "Defining new target libxc::XC_Fortran...")
    add_library(libxc::XC_Fortran INTERFACE IMPORTED)
    target_link_libraries(libxc::XC_Fortran INTERFACE Libxc::xc_Fortran)
  endif()
 endif()

 if(NOT LIBXC_Fortran_FOUND)
   message(WARNING
    "Libxc support has been requested, but the fortran libxc library cannot be found.")
   message(FATAL_ERROR "Libxc could not be found by CMake")
 endif()

  target_compile_definitions(
  ${PROJECT_NAME}-lib
  PRIVATE
  HAVE_LIBXC
  )

  target_link_libraries(
    "${PROJECT_NAME}-lib"
    PUBLIC
    libxc::XC_Fortran
  )
endif()

if(LIBGRIDXC_WITH_GRID_SP)
  target_compile_definitions(
  ${PROJECT_NAME}-lib
  PUBLIC
  GRID_SP
  )
endif()


if(LIBGRIDXC_WITH_MPI)
  target_compile_definitions(
  "${PROJECT_NAME}-lib"
  PRIVATE HAVE_MPI
  )

  target_link_libraries("${PROJECT_NAME}-lib" PUBLIC MPI::MPI_Fortran)

endif()

set(
  module-dir
  "${PROJECT_NAME}/${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}"
)

target_include_directories(
  "${PROJECT_NAME}-lib"
  PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${module-dir}>
)

#
# This auxiliary target is useful when we compile on the fly, and
# we employ the idiom
#
#     add_subdirectory("Path/to/libgridxc")
#     add_library(libgridxc::libgridxc ALIAS libgridxc)
#
# instead of using the imported target libgridxc::libgridxc as obtained,
# for example, with 'find_package'.
# 
#
add_library("${PROJECT_NAME}" INTERFACE)
target_link_libraries("${PROJECT_NAME}" INTERFACE "${PROJECT_NAME}-lib")

# For future uses, we might create an alias target here, to exploit
# the new feature of integration of 'FetchContent' and 'find_package'
# It is enabled by a variable since old clients might still have
# the aliasing statement hardwired after the FetchContent processing.

if (${LIBGRIDXC_CREATE_TARGET_ALIAS})
  add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS ${PROJECT_NAME})
endif()

if (LIBGRIDXC_INSTALL)
  # Export targets for other projects
  
  install(
    TARGETS
    "${PROJECT_NAME}"
    "${PROJECT_NAME}-lib"
    EXPORT
    "${PROJECT_NAME}-targets"
    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  )
  install(
    EXPORT
    "${PROJECT_NAME}-targets"
    NAMESPACE
    "${PROJECT_NAME}::"
    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
  )
  install(
    DIRECTORY
    "${CMAKE_CURRENT_BINARY_DIR}/include/"
    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${module-dir}"
  )
  # Package license files
  install(
    FILES
    "COPYING"
    DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/${PROJECT_NAME}"
  )

endif(LIBGRIDXC_INSTALL)

if(LIBGRIDXC_BUILD_DOCS)
  add_subdirectory("docs")
endif(LIBGRIDXC_BUILD_DOCS)

if(LIBGRIDXC_TESTS)
  # add the testsuite

  enable_testing()
  add_subdirectory("Testers")
  
endif(LIBGRIDXC_TESTS)

list(POP_BACK CMAKE_MESSAGE_CONTEXT)
