# portion of https://github.com/lammps/lammps/raw/master/cmake/CMakeLists.txt
# renamed to lowercase to test Windows behavior
########################################
# CMake build system
# This file is part of LAMMPS
# Created by Christoph Junghans and Richard Berger
cmake_minimum_required(VERSION 3.10)
# set policy to silence warnings about ignoring <PackageName>_ROOT but use it
if(POLICY CMP0074)
  cmake_policy(SET CMP0074 NEW)
endif()
# set policy to silence warnings about missing executable permissions in
# pythonx.y-config when cross-compiling. review occasionally if it may be set to NEW
if(POLICY CMP0109)
  cmake_policy(SET CMP0109 OLD)
endif()
########################################

project(lammps CXX)
set(SOVERSION 0)

get_filename_component(LAMMPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.. ABSOLUTE)
get_filename_component(LAMMPS_LIB_BINARY_DIR ${CMAKE_BINARY_DIR}/lib ABSOLUTE)

set(LAMMPS_SOURCE_DIR     ${LAMMPS_DIR}/src)
set(LAMMPS_LIB_SOURCE_DIR ${LAMMPS_DIR}/lib)
set(LAMMPS_DOC_DIR        ${LAMMPS_DIR}/doc)
set(LAMMPS_TOOLS_DIR      ${LAMMPS_DIR}/tools)
set(LAMMPS_PYTHON_DIR     ${LAMMPS_DIR}/python)
set(LAMMPS_POTENTIALS_DIR ${LAMMPS_DIR}/potentials)

set(LAMMPS_DOWNLOADS_URL "https://download.lammps.org" CACHE STRING "Base URL for LAMMPS downloads")
set(LAMMPS_POTENTIALS_URL "${LAMMPS_DOWNLOADS_URL}/potentials")
set(LAMMPS_THIRDPARTY_URL "${LAMMPS_DOWNLOADS_URL}/thirdparty")
mark_as_advanced(LAMMPS_DOWNLOADS_URL)

find_package(Git)

# by default, install into $HOME/.local (not /usr/local), so that no root access (and sudo!!) is needed
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND (NOT CMAKE_CROSSCOMPILING))
    set(CMAKE_INSTALL_PREFIX "$ENV{USERPROFILE}/LAMMPS" CACHE PATH "Default install path" FORCE)
  else()
    set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "Default install path" FORCE)
  endif()
endif()

# If enabled, no need to use LD_LIBRARY_PATH / DYLD_LIBRARY_PATH when installed
option(LAMMPS_INSTALL_RPATH "Set runtime path for shared libraries linked to LAMMPS binaries" OFF)
if(LAMMPS_INSTALL_RPATH)
  set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
endif()

# Cmake modules/macros are in a subdirectory to keep this file cleaner
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules)

# make sure LIBRARY_PATH is set if environment variable is set
if(DEFINED ENV{LIBRARY_PATH})
  list(APPEND CMAKE_LIBRARY_PATH "$ENV{LIBRARY_PATH}")
  message(STATUS "Appending $ENV{LIBRARY_PATH} to CMAKE_LIBRARY_PATH: ${CMAKE_LIBRARY_PATH}")
endif()

include(LAMMPSUtils)

get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h PROJECT_VERSION)

include(PreventInSourceBuilds)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS)
  set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS)
string(TOUPPER "${CMAKE_BUILD_TYPE}" BTYPE)

# check for files auto-generated by make-based buildsystem
# this is fast, so check for it all the time
check_for_autogen_files(${LAMMPS_SOURCE_DIR})

######################################################################
# compiler tests
# these need ot be done early (before further tests).
#####################################################################
include(CheckIncludeFileCXX)

# set required compiler flags and compiler/CPU arch specific optimizations
if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") OR (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM"))
  if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
    if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qrestrict")
    endif()
    if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4)
      set(CMAKE_TUNE_DEFAULT "/QxCOMMON-AVX512")
    else()
      set(CMAKE_TUNE_DEFAULT "/QxHost")
    endif()
  else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4)
      set(CMAKE_TUNE_DEFAULT "-xCOMMON-AVX512")
    else()
      set(CMAKE_TUNE_DEFAULT "-xHost")
    endif()
  endif()
endif()

# we require C++11 without extensions. Kokkos requires at least C++14 (currently)
set(CMAKE_CXX_STANDARD 11)
if(PKG_KOKKOS AND (CMAKE_CXX_STANDARD LESS 14))
  set(CMAKE_CXX_STANDARD 14)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Use compiler extensions")
# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro
# and prints lots of pointless warnings about "unsafe" functions
if(MSVC)
  add_compile_options(/Zc:__cplusplus)
  add_compile_options(/wd4244)
  add_compile_options(/wd4267)
  add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

# export all symbols when building a .dll file on windows
if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND BUILD_SHARED_LIBS)
  set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

########################################################################
# User input options                                                   #
########################################################################
set(LAMMPS_MACHINE "" CACHE STRING "Suffix to append to lmp binary (WON'T enable any features automatically")
mark_as_advanced(LAMMPS_MACHINE)
if(LAMMPS_MACHINE)
  set(LAMMPS_MACHINE "_${LAMMPS_MACHINE}")
endif()
set(LAMMPS_BINARY lmp${LAMMPS_MACHINE})

option(BUILD_SHARED_LIBS "Build shared library" OFF)
if(BUILD_SHARED_LIBS) # for all pkg libs, mpi_stubs and linalg
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF)
option(BUILD_LAMMPS_SHELL "Build and install the LAMMPS shell" OFF)

# allow enabling clang-tidy for C++ files
set(ENABLE_CLANG_TIDY OFF CACHE BOOL "Include clang-tidy processing when compiling")
if(ENABLE_CLANG_TIDY)
  set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*-header-filter=.*" CACHE STRING "")
endif()

include(GNUInstallDirs)
file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp)
file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp)
list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES})
add_library(lammps ${ALL_SOURCES})

# tell CMake to export all symbols to a .dll on Windows with MinGW cross-compilers
if(BUILD_SHARED_LIBS AND (CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
  set_target_properties(lammps PROPERTIES LINK_FLAGS "-Wl,--export-all-symbols")
endif()

add_executable(lmp ${MAIN_SOURCES})
target_link_libraries(lmp PRIVATE lammps)
set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY})
install(TARGETS lmp EXPORT LAMMPS_Targets DESTINATION ${CMAKE_INSTALL_BINDIR})

option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF)

set(STANDARD_PACKAGES
  ADIOS
  ASPHERE
  ATC
  AWPMD
  BOCS
  BODY
  BROWNIAN
  CG-DNA
  CG-SDK
  CLASS2
  COLLOID
  COLVARS
  COMPRESS
  DIELECTRIC
  DIFFRACTION
  DIPOLE
  DPD-BASIC
  DPD-MESO
  DPD-REACT
  DPD-SMOOTH
  DRUDE
  EFF
  EXTRA-COMPUTE
  EXTRA-DUMP
  EXTRA-FIX
  EXTRA-MOLECULE
  EXTRA-PAIR
  FEP
  GRANULAR
  H5MD
  INTERLAYER
  KIM
  KSPACE
  LATBOLTZ
  LATTE
  MACHDYN
  MANIFOLD
  MANYBODY
  MC
  MDI
  MEAM
  MESONT
  MESSAGE
  MGPT
  MISC
  ML-HDNNP
  ML-IAP
  ML-PACE
  ML-QUIP
  ML-RANN
  ML-SNAP
  MOFFF
  MOLECULE
  MOLFILE
  MPIIO
  MSCG
  NETCDF
  ORIENT
  PERI
  PHONON
  PLUGIN
  PLUMED
  POEMS
  PTM
  PYTHON
  QEQ
  QMMM
  QTB
  REACTION
  REAXFF
  REPLICA
  RIGID
  SCAFACOS
  SHOCK
  SMTBQ
  SPH
  SPIN
  SRD
  TALLY
  UEF
  VORONOI
  VTK
  YAFF)

set(SUFFIX_PACKAGES CORESHELL GPU KOKKOS OPT INTEL OPENMP)

foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
  option(PKG_${PKG} "Build ${PKG} Package" OFF)
endforeach()

######################################################
# packages with special compiler needs or external libs
######################################################
target_include_directories(lammps PUBLIC $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}>)

if(PKG_ADIOS)
  # The search for ADIOS2 must come before MPI because
  # it includes its own MPI search with the latest FindMPI.cmake
  # script that defines the MPI::MPI_C target
  enable_language(C)
  find_package(ADIOS2 REQUIRED)
  target_link_libraries(lammps PRIVATE adios2::adios2)
endif()

if(NOT CMAKE_CROSSCOMPILING)
  find_package(MPI QUIET)
  option(BUILD_MPI "Build MPI version" ${MPI_FOUND})
else()
  option(BUILD_MPI "Build MPI version" OFF)
endif()

if(BUILD_MPI)
  # do not include the (obsolete) MPI C++ bindings which makes
  # for leaner object files and avoids namespace conflicts
  set(MPI_CXX_SKIP_MPICXX TRUE)
  # We use a non-standard procedure to cross-compile with MPI on Windows
  if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
    include(MPI4WIN)
    target_link_libraries(lammps PUBLIC MPI::MPI_CXX)
  else()
    find_package(MPI REQUIRED)
    target_link_libraries(lammps PUBLIC MPI::MPI_CXX)
    option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF)
    if(LAMMPS_LONGLONG_TO_LONG)
      target_compile_definitions(lammps PRIVATE -DLAMMPS_LONGLONG_TO_LONG)
    endif()
  endif()
else()
  file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.cpp)
  add_library(mpi_stubs STATIC ${MPI_SOURCES})
  set_target_properties(mpi_stubs PROPERTIES OUTPUT_NAME lammps_mpi_stubs${LAMMPS_MACHINE})
  target_include_directories(mpi_stubs PUBLIC $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}/STUBS>)
  if(BUILD_SHARED_LIBS)
    target_link_libraries(lammps PRIVATE mpi_stubs)
    if(MSVC)
      target_link_libraries(lmp PRIVATE mpi_stubs)
      target_include_directories(lmp INTERFACE $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}/STUBS>)
      target_compile_definitions(lmp INTERFACE $<INSTALL_INTERFACE:LAMMPS_LIB_NO_MPI>)
    endif(MSVC)
    target_include_directories(lammps INTERFACE $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}/STUBS>)
    target_compile_definitions(lammps INTERFACE $<INSTALL_INTERFACE:LAMMPS_LIB_NO_MPI>)
  else()
    target_link_libraries(lammps PUBLIC mpi_stubs)
  endif()
  add_library(MPI::MPI_CXX ALIAS mpi_stubs)
endif()

set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallsmall: all 32-bit, smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)")
set(LAMMPS_SIZES_VALUES smallbig bigbig smallsmall)
set_property(CACHE LAMMPS_SIZES PROPERTY STRINGS ${LAMMPS_SIZES_VALUES})
validate_option(LAMMPS_SIZES LAMMPS_SIZES_VALUES)
string(TOUPPER ${LAMMPS_SIZES} LAMMPS_SIZES)
target_compile_definitions(lammps PUBLIC -DLAMMPS_${LAMMPS_SIZES})

# posix_memalign is not available on Windows
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  set(LAMMPS_MEMALIGN "0" CACHE STRING "posix_memalign() is not available on Windows" FORCE)
else()
  set(LAMMPS_MEMALIGN "64" CACHE STRING "enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. Set to 0 to disable")
endif()
if(NOT ${LAMMPS_MEMALIGN} STREQUAL "0")
  target_compile_definitions(lammps PRIVATE -DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN})
endif()

option(LAMMPS_EXCEPTIONS "enable the use of C++ exceptions for error messages (useful for library interface)" ${ENABLE_TESTING})
if(LAMMPS_EXCEPTIONS)
  target_compile_definitions(lammps PUBLIC -DLAMMPS_EXCEPTIONS)
endif()
