#  Copyright (C) 2018 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
# Oct 2018
# YL 13/07/2024: added support for NAMD 3.0

# FetchContent isn't available until 3.11

include(ExternalProject)

set(CMAKE_VERBOSE_MAKEFILE:BOOL TRUE)

# utils
include(${CHEMSH_DIR}/chemsh/utils/cmake/colours.cmake)

# function to get the NAMD path
function(get_namd_dir NAMD)

    # try to convert to absolte full path: when it is a URL, it appears as "${CMAKE_CURRENT_SOURCE_DIR}${NAMD}" and will not be taken as "EXISTS"
    get_filename_component(NAMD_ABSOLUTE "${NAMD}" ABSOLUTE)

    # NAMD source location
    # if file or directory
    if(EXISTS ${NAMD_ABSOLUTE})
        # do not use git
        set(NAMD_GIT_REPO "")
        set(NAMD_GIT      OFF)
        # set a git revision number (notice the missing '$'!)
        if(DEFINED ENV{NAMD_GIT_REVISION})
          set(NAMD_GIT_REVISION $ENV{NAMD_GIT_REVISION})
        else()
          set(NAMD_GIT_REVISION "unknown")
        endif()
        # if directory
        if(IS_DIRECTORY ${NAMD_ABSOLUTE})
            # TODO: should be obsolete
            # stop if not absolute path
            if(NOT IS_ABSOLUTE ${NAMD_ABSOLUTE})
                message(FATAL_ERROR "${BoldRed}NAMD_REPO not given in full absolute path. Exiting...${EndColour}")
            endif()
            set(NAMD_DIR     ${NAMD_ABSOLUTE})
            set(NAMD_SRC_DIR ${NAMD_ABSOLUTE})
            set(NAMD_SRC_DIR ${NAMD_ABSOLUTE} PARENT_SCOPE)
            set(NAMD_TARBALL "")
        # if file (tar ball)
        else()
            set(NAMD_TARBALL ${NAMD})
            # YL 05/11/2018: a charm++ name must be analysed for getting a proper WORKING_DIRECTORY during the extraction of the NAMD tarball which should be in theory at the "configure" stage but has to be executed within the "build"-stage ExternalProject_Add(). However at the "build" stage, CMake has NO way to get a returned value from an external script (or even NO way to define an evnvar in the script). Therefore we apply this execute_process() at the "configure" stage.
            # YL 05/11/2018: we have to use `cmake --build dir` because `cmake -P script.cmake` is not allowed to do anything target-related and functions such as ExternalProject_Add() is not scriptable!
            set(NAMD_DIR           ${CHEMSH_DIR}/chemsh/interfaces/namd)
            set(NAMD_DEST_DIR      ${NAMD_DIR}/src)
            set(NAMD_SRC_DIR       ${NAMD_DEST_DIR} PARENT_SCOPE)
            set(NAMD_BINARY_DIR    ${NAMD_DIR}/${CHEMSH_ARCH})
            # YL 02/10/2020: FetchContent is not available until CMake 3.11
            #                this is a copy of FetchContent 3.16 in chemsh/utils/cmake
            FetchContent_Declare(
                namd_source
                URL ${NAMD_ABSOLUTE}
                DOWNLOAD_DIR ${CMAKE_CURRENT_LIST_DIR}
            )
            FetchContent_GetProperties(namd_source)
            if(NOT namd_source_POPULATED)
                FetchContent_Populate(
                    namd_source
                    URL          ${NAMD_ABSOLUTE}
                    SOURCE_DIR   ${NAMD_DEST_DIR}
                    BINARY_DIR   ${NAMD_BINARY_DIR}/build
                    SUBBUILD_DIR ${NAMD_BINARY_DIR}/subbuild
                )
            endif()
        endif()
    # else: use git repository
    else()
        message("${BoldWhite}NAMD${EndColour} repository URL: ${NAMD_ABSOLUTE}")
        set(NAMD_GIT      ON)
        set(NAMD_GIT_REPO ${NAMD})
        set(NAMD_TARBALL  "")
        set(NAMD_DIR      ${CMAKE_CURRENT_LIST_DIR}/git)
        set(NAMD_SRC_DIR  ${NAMD_DIR})
    endif()

endfunction()

if(NOT "${NAMD}" STREQUAL "")
    project(NAMD LANGUAGES C CXX Fortran)
# YL 02/10/2020: officially FetchContent is not available until CMake 3.11 but we have a copy of 3.16 (3-clause BSD) as a built-in utility
#    cmake_minimum_required(VERSION 3.11)
    if(${CMAKE_VERSION} VERSION_LESS "3.11")
        include(${CHEMSH_DIR}/chemsh/utils/cmake/fetch_content.cmake)
    else()
        include(FetchContent)
    endif()
    get_namd_dir("${NAMD}")
    # cache-level variable cannot be set within a function
    set(NAMD_SRC_DIR "${NAMD_SRC_DIR}" CACHE FILEPATH "" FORCE)
else()
    add_library(namd SHARED namd_dummy.c)
    return()
endif()

# get the NAMD version
file(READ ${NAMD_SRC_DIR}/Makefile NAMD_VERSION LIMIT 80)
string(REGEX MATCH "[+-]?([0-9]*[.])?[0-9]+" NAMD_VERSION "${NAMD_VERSION}")
set(NAMD_NAME NAMD-${NAMD_VERSION})

# MPI version
if(WITH_MPI)
    # since CMake 3.12 MPI_ROOT will be used for searching
    # see details by: cmake --help-policy CMP0074
# YL 03/10/2020: commented out for now to meet CMake 3.10
#    cmake_policy(SET CMP0074 NEW)
    find_package(MPI REQUIRED)
    # get the path to MPI lib because find_package(MPI) can't define the variables
    if(MPI_FOUND AND MPI_CXX_COMPILER AND NOT MPI_CXX_LINK_FLAGS)
        get_filename_component(MPI_CXX_LIB_DIR "${MPI_CXX_COMPILER}" DIRECTORY)
        # YL 20/04/2022: Intel v21+ has a different location
        if(${Fortran_COMPILER_VERSION_TWEAK} VERSION_GREATER_EQUAL 20210000)
            get_filename_component(MPI_CXX_LIB_DIR "${MPI_CXX_LIB_DIR}/../lib" ABSOLUTE)
        else()
            # YL 13/07/2024: lib rather than lib64 in Intel 2024.2
            if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
                get_filename_component(MPI_CXX_LIB_DIR "${MPI_CXX_LIB_DIR}/../lib" ABSOLUTE)
            else()
                get_filename_component(MPI_CXX_LIB_DIR "${MPI_CXX_LIB_DIR}/../lib64" ABSOLUTE)
            endif()
        endif()
        set(MPI_CXX_LINK_FLAGS "-L${MPI_CXX_LIB_DIR} -lmpi -ldl -lrt -lpthread")
    endif()
    set(ENV{MPICXX} ${CMAKE_CXX_COMPILER})
    if(${CHEMSH_ARCH} STREQUAL "intel")
        set(CHARM++_ARCH "mpi-linux-x86_64-ifort-mpicxx")
        # YL 14/07/2024: CHARM++ 8.0+ (in NAMD 3+) has a arch name different from older versions
        if(${NAMD_VERSION} VERSION_GREATER_EQUAL 3.0)
            if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
                if("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "IntelLLVM")
                    set(CHARM++_ARCH "mpi-linux-x86_64-icx-ifx")
                else()
                    set(CHARM++_ARCH "mpi-linux-x86_64-icx-ifort")
                endif()
            else()
                if("${CMAKE_Fortran_COMPILER_ID}" STREQUAL "IntelLLVM")
                    set(CHARM++_ARCH "mpi-linux-x86_64-icc-ifx")
                else()
                    set(CHARM++_ARCH "mpi-linux-x86_64-icc-ifort")
                endif()
            endif()
        endif()
        set(CHARM++_TARGET_NAME "charm++_mpi_intel")
    elseif(${CHEMSH_ARCH} STREQUAL "gnu")
        if(${NAMD_VERSION} VERSION_GREATER_EQUAL 3.0)
            set(CHARM++_ARCH "mpi-linux-x86_64-mpicxx-gfortran")
        else()
            set(CHARM++_ARCH "mpi-linux-x86_64-gfortran-mpicxx")
        endif()
        set(CHARM++_TARGET_NAME "charm++_mpi_gnu")
    elseif(${CHEMSH_ARCH} STREQUAL "cpe-gnu")
        if(${NAMD_VERSION} VERSION_GREATER_EQUAL 3.0)
            set(CHARM++_ARCH "mpi-linux-x86_64-gcc-gfortran")
        else()
            set(CHARM++_ARCH "mpi-linux-x86_64-gfortran-gcc")
        endif()
        set(CHARM++_TARGET_NAME "charm++_mpi_gnu")
    endif()
    # YL 12/03/2026: set the MPI executable for all MPI builds, not just cpe-gnu
    set(NAMD_MPIEXEC_EXECUTABLE "${MPIEXEC_EXECUTABLE}")

# serial version
else()
    set(ENV{MPICXX} "")
    get_filename_component(CMAKE_Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME)
    get_filename_component(CMAKE_C_COMPILER_NAME ${CMAKE_C_COMPILER} NAME)
    if(${NAMD_VERSION} VERSION_GREATER_EQUAL 3.0)
        set(CHARM++_ARCH_SUFFIX "-${CMAKE_C_COMPILER_NAME}-${CMAKE_Fortran_COMPILER_NAME}")
    else()
        set(CHARM++_ARCH_SUFFIX "-${CMAKE_Fortran_COMPILER_NAME}-${CMAKE_C_COMPILER_NAME}")
    endif()
    set(CHARM++_ARCH "multicore-linux-x86_64${CHARM++_ARCH_SUFFIX}")
    if(${CHEMSH_ARCH} STREQUAL "intel")
        set(CHARM++_TARGET_NAME "charm++_multicore_intel")
    elseif(${CHEMSH_ARCH} STREQUAL "gnu")
        set(CHARM++_TARGET_NAME "charm++_multicore_gnu")
    elseif(${CHEMSH_ARCH} STREQUAL "cpe-gnu")
        set(CHARM++_TARGET_NAME "charm++_multicore_gnu")
    endif()
endif()


# Tcl
# YL 12/03/2026: do NOT use REQUIRED because with this archiac function (not supporting COMPONENTS argument) CMake will search for Tk as well
find_package(TCL)
# YL 12/03/2026: I don't know why it worked before but without Tcl NAMD v3.0.2 can't parse input script keywords "run", "minimize", or "reinitvels"!
if(NOT TCL_INCLUDE_PATH)
    message(FATAL_ERROR "Tcl headers needed by NAMD not found. Please install tcl-dev (e.g., tcl8.6-dev on Debian/Ubuntu).")
endif()
if(TCL_FOUND)
    get_filename_component(CHEMSH_TCL_LIB_DIR ${TCL_LIBRARY} DIRECTORY CACHE)
    # LAST_EXT or NAME_WLE is not available in 3.10
    get_filename_component(CHEMSH_TCL_LIB_NAME_WE ${TCL_LIBRARY} NAME CACHE)
    if(EXISTS ${NAMD_SRC_DIR}/arch/Linux-x86_64.tcl)
        file(RENAME ${NAMD_SRC_DIR}/arch/Linux-x86_64.tcl ${NAMD_SRC_DIR}/arch/Linux-x86_64.tcl.BAK)
    endif()
    # remove the leading "lib" and trailing ".so"
    string(REGEX REPLACE "lib([^ ]*)" "\\1" CHEMSH_TCL_LIB_NAME_WE ${CHEMSH_TCL_LIB_NAME_WE})
    string(REGEX REPLACE "([^ ]*).so" "\\1" CHEMSH_TCL_LIB_NAME_WE ${CHEMSH_TCL_LIB_NAME_WE})
    configure_file(Linux-x86_64.tcl.in ${NAMD_SRC_DIR}/arch/Linux-x86_64.tcl @ONLY)
    set(NAMD_TCL_ARGS "--with-tcl")
    set(NAMD_TCL_FLAGS "-I${TCL_INCLUDE_PATH} -L${CHEMSH_TCL_LIB_DIR} -l${CHEMSH_TCL_LIB_NAME_WE}")
# YL 12/03/2026: no longer used because we now force a Tcl installation
else()
    set(NAMD_TCL_ARGS "--without-tcl")
    message("WARNING: NAMD will be built without Tcl and PSFGEN may not function!")
endif()

# Supported compilers: clang craycc gcc gcc3 icc icc8 iccstatic mpicxx pathscale pgcc xlc xlc64
# Supported options: bigemulator bigsim causalft cuda g95 gfortran gm gm2 ifort lam lcs mic mlogft mpt ooc papi persistent pgf90 pthreads scyld smp syncft tsan
# -D__PURE_INTEL_C99_HEADERS__ -D__PURE_INTEL_C99_HEADERS__
if(${CHEMSH_ARCH} STREQUAL "intel")
    if(NOT DEBUG)
        if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
            set(WARNING_FLAGS "-diag-disable=cpu-dispatch,266,10441,15552 -Wno-register -Wnon-c-typedef-for-linkage -Wno-unused-command-line-argument -Wno-extra-tokens -Wno-profile-instr-missing -Wno-pass-failed -Wno-format-security -Wno-inconsistent-missing-override -Wno-parentheses -Wno-format-extra-args -Wno-mismatched-new-delete -Wno-unqualified-std-cast-call -Wno-logical-not-parentheses -Wno-parentheses-equality -Wno-sizeof-pointer-memaccess -Wno-format -Wno-deprecated-declarations -Wno-undefined-bool-conversion -Wno-fortify-source -Wno-tautological-undefined-compare")
        else()
            set(WARNING_FLAGS "-diag-disable=cpu-dispatch,266,10441,15552")
        endif()
    endif()
    # YL 14/07/2024: NAMD 3+ supports icx
    if(${NAMD_VERSION} VERSION_GREATER_EQUAL 3.0)
        if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
            set(NAMD_ARCH Linux-x86_64-icx)
        else()
            set(NAMD_ARCH Linux-x86_64-icc)
        endif()
    else()
        set(NAMD_ARCH Linux-x86_64-icc)
    endif()
    # -m64 for Linux
    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "IntelLLVM")
        set(NAMD_C_COMPILER   "${CMAKE_C_COMPILER} -fPIC -m64 -qopenmp-simd ${WARNING_FLAGS} -O3 ${MATH_HEADER_MACROS}")
    # YL 13/07/2024: this is no longer needed and breaks compilation by Intel 2024.2
    else()
        set(NAMD_C_COMPILER   "${CMAKE_C_COMPILER} -fPIC -m64 -qopenmp-simd ${WARNING_FLAGS} -O3 ${MATH_HEADER_MACROS} -D_Float32=float -D_Float32x=double -D_Float64=double -D_Float64x=__float128")
    endif()
    set(NAMD_C_FLAGS      "-diag-enable=power -diag-disable=10441")
    set(NAMD_CXX_FLAGS    "-diag-enable=power")
    # YL 24/09/2020: this method solves the long-exsiting problem of Intel compiler with system math.h on some Linux OSs
    #                see https://community.intel.com/t5/Intel-C-Compiler/LIB-VERSION-TYPE-is-undefined-icc-and-icps-errors-under-Debian/m-p/1212014#M37597
    set(NAMD_CXX_COMPILER "${CMAKE_CXX_COMPILER} -fPIC -m64 -qopenmp-simd ${WARNING_FLAGS} -std=c++11 -O3 ${MATH_HEADER_MACROS}")
    # flags to pass to Charm++, NB: -lmpi_dbg is required
    # YL 19/03/2021: due to unknown recent updates, -lmpicxx -lmpifort -lmpi_dbg -lmpigi are no longer needed
    if(WITH_MPI)
        set(NAMD_C_FLAGS    "${NAMD_C_FLAGS}")
        set(NAMD_LD_FLAGS   "-L${MPI_CXX_LIB_DIR} -lmpi -ldl -lrt -lpthread")
        set(NAMD_LD++_FLAGS "${MPI_CXX_LINK_FLAGS}")
        message("")
        message("${BoldWhite}NB: If you see the warning message${EndColour}")
        message("${BoldWhite}    ld: warning: libmpi.so.[xx], needed by [...]/intel/[...]/libmpifort.so, may conflict with libmpi.so.[yy]${EndColour}")
        message("${BoldWhite}    It means the Intel MPI conflicts with another MPI implementation (e.g., OpenMPI) and you must uninstall/unload the latter${EndColour}")
        message("")
    endif()
    set(CHARM++_OPTS       "-f90 ${CMAKE_Fortran_COMPILER} -cc ${CMAKE_C_COMPILER} -cc-option ${WARNING_FLAGS} -c++ ${CMAKE_CXX_COMPILER} -ld ${CMAKE_C_COMPILER} -ld-option ${NAMD_LD_FLAGS} -ld++ ${CMAKE_CXX_COMPILER} -ld++-option ${NAMD_LD++_FLAGS}")

elseif(${CHEMSH_ARCH} STREQUAL "gnu")
    set(NAMD_ARCH Linux-x86_64-g++)
    set(NAMD_C_COMPILER "${CMAKE_C_COMPILER} -fPIC -m64 -O3 -w")
    # doesn't work, will be removed by NAMD
    if(NOT DEBUG)
        set(WARNING_FLAGS "-w")
    endif()
    set(NAMD_C_FLAGS    "-fexpensive-optimizations -ffast-math -fno-finite-math-only ${WARNING_FLAGS}")
    set(NAMD_CXX_COMPILER "${CMAKE_CXX_COMPILER} -fPIC -m64 -std=c++0x -O3")
    set(NAMD_CXX_FLAGS    "-fexpensive-optimizations -ffast-math -fno-finite-math-only ${WARNING_FLAGS}")
    set(CHARM++_OPTS      "-f90 ${CMAKE_Fortran_COMPILER} -cc ${CMAKE_C_COMPILER} -cc-option ${WARNING_FLAGS} -c++ ${CMAKE_CXX_COMPILER} -c++-option ${WARNING_FLAGS} -ld ${CMAKE_C_COMPILER} -ld++ ${CMAKE_CXX_COMPILER} -ld++-option ${WARNING_FLAGS} ${MPI_CXX_LINK_FLAGS}")

elseif(${CHEMSH_ARCH} STREQUAL "cpe-gnu")
    set(NAMD_ARCH Linux-x86_64-g++)
    set(NAMD_C_COMPILER "${CMAKE_C_COMPILER} -fPIC -m64 -O3 -w")
    # doesn't work, will be removed by NAMD
    if(NOT DEBUG)
        set(WARNING_FLAGS "-w")
    endif()
    set(NAMD_C_FLAGS    "-fexpensive-optimizations -ffast-math -fno-finite-math-only ${WARNING_FLAGS}")
    set(NAMD_CXX_COMPILER "${CMAKE_CXX_COMPILER} -fPIC -m64 -std=c++0x -O3")
    set(NAMD_CXX_FLAGS    "-fexpensive-optimizations -ffast-math -fno-finite-math-only ${WARNING_FLAGS}")
    set(CHARM++_OPTS      "-f90 ${CMAKE_Fortran_COMPILER} -cc ${CMAKE_C_COMPILER} -cc-option ${WARNING_FLAGS} -c++ ${CMAKE_CXX_COMPILER} -c++-option ${WARNING_FLAGS} -ld ${CMAKE_C_COMPILER} -ld++ ${CMAKE_CXX_COMPILER} -ld++-option ${WARNING_FLAGS} ${MPI_CXX_LINK_FLAGS}")
endif()

# FFTW
if("${FFTW_DIR}" STREQUAL "")
    set(NAMD_FFTW_ARGS "--without-fftw")
    message("${BoldWhite}NAMD WARNING${EndColour}: ${Red}FFTW not enabled. Some functions of NAMD such as PME cannot work. To enable FFTW see ChemShell installer's helper${EndColour}")
# don't use quotation marks here!
else()
    # YL 20/12/2021: ChemShell's variable ${FFTW_DIR} (from `./setup --fftw`) means the library directory, but NAMD needs the root dir for --fftw-prefix
    get_filename_component(NAMD_FFTW_DIR ${FFTW_DIR} DIRECTORY)
    set(NAMD_FFTW_ARGS --with-fftw3 --fftw-prefix)
    set(NAMD_FFTW_FLAGS -I${FFTW_INCLUDE_DIR})
endif()

# configure and build
if(DEBUG)
    set(NAMD_CONFIGURE_DEBUG "--with-debug")
endif()
set(NAMD_CONFIGURE_COMMAND bash config ${NAMD_ARCH} --charm-base ${CHEMSH_DIR}/chemsh/parallel/charm++ --charm-arch ${CHARM++_ARCH} --charm-opts ${CHARM++_OPTS} --cc "${NAMD_C_COMPILER}" --cxx "${NAMD_CXX_COMPILER}" --cc-opts "${NAMD_C_FLAGS} ${NAMD_TCL_FLAGS} ${NAMD_FFTW_FLAGS}" --cxx-opts "${NAMD_CXX_FLAGS} -I${CHARM++_DIR}/include ${NAMD_TCL_FLAGS} ${NAMD_FFTW_FLAGS}" ${NAMD_TCL_ARGS} ${NAMD_FFTW_ARGS} "${NAMD_FFTW_DIR}" ${NAMD_CONFIGURE_DEBUG} > config.log)
set(NAMD_BUILD_COMMAND make -j${CHEMSH_MAKE_NJOBS})


