diff --git a/CMakeLists.txt b/CMakeLists.txt index faa19a5..577c9e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,19 @@ +# CMakeLists.txt for building VASP (Vienna Ab Initio Simulation Package) +# +# Original CMake port by Simon Frasch (CSCS) +# GitHub: https://github.com/AdhocMan/vasp_cmake/ +# +# This file configures the build system for VASP using CMake. + cmake_minimum_required(VERSION 3.20 FATAL_ERROR) +set(CMAKE_DEPENDS_USE_COMPILER TRUE) set(CMAKE_POLICY_DEFAULT_CMP0048 NEW) # set default flags. Must be called before project() enables languages. macro(set_mode_flags languages mode value) - foreach(lang ${languages}) - set(CMAKE_${lang}_FLAGS_${mode} "${value}" CACHE STRING "") - endforeach() + foreach(lang ${languages}) + set(CMAKE_${lang}_FLAGS_${mode} "${value}" CACHE STRING "") + endforeach() endmacro() set_mode_flags("C;CXX" "DEBUG" "-g") @@ -18,36 +26,44 @@ set_mode_flags("Fortran" "RELWITHDEBINFO" "-g") set_mode_flags("Fortran" "RELEASE" "") set_mode_flags("Fortran" "MINSIZEREL" "") +message(STATUS "-------- compiler detection -------------") project(vasp - VERSION 6.3.0 - DESCRIPTION "VASP" - LANGUAGES Fortran C CXX) + VERSION 6.5.0 + DESCRIPTION "VASP" + LANGUAGES Fortran C CXX) + +# check for NEC Fortran compiler +string(FIND "${CMAKE_Fortran_COMPILER}" "nfort" FOUND_NFORT) +if (FOUND_NFORT GREATER -1) + set(CMAKE_Fortran_COMPILER_ID NFORT) + message(STATUS "Detected NEC Fortran compiler nfort") +endif() set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # allow {module}_ROOT variables to be set if(POLICY CMP0074) - cmake_policy(SET CMP0074 NEW) + cmake_policy(SET CMP0074 NEW) endif() # use INTERFACE_LINK_LIBRARIES property if available if(POLICY CMP0022) - cmake_policy(SET CMP0022 NEW) + cmake_policy(SET CMP0022 NEW) endif() # set default build type to RELEASE if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "RelWithDebInfo" - ) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "RelWithDebInfo" + ) endif() # set binary directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -# make sure preprocessing is on -set(CMAKE_Fortran_PREPROCESS ON) +# make sure preprocessing is off! Custom preprocessor is used in src/CMakeLists.txt +set(CMAKE_Fortran_PREPROCESS OFF) # Get GNU standard install prefixes include(GNUInstallDirs) @@ -57,13 +73,13 @@ include(CMakeDependentOption) option(VASP_PROFILING "Enable profiling" OFF) set(VASP_CACHE_SIZE "4000" CACHE STRING "Cache size") -option(VASP_COLLECTIVE "Enable MPI collectives" OFF) +option(VASP_COLLECTIVE "Enable MPI collectives" ON) set(VASP_MPI_BLOCK "8000" CACHE STRING "MPI block size") set(VASP_HOST_NAME ${CMAKE_SYSTEM_NAME} CACHE STRING "Host system name") -option(VASP_AVOIDALLOC "Avoid automatic allocation" OFF) +option(VASP_AVOIDALLOC "Avoid automatic allocation" ON) option(VASP_VASP6 "Enable VASP 6.x features" ON) option(VASP_TBDYN "Enable advanced molecular dynamics" ON) -option(VASP_FOCK_DBLBUF "Enable double buffering for exchange potential" OFF) +option(VASP_FOCK_DBLBUF "Enable double buffering for exchange potential" ON) option(VASP_SHMEM "Enable shared memory for reduced memory usage" OFF) option(VASP_SHMEM_BCAST "Enable shared memory MPI bcast" OFF) option(VASP_SHMEM_RPROJ "Enable shared memory for PAW projections" OFF) @@ -71,18 +87,25 @@ option(VASP_SYSV "Enable shared-memory for ipcs and system-V" OFF) option(VASP_MPI_INPLACE "Use MPI inplace" ON) option(VASP_OPENMP "Enable OpenMP" OFF) +option(VASP_PLUGINS "Enable VASP Plugin support" OFF) option(VASP_FFTLIB "Enable internal FFTLIB" OFF) -option(VASP_SCALAPACK "Enable ScaLAPACK" OFF) -option(VASP_HDF5 "Enable hdf5" OFF) +option(VASP_SCALAPACK "Enable ScaLAPACK" ON) +option(QD_EMULATE "use QD library for quadruple precision types" OFF) +option(USE_ERF "use internal ERF implementation" OFF) + option(VASP_LIBBEEF "Enable libbeef for van-der-Waals functionals" OFF) option(VASP_DFTD4 "Enable DFTD4 library" OFF) option(VASP_WANNIER90 "Enable Wannier90 library" OFF) option(VASP_LIBXC "Enable Libxc library" OFF) option(VASP_CUDA "Enable cuda accelaration" OFF) +option(VASP_OMP_OFFLOAD "Enable OMP device offloading" OFF) set(VASP_CUDA_VERSION "Default" CACHE STRING "Set the CUDA version passed on to the NVHPC compiler") -cmake_dependent_option(VASP_NCCLP2P "Enable NCCL library collectives instead of MPI" ON "VASP_CUDA" OFF) cmake_dependent_option(VASP_CUSOLVERMP "Enable usage of cuSOLVERmp" OFF "VASP_CUDA" OFF) +set(VASP_PP_EXTRA "" CACHE STRING "Extra preprocessor flags not covered by the options above") + +option(VASP_TESTSUITE "Enable testsuite in build dir" ON) + set(CMAKE_CUDA_ARCHITECTURES "native" CACHE STRING "Cuda architectures list or native for automatic detection. Example: \"60;70;80\"") # Additional options for source file selection and optimization flags @@ -90,116 +113,247 @@ include(cmake/sources_and_flags_options.cmake) set(VASP_EXTERNAL_LIBS) -set(VASP_DEFINITIONS - MPI - "HOST=\"${VASP_HOST_NAME}\"" - MPI_BLOCK=${VASP_MPI_BLOCK} - CACHE_SIZE=${VASP_CACHE_SIZE} - $<$:MPI_INPLACE> - $<$:PROFILING> - $<$:use_collective> - $<$:avoidalloc> - $<$:vasp6> - $<$:tbdyn> - $<$:fock_dblbuf> - $<$:use_shmem> - $<$:shmem_bcast_buffer> - $<$:shmem_rproj> - $<$:sysv> - $<$:_OPENMP> - $<$:scaLAPACK> - $<$:VASP_HDF5> - $<$:USELIBXC> - $<$:VASP2WANNIER90> - # nvhpc already defines _OPENACC with "-acc", but not defining it seems to cause issues with dependency detection with make. Ninja works without it. - $<$:ACC_OFFLOAD> - $<$:USENCCL> - $<$:USENCCLP2P> - $<$:CUSOLVERMP> - $<$:CUBLASMP> - ) +# Get the LIBRARY_PATH environment variable and convert it to a CMake list +set(ENV_LIBRARY_PATH $ENV{LIBRARY_PATH}) +string(REPLACE ":" ";" LIBRARY_PATH_LIST "${ENV_LIBRARY_PATH}") +# Append LIBRARY_PATH to CMAKE_LIBRARY_PATH and CMAKE_PREFIX_PATH +list(APPEND CMAKE_LIBRARY_PATH ${LIBRARY_PATH_LIST}) +foreach(PATH ${CMAKE_LIBRARY_PATH}) + get_filename_component(PARENT_DIR ${PATH} PATH) + list(APPEND CMAKE_PREFIX_PATH ${PARENT_DIR}) + list(APPEND CMAKE_INCLUDE_PATH ${PARENT_DIR}/include) +endforeach() + +#----------------------------- +# mandatory external libraries +#----------------------------- +message(STATUS "-------- MPI detection ------------------") +find_package(MPI MODULE REQUIRED + COMPONENTS Fortran) +list(APPEND VASP_EXTERNAL_LIBS MPI::MPI_Fortran) +# for scaLAPACK it is useful to detect if we are using OMPI +set (MPI_IS_OMPI FALSE) +execute_process(COMMAND grep -i "OMPI_MPI" ${MPI_Fortran_F77_HEADER_DIR}/mpi.h + RESULT_VARIABLE MPI_GREP_RESULT + OUTPUT_QUIET + ERROR_QUIET) + +if(MPI_GREP_RESULT EQUAL 0) + set(MPI_IS_OMPI TRUE) +endif() -if(VASP_OPENMP) - find_package(OpenMP MODULE COMPONENTS Fortran CXX REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS OpenMP::OpenMP_Fortran OpenMP::OpenMP_CXX) +message(STATUS "-------- Lapack detection ---------------") +set(BLA_SIZEOF_INTEGER 4) # only look for 32-bit BLAS / LAPACK +# for NEC we specify the linking library manually +if(CMAKE_Fortran_COMPILER_ID STREQUAL "NFORT") + set(BLAS_LIBRARIES "-lblas_sequential -lcblas" CACHE STRING "Manually set BLAS libraries" FORCE) endif() +find_package(BLAS MODULE REQUIRED) +list(APPEND VASP_EXTERNAL_LIBS BLAS::BLAS) + +find_package(LAPACK MODULE REQUIRED) +list(APPEND VASP_EXTERNAL_LIBS LAPACK::LAPACK) +message(STATUS "-------- FFTW detection -----------------") +# The FindFFTW module will use the blas library if it provides FFTW symbols like MKL or ArmPL +# for NEC we specify the linking library manually +if(CMAKE_Fortran_COMPILER_ID STREQUAL "NFORT") + set(NLC_ROOT $ENV{NLC_ROOT}) + add_library(FFTW::FFTW_SERIAL INTERFACE IMPORTED) + set_property(TARGET FFTW::FFTW_SERIAL PROPERTY INTERFACE_LINK_LIBRARIES aslfftw3_mpi asl_mpi_sequential) + set_property(TARGET FFTW::FFTW_SERIAL PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${NLC_ROOT}/include) + target_compile_options(FFTW::FFTW_SERIAL INTERFACE -cxxlib -static -static-nec) + list(APPEND VASP_EXTERNAL_LIBS FFTW::FFTW_SERIAL) +else() + if(VASP_OPENMP) + find_package(FFTW MODULE REQUIRED COMPONENTS OMP) + list(APPEND VASP_EXTERNAL_LIBS FFTW::FFTW_OMP) + else() + find_package(FFTW MODULE REQUIRED COMPONENTS SERIAL) + list(APPEND VASP_EXTERNAL_LIBS FFTW::FFTW_SERIAL) + endif() +endif() + +#----------------------------- +# optional external libraries +#----------------------------- if(VASP_SCALAPACK) - find_package(SCALAPACK MODULE REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS SCALAPACK::SCALAPACK) + message(STATUS "-------- ScaLAPACK detection ------------") + find_package(SCALAPACK MODULE REQUIRED) + list(APPEND VASP_EXTERNAL_LIBS SCALAPACK::SCALAPACK) endif() -if(VASP_HDF5) - find_package(HDF5 MODULE COMPONENTS Fortran REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS hdf5::hdf5_fortran) +message(STATUS "-------- Optional dependencies ----------") + +if(VASP_OPENMP) + find_package(OpenMP MODULE COMPONENTS Fortran CXX REQUIRED) + list(APPEND VASP_EXTERNAL_LIBS OpenMP::OpenMP_Fortran OpenMP::OpenMP_CXX) +endif() + +# try to find HDF5 always +find_package(HDF5 MODULE COMPONENTS Fortran) +if(HDF5_FOUND) + list(APPEND VASP_EXTERNAL_LIBS hdf5::hdf5_fortran) + set(VASP_HDF5 ON) +else() + message(STATUS "HDF5 not found - VASP HDF5 support disabled.") + set(VASP_HDF5 OFF) endif() if(VASP_LIBXC) - find_package(LibXC MODULE REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS LibXC::libxc) + find_package(LibXC MODULE REQUIRED) + list(APPEND VASP_EXTERNAL_LIBS LibXC::libxc) endif() if(VASP_WANNIER90) - find_package(WANNIER90 MODULE REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS WANNIER90::wannier90) + find_package(WANNIER90 MODULE REQUIRED) + list(APPEND VASP_EXTERNAL_LIBS WANNIER90::wannier90) endif() -#TODO: remaining options if(VASP_LIBBEEF OR VASP_DFTD4) - message(FATAL_ERROR "VASP_LIBBEEF and VASP_DFTD4 not yet supported through CMake.") + message(FATAL_ERROR "VASP_LIBBEEF and VASP_DFTD4 not yet supported through CMake.") endif() - -find_package(MPI MODULE REQUIRED COMPONENTS Fortran) -list(APPEND VASP_EXTERNAL_LIBS MPI::MPI_Fortran) - -set(BLA_SIZEOF_INTEGER 4) # only look for 32-bit BLAS / LAPACK -find_package(BLAS MODULE REQUIRED) -list(APPEND VASP_EXTERNAL_LIBS BLAS::BLAS) - -find_package(LAPACK MODULE REQUIRED) -list(APPEND VASP_EXTERNAL_LIBS LAPACK::LAPACK) - -# The FindFFTW module will use the blas library if it provides FFTW symbols like MKL or ArmPL -if(VASP_OPENMP) - find_package(FFTW MODULE REQUIRED COMPONENTS OMP) - list(APPEND VASP_EXTERNAL_LIBS FFTW::FFTW_OMP) -else() - find_package(FFTW MODULE REQUIRED COMPONENTS SERIAL) - list(APPEND VASP_EXTERNAL_LIBS FFTW::FFTW_SERIAL) +#----------------------------- +# GPU support +#----------------------------- + +# Find CUDA +message(STATUS "-------- GPU support detection ----------") +include(CheckLanguage) +check_language(CUDA) +if(CMAKE_CUDA_COMPILER) + enable_language(CUDA) + set(VASP_CUDA ON) endif() - if(VASP_CUDA) - if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") - message(FATAL_ERROR "CUDA accelaration requires NVHPC fortran compiler.") - endif() - + message(STATUS "CUDA and an offloading device was found enabling OpenACC port") + + if(${CMAKE_CUDA_ARCHITECTURES} STREQUAL "native") + message(STATUS "setting default CUDA compute capability of present device") + set(VASP_GPU_FLAG "-gpu=ccnative") + message(STATUS "overwrite this by calling cmake with -DCMAKE_CUDA_ARCHITECTURES=XX") + else() + message(STATUS "setting user specified CUDA compute capability") set(VASP_CUDA_ARCH ${CMAKE_CUDA_ARCHITECTURES}) list(POP_FRONT VASP_CUDA_ARCH VASP_FIRST_ARCH) set(VASP_GPU_FLAG "-gpu=cc${VASP_FIRST_ARCH}") foreach(arch IN LISTS VASP_CUDA_ARCH) - set(VASP_GPU_FLAG "${VASP_GPU_FLAG},cc${arch}") + set(VASP_GPU_FLAG "${VASP_GPU_FLAG},cc${arch}") endforeach() + endif() + + if(VASP_CUDA_VERSION AND NOT ${VASP_CUDA_VERSION} STREQUAL "Default") + message(STATUS "CUDA version: ${VASP_CUDA_VERSION}") + set(VASP_GPU_FLAG "${VASP_GPU_FLAG},cuda${VASP_CUDA_VERSION}") + else() + message(STATUS "default CUDA version, use -DVASP_CUDA_VERSION=XX to change") + endif() + message(STATUS "CUDA compile flags: ${VASP_GPU_FLAG}") + + set(_CUDA_LIB_LIST "cublas,cusolver,cufft,nccl") + if(VASP_CUSOLVERMP) + set(_CUDA_LIB_LIST "${_CUDA_LIB_LIST},cusolvermp,cublasmp") + endif() + + list(APPEND VASP_FORTRAN_FLAGS -acc ${VASP_GPU_FLAG}) + list(APPEND VASP_EXTERNAL_LIBS "-cudalib=${_CUDA_LIB_LIST} -cuda -acc ${VASP_GPU_FLAG}") +endif() - if(VASP_CUDA_VERSION AND NOT ${VASP_CUDA_VERSION} STREQUAL "Default") - set(VASP_GPU_FLAG "${VASP_GPU_FLAG},cuda${VASP_CUDA_VERSION}") - endif() +if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC" OR QD_EMULATE) + set(QD_EMULATE ON) +endif() - set(_CUDA_LIB_LIST "cublas,cusolver,cufft,nccl") - if(VASP_CUSOLVERMP) - set(_CUDA_LIB_LIST "${_CUDA_LIB_LIST},cusolvermp,cublasmp") - endif() +if(QD_EMULATE) + find_package(QD MODULE REQUIRED) + list(APPEND VASP_EXTERNAL_LIBS QD::qd) + set(QD_EMULATE ON) +endif() + +message(STATUS "-------- done checking dependencies -----") - list(APPEND VASP_FORTRAN_FLAGS -acc ${VASP_GPU_FLAG}) - list(APPEND VASP_EXTERNAL_LIBS "-cudalib=${_CUDA_LIB_LIST} -cuda -acc ${VASP_GPU_FLAG}") +#----------------------------- +# set precompiler definitions +#----------------------------- +set(VASP_DEFINITIONS + MPI + "HOST=\"${VASP_HOST_NAME}\"" + MPI_BLOCK=${VASP_MPI_BLOCK} + CACHE_SIZE=${VASP_CACHE_SIZE} + $<$:MPI_INPLACE> + $<$:PROFILING> + $<$:use_collective> + $<$:avoidalloc> + $<$:vasp6> + $<$:tbdyn> + $<$:fock_dblbuf> + $<$:use_shmem> + $<$:shmem_bcast_buffer> + $<$:shmem_rproj> + $<$:sysv> + $<$:_OPENMP> + $<$:scaLAPACK> + $<$:VASP_HDF5> + $<$:PLUGINS> + $<$:USELIBXC> + $<$:VASP2WANNIER90> + $<$:qd_emulate> + # nvhpc already defines _OPENACC with "-acc", but not defining it seems to cause issues with dependency detection with make. Ninja works without it. + $<$:ACC_OFFLOAD> + $<$:USENCCL> + $<$:NVCUDA> + $<$:CUSOLVERMP> + $<$:CUBLASMP> +) + +# add additional preprocessor flags passed via VASP_PP_EXTRA +if(VASP_PP_EXTRA AND NOT VASP_PP_EXTRA STREQUAL "") + separate_arguments(PP_EXTRA UNIX_COMMAND "${VASP_PP_EXTRA}") + list(APPEND VASP_DEFINITIONS ${PP_EXTRA}) endif() -if(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") - find_package(QD MODULE REQUIRED) - list(APPEND VASP_EXTERNAL_LIBS QD::qd) - list(APPEND VASP_DEFINITIONS qd_emulate) +# NEC compiler specific definitions +if(CMAKE_Fortran_COMPILER_ID STREQUAL "NFORT") + list(APPEND VASP_DEFINITIONS __NEC__) + list(APPEND VASP_DEFINITIONS __NEC_TUNE__) + list(APPEND VASP_DEFINITIONS DCRREXP_inline ) + list(APPEND VASP_DEFINITIONS RPROMU_DGEMV) + list(APPEND VASP_DEFINITIONS USE_ERF) endif() +# Convert the target definitions to preprocessor flags +set(PREPROCESSOR_DEFINITIONS "") +foreach(DEFINITION ${VASP_DEFINITIONS}) + if(DEFINITION MATCHES "^\\$<\\$:(.+)>$") # Match the pattern + set(BOOL_VALUE ${CMAKE_MATCH_1}) # Extract ON/OFF + set(ACTUAL_DEFINITION ${CMAKE_MATCH_2}) # Extract the actual macro name + + if(BOOL_VALUE STREQUAL "ON") # Only add if BOOL is ON + list(APPEND PREPROCESSOR_DEFINITIONS "-D${ACTUAL_DEFINITION}") + endif() + else() + # escape strings to pass them correctly + string(REPLACE "\"" "\\\"" ESCAPED_DEFINITION "${DEFINITION}") + list(APPEND PREPROCESSOR_DEFINITIONS "-D${ESCAPED_DEFINITION}") + endif() +endforeach() +# print the preprocessor definitions once +if(NOT PP_MESSAGE_SHOWN) + string(JOIN "\n " PP_LIST_FORMAT ${PREPROCESSOR_DEFINITIONS}) + message(STATUS "VASP preprocessor definitions (CPP_OPTIONS):") + message(STATUS "${PP_LIST_FORMAT}") +endif() +set(PP_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") + +# move on to the actual build add_subdirectory(src) + +# Testing +if(VASP_TESTSUITE) + # for now just use the custom runtest script + # enable testing here if other tests are added + # enable_testing() + add_subdirectory(testsuite) +endif() diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index e027f2a..8b1fec9 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -25,12 +25,17 @@ endif() macro(find_ffftw_component name lib_name lib_symbol) # set paths to look for library - set(_FFTW_${name}_PATHS ${FFTW_${name}_ROOT} $ENV{FFTW_${name}_ROOT}) - set(_FFTW_${name}_INCLUDE_PATHS) - + if(DEFINED ENV{FFTW_${name}_ROOT} AND NOT "$ENV{FFTW_${name}_ROOT}" STREQUAL "") + set(_FFTW_${name}_PATHS $ENV{FFTW_${name}_ROOT}) + else() + # Check for FFTW_ROOT environment variable + if(DEFINED ENV{FFTW_ROOT} AND NOT "$ENV{FFTW_ROOT}" STREQUAL "") + set(_FFTW_${name}_PATHS $ENV{FFTW_ROOT}) + endif() + endif() set(_FFTW_${name}_DEFAULT_PATH_SWITCH) - + # check if FFTW is contained in BLAS library if(TARGET BLAS::BLAS) set(CMAKE_REQUIRED_LIBRARIES BLAS::BLAS) @@ -50,6 +55,10 @@ macro(find_ffftw_component name lib_name lib_symbol) endif() endif() + # also add MKLROOT if it is defined: + if(DEFINED ENV{MKLROOT}) + list(APPEND _FFTW_${name}_PATHS $ENV{MKLROOT}) + endif() if(_FFTW_${name}_PATHS) # disable default paths if ROOT is set @@ -69,7 +78,7 @@ macro(find_ffftw_component name lib_name lib_symbol) FFTW_${name}_LIBRARIES NAMES ${lib_name} HINTS ${_FFTW_${name}_PATHS} - PATH_SUFFIXES "lib" "lib64" + PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" ${_FFTW_${name}_DEFAULT_PATH_SWITCH} ) endif() @@ -84,11 +93,19 @@ macro(find_ffftw_component name lib_name lib_symbol) # add target to link against if(FFTW_${name}_LIBRARIES AND FFTW_${name}_INCLUDE_DIRS) + if(NOT FFTW_MESSAGE_SHOWN) + if(${FFTW_${name}_LIBRARIES} STREQUAL "BLAS::BLAS") + message(STATUS "Found FFTW library: ${FFTW_${name}_LIBRARIES} (contained in BLAS)") + else() + message(STATUS "Found FFTW library: ${FFTW_${name}_LIBRARIES}") + endif() + endif() if(NOT TARGET FFTW::FFTW_${name}) add_library(FFTW::FFTW_${name} INTERFACE IMPORTED) endif() set_property(TARGET FFTW::FFTW_${name} PROPERTY INTERFACE_LINK_LIBRARIES ${FFTW_${name}_LIBRARIES}) set_property(TARGET FFTW::FFTW_${name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW_${name}_INCLUDE_DIRS}) + set(FFTW_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") endif() # prevent clutter in cache @@ -125,5 +142,7 @@ endforeach() # check if found include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(FFTW REQUIRED_VARS ${FFTW_REQUIRED_VARS}) +find_package_handle_standard_args(FFTW + REQUIRED_VARS ${FFTW_REQUIRED_VARS} + FAIL_MESSAGE "Could not find FFTW libraries, please specify FFTW_ROOT or set as environment variable") MARK_AS_ADVANCED(FFTW_FOUND) diff --git a/cmake/FindLibXC.cmake b/cmake/FindLibXC.cmake index 668d102..38b342f 100644 --- a/cmake/FindLibXC.cmake +++ b/cmake/FindLibXC.cmake @@ -19,6 +19,7 @@ # LibXC::libxc #set paths to look for library from ROOT variables.If new policy is set, find_library() automatically uses them. +set(_LibXC_PATHS) if(NOT POLICY CMP0074) set(_LibXC_PATHS ${LibXC_ROOT} $ENV{LibXC_ROOT}) endif() @@ -44,15 +45,21 @@ find_path( # check if found include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LibXC REQUIRED_VARS LibXC_INCLUDE_DIRS LibXC_LIBRARIES LibXC_FORTRAN_LIBRARIES) +find_package_handle_standard_args(LibXC + REQUIRED_VARS LibXC_INCLUDE_DIRS LibXC_LIBRARIES LibXC_FORTRAN_LIBRARIES + FAIL_MESSAGE "Could not find LibXC library, please specify LibXC_ROOT or set as environment variable") # add target to link against if(LibXC_FOUND) - if(NOT TARGET LibXC::libxc) - add_library(LibXC::libxc INTERFACE IMPORTED) - endif() - set_property(TARGET LibXC::libxc PROPERTY INTERFACE_LINK_LIBRARIES ${LibXC_LIBRARIES} ${LibXC_FORTRAN_LIBRARIES}) - set_property(TARGET LibXC::libxc PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LibXC_INCLUDE_DIRS}) + if(NOT LIBXC_MESSAGE_SHOWN) + message(STATUS "Found LIBXC library: ${LibXC_LIBRARIES}") + endif() + set(LIBXC_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") + if(NOT TARGET LibXC::libxc) + add_library(LibXC::libxc INTERFACE IMPORTED) + endif() + set_property(TARGET LibXC::libxc PROPERTY INTERFACE_LINK_LIBRARIES ${LibXC_LIBRARIES} ${LibXC_FORTRAN_LIBRARIES}) + set_property(TARGET LibXC::libxc PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LibXC_INCLUDE_DIRS}) endif() # prevent clutter in cache diff --git a/cmake/FindQD.cmake b/cmake/FindQD.cmake index 622073d..0f68f21 100644 --- a/cmake/FindQD.cmake +++ b/cmake/FindQD.cmake @@ -19,6 +19,7 @@ # QD::qd #set paths to look for library from ROOT variables.If new policy is set, find_library() automatically uses them. +set(_QD_PATHS) if(NOT POLICY CMP0074) set(_QD_PATHS ${QD_ROOT} $ENV{QD_ROOT}) endif() @@ -55,15 +56,21 @@ find_path( # check if found include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(QD REQUIRED_VARS QD_INCLUDE_DIRS QD_LIBRARIES QD_FORTRAN_LIBRARIES) +find_package_handle_standard_args(QD + REQUIRED_VARS QD_INCLUDE_DIRS QD_LIBRARIES QD_FORTRAN_LIBRARIES + FAIL_MESSAGE "Could not find QD library, please specify QD_ROOT or set as environment variable") # add target to link against if(QD_FOUND) - if(NOT TARGET QD::qd) - add_library(QD::qd INTERFACE IMPORTED) - endif() - set_property(TARGET QD::qd PROPERTY INTERFACE_LINK_LIBRARIES ${QD_LIBRARIES} ${QD_FORTRAN_LIBRARIES}) - set_property(TARGET QD::qd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${QD_INCLUDE_DIRS}) + if(NOT QD_MESSAGE_SHOWN) + message(STATUS "Found QD library: ${QD_LIBRARIES}") + endif() + set(QD_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") + if(NOT TARGET QD::qd) + add_library(QD::qd INTERFACE IMPORTED) + endif() + set_property(TARGET QD::qd PROPERTY INTERFACE_LINK_LIBRARIES ${QD_LIBRARIES} ${QD_FORTRAN_LIBRARIES}) + set_property(TARGET QD::qd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${QD_INCLUDE_DIRS}) endif() # prevent clutter in cache diff --git a/cmake/FindSCALAPACK.cmake b/cmake/FindSCALAPACK.cmake index 7ab0729..db055d7 100644 --- a/cmake/FindSCALAPACK.cmake +++ b/cmake/FindSCALAPACK.cmake @@ -1,65 +1,92 @@ -#.rst: -# FindSCALAPACK -# ----------- -# -# This module searches for the ScaLAPACK library. -# -# The following variables are set -# -# :: -# -# SCALAPACK_FOUND - True if double precision ScaLAPACK library is found -# SCALAPACK_FLOAT_FOUND - True if single precision ScaLAPACK library is found -# SCALAPACK_LIBRARIES - The required libraries -# SCALAPACK_INCLUDE_DIRS - The required include directory -# -# The following import target is created -# -# :: -# -# SCALAPACK::SCALAPACK - - - -# set paths to look for library set(_SCALAPACK_PATHS ${SCALAPACK_ROOT} $ENV{SCALAPACK_ROOT}) +set(MKLROOT $ENV{MKLROOT}) set(_SCALAPACK_INCLUDE_PATHS) - set(_SCALAPACK_DEFAULT_PATH_SWITCH) +# First try to see if the user has its own build scalapack library and prioritize it if(_SCALAPACK_PATHS) - # disable default paths if ROOT is set - set(_SCALAPACK_DEFAULT_PATH_SWITCH NO_DEFAULT_PATH) + # disable default paths if ROOT is set + set(_SCALAPACK_DEFAULT_PATH_SWITCH NO_DEFAULT_PATH) else() - # try to detect location with pkgconfig - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - pkg_check_modules(PKG_SCALAPACK QUIET "scalapack") - endif() - set(_SCALAPACK_PATHS ${PKG_SCALAPACK_LIBRARY_DIRS}) - set(_SCALAPACK_INCLUDE_PATHS ${PKG_SCALAPACK_INCLUDE_DIRS}) + # try to detect location with pkgconfig + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(PKG_SCALAPACK QUIET "scalapack") + endif() + set(_SCALAPACK_PATHS ${PKG_SCALAPACK_LIBRARY_DIRS}) + set(_SCALAPACK_INCLUDE_PATHS ${PKG_SCALAPACK_INCLUDE_DIRS}) endif() find_library( - SCALAPACK_LIBRARIES - NAMES "scalapack" "scalapack-mpich" "scalapack-openmpi" - HINTS ${_SCALAPACK_PATHS} - PATH_SUFFIXES "lib" "lib64" - ${_SCALAPACK_DEFAULT_PATH_SWITCH} + SCALAPACK_LIBRARIES + NAMES scalapack scalapack-mpich scalapack-openmpi + HINTS ${_SCALAPACK_PATHS} + PATH_SUFFIXES "lib" "lib64" + ${_SCALAPACK_DEFAULT_PATH_SWITCH} ) -# check if found -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SCALAPACK REQUIRED_VARS SCALAPACK_LIBRARIES ) +# if we did not find it yet and LAPACK is provided by Intel MKL try this +if(NOT SCALAPACK_LIBRARIES AND LAPACK_LIBRARIES MATCHES "mkl") + + # check first if we are using openmpi + set (MPI_IS_OMPI FALSE) + execute_process(COMMAND grep -i "OMPI_MPI" ${MPI_Fortran_F77_HEADER_DIR}/mpi.h + RESULT_VARIABLE MPI_GREP_RESULT + OUTPUT_QUIET + ERROR_QUIET) + + if(MPI_GREP_RESULT EQUAL 0) + set(MPI_MODE openmpi) + else() + set(MPI_MODE intelmpi) + endif() + # now check if lapack is lp or ilp and use scalapack from mkl + if(LAPACK_LIBRARIES MATCHES "ilp64") + set(MKL_SCALAPACK_NAMES mkl_scalapack_ilp64) + set(MKL_BLACS_MPI_NAMES mkl_blacs_${$MPI_MODE}_ilp64) + else() + set(MKL_SCALAPACK_NAMES mkl_scalapack_lp64) + set(MKL_BLACS_MPI_NAMES mkl_blacs_${MPI_MODE}_lp64) + endif() + + find_library( + MKL_SCALAPACK_LIBRARY + NAMES ${MKL_SCALAPACK_NAMES} + HINTS ${_SCALAPACK_PATHS} ${MKLROOT} + PATH_SUFFIXES "lib" "lib64" "lib/intel64" + ) + + find_library( + MKL_BLACS_LIBRARY + NAMES ${MKL_BLACS_MPI_NAMES} + HINTS ${_SCALAPACK_PATHS} ${MKLROOT} + PATH_SUFFIXES "lib" "lib64" "lib/intel64" + ) + + if(MKL_SCALAPACK_LIBRARY AND MKL_BLACS_LIBRARY) + if(NOT SCALAPACK_MESSAGE_SHOWN) + message(STATUS "Found ScaLAPACK provided via Intel MKL") + endif() + set(SCALAPACK_LIBRARIES ${MKL_SCALAPACK_LIBRARY} ${MKL_BLACS_LIBRARY}) + else() + message(STATUS "Could not find Intel MKL Scalapack or BLACS libraries") + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SCALAPACK + REQUIRED_VARS SCALAPACK_LIBRARIES + FAIL_MESSAGE "Could not find ScaLAPACK, please specify SCALAPACK_ROOT or set as environment variable") # add target to link against if(SCALAPACK_FOUND) - if(NOT TARGET SCALAPACK::SCALAPACK) - add_library(SCALAPACK::SCALAPACK INTERFACE IMPORTED) - endif() - set_property(TARGET SCALAPACK::SCALAPACK PROPERTY INTERFACE_LINK_LIBRARIES ${SCALAPACK_LIBRARIES}) + if(NOT TARGET SCALAPACK::SCALAPACK) + add_library(SCALAPACK::SCALAPACK INTERFACE IMPORTED) + endif() + set_property(TARGET SCALAPACK::SCALAPACK PROPERTY INTERFACE_LINK_LIBRARIES ${SCALAPACK_LIBRARIES}) + set(SCALAPACK_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") endif() # prevent clutter in cache -MARK_AS_ADVANCED(SCALAPACK_FOUND SCALAPACK_LIBRARIES SCALAPACK_INCLUDE_DIRS pkgcfg_lib_PKG_SCALAPACK_scalapack ) +mark_as_advanced(SCALAPACK_FOUND SCALAPACK_LIBRARIES SCALAPACK_INCLUDE_DIRS pkgcfg_lib_PKG_SCALAPACK_scalapack ) diff --git a/cmake/FindWANNIER90.cmake b/cmake/FindWANNIER90.cmake index 0b8ab65..0812d9a 100644 --- a/cmake/FindWANNIER90.cmake +++ b/cmake/FindWANNIER90.cmake @@ -19,6 +19,7 @@ # WANNIER90::wannier90 #set paths to look for library from ROOT variables.If new policy is set, find_library() automatically uses them. +set(_WANNIER90_PATHS) if(NOT POLICY CMP0074) set(_WANNIER90_PATHS ${WANNIER90_ROOT} $ENV{WANNIER90_ROOT}) endif() @@ -38,15 +39,21 @@ find_path( # check if found include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(WANNIER90 REQUIRED_VARS WANNIER90_INCLUDE_DIRS WANNIER90_LIBRARIES) +find_package_handle_standard_args(WANNIER90 + REQUIRED_VARS WANNIER90_INCLUDE_DIRS WANNIER90_LIBRARIES + FAIL_MESSAGE "Could not find Wannier90 library, please specify WANNIER90_ROOT or set as environment variable") # add target to link against if(WANNIER90_FOUND) - if(NOT TARGET WANNIER90::wannier90) - add_library(WANNIER90::wannier90 INTERFACE IMPORTED) - endif() - set_property(TARGET WANNIER90::wannier90 PROPERTY INTERFACE_LINK_LIBRARIES ${WANNIER90_LIBRARIES}) - set_property(TARGET WANNIER90::wannier90 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${WANNIER90_INCLUDE_DIRS}) + if(NOT W90_MESSAGE_SHOWN) + message(STATUS "Found Wannier90 library: ${WANNIER90_LIBRARIES}") + endif() + set(W90_MESSAGE_SHOWN TRUE CACHE INTERNAL "Message shown flag") + if(NOT TARGET WANNIER90::wannier90) + add_library(WANNIER90::wannier90 INTERFACE IMPORTED) + endif() + set_property(TARGET WANNIER90::wannier90 PROPERTY INTERFACE_LINK_LIBRARIES ${WANNIER90_LIBRARIES}) + set_property(TARGET WANNIER90::wannier90 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${WANNIER90_INCLUDE_DIRS}) endif() # prevent clutter in cache diff --git a/cmake/sources_and_flags_options.cmake b/cmake/sources_and_flags_options.cmake index aa4806b..35fca1f 100644 --- a/cmake/sources_and_flags_options.cmake +++ b/cmake/sources_and_flags_options.cmake @@ -1,26 +1,29 @@ set(_VASP_OFLAG_DEFAULT -O2) +set(_VASP_OFLAG_DEB -g) set(_VASP_OFLAG_O1 -O1) set(_VASP_OFLAG_O2 -O2) set(_VASP_OFLAG_O3 -O3) set(_VASP_OFLAG_MAIN -O0) set(_VASP_OFLAG_C_LIB -O) +set(_VASP_SOURCES_DEB) set(_VASP_SOURCES_O1) set(_VASP_SOURCES_O2) set(_VASP_SOURCES_O3) set(_VASP_SOURCES_IN) +# read here all required source files from the .objects file file(READ "${PROJECT_SOURCE_DIR}/src/.objects" VASP_OBJECTS_CONTENT) # convert a string containing object file names to a list of fortran files with ".F" suffix function(objects_to_fortran_files objects_string out_var_name) - string(REGEX MATCHALL "[a-zA-Z_0-9-]+\.o" objects ${objects_string}) - set(_files) - foreach(obj IN LISTS objects) - string(REGEX REPLACE "\\.[^.]*$" "" file_name ${obj}) - list(APPEND _files ${file_name}.F) - endforeach() - set(${out_var_name} ${_files} PARENT_SCOPE) + string(REGEX MATCHALL "[a-zA-Z_0-9-]+\.o" objects ${objects_string}) + set(_files) + foreach(obj IN LISTS objects) + string(REGEX REPLACE "\\.[^.]*$" "" file_name ${obj}) + list(APPEND _files ${file_name}.F) + endforeach() + set(${out_var_name} ${_files} PARENT_SCOPE) endfunction() string(REGEX MATCH ".*SOURCE_O1" _VASP_OBJECTS ${VASP_OBJECTS_CONTENT}) @@ -39,59 +42,84 @@ set(_VASP_SOURCES "") # Compiler specific modifications ################################# +# IMPORTANT: if the compiler is not identified, the precompiler falls back to gcc + # Languages must be enabled to check compiler id enable_language(C CXX Fortran) +# now we specify compiler specific options and importantly +# specify how the preprocessor should be called set(VASP_FORTRAN_FLAGS) +set(VASP_FORTRAN_LINKER_FLAGS) # note: free and fixed format flags are set through target properties if(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") - list(APPEND VASP_FORTRAN_FLAGS -ffree-line-length-none -w -ffpe-summary=invalid,zero,overflow -fallow-argument-mismatch) - # extend list of specially optimized files - list(APPEND _VASP_SOURCES_O1 fftw3d.F fftmpi.F fftmpiw.F) - list(APPEND _VASP_SOURCES_O2 fft3dlib.F) -elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") - list(APPEND VASP_FORTRAN_FLAGS -w0 -names lowercase -assume byterecl -w) - set(_VASP_OFLAG_DEFAULT -O2) - # extend list of specially optimized files - list(APPEND _VASP_SOURCES_O1 fftw3d.F fftmpi.F fftmpiw.F) - list(APPEND _VASP_SOURCES_O2 fft3dlib.F) + set(FPP_COMMAND ${CMAKE_Fortran_COMPILER} -E -C -w) + list(APPEND VASP_FORTRAN_FLAGS -ffree-line-length-none -w -ffpe-summary=invalid,zero,overflow -fallow-argument-mismatch) + set(_VASP_OFLAG_DEFAULT -O3) + set(_VASP_OFLAG_DEB -g -Wall -Wextra -Warray-temporaries -Wconversion -fimplicit-none -fbacktrace -ffree-line-length-0 -fcheck=all -ffpe-trap=invalid,zero,overflow,underflow -finit-real=nan) +elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel" OR CMAKE_Fortran_COMPILER_ID MATCHES "IntelLLVM") + set(FPP_COMMAND fpp -f_com=no -free -w0) + list(APPEND VASP_FORTRAN_FLAGS -w0 -names lowercase -assume byterecl -w) + set(_VASP_OFLAG_DEFAULT -O2) + set(_VASP_OFLAG_DEB -g -check all -fpe0 -warn -traceback -debug extended) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NVHPC") - list(APPEND VASP_FORTRAN_FLAGS -Mbackslash -Mlarge_arrays -Mextend -Minform=severe) - set(_VASP_OFLAG_DEFAULT -fast) - set(_VASP_OFLAG_MAIN -O0 -traceback) - # overwrite list of specially optimized files - set(_VASP_SOURCES_O1 pade_fit.F minimax_dependence.F) - set(_VASP_SOURCES_O2 pead.F) -endif() - -if(NOT _VASP_OFLAG_IN) + set(FPP_COMMAND ${CMAKE_Fortran_COMPILER} -Mpreprocess -Mfree -Mextend -E) + list(APPEND VASP_FORTRAN_FLAGS -Mbackslash -Mlarge_arrays -Mextend) + list(APPEND VASP_FORTRAN_LINKER_FLAGS -mp -c++libs) + set(_VASP_OFLAG_DEFAULT -fast) + set(_VASP_OFLAG_MAIN -O0 -traceback) + set(_VASP_SOURCES_O1 pade_fit.F minimax_dependence.F) + set(_VASP_SOURCES_O2 pead.F) + set(_VASP_OFLAG_DEB -Minfo=all -g -traceback) +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Flang") + set(FPP_COMMAND ${CMAKE_Fortran_COMPILER} -E -ffree-form -C -w) + set(_VASP_OFLAG_DEFAULT -O2) + list(APPEND VASP_FORTRAN_FLAGS -ffree-form -ffree-line-length-none -w -fno-fortran-main -Mbackslash) + set(_VASP_OFLAG_DEB -g) +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Fujitsu") + set(FPP_COMMAND ${CMAKE_Fortran_COMPILER} -Ccpp -E) + set(_VASP_OFLAG_DEFAULT --Kfast) + list(APPEND VASP_FORTRAN_FLAGS -Ksimd_nouse_multiple_structures -X03) + list(APPEND VASP_FORTRAN_LINKER_FLAGS -Kfz,simd_nouse_multiple_structures) + set(_VASP_SOURCES_O1 elphon_common.F minimax_dependence.F) + set(_VASP_SOURCES_O2 nonl.F vdw_nl.F) +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NFORT") + set(FPP_COMMAND gcc -E -C -w) + list(APPEND VASP_FORTRAN_FLAGS -no-ftrace -finline-functions -finline-file=random.f90 -fdiag-parallel=0 -fdiag-vector=0 -fdiag-inline=0 -w) + list(APPEND VASP_FORTRAN_LINKER_FLAGS -cxxlib) + set(_VASP_OFLAG_DEFAULT -O3) + endif() + + if(NOT _VASP_OFLAG_IN) set(_VASP_OFLAG_IN ${_VASP_OFLAG_DEFAULT}) -endif() -if(NOT _VASP_OFLAG_LIB) + endif() + if(NOT _VASP_OFLAG_LIB) set(_VASP_OFLAG_LIB ${_VASP_OFLAG_O1}) -endif() - - -######################### -# Set user facing options -######################### - -# set default optimization flags. Input from cmake/default_flags.cmake -set(VASP_OFLAG_DEFAULT "${_VASP_OFLAG_DEFAULT}" CACHE STRING "Default optimization flag") -set(VASP_OFLAG_O1 "${_VASP_OFLAG_O1}" CACHE STRING "") -set(VASP_OFLAG_O2 "${_VASP_OFLAG_O2}" CACHE STRING "") -set(VASP_OFLAG_O3 "${_VASP_OFLAG_O3}" CACHE STRING "") -set(VASP_OFLAG_LIB "${_VASP_OFLAG_LIB}" CACHE STRING "") -set(VASP_OFLAG_C_LIB "${_VASP_OFLAG_C_LIB}" CACHE STRING "") -set(VASP_OFLAG_IN "${_VASP_OFLAG_IN}" CACHE STRING "") -set(VASP_OFLAG_MAIN "${_VASP_OFLAG_MAIN}" CACHE STRING "") -set(VASP_SOURCES_O1 "${_VASP_SOURCES_O1}" CACHE STRING "") -set(VASP_SOURCES_O2 "${_VASP_SOURCES_O2}" CACHE STRING "") -set(VASP_SOURCES_O3 "${_VASP_SOURCES_O3}" CACHE STRING "") -set(VASP_SOURCES_IN "${_VASP_SOURCES_IN}" CACHE STRING "") -set(VASP_SOURCES "${_VASP_SOURCES}" CACHE STRING "Additional files to build") -set(VASP_SOURCES_DEFAULT "${_VASP_SOURCES_DEFAULT}" CACHE STRING "List of default sources to build") -mark_as_advanced(VASP_SOURCES_DEFAULT) # long list, hide by default in gui + endif() + + + ######################### + # Set user facing options + ######################### + + # set default optimization flags. + set(VASP_OFLAG_DEFAULT "${_VASP_OFLAG_DEFAULT}" CACHE STRING "Default optimization flag") + set(VASP_OFLAG_DEB "${_VASP_OFLAG_DEB}" CACHE STRING "") + set(VASP_OFLAG_O1 "${_VASP_OFLAG_O1}" CACHE STRING "") + set(VASP_OFLAG_O2 "${_VASP_OFLAG_O2}" CACHE STRING "") + set(VASP_OFLAG_O3 "${_VASP_OFLAG_O3}" CACHE STRING "") + set(VASP_OFLAG_LIB "${_VASP_OFLAG_LIB}" CACHE STRING "") + set(VASP_OFLAG_C_LIB "${_VASP_OFLAG_C_LIB}" CACHE STRING "") + set(VASP_OFLAG_IN "${_VASP_OFLAG_IN}" CACHE STRING "") + set(VASP_OFLAG_MAIN "${_VASP_OFLAG_MAIN}" CACHE STRING "") + set(VASP_SOURCES_DEB "${_VASP_SOURCES_DEB}" CACHE STRING "") + set(VASP_SOURCES_O1 "${_VASP_SOURCES_O1}" CACHE STRING "") + set(VASP_SOURCES_O2 "${_VASP_SOURCES_O2}" CACHE STRING "") + set(VASP_SOURCES_O3 "${_VASP_SOURCES_O3}" CACHE STRING "") + set(VASP_SOURCES_IN "${_VASP_SOURCES_IN}" CACHE STRING "") + set(VASP_SOURCES "${_VASP_SOURCES}" CACHE STRING "Additional files to build") + set(VASP_SOURCES_DEFAULT "${_VASP_SOURCES_DEFAULT}" CACHE STRING "List of default sources to build") + mark_as_advanced(VASP_SOURCES_DEFAULT) # long list, hide by default in gui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37a8ed7..4c880d6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,69 +1,120 @@ function(vasp_create_executable name sources) - add_executable(${name} ${sources}) - target_compile_definitions(${name} PRIVATE ${VASP_DEFINITIONS}) - target_compile_options(${name} PRIVATE $<$:${VASP_FORTRAN_FLAGS}>) - target_link_libraries(${name} PRIVATE linpack_objects lib_objects parser_objects ${VASP_EXTERNAL_LIBS}) - set_target_properties(${name} PROPERTIES LINKER_LANGUAGE Fortran) - set_target_properties(${name} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${name}_mod_files) - set_target_properties(${name} PROPERTIES Fortran_FORMAT FREE) - if(VASP_FFTLIB) - target_link_libraries(vasp_std PRIVATE fftlib_objects) - endif() -endfunction() + # preprocessing all sources + set(PREPROCESSED_DIR "${CMAKE_CURRENT_BINARY_DIR}/${name}") + file(MAKE_DIRECTORY ${PREPROCESSED_DIR}) + # copy all include files over + file(GLOB INCLUDE_FILES "${PROJECT_SOURCE_DIR}/src/*.inc") + foreach(INCLUDE_FILE ${INCLUDE_FILES}) + get_filename_component(FILE_NAME ${INCLUDE_FILE} NAME) + configure_file(${INCLUDE_FILE} ${PREPROCESSED_DIR}/${FILE_NAME} COPYONLY) + endforeach() -set(VASP_SOURCES ${VASP_SOURCES} ${VASP_SOURCES_DEFAULT}) -list(APPEND VASP_SOURCES main.F) + # now we have to add the PP options incl vasp version specific ones + set(PP_DEF_${name} PREPROCESSOR_DEFINITIONS) + if (${name} STREQUAL "vasp_std") + list(APPEND PP_DEF_${name} "-DNGZhalf") + endif() + if (${name} STREQUAL "vasp_gam") + list(APPEND PP_DEF_${name} "-DNGZhalf") + list(APPEND PP_DEF_${name} "-DwNGZhalf") + endif() + # Add custom command to run preprocessor + # without this problems occur with: + # file dependencies, empty module files, intel oneapi 2025 (no option to pass fpp options) + # this also cleanly separates the pp part from the build part + foreach(SOURCE_FILE ${sources}) + get_filename_component(FILE_NAME ${SOURCE_FILE} NAME_WE) + set(PREPROCESSED_FILE ${PREPROCESSED_DIR}/${FILE_NAME}.f90) -list(REMOVE_ITEM VASP_SOURCES - wave_gpu.F # does not exist + add_custom_command( + OUTPUT ${PREPROCESSED_FILE} + COMMAND ${FPP_COMMAND} ${PREPROCESSOR_DEFINITIONS} ${PROJECT_SOURCE_DIR}/src/${SOURCE_FILE} > ${PREPROCESSED_FILE} + DEPENDS ${SOURCE_FILE} + COMMENT "Preprocessing ${SOURCE_FILE}" ) -if(NOT VASP_CUDA) - list(REMOVE_ITEM VASP_SOURCES - openacc.F # issues when compiling without nvfortran. Not required without CUDA. - ) -endif() -list(REMOVE_DUPLICATES VASP_SOURCES) -# set optmization flags -foreach(source IN LISTS VASP_SOURCES) + list(APPEND PREPROCESSED_SOURCES ${PREPROCESSED_FILE}) + endforeach() + + # run preprocessing before compiling + add_custom_target(${name}_pp DEPENDS ${PREPROCESSED_SOURCES}) + + # set optimization flags + foreach(pp_source ${PREPROCESSED_SOURCES}) + get_filename_component(source ${pp_source} NAME_WE) set(_opt_flag ${VASP_OFLAG_DEFAULT}) - if(${source} IN_LIST VASP_SOURCES_O3) - set(_opt_flag ${VASP_OFLAG_O3}) + if(${source}.F IN_LIST VASP_SOURCES_O3) + set(_opt_flag ${VASP_OFLAG_O3}) + endif() + if(${source}.F IN_LIST VASP_SOURCES_O2) + set(_opt_flag ${VASP_OFLAG_O2}) endif() - if(${source} IN_LIST VASP_SOURCES_O2) - set(_opt_flag ${VASP_OFLAG_O2}) + if(${source}.F IN_LIST VASP_SOURCES_O1) + set(_opt_flag ${VASP_OFLAG_O1}) endif() - if(${source} IN_LIST VASP_SOURCES_O1) - set(_opt_flag ${VASP_OFLAG_O1}) + if(${source}.F IN_LIST VASP_SOURCES_IN) + set(_opt_flag ${VASP_OFLAG_IN}) endif() - if(${source} IN_LIST VASP_SOURCES_IN) - set(_opt_flag ${VASP_OFLAG_IN}) + if(${source}.F IN_LIST VASP_SOURCES_DEB) + if(${name} STREQUAL "vasp_std") + message(STATUS "debugging for ${source} enabled. Flags: ${VASP_OFLAG_DEB}") + endif() + set(_opt_flag ${VASP_OFLAG_DEB}) endif() - if(${source} STREQUAL "main.F") - set(_opt_flag ${VASP_OFLAG_MAIN}) + if(${source}.F STREQUAL "main.F") + set(_opt_flag ${VASP_OFLAG_MAIN}) endif() list(JOIN _opt_flag " " _opt_flag_str) # convert list to string - set_source_files_properties(${source} PROPERTIES COMPILE_FLAGS ${_opt_flag_str}) -endforeach() + set_source_files_properties(${pp_source} PROPERTIES COMPILE_FLAGS ${_opt_flag_str}) + endforeach() -if(VASP_FFTLIB) - add_subdirectory(fftlib) + # now create the actual target + add_executable(${name} ${PREPROCESSED_SOURCES}) + + target_compile_options(${name} PRIVATE $<$:${VASP_FORTRAN_FLAGS}>) + target_link_options(${name} PRIVATE $<$:${VASP_FORTRAN_LINKER_FLAGS}>) + target_link_libraries(${name} PRIVATE linpack_objects lib_objects parser_objects ${VASP_EXTERNAL_LIBS}) + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE Fortran) + set_target_properties(${name} PROPERTIES Fortran_MODULE_DIRECTORY ${PREPROCESSED_DIR}) + set_target_properties(${name} PROPERTIES Fortran_FORMAT FREE) + # making LIB_DIR/mod available for libraries linking LIB + target_include_directories(${name} INTERFACE ${PREPROCESSED_DIR}) + if(VASP_FFTLIB) + target_link_libraries(vasp_std PRIVATE fftlib_objects) + endif() +endfunction() + +#-------------------------------------------- +# add src files add run custom target command +#-------------------------------------------- + +# add all source files +set(VASP_SOURCES ${VASP_SOURCES} ${VASP_SOURCES_DEFAULT}) +list(APPEND VASP_SOURCES main.F) +list(REMOVE_DUPLICATES VASP_SOURCES) + +if(NOT ${VASP_SOURCES_DEB} STREQUAL "") + message(STATUS "for debug marked files: ${VASP_SOURCES_DEB}") endif() +# add extra source files for the lib +if(VASP_FFTLIB) + add_subdirectory(fftlib) +endif() add_subdirectory(lib) add_subdirectory(parser) - +# here the add_executables are generated via the custom function vasp_create_executable(vasp_std "${VASP_SOURCES}") -target_compile_definitions(vasp_std PRIVATE NGZhalf) - vasp_create_executable(vasp_gam "${VASP_SOURCES}") -target_compile_definitions(vasp_gam PRIVATE NGZhalf wNGZhalf) - vasp_create_executable(vasp_ncl "${VASP_SOURCES}") install(TARGETS vasp_std DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS vasp_gam DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS vasp_ncl DESTINATION ${CMAKE_INSTALL_BINDIR}) +# if no install prefix is set, use the current source dir/bin folder as in the old build system +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/bin CACHE PATH "Default install path" FORCE) +endif() diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 81c73fa..dca5dac 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,24 +1,63 @@ add_library(linpack_objects OBJECT - linpack_double.f - ) + linpack_double.f +) target_compile_options(linpack_objects PRIVATE $<$:${VASP_LINPACK_FORTRAN_FLAGS}>) set_target_properties(linpack_objects PROPERTIES Fortran_FORMAT FIXED) -add_library(lib_objects OBJECT - preclib.F - timing_.c - derrf_.c - dclock_.c - diolib.F - dlexlib.F - drdatab.F +set(PREPROCESSED_SOURCES "") + +# Define source files for lib +set(SOURCE_FILES + preclib.F + diolib.F + dlexlib.F + drdatab.F + timing_.c + derrf_.c + dclock_.c +) + +# also here we have to invoke the preprocessor manually for Fortran files +foreach(SOURCE_FILE ${SOURCE_FILES}) + # Extract filename without extension + get_filename_component(SOURCE_NAME_WE ${SOURCE_FILE} NAME_WE) + get_filename_component(SOURCE_EXT ${SOURCE_FILE} EXT) + set(PREPROCESSED_DIR "${CMAKE_CURRENT_BINARY_DIR}") + file(MAKE_DIRECTORY ${PREPROCESSED_DIR}) + + # Define output file with correct suffix + if(SOURCE_EXT MATCHES "\\.F$") + set(PREPROCESSED_FILE ${PREPROCESSED_DIR}/${SOURCE_NAME_WE}.f90) + set(PREPROCESS_COMMAND ${FPP_COMMAND}) + # Custom command to preprocess the file + add_custom_command( + OUTPUT ${PREPROCESSED_FILE} + COMMAND ${PREPROCESS_COMMAND} ${PREPROCESSOR_DEFINITIONS} ${PROJECT_SOURCE_DIR}/src/lib/${SOURCE_FILE} > ${PREPROCESSED_FILE} + DEPENDS ${PROJECT_SOURCE_DIR}/src/lib/${SOURCE_FILE} + COMMENT "Preprocessing ${SOURCE_FILE}" ) + # for C-files we need to copy the file to the preprocessed directory but no preprocessing necessary + elseif(SOURCE_EXT MATCHES "\\.c$") + set(PREPROCESSED_FILE ${PREPROCESSED_DIR}/${SOURCE_NAME_WE}.c) + configure_file(${SOURCE_FILE} ${PREPROCESSED_DIR}/${SOURCE_NAME_WE}.c COPYONLY) + endif() + + # Collect preprocessed files + list(APPEND PREPROCESSED_SOURCES ${PREPROCESSED_FILE}) +endforeach() + +# Now, use the preprocessed files in the library +add_library(lib_objects OBJECT ${PREPROCESSED_SOURCES}) -target_link_libraries(lib_objects PRIVATE linpack_objects) +# Apply the same Fortran properties and compiler options set_target_properties(lib_objects PROPERTIES Fortran_FORMAT FREE) -target_compile_options(lib_objects PRIVATE $<$:${VASP_LIB_FORTRAN_FLAGS}> $<$:${VASP_OFLAG_LIB}> $<$:${VASP_OFLAG_C_LIB}>) +target_compile_options(lib_objects PRIVATE + $<$:${VASP_LIB_FORTRAN_FLAGS}> + $<$:${VASP_OFLAG_LIB}> + $<$:${VASP_OFLAG_C_LIB}>) +target_link_options(lib_objects PRIVATE $<$:${VASP_FORTRAN_LINKER_FLAGS}>) if(CMAKE_C_COMPILER_ID STREQUAL "NVHPC") - target_compile_options(lib_objects PRIVATE $<$:--diag_suppress set_but_not_used>) + target_compile_options(lib_objects PRIVATE $<$:--diag_suppress set_but_not_used>) endif() diff --git a/testsuite/CMakeLists.txt b/testsuite/CMakeLists.txt new file mode 100644 index 0000000..eb2846b --- /dev/null +++ b/testsuite/CMakeLists.txt @@ -0,0 +1,33 @@ +message(STATUS "-------- preparing testsuite ------------") + +add_custom_target(copy_tests + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/" + "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Copying testsuite" +) + +# build compare numbertable +add_executable(compare_numbertable_new tools/compare_numbertable_new.f90) +set_target_properties(compare_numbertable_new + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tools" +) +set_target_properties(compare_numbertable_new PROPERTIES Fortran_FORMAT FREE) + +# Set executable permissions for the runtest script +execute_process(COMMAND chmod +x "${CMAKE_BINARY_DIR}/testsuite/runtest") + +# add test command for fast testsuite +add_custom_target(test + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/runtest --fast 2>&1 | tee testsuite.log + COMMENT "Run the fast testsuite" +) +add_dependencies(test copy_tests) + +add_custom_target(test_all + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/runtest --all 2>&1 | tee testsuite.log + COMMENT "Run the full testsuite" +) +add_dependencies(test_all copy_tests) +