# Build DL_FIND as a shared library using its native Makefile

#  Copyright (C) 2017, 2019 The authors of Py-ChemShell
#
#  This file is part of Py-ChemShell.
#
#  Py-ChemShell is free software: you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  Py-ChemShell is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with Py-ChemShell.  If not, see
#  <http://www.gnu.org/licenses/>.

# you.lu@stfc.ac.uk, July 2015
# TWK: modified following transfer of DL-FIND repository to git, Feb 2019
#      DL-FIND is now checked out automatically as a git submodule

#cmake_minimum_required(VERSION 2.8)

# if OLDALLOC for pgf95, uncomment:
option(OLDALLOC "Old alloction for pgf95" OFF)
if(OLDALLOC)
  add_definitions(-DOLDALLOC)
endif()

# switch: update source code from svn
# FIXME: not in use
if($ENV{DLF_UPDATE})
  set(DLF_NO_UPDATE 0)
else()
  set(DLF_NO_UPDATE 1)
endif()

# paths
set(CMAKE_Fortran_MODULE_DIRECTORY ${CHEMSH_BUILD_DIR}/modules/dl_find)
include_directories(${CHEMSH_BUILD_DIR}/modules
                    ${CHEMSH_BUILD_DIR}/modules/parallel
                    ${CHEMSH_BUILD_DIR}/modules/dl_py2f)

# get DL_FIND source as external project
include(ExternalProject)

# name for external project
set(DLF_NAME "DL_FIND")

# try to convert to absolte full path: when it is a URL, it appears as "${CMAKE_CURRENT_SOURCE_DIR}${DL_FIND}" and will not be taken as "EXISTS"
set(DLF_ABSOLUTE "${CMAKE_CURRENT_SOURCE_DIR}/src")

# Check DL_FIND source location exists
if(EXISTS ${DLF_ABSOLUTE})
    # set a legacy svn revision number (notice the missing '$'!)
    if(DEFINED ENV{DLF_SVN_REVISION})
      set(DLF_SVN_REVISION $ENV{DLF_SVN_REVISION})
    else()
      set(DLF_SVN_REVISION "unknown")
    endif()
    # Check source location is a directory
    if(IS_DIRECTORY ${DLF_ABSOLUTE})
        set(DLF_DIR     ${DLF_ABSOLUTE})
        set(DLF_SRC_DIR ${DLF_ABSOLUTE})
    # otherwise abort compilation
    else()
        message(FATAL_ERROR "${BoldRed}Directory expected for DLF_REPO but file found. Exiting...${EndColour}")
    endif()
# abort compilation if DL-FIND cannot be located
else()
    message(FATAL_ERROR "${BoldRed}DL-FIND submodule not found. Exiting...${EndColour}")
endif()

# dump aux script dlf_svnversion.cmake (will be run by ExternalProject_Add)
# TWK TODO to be removed once svn revision processing code is removed from DL-FIND
set(DLF_SVNVERSION_SCRIPT
    "# as we no longer use svn patch dlf_svnversion.f90 with unknown rev
    set\(DLF_SVN_REVISION \"r\${\${DLF_NAME}_unknown}\"\)
    file\(WRITE \"${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.f90\" \"subroutine dlf_svnversion\\(iver\\)\\n    character\\(*\\) :: iver\\n    iver='\"\)
    file\(APPEND \"${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.f90\" \"\${DLF_SVN_REVISION}\"\)
    file\(APPEND \"${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.f90\" \"'\\nendsubroutine dlf_svnversion\"\)"
)
# this step is always run
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.cmake" "${DLF_SVNVERSION_SCRIPT}")

ExternalProject_Add(
    ${DLF_NAME}
    PREFIX              ${CHEMSH_ARCH}
    STAMP_DIR           ${CHEMSH_ARCH}/stamp
    TMP_DIR             ${CHEMSH_ARCH}/tmp
    SOURCE_DIR          ${DLF_DIR}
    CONFIGURE_COMMAND   ""
    BUILD_COMMAND       ${CMAKE_COMMAND} -E cmake_echo_color
                                         --switch=$(COLOR)
                                         --magenta
                                         --bold "Architecture for which '${DLF_NAME}' is built: '${CHEMSH_ARCH}'"
    INSTALL_COMMAND     ""
)

# this always runs to patch dlf_svnversion.f90
ExternalProject_Add_Step(
    ${DLF_NAME} DLF_PATCH
    COMMENT           "Generating 'dlf_svnversion.f90'..."
    ALWAYS            1
    DEPENDEES         install
    COMMAND           ${CMAKE_COMMAND} -DDLF_DIR:STRING=${DLF_DIR}
                                       -DDLF_NAME:STRING=${DLF_NAME}
                                       -DDLF_SVN_REVISION:STRING=${DLF_SVN_REVISION}
                                       -P ${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.cmake
    COMMAND           ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_SOURCE_DIR}/dlf_svnversion.cmake
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

# select source:
#   do NOT use autocmd file(GLOB_RECURSE ...), otherwise the source files are yet to be ready as CMake always run these commands before any building steps. manually listing source files will force dependency check due to set_source_files_properties(${DLF_FSOURCES} PROPERTIES GENERATED TRUE)
#   do so also for purpose of maintanance.
# FIXME: no mpi
# file(GLOB_RECURSE DLF_FSOURCES "${DLF_SRC_DIR}/*.f90")
# file(GLOB_RECURSE DLF_CSOURCES "${DLF_SRC_DIR}/*.c")
# list(REMOVE_ITEM DLF_FSOURCES ${DLF_SRC_DIR}/main.f90
#                               ${DLF_SRC_DIR}/dlf_mpi.f90
#                               ${DLF_SRC_DIR}/dlfind_crystal.f90
#                               ${DLF_SRC_DIR}/draw.f90
# )
list(APPEND DLF_FSOURCES ${DLF_SRC_DIR}/dl-find.f90
                         ${DLF_SRC_DIR}/dlf_allocate.f90
                         ${DLF_SRC_DIR}/dlf_checkpoint.f90
                         ${DLF_SRC_DIR}/dlf_conint.f90
                         ${DLF_SRC_DIR}/dlf_convergence.f90
                         ${DLF_SRC_DIR}/dlf_coords.f90
                         ${DLF_SRC_DIR}/dlf_dimer.f90
                         ${DLF_SRC_DIR}/dlf_formstep.f90
                         ${DLF_SRC_DIR}/dlf_global_module.f90
                         ${DLF_SRC_DIR}/dlf_hdlc_constraint.f90
                         ${DLF_SRC_DIR}/dlf_hdlc_hdlclib.f90
                         ${DLF_SRC_DIR}/dlf_hdlc_interface.f90
                         ${DLF_SRC_DIR}/dlf_hdlc_matrixlib.f90
                         ${DLF_SRC_DIR}/dlf_hdlc_primitive.f90
                         ${DLF_SRC_DIR}/dlf_lbfgs.f90
                         ${DLF_SRC_DIR}/dlf_linalg.f90
                         ${DLF_SRC_DIR}/dlf_microiter.f90
#                         ${DLF_SRC_DIR}/dlf_mpi.f90
                         ${DLF_SRC_DIR}/dlf_neb.f90
                         ${DLF_SRC_DIR}/dlf_parallel_opt.f90
                         ${DLF_SRC_DIR}/dlf_qts.f90
                         ${DLF_SRC_DIR}/dlf_scalestep.f90
                         ${DLF_SRC_DIR}/dlf_sort.f90
                         ${DLF_SRC_DIR}/dlf_stat_module.f90
                         ${DLF_SRC_DIR}/dlf_task.f90
                         ${DLF_SRC_DIR}/dlf_time.f90
                         ${DLF_SRC_DIR}/dlf_util.f90
#                         ${DLF_SRC_DIR}/dlfind_crystal.f90
#                         ${DLF_SRC_DIR}/draw.f90
#                         ${DLF_SRC_DIR}/main.f90
)

# if parallel
if(WITH_MPI)
    message("${BoldWhite}DL_FIND${EndColour} will be built with MPI support")
    list(APPEND DLF_FSOURCES ${DLF_SRC_DIR}/dlf_mpi.f90)
else()
    message("${BoldWhite}DL_FIND${EndColour} will be built without MPI support")
    list(APPEND DLF_FSOURCES ${DLF_SRC_DIR}/dlf_serial.f90)
endif()

# ChemShell/DL_FIND interface files
list(APPEND DLF_FSOURCES "dl_find.f90" "dlf_routines.f90" "dlf_svnversion.f90")

# setting property GENERATED forces CMake to check dependency
set_source_files_properties(${DLF_FSOURCES} PROPERTIES GENERATED TRUE)

# FLAGS
set(CMAKE_SHARED_LINKER_FLAGS "-DOLDALLOC=OFF")


# compile:
#   do not run add_library(dlf SHARED ${DLF_FSOURCES} dlf_svnversion.f90 dlf_xxx.f90 dlf_yyy.f90) as the source files may not be ready yet
add_library(dlf SHARED ${DLF_FSOURCES})
add_dependencies(dlf ${DLF_NAME})
add_dependencies(dlf parallel)
target_link_libraries(dlf dl_py2f parallel)

# preprocessor using lowercase .f90 extension
if(${CHEMSH_ARCH} STREQUAL "gnu")
    if(DEBUG)
        set_target_properties(dlf PROPERTIES COMPILE_FLAGS "-cpp -Wall")
    else()
        if(${CMAKE_Fortran_COMPILER_VERSION} VERSION_GREATER_EQUAL "10.0")
            set_target_properties(dlf PROPERTIES COMPILE_FLAGS "-cpp -fallow-argument-mismatch -Wno-argument-mismatch -Wno-all")
        else()
            set_target_properties(dlf PROPERTIES COMPILE_FLAGS "-cpp -Wno-argument-mismatch -Wno-all")
        endif()
    endif()
    target_link_libraries(dlf ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
    target_link_libraries(dlf ${CHEMSH_ScaLAPACK_FLAGS})
elseif(${CHEMSH_ARCH} STREQUAL "cpe-gnu")
    set_target_properties(dlf PROPERTIES COMPILE_FLAGS "-cpp")
    target_link_libraries(dlf ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
    target_link_libraries(dlf ${CHEMSH_ScaLAPACK_FLAGS})
    # TWK 23/08/2022 Expects a flag but may be empty, e.g. with Cray libsci which is automatically linked in.
    if(NOT("${CHEMSH_MKL_FLAGS}" STREQUAL ""))
        set_target_properties(dlf PROPERTIES LINK_FLAGS ${CHEMSH_MKL_FLAGS})
    endif()
elseif(${CHEMSH_ARCH} STREQUAL "intel")
    set_target_properties(dlf PROPERTIES COMPILE_FLAGS "-fpp")
    # TWK 4/3/2021 Using target_link_libraries puts the MKL flags in the
    #              correct position on the link line (i.e. at the end, after files)
    target_link_libraries(dlf ${CHEMSH_MKL_FLAGS})
endif()