# force to recompile
if(NAMD_RECOMPILE)
    # remove build directory
    file(REMOVE_RECURSE ${NAMD_SRC_DIR}/${NAMD_ARCH})
    set(NAMD_CLEAN_COMMENT "Cleaning up previous configurations for '${NAMD_NAME}'...")
    # switch on configure
    set(NAMD_RECONFIGURE ON)
# no recompile from the user
else()
    # already built before
    if(EXISTS ${NAMD_SRC_DIR}/${NAMD_ARCH}/namd2 OR EXISTS ${NAMD_SRC_DIR}/${NAMD_ARCH}/namd3)
        message("${NAMD_NAME} was already successfully built under")
        message("${NAMD_SRC_DIR}/${NAMD_ARCH}")
        set(NAMD_RECONFIGURE OFF)
        set(NAMD_CONFIGURE_COMMAND "")
        set(NAMD_BUILD_COMMAND     "")
    # previous build wasn't successful
    else()
        message("${NAMD_NAME} has not been successfully built")
        set(NAMD_CLEAN_COMMENT "Cleaning up previous configurations for '${NAMD_NAME}'...")
        file(REMOVE_RECURSE ${NAMD_SRC_DIR}/${NAMD_ARCH})
        set(NAMD_RECONFIGURE ON)
    endif()
endif()


# save the NAMD location to a file so that Py-ChemShell can know the default path
set(NAMD_PATH ${NAMD_SRC_DIR}/${NAMD_ARCH})
configure_file(namd_path.py.in namd_path.py @ONLY)

set(CHARM++_DIR ${CHEMSH_DIR}/chemsh/parallel/charm++)

# remove the build dir if rebuild requested
if(NAMD_RECOMPILE)
else()
    set(NAMD_CLEAN_COMMENT "")
endif()

ExternalProject_Add(
    ${NAMD_NAME}
    PREFIX              ${NAMD_SRC_DIR}/${CHEMSH_ARCH}
    STAMP_DIR           ${NAMD_SRC_DIR}/${CHEMSH_ARCH}/stamp
    TMP_DIR             ${NAMD_SRC_DIR}/${CHEMSH_ARCH}/tmp
    BINARY_DIR          ${NAMD_SRC_DIR}
    DOWNLOAD_COMMAND    ""
    UPDATE_COMMAND      ""
    CONFIGURE_COMMAND   ${CMAKE_COMMAND} -E cmake_echo_color --switch=$(COLOR) --magenta --bold "Architecture for which NAMD is built: '${NAMD_ARCH}'"
    BUILD_COMMAND       ""
    BUILD_ALWAYS        ${NAMD_RECOMPILE}
    INSTALL_COMMAND     ""
    WORKING_DIRECTORY   ${NAMD_SRC_DIR}
)

ExternalProject_Add_Step(
    ${NAMD_NAME}      NAMD_CLEAN
    COMMENT           ${NAMD_CLEAN_COMMENT}
    ALWAYS            NAMD_RECONFIGURE
    DEPENDEES         configure
    COMMAND           ${NAMD_CLEAN_COMMAND}
    WORKING_DIRECTORY ${NAMD_SRC_DIR}
)

#set(NAMD_CONFIGURE_COMMAND1 "sh config ${NAMD_ARCH} --charm-base ${CHEMSH_DIR}/chemsh/parallel/charm++ --charm-arch ${CHARM++_ARCH} --cc ${NAMD_C_COMPILER} --cxx ${NAMD_CXX_COMPILER} --cc-opts ${NAMD_C_FLAGS} --cxx-opts ${NAMD_CXX_FLAGS} --without-tcl ${NAMD_FFTW_ARGS} ${FFTW_DIR}")
#

ExternalProject_Add_Step(
    ${NAMD_NAME}      NAMD_CONFIGURE
    COMMENT           "Configuring '${NAMD_NAME}'..."
    ALWAYS            NAMD_RECONFIGURE
    DEPENDEES         NAMD_CLEAN
    COMMAND           ${NAMD_CONFIGURE_COMMAND}
    WORKING_DIRECTORY ${NAMD_SRC_DIR}
)

ExternalProject_Add_Step(
    ${NAMD_NAME}      NAMD_BUILD
    COMMENT           "Compiling '${NAMD_NAME}'..."
    ALWAYS            NAMD_RECONFIGURE
    DEPENDEES         NAMD_CONFIGURE
    COMMAND           ${NAMD_BUILD_COMMAND}
    WORKING_DIRECTORY ${NAMD_SRC_DIR}/${NAMD_ARCH}
)

if("${CHARM++_TARGET_NAME}" STREQUAL "")
    message(FATAL_ERROR "CHARM++_TARGET_NAME not defined! Please contact the ChemShell developers.")
endif()
add_dependencies(${NAMD_NAME} ${CHARM++_TARGET_NAME})

# YL 02/10/2020: not in use currently
set(NAMD_OBJ_DIR ${NAMD_SRC_DIR}/${NAMD_ARCH}/obj)
list(APPEND NAMD_OBJECTS
${NAMD_OBJ_DIR}/AlgNbor.o              ${NAMD_OBJ_DIR}/colvarcomp_angles.o    ${NAMD_OBJ_DIR}/ComputeConsForceMsgs.o ${NAMD_OBJ_DIR}/ComputeHomePatch.o            ${NAMD_OBJ_DIR}/ComputeNonbondedTI.o   ${NAMD_OBJ_DIR}/DataStream.o         ${NAMD_OBJ_DIR}/GlobalMasterEasy.o       ${NAMD_OBJ_DIR}/jsplugin.o           ${NAMD_OBJ_DIR}/namdbinplugin.o    ${NAMD_OBJ_DIR}/PDB.o              ${NAMD_OBJ_DIR}/Settle.o
${NAMD_OBJ_DIR}/AlgRecBisection.o      ${NAMD_OBJ_DIR}/colvarcomp_coordnums.o ${NAMD_OBJ_DIR}/ComputeConsForce.o     ${NAMD_OBJ_DIR}/ComputeImpropers.o            ${NAMD_OBJ_DIR}/ComputeNonbondedUtil.o ${NAMD_OBJ_DIR}/dcdlib.o             ${NAMD_OBJ_DIR}/GlobalMasterFreeEnergy.o ${NAMD_OBJ_DIR}/LdbCoordinator.o     ${NAMD_OBJ_DIR}/NamdCentLB.o       ${NAMD_OBJ_DIR}/pdbplugin.o        ${NAMD_OBJ_DIR}/SimParameters.o
${NAMD_OBJ_DIR}/AlgSeven.o             ${NAMD_OBJ_DIR}/colvarcomp_distances.o ${NAMD_OBJ_DIR}/ComputeCrossterms.o    ${NAMD_OBJ_DIR}/ComputeLCPO.o                 ${NAMD_OBJ_DIR}/Compute.o              ${NAMD_OBJ_DIR}/dcdplugin.o          ${NAMD_OBJ_DIR}/GlobalMasterIMD.o        ${NAMD_OBJ_DIR}/LJTable.o            ${NAMD_OBJ_DIR}/NamdDummyLB.o      ${NAMD_OBJ_DIR}/PluginIOMgr.o      ${NAMD_OBJ_DIR}/SortAtoms.o
${NAMD_OBJ_DIR}/AtomMap.o              ${NAMD_OBJ_DIR}/colvarcomp.o           ${NAMD_OBJ_DIR}/ComputeCUDAMgr.o       ${NAMD_OBJ_DIR}/ComputeMap.o                  ${NAMD_OBJ_DIR}/ComputePatch.o         ${NAMD_OBJ_DIR}/DeviceCUDA.o         ${NAMD_OBJ_DIR}/GlobalMasterMisc.o       ${NAMD_OBJ_DIR}/mainfunc.o           ${NAMD_OBJ_DIR}/NamdHybridLB.o     ${NAMD_OBJ_DIR}/PmeKSpace.o        ${NAMD_OBJ_DIR}/sortreplicas.o
${NAMD_OBJ_DIR}/BackEnd.o              ${NAMD_OBJ_DIR}/colvarcomp_protein.o   ${NAMD_OBJ_DIR}/ComputeCylindricalBC.o ${NAMD_OBJ_DIR}/ComputeMgr.o                  ${NAMD_OBJ_DIR}/ComputePatchPair.o     ${NAMD_OBJ_DIR}/DumpBench.o          ${NAMD_OBJ_DIR}/GlobalMaster.o           ${NAMD_OBJ_DIR}/main.o               ${NAMD_OBJ_DIR}/NamdNborLB.o       ${NAMD_OBJ_DIR}/PmeRealSpace.o     ${NAMD_OBJ_DIR}/stringhash.o
${NAMD_OBJ_DIR}/BroadcastClient.o      ${NAMD_OBJ_DIR}/colvarcomp_rotations.o ${NAMD_OBJ_DIR}/ComputeDihedrals.o     ${NAMD_OBJ_DIR}/ComputeMoa.o                  ${NAMD_OBJ_DIR}/ComputePmeCUDAMgr.o    ${NAMD_OBJ_DIR}/eabf1D.o             ${NAMD_OBJ_DIR}/GlobalMasterServer.o     ${NAMD_OBJ_DIR}/Matrix4Symmetry.o    ${NAMD_OBJ_DIR}/NamdOneTools.o     ${NAMD_OBJ_DIR}/PmeSolver.o        ${NAMD_OBJ_DIR}/strlib.o
${NAMD_OBJ_DIR}/BroadcastMgr.o         ${NAMD_OBJ_DIR}/colvardeps.o           ${NAMD_OBJ_DIR}/ComputeDPMEMsgs.o      ${NAMD_OBJ_DIR}/ComputeMsmMsa.o               ${NAMD_OBJ_DIR}/ComputePmeCUDA.o       ${NAMD_OBJ_DIR}/eabf2D.o             ${NAMD_OBJ_DIR}/GlobalMasterSMD.o        ${NAMD_OBJ_DIR}/Measure.o            ${NAMD_OBJ_DIR}/NamdState.o        ${NAMD_OBJ_DIR}/ProcessorPrivate.o ${NAMD_OBJ_DIR}/Sync.o
${NAMD_OBJ_DIR}/buildinfo.C            ${NAMD_OBJ_DIR}/colvargrid.o           ${NAMD_OBJ_DIR}/ComputeDPME.o          ${NAMD_OBJ_DIR}/ComputeMsm.o                  ${NAMD_OBJ_DIR}/ComputePme.o           ${NAMD_OBJ_DIR}/eabffunc.o           ${NAMD_OBJ_DIR}/GlobalMasterSymmetry.o   ${NAMD_OBJ_DIR}/memarena.o           ${NAMD_OBJ_DIR}/Node.o             ${NAMD_OBJ_DIR}/ProxyMgr.o         ${NAMD_OBJ_DIR}/TclCommands.o
${NAMD_OBJ_DIR}/buildinfo.o            ${NAMD_OBJ_DIR}/colvarmodule.o         ${NAMD_OBJ_DIR}/ComputeDPMTA.o         ${NAMD_OBJ_DIR}/ComputeMsmSerial.o            ${NAMD_OBJ_DIR}/ComputeQM.o            ${NAMD_OBJ_DIR}/eabfTcl.o            ${NAMD_OBJ_DIR}/GlobalMasterTcl.o        ${NAMD_OBJ_DIR}/memusage.o           ${NAMD_OBJ_DIR}/OptPme.o           ${NAMD_OBJ_DIR}/ProxyPatch.o       ${NAMD_OBJ_DIR}/tcl_main.o
${NAMD_OBJ_DIR}/ccsinterface.o         ${NAMD_OBJ_DIR}/colvar.o               ${NAMD_OBJ_DIR}/ComputeEField.o        ${NAMD_OBJ_DIR}/ComputeNonbondedCUDAExcl.o    ${NAMD_OBJ_DIR}/ComputeRestraints.o    ${NAMD_OBJ_DIR}/erf.o                ${NAMD_OBJ_DIR}/GlobalMasterTest.o       ${NAMD_OBJ_DIR}/MGridforceParams.o   ${NAMD_OBJ_DIR}/OptPmeRealSpace.o  ${NAMD_OBJ_DIR}/psf_file_extract.o ${NAMD_OBJ_DIR}/tcl_psfgen.o
${NAMD_OBJ_DIR}/charmm_file.o          ${NAMD_OBJ_DIR}/colvarparse.o          ${NAMD_OBJ_DIR}/ComputeEwald.o         ${NAMD_OBJ_DIR}/ComputeNonbondedCUDA.o        ${NAMD_OBJ_DIR}/ComputeSphericalBC.o   ${NAMD_OBJ_DIR}/extract_alias.o      ${NAMD_OBJ_DIR}/GlobalMasterTMD.o        ${NAMD_OBJ_DIR}/MigrateAtomsMsg.o    ${NAMD_OBJ_DIR}/Output.o           ${NAMD_OBJ_DIR}/psf_file.o         ${NAMD_OBJ_DIR}/topo_defs.o
${NAMD_OBJ_DIR}/charmm_parse_topo_defs.${NAMD_OBJ_DIR}/colvarproxy_namd.o     ${NAMD_OBJ_DIR}/ComputeExt.o           ${NAMD_OBJ_DIR}/ComputeNonbondedFEP.o         ${NAMD_OBJ_DIR}/ComputeStir.o          ${NAMD_OBJ_DIR}/fitrms.o             ${NAMD_OBJ_DIR}/GoMolecule.o             ${NAMD_OBJ_DIR}/Molecule2.o          ${NAMD_OBJ_DIR}/ParallelIOMgr.o    ${NAMD_OBJ_DIR}/psfplugin.o        ${NAMD_OBJ_DIR}/topo_mol.o
${NAMD_OBJ_DIR}/CollectionMaster.o     ${NAMD_OBJ_DIR}/colvarscript.o         ${NAMD_OBJ_DIR}/ComputeFmmSerial.o     ${NAMD_OBJ_DIR}/ComputeNonbondedGo.o          ${NAMD_OBJ_DIR}/ComputeTclBC.o         ${NAMD_OBJ_DIR}/FreeEnergyAssert.o   ${NAMD_OBJ_DIR}/GridForceGrid.o          ${NAMD_OBJ_DIR}/Molecule.o           ${NAMD_OBJ_DIR}/Parameters.o       ${NAMD_OBJ_DIR}/pub3dfft.o         ${NAMD_OBJ_DIR}/topo_mol_output.o
${NAMD_OBJ_DIR}/CollectionMgr.o        ${NAMD_OBJ_DIR}/colvartypes.o          ${NAMD_OBJ_DIR}/ComputeFullDirect.o    ${NAMD_OBJ_DIR}/ComputeNonbondedLES.o         ${NAMD_OBJ_DIR}/ComputeThole.o         ${NAMD_OBJ_DIR}/FreeEnergyGroup.o    ${NAMD_OBJ_DIR}/GromacsTopFile.o         ${NAMD_OBJ_DIR}/MoleculeQM.o         ${NAMD_OBJ_DIR}/parm.o             ${NAMD_OBJ_DIR}/Rebalancer.o       ${NAMD_OBJ_DIR}/topo_mol_pluginio.o
${NAMD_OBJ_DIR}/colvaratoms.o          ${NAMD_OBJ_DIR}/colvarvalue.o          ${NAMD_OBJ_DIR}/ComputeGBIS.o          ${NAMD_OBJ_DIR}/ComputeNonbondedMICKernel.o   ${NAMD_OBJ_DIR}/ConfigList.o           ${NAMD_OBJ_DIR}/FreeEnergyLambda.o   ${NAMD_OBJ_DIR}/hasharray.o              ${NAMD_OBJ_DIR}/msm_longrng.o        ${NAMD_OBJ_DIR}/ParseOptions.o     ${NAMD_OBJ_DIR}/RecBisection.o     ${NAMD_OBJ_DIR}/TorusLB.o
${NAMD_OBJ_DIR}/colvarbias_abf.o       ${NAMD_OBJ_DIR}/common.o               ${NAMD_OBJ_DIR}/ComputeGBISser.o       ${NAMD_OBJ_DIR}/ComputeNonbondedMIC.o         ${NAMD_OBJ_DIR}/Controller.o           ${NAMD_OBJ_DIR}/FreeEnergyLambdMgr.o ${NAMD_OBJ_DIR}/hash.o                   ${NAMD_OBJ_DIR}/msm_longrng_sprec.o  ${NAMD_OBJ_DIR}/PatchMap.o         ${NAMD_OBJ_DIR}/ReductionMgr.o     ${NAMD_OBJ_DIR}/vmdsock.o
${NAMD_OBJ_DIR}/colvarbias_alb.o       ${NAMD_OBJ_DIR}/Communicate.o          ${NAMD_OBJ_DIR}/ComputeGlobalMsgs.o    ${NAMD_OBJ_DIR}/ComputeNonbondedPair.o        ${NAMD_OBJ_DIR}/CudaComputeNonbonded.o ${NAMD_OBJ_DIR}/FreeEnergyParse.o    ${NAMD_OBJ_DIR}/heap.o                   ${NAMD_OBJ_DIR}/msm.o                ${NAMD_OBJ_DIR}/PatchMgr.o         ${NAMD_OBJ_DIR}/RefineOnly.o       ${NAMD_OBJ_DIR}/wkfutils.o
${NAMD_OBJ_DIR}/colvarbias_histogram.o ${NAMD_OBJ_DIR}/CompressPsf.o          ${NAMD_OBJ_DIR}/ComputeGlobal.o        ${NAMD_OBJ_DIR}/ComputeNonbondedPProf.o       ${NAMD_OBJ_DIR}/CudaPmeSolver.o        ${NAMD_OBJ_DIR}/FreeEnergyRestrain.o ${NAMD_OBJ_DIR}/HomePatch.o              ${NAMD_OBJ_DIR}/msm_setup.o          ${NAMD_OBJ_DIR}/Patch.o            ${NAMD_OBJ_DIR}/RefineTorusLB.o    ${NAMD_OBJ_DIR}/WorkDistrib.o
${NAMD_OBJ_DIR}/colvarbias_meta.o      ${NAMD_OBJ_DIR}/ComputeAngles.o        ${NAMD_OBJ_DIR}/ComputeGridForce.o     ${NAMD_OBJ_DIR}/ComputeNonbondedSelf.o        ${NAMD_OBJ_DIR}/CudaPmeSolverUtil.o    ${NAMD_OBJ_DIR}/FreeEnergyRMgr.o     ${NAMD_OBJ_DIR}/imd.o                    ${NAMD_OBJ_DIR}/msm_shortrng.o       ${NAMD_OBJ_DIR}/PDBData.o          ${NAMD_OBJ_DIR}/ScriptTcl.o
${NAMD_OBJ_DIR}/colvarbias.o           ${NAMD_OBJ_DIR}/ComputeAniso.o         ${NAMD_OBJ_DIR}/ComputeGromacsPair.o   ${NAMD_OBJ_DIR}/ComputeNonbondedStd.o         ${NAMD_OBJ_DIR}/CudaUtils.o            ${NAMD_OBJ_DIR}/FreeEnergyVector.o   ${NAMD_OBJ_DIR}/IMDOutput.o              ${NAMD_OBJ_DIR}/msm_shortrng_sprec.o ${NAMD_OBJ_DIR}/pdb_file_extract.o ${NAMD_OBJ_DIR}/Sequencer.o
${NAMD_OBJ_DIR}/colvarbias_restraint.o ${NAMD_OBJ_DIR}/ComputeBonds.o         ${NAMD_OBJ_DIR}/ComputeHomePatches.o   ${NAMD_OBJ_DIR}/ComputeNonbondedTabEnergies.o ${NAMD_OBJ_DIR}/DataExchanger.o        ${NAMD_OBJ_DIR}/fstream_namd.o       ${NAMD_OBJ_DIR}/InfoStream.o             ${NAMD_OBJ_DIR}/MStream.o            ${NAMD_OBJ_DIR}/pdb_file.o         ${NAMD_OBJ_DIR}/Set.o)

add_custom_command(OUTPUT libnamd.a
                   COMMAND ${CMAKE_AR} crs libnamd.a ${NAMD_OBJECTS})

add_custom_target(libnamd.a ALL DEPENDS libnamd.a)

add_library(namd SHARED namd_dummy.c)

set_target_properties(namd PROPERTIES LINKER_LANGUAGE "C" LINK_FLAGS "${CHEMSH_LINK_FLAGS}")
#set_target_properties(namd PROPERTIES LINK_FLAGS "-Wl,--whole-archive             \
#                                                  libnamd.a \
#                                                  -Wl,--no-whole-archive          \
#                                                 ")


set_directory_properties(PROPERTIES
    ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_LIST_DIR}/src;"
)
