#!/usr/bin/env bash # Purpose: Build CP2K using Spack and CMake locally within the folder CP2K_ROOT # which defaults to the current working directory. This should be a # "cp2k/" folder containing the CP2K source tree which can be download with # # > git clone https://github.com/cp2k/cp2k.git cp2k # # and after # # > cd cp2k # # this script can be run in subshell using the default options with # # > ./make_cp2k.sh # # The flags -h or --help print the available options. # # The first run will take longer as it will build all CP2K dependencies # with Spack. The Spack installation is kept fully local in the subfolder # cp2k/spack which corresponds to the tools/toolchain/install folder # created by the CP2K toolchain. # # Subsequent runs of the script will use the software stack from that # cp2k/spack/ folder. # # A rebuild of all CP2K dependencies can be enforced simply by removing # or renaming the folder cp2k/spack. The latter allows for keeping different # software stacks (see also -bd and -bd_only flags). # # It is recommended to store already compiled packages in a cache (default). # This will accelerate the (re)build of the CP2K dependencies with Spack # significantly (see -uc flag). # # After the CP2K dependencies are built with Spack, CP2K itself is built # and installed using CMake in the subfolders cp2k/build and cp2k/install, # respectively. # # Subsequent runs of the script will use the CMake configuration in the # subfolder cp2k/build. A rebuild of CP2K from scratch can be enforced # by removing or renaming that subfolder. # # A CP2K regression run can be launched automatically by adding the flag # -t "" (or --test ""). This flag expects a string with the TESTOPTS, e.g. # # > ./make_cp2k.sh -t "--maxtasks 8 --restrictdir QS/regtest-gpw-1" # # Alternatively, the script cp2k/install/bin/run_tests can be launched # after a successful CP2K build. Usage examples are printed at the end. # Authors: Matthias Krack (MK) # Version: 2.0 # Facilitate the deugging of this script set -uo pipefail # Retrieve script name SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" # Check if the script is sourced or run in a subshell if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then echo "${SCRIPT_NAME}: Running script in sourcing mode" echo "${SCRIPT_NAME}: All changes from this script will become effective within the current shell" EXIT_CMD="return" else echo "${SCRIPT_NAME}: Running script in subshell mode" echo "${SCRIPT_NAME}: Changes from this script in the shell environment are lost after completion" EXIT_CMD="exit" fi # Check platform if [[ "$(uname -s)" == "Darwin" ]]; then echo "ERROR: A build for Apple macOS (Darwin, Homebrew) is not supported yet," echo " but CP2K can be built within a container using podman." echo " Check the Dockerfiles in the folder cp2k/tools/docker like" echo " Dockerfile.test_spack_openmpi-psmp and the usage description in their header" ${EXIT_CMD} 1 fi # Help finding ldconfig if ! command -v ldconfig &> /dev/null; then PATH="${PATH}:/sbin" fi # Check if all mandatory packages are installed in the environment for package in awk bzip2 find g++ gcc gfortran git gzip ldconfig make patch python3 tar wget xz; do if ! command -v "${package}" &> /dev/null; then echo "ERROR: The package \"${package}\" is mandatory to build CP2K with Spack/CMake" echo " Install the missing package and re-run the script" ${EXIT_CMD} 1 fi done # Disable python bytecode generation to suppress __pycache__ folder creation export PYTHONDONTWRITEBYTECODE=1 # Print OS info if available if [[ -f /etc/os-release ]]; then echo "" cat /etc/os-release fi # Check bash version if ((BASH_VERSINFO < 4)); then echo "" echo "ERROR: The employed bash version ${BASH_VERSION} is too old (from 2004)" echo " Install a newer bash version" if [[ "$(uname -s)" == "Darwin" ]]; then echo "HINT: Use the bash command provided by Homebrew with Apple" echo " /opt/homebrew/bin should precede /bin/bash in the PATH" echo " In sourcing mode, run /opt/homebrew/bin/bash first before sourcing this script" fi ${EXIT_CMD} 1 elif ((BASH_VERSINFO < 5)); then echo -e "\nWARNING: The employed bash version ${BASH_VERSION} is quite old (from 2009)" else echo -e "\nINFO: Using bash version ${BASH_VERSION}" fi # Check if the python3 version is new enough for spack if ! python3 -c 'import sys; sys.exit(not(sys.version_info >= (3, 10)))'; then echo "" echo "ERROR: Python version is NOT >= 3.10 (needed for Spack)" echo " Found only $(python3 -V)" ${EXIT_CMD} 1 else echo -e "\nINFO: Found $(python3 -V)" fi # Default values BUILD_DEPS="if_needed" BUILD_DEPS_ONLY="no" BUILD_SHARED_LIBS="${BUILD_SHARED_LIBS:-ON}" CP2K_BUILD_TYPE="${CP2K_BUILD_TYPE:-Release}" DEPS_BUILD_TYPE="${DEPS_BUILD_TYPE:-Release}" CMAKE_FEATURE_FLAG_ALL="-DCP2K_USE_EVERYTHING=ON" # all features are activated by default CMAKE_FEATURE_FLAGS="-DCP2K_BLAS_VENDOR=OpenBLAS" # LAPACK/BLAS from OpenBLAS by default CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_FFTW3=ON" # FFTW3 is always activated unless explicitly disabled CMAKE_FEATURE_FLAG_MPI="-DCP2K_USE_MPI=ON" # MPI is switched on by default CMAKE_FEATURE_FLAGS_GPU="-DCP2K_USE_SPLA_GEMM_OFFLOADING=ON" CRAY="no" CUDA_SM_CODE=0 GCC_VERSION="auto" GPU_MODEL="none" HELP="no" INSTALL_MESSAGE="NEVER" MPI_MODE="mpich" if command -v nproc &> /dev/null; then MAX_PROCS=$(nproc) NUM_PROCS=${NUM_PROCS:-${MAX_PROCS}} else MAX_PROCS=-1 NUM_PROCS=${NUM_PROCS:-8} fi NUM_PACKAGES=2 NVCC_VERSION=0 REBUILD_CP2K="no" RUN_TEST="no" SED_PATTERN_LIST="" TESTOPTS="" USE_CACHE="folder" USE_EXTERNALS="no" USE_OPENCL="no" VERBOSE=0 VERBOSE_FLAG="--quiet" VERBOSE_MAKEFILE="OFF" VERBOSE_SPACK="" export CP2K_ENV="cp2k_env" export CP2K_ROOT=${CP2K_ROOT:-${PWD}} export CP2K_VERSION="${CP2K_VERSION:-psmp}" export BUILD_PATH="${BUILD_PATH:-${CP2K_ROOT}}" export INSTALL_PREFIX="${INSTALL_PREFIX:-${CP2K_ROOT}/install}" # Parse flags while [[ $# -gt 0 ]]; do case "$1" in -bd | --build_deps | --build_dependencies) BUILD_DEPS="always" shift 1 ;; -bd_only | --build_deps_only | --build_dependencies_only) BUILD_DEPS="always" BUILD_DEPS_ONLY="yes" shift 1 ;; -bp | --build_path) if (($# > 1)); then BUILD_PATH="$(realpath "${2}")" else echo "ERROR: No build path argument found for flag \"${1}\"" ${EXIT_CMD} 1 fi shift 2 ;; -bsl | --build_static_libcp2k) BUILD_SHARED_LIBS="OFF" shift 1 ;; -bt | --build_type) CP2K_BUILD_TYPE="${2}" case "${CP2K_BUILD_TYPE}" in Debug) CP2K_VERSION="${CP2K_VERSION/smp/dbg}" ;; Release | RelWithDebInfo) CP2K_VERSION="${CP2K_VERSION/dbg/smp}" ;; esac shift 2 ;; -cray) CRAY="yes" shift 1 ;; -cv | --cp2k_version) if (($# > 1)); then case "${2,,}" in pdbg | psmp | sdbg | ssmp | ssmp-static) CP2K_VERSION="${2,,}" # Set build type case "${CP2K_VERSION}" in pdbg | sdbg) CP2K_BUILD_TYPE="Debug" DEPS_BUILD_TYPE="RelWithDebInfo" ;; psmp | ssmp | ssmp-static) CP2K_BUILD_TYPE="Release" DEPS_BUILD_TYPE="Release" ;; esac # Disable MPI for a serial CP2K binary case "${CP2K_VERSION}" in sdbg | ssmp | ssmp-static) MPI_MODE="no" CMAKE_FEATURE_FLAG_MPI="-DCP2K_USE_MPI=OFF" ;; esac # Apply specific package selection for statically linked binaries case "${CP2K_VERSION}" in ssmp-static) CMAKE_FEATURE_FLAG_ALL="-DCP2K_USE_EVERYTHING=ON" for package in libfci libint2 libxc libxs spglib vori tblite; do CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_${package^^}=ON" done for package in ace deepmd gauxc greenx hdf5 libgint libtorch pexsi trexio; do CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_${package^^}=OFF" done ;; esac ;; *) echo "ERROR: Invalid CP2K version \"${2}\" specified (choose pdbg, psmp, sdbg, ssmp, or ssmp-static)" ${EXIT_CMD} 1 ;; esac else echo "ERROR: No argument found for flag \"${1}\" (choose pdbg, psmp, sdbg, ssmp, or ssmp-static)" ${EXIT_CMD} 1 fi shift 2 ;; -df | --disable | --disable_feature | -ef | --enable | --enable_feature) if (($# > 1)); then case "${1}" in -df | --disable | --disable_feature) ON_OFF="OFF" SUBST="s/^ /#/'" ;; -ef | --enable | --enable_feature) ON_OFF="ON" SUBST="s/#/ /'" ;; esac case "${2,,}" in all) # Enable or disable all features CMAKE_FEATURE_FLAG_ALL="-DCP2K_USE_EVERYTHING=${ON_OFF}" for package in adios2 cosma deepmdkit dla-future dla-future-fortran elpa \ gauxc greenx hdf5 libfabric libfci libint libvdwxc libsmeagol libvori \ libxc libxs libxsmm mimic-mcl openpmd-api pace pexsi plumed py-torch sirius \ spfft spglib spla tblite trexio; do SED_PATTERN_LIST+=" -e '/\s*-\s+\"${package}@/ ${SUBST}" done # dbcsr must use blas as fallback when libxs/libxsmm is disabled if [[ "${ON_OFF}" == "OFF" ]]; then SED_PATTERN_LIST+=" -e '/\s*-\s+\"smm=libxs\"/ s/libxs/blas/'" fi ;; ace | cosma | deepmd | dftd4 | dlaf | elpa | fftw3 | gauxc | greenx | hdf5 | libfci | \ libgint | libint2 | libsmeagol | libtorch | libxc | libxs | mimic | openpmd | pexsi | \ plumed | spglib | tblite | trexio | vori) CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_${2^^}=${ON_OFF}" # Translate package selection to sed pattern case "${2,,}" in ace) SED_PATTERN_LIST+=" -e '/\s*-\s+\"p${2,,}@/ ${SUBST}" ;; cosma | elpa | greenx | hdf5 | libfci | libsmeagol | libxc | pexsi | plumed | \ spglib | trexio) SED_PATTERN_LIST+=" -e '/\s*-\s+\"${2,,}@/ ${SUBST}" ;; deepmd) SED_PATTERN_LIST+=" -e '/\s*-\s+\"${2,,}kit@/ ${SUBST}" if [[ "${ON_OFF}" == "ON" ]]; then # DeePMD-kit requires libtorch CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_LIBTORCH=${ON_OFF}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"py-torch@/ ${SUBST}" fi ;; dftd4) SED_PATTERN_LIST+=" -e '/\s*-\s+\"${2,,}@/ ${SUBST}" if [[ "${ON_OFF}" == "ON" ]]; then echo "INFO: tblite is disabled to avoid conflicts when dftd4 is used" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_TBLITE=OFF" SED_PATTERN_LIST+=" -e '/\s*-\s+\"tblite@/ s/^ /#/'" fi ;; dlaf) SED_PATTERN_LIST+=" -e '/\s*-\s+\"dla-future.*@/ ${SUBST}" if [[ "${ON_OFF}" == "ON" ]]; then SED_PATTERN_LIST+=" -e 's/\~dlaf/\+dlaf/'" else SED_PATTERN_LIST+=" -e 's/\+dlaf/\~dlaf/'" fi ;; fftw3) SED_PATTERN_LIST+=" -e '/\s*-\s+\"fftw@/ ${SUBST}" ;; gauxc) SED_PATTERN_LIST+=" -e '/\s*-\s+\"${2,,}@/ ${SUBST}" if [[ "${ON_OFF}" == "ON" ]]; then # GauXC requires libtorch CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_LIBTORCH=${ON_OFF}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"py-torch@/ ${SUBST}" fi ;; libint2) SED_PATTERN_LIST+=" -e '/\s*-\s+\"libint@/ ${SUBST}" ;; libtorch) SED_PATTERN_LIST+=" -e '/\s*-\s+\"py-torch@/ ${SUBST}" if [[ "${ON_OFF}" == "OFF" ]]; then # DeePMD-kit and GauXC require libtorch CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_DEEPMD=${ON_OFF}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"deepmdkit@/ ${SUBST}" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_GAUXC=${ON_OFF}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"gauxc@/ ${SUBST}" fi ;; libxs) SED_PATTERN_LIST+=" -e '/\s*-\s+\"libxs@/ ${SUBST}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"libxsmm@/ ${SUBST}" if [[ "${ON_OFF}" == "OFF" ]]; then SED_PATTERN_LIST+=" -e '/\s*-\s+\"smm=${2,,}\"/ s/${2,,}/blas/'" fi ;; mimic) SED_PATTERN_LIST+=" -e '/\s*-\s+\"mimic-mcl@/ ${SUBST}" ;; openpmd | adios2) SED_PATTERN_LIST+=" -e '/\s*-\s+\"adios2@/ ${SUBST}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"openpmd-api@/ ${SUBST}" ;; tblite) SED_PATTERN_LIST+=" -e '/\s*-\s+\"${2,,}@/ ${SUBST}" if [[ "${ON_OFF}" == "ON" ]]; then echo "INFO: dftd4 is disabled to avoid conflicts when tblite is used" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_DFTD4=OFF" SED_PATTERN_LIST+=" -e '/\s*-\s+\"dftd4@/ s/^ /#/'" fi ;; vori) SED_PATTERN_LIST+=" -e '/\s*-\s+\"lib${2,,}@/ ${SUBST}" ;; esac ;; libvdwxc | spfft | spla | sirius) echo "WARNING: You have enabled or disabled one of the packages libvdwxc, spfft, spla, sirius" echo " which means that the other packages will also be enabled or disabled" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_LIBVDWXC=${ON_OFF} -DCP2K_USE_SpFFT=${ON_OFF}" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_SPLA=${ON_OFF} -DCP2K_USE_SIRIUS=${ON_OFF}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"libvdwxc@/ ${SUBST}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"spfft@/ ${SUBST}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"spla@/ ${SUBST}" SED_PATTERN_LIST+=" -e '/\s*-\s+\"sirius@/ ${SUBST}" ;; cray_pm_accel_energy | cusolver_mp | spla_gemm_offloading | unified_memory) CMAKE_FEATURE_FLAGS_GPU+=" -DCP2K_USE_${2^^}=${ON_OFF}" ;; dbm_gpu | elpa_gpu | grid_gpu | pw_gpu) CMAKE_FEATURE_FLAGS_GPU+=" -DCP2K_ENABLE_${2^^}=${ON_OFF}" ;; none) # do nothing ;; *) echo "ERROR: Unknown CP2K feature \"${2}\" specified" ${EXIT_CMD} 1 ;; esac else echo "ERROR: No feature found for flag \"${1}\"" ${EXIT_CMD} 1 fi shift 2 ;; -gv | --gcc_version) if (($# > 1)); then case "${2}" in 1[0-6]) GCC_VERSION="${2}" ;; *) echo "ERROR: Invalid GCC version \"${2}\" specified (choose from 10 to 16)" ${EXIT_CMD} 1 ;; esac else echo "ERROR: No argument found for flag \"${1}\" (choose a GCC version)" ${EXIT_CMD} 1 fi shift 2 ;; -gm | -gpu | --gpu_model) if (($# > 1)); then case "${2^^}" in P100 | V100 | T400 | A100 | A40 | H100 | H200 | GH200) GPU_MODEL="${2^^}" case "${GPU_MODEL}" in P100) CUDA_SM_CODE=60 ;; V100) CUDA_SM_CODE=70 ;; T400) CUDA_SM_CODE=75 ;; A100) CUDA_SM_CODE=80 ;; A40) CUDA_SM_CODE=86 ;; H100 | H200 | GH200) CUDA_SM_CODE=90 ;; esac ;; 60 | 70 | 75 | 80 | 86 | 87 | 89 | 90 | 120 | 121) CUDA_SM_CODE=${2} ;; NONE) GPU_MODEL="${2,,}" ;; *) echo -e "\nERROR: Unknown GPU model \"${2}\" specified (choose , P100, V100, T400, A100, A40, H100, H200, GH200 or none)\n" ${EXIT_CMD} 1 ;; esac else echo -e "\nERROR: No argument found for flag \"${1}\" (choose , P100, V100, T400, A100, A40, H100, H200, GH200 or none)\n" ${EXIT_CMD} 1 fi shift 2 ;; -h | --help) HELP="yes" shift 1 ;; -ip | --install_path | --install_prefix) if (($# > 1)); then INSTALL_PREFIX="$(realpath "${2}")" else echo "ERROR: No install path argument found for flag \"${1}\"" ${EXIT_CMD} 1 fi shift 2 ;; -j) if (($# > 1)); then case "${2}" in -*) shift 1 ;; [0-9]*) NUM_PROCS="${2}" shift 2 ;; *) echo "ERROR: The -j flag can only be followed by an integer number, found \"${2}\"" ${EXIT_CMD} 1 ;; esac else shift 1 fi ;; -j[0-9]*) NUM_PROCS="${1#-j}" shift 1 ;; -mpi | --mpi_mode) if (($# > 1)); then case "${2,,}" in mpich | openmpi) CMAKE_FEATURE_FLAG_MPI="-DCP2K_USE_MPI=ON" MPI_MODE="${2,,}" ;; no | none | off) CMAKE_FEATURE_FLAG_MPI="-DCP2K_USE_MPI=OFF" MPI_MODE="no" ;; *) echo "ERROR: Unknown MPI mode \"${2}\" specified (choose mpich, openmpi, or no)" ${EXIT_CMD} 1 ;; esac else echo "ERROR: No argument found for flag \"${1}\"" echo " The MPI mode is required (choose mpich, openmpi, or no)" ${EXIT_CMD} 1 fi shift 2 ;; -np | --num_packages) if (($# > 1)); then case "${2}" in -*) shift 1 ;; [0-9]*) NUM_PACKAGES="${2}" shift 2 ;; *) echo "ERROR: The -np flag can only be followed by an integer number, found \"${2}\"" ${EXIT_CMD} 1 ;; esac else shift 1 fi ;; -opencl) USE_OPENCL="yes" shift 1 ;; -rc | --rebuild_cp2k) REBUILD_CP2K="yes" shift 1 ;; -t | --test) RUN_TEST="yes" if (($# > 1)); then TESTOPTS="${2}" else echo "ERROR: No argument found for flag \"${1}\"" echo " A string argument with the TESTOPTS (even an empty one \"\") is required" ${EXIT_CMD} 1 fi shift 2 ;; -uc | --use_cache) if (($# > 1)); then case "${2,,}" in folder | minio | no | none) USE_CACHE="${2,,}" ;; *) echo "ERROR: Invalid cache mode \"${2}\" specified (choose folder, minio or no)" ${EXIT_CMD} 1 ;; esac else echo "ERROR: No argument found for flag \"${1}\" (choose folder, minio or no)" ${EXIT_CMD} 1 fi shift 2 ;; -ue | --use_externals) USE_EXTERNALS="yes" shift 1 ;; -v | --verbose) VERBOSE=1 INSTALL_MESSAGE="LAZY" VERBOSE_FLAG="--verbose" VERBOSE_MAKEFILE="ON" VERBOSE_SPACK="--verbose" shift 1 ;; --) shift 1 break ;; -*) echo "ERROR: Unknown option \"${1}\" specified" ${EXIT_CMD} 1 ;; *) break ;; esac done # Remove leading zeros from NUM_PACKAGES and NUM_PROCS NUM_PACKAGES=$(awk '{print $1+0}' <<< "${NUM_PACKAGES}") NUM_PROCS=$(awk '{print $1+0}' <<< "${NUM_PROCS}") # Check if we are working within a docker or podman container [[ -f /.dockerenv || -f /run/.containerenv ]] && IN_CONTAINER="yes" || IN_CONTAINER="no" # Assemble CMake feature flag list CMAKE_FEATURE_FLAGS="${CMAKE_FEATURE_FLAG_ALL} ${CMAKE_FEATURE_FLAG_MPI} ${CMAKE_FEATURE_FLAGS}" # DLA-Future does not work with MPICH yet case "${MPI_MODE}" in mpich | openmpi) if [[ "${CMAKE_FEATURE_FLAGS}" == *"-DCP2K_USE_EVERYTHING=ON"* ]] || [[ "${CMAKE_FEATURE_FLAGS}" == *"-DCP2K_USE_DLAF=ON"* ]]; then echo -e "\nINFO: DLA-Future does not work with ${MPI_MODE^^} yet and is disabled" CMAKE_FEATURE_FLAGS+=" -DCP2K_USE_DLAF=OFF" SED_PATTERN_LIST+=" -e '/\s*-\s+\"dla-future.*@/ s/^ /#/'" SED_PATTERN_LIST+=" -e 's/\+dlaf/\~dlaf/'" fi ;; esac # Clean CMake feature flag list from repeated entries and keep only the last definition declare -A last=() order=() # First pass: record the last occurrence of each flag for flag in ${CMAKE_FEATURE_FLAGS}; do name=${flag%=*} last[${name}]=${flag} order+=("${name}") done # Second pass: output only the last definition per flag # but respecting original order of last appearance declare -A seen=() out=() for name in "${order[@]}"; do if [[ -z ${seen[${name}]+_} ]]; then seen[${name}]=1 out+=("${last[${name}]}") fi done CMAKE_FEATURE_FLAGS="$(printf '%s\n' "${out[*]}")" export BUILD_DEPS BUILD_DEPS_ONLY BUILD_SHARED_LIBS CMAKE_FEATURE_FLAGS CMAKE_FEATURE_FLAGS_GPU CP2K_BUILD_TYPE \ CRAY CUDA_SM_CODE DEPS_BUILD_TYPE GCC_VERSION GPU_MODEL IN_CONTAINER INSTALL_MESSAGE MPI_MODE NUM_PACKAGES \ NUM_PROCS REBUILD_CP2K RUN_TEST TESTOPTS USE_CACHE USE_OPENCL VERBOSE VERBOSE_FLAG VERBOSE_MAKEFILE VERBOSE_SPACK # Show help if requested if [[ "${HELP}" == "yes" ]]; then echo "" echo "Usage: ${SCRIPT_NAME} [-bd | --build_deps]" echo " [-bd_only | --build_deps_only]" echo " [-bp | --build_path PATH]" echo " [-bsl | --build_static_libcp2k]" echo " [-bt | --build_type (Debug | Release | RelWithDebInfo)]" echo " [-cray]" echo " [-cv | --cp2k_version (pdbg | psmp | sdbg | ssmp | ssmp-static)]" echo " [-df | --disable | --disable_feature (all | FEATURE | PACKAGE | none)" echo " [-ef | --enable | --enable_feature (all | FEATURE | PACKAGE | none)" echo " [-gm | -gpu | --gpu_model ( | P100 | V100 | T400 | A100 | H100 | H200 | GH200 | none)]" echo " [-gv | --gcc_version (10 | 11 | 12 | 13 | 14 | 15 | 16)]" echo " [-h | --help]" echo " [-ip | --install_path PATH]" echo " [-j #PROCESSES]" echo " [-mpi | --mpi_mode (mpich | no | openmpi)]" echo " [-np | --num_packages #PACKAGES]" echo " [-rc | --rebuild_cp2k]" echo " [-t | --test \"TESTOPTS\"]" echo " [-uc | --use_cache (folder | minio | no | none)]" echo " [-ue | --use_externals]" echo " [-v | --verbose]" echo "" echo "Flags:" echo " --build_deps : Force a rebuild of all CP2K dependencies from scratch (removes the spack folder)" echo " --build_deps_only : Rebuild ONLY the CP2K dependencies from scratch (removes the spack folder)" echo " --build_path : Define the CP2K build path (default: ${CP2K_ROOT})" echo " --build_static_libcp2k: Build a static CP2K library libcp2k.a instead of the default shared one libcp2k.so" echo " --build_type : Set preferred CMake build type for CP2K (default: \"Release\")" echo " --cp2k_version : CP2K version to be built (default: \"psmp\")" echo " -cray : Use Cray specific spack configuration" echo " --enable_feature : Enable feature or package (default: all)" echo " --disable_feature : Disable feature or package" echo " --help : Print this help information" echo " --gcc_version : Use the specified GCC version (default: automatically decided by spack)" echo " --gpu_model : Select GPU model (default: none)" echo " --install_path : Define the CP2K installation path (default: ./install)" echo " -j : Maximum number of processes used in parallel" echo " --mpi_mode : Set preferred MPI mode (default: \"mpich\")" echo " --num_packages : Maximum number of packages built by spack in parallel (default: 4)" echo " -opencl : Perform build with OpenCL support" echo " --rebuild_cp2k : Rebuild CP2K: removes the build folder (default: no)" echo " --test : Perform a regression test run after a successful build" echo " --use_cache : Use a \"folder\", a \"MinIO\" object storage container (requires podman) or \"no\" cache" echo " Set the environment variable SPACK_CACHE to specify the folder name, e.g." echo " SPACK_CACHE=\"file://${CP2K_ROOT}/spack_cache\" (default)" echo " --use_externals : Use external packages installed on the host system. This results in much" echo " faster build times, but it can also cause conflicts with outdated packages" echo " pulled in from the host system, e.g. old python or gcc versions" echo " --verbose : Write verbose output" echo "" echo "Hints:" echo " - Remove the folder ${CP2K_ROOT}/build to (re)build CP2K from scratch" echo " (see also --rebuild_cp2k flag)" echo " - Remove the folder ${CP2K_ROOT}/spack to (re)build CP2K and all its dependencies from scratch" echo " (see also --build_deps flag)" echo " - The folder ${CP2K_ROOT}/install is updated after each successful run" echo "" echo "Packages: all | ace | cosma | deepmd | dftd4 | dlaf | elpa | fftw3 | gauxc | greenx | hdf5 | libfci |" echo " libgint | libint | libsmeagol | libtorch | libvdwxc | libxs | mimic | openpmd | pexsi | plumed |" echo " sirius | spfft | spglib | spla | tblite | trexio | vori " echo "" echo "Features: cray_pm_accel_energy | cusolver_mp | dbm_gpu | elpa_gpu | grid_gpu | pw_gpu |" echo " spla_gemm_offloading | unified_memory" echo "" ${EXIT_CMD} fi echo "" echo "BUILD_DEPS = ${BUILD_DEPS}" echo "BUILD_DEPS_ONLY = ${BUILD_DEPS_ONLY}" echo "BUILD_PATH = ${BUILD_PATH}" echo "BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}" echo "CP2K_BUILD_TYPE = ${CP2K_BUILD_TYPE}" echo "CP2K_VERSION = ${CP2K_VERSION}" echo "CRAY = ${CRAY}" echo "DEPS_BUILD_TYPE = ${DEPS_BUILD_TYPE}" echo "GCC_VERSION = ${GCC_VERSION}" if ((CUDA_SM_CODE > 0)); then echo "GPU = ${GPU_MODEL} (CUDA SM code: ${CUDA_SM_CODE})" else echo "GPU = ${GPU_MODEL}" fi echo "INSTALL_PREFIX = ${INSTALL_PREFIX}" echo "INSTALL_MESSAGE = ${INSTALL_MESSAGE}" echo "IN_CONTAINER = ${IN_CONTAINER}" echo "MPI_MODE = ${MPI_MODE}" echo "NUM_PACKAGES = ${NUM_PACKAGES} (packages are built by spack concurrently)" echo "NUM_PROCS = ${NUM_PROCS} (processes)" echo "Physical cores = $(lscpu -p=Core,Socket | grep -v '#' | sort -u | wc -l) (host view)" echo "REBUILD_CP2K = ${REBUILD_CP2K}" echo "RUN_TEST = ${RUN_TEST}" if [[ "${RUN_TEST}" == "yes" ]]; then echo "TESTOPTS = \"${TESTOPTS}\"" fi echo "USE_CACHE = ${USE_CACHE}" echo "USE_EXTERNALS = ${USE_EXTERNALS}" echo "USE_OPENCL = ${USE_OPENCL}" echo "VERBOSE_FLAG = ${VERBOSE_FLAG}" echo "VERBOSE_MAKEFILE = ${VERBOSE_MAKEFILE}" echo "VERBOSE = ${VERBOSE}" if (($# > 0)); then echo "Remaining args =" "$@" "(not used)" fi echo "" echo "LD_LIBRARY_PATH = ${LD_LIBRARY_PATH:-}" echo "" echo "PATH = ${PATH:-}" echo "" echo "CMAKE_FEATURE_FLAGS = ${CMAKE_FEATURE_FLAGS}" echo "" ((VERBOSE > 0)) && echo -e "SED_PATTERN_LIST = ${SED_PATTERN_LIST}\n" # Check if a valid number for the packages to be built by spack in parallel is given if ((NUM_PACKAGES < 1)); then echo -e "\nERROR: The requested number of packages to be built by spack in parallel should be larger than 0, found \"${NUM_PACKAGES}\"" ${EXIT_CMD} 1 elif ((NUM_PROCS > 0)) && ((NUM_PACKAGES > NUM_PROCS)); then echo -e "\nERROR: The requested number of packages to be built in parallel by spack (${NUM_PACKAGES}) is larger than the requested number of processes (${NUM_PROCS})" ${EXIT_CMD} 1 fi # Check if a valid number of processes is requested if ((NUM_PROCS < 1)); then echo "ERROR: The requested number of processes should be larger than 0, found \"${NUM_PROCS}\"" ${EXIT_CMD} 1 elif ((MAX_PROCS > 0)) && ((NUM_PROCS > MAX_PROCS)); then echo "WARNING: The requested number of processes (${NUM_PROCS}) is larger than the detected number of CPU cores (${MAX_PROCS})" fi # Check if a valid CMake build type is selected for the dependencies case "${DEPS_BUILD_TYPE^}" in Release | RelWithDebInfo) true ;; Debug) echo "ERROR: The CMake build type \"${DEPS_BUILD_TYPE}\" is not supported for building the dependencies" ${EXIT_CMD} 1 ;; *) echo "ERROR: Invalid CMake build type \"${DEPS_BUILD_TYPE}\" selected for building the dependencies" ${EXIT_CMD} 1 ;; esac # Check if a valid CMake build type is selected for CP2K case "${CP2K_BUILD_TYPE^}" in Debug | Release | RelWithDebInfo) true ;; *) echo "ERROR: Invalid CMake build type \"${CP2K_BUILD_TYPE}\" selected for building CP2K" ${EXIT_CMD} 1 ;; esac # Check if a valid MPI type is selected case "${MPI_MODE}" in mpich | openmpi) if [[ "${CP2K_VERSION}" == "ssmp"* ]]; then echo "ERROR: MPI type \"${MPI_MODE}\" specified for building a serial CP2K binary" ${EXIT_CMD} 1 fi ;; no) if [[ "${CP2K_VERSION}" == "psmp" ]]; then echo "ERROR: MPI type \"${MPI_MODE}\" specified for building an MPI-parallel CP2K binary" ${EXIT_CMD} 1 fi ;; *) echo "ERROR: Invalid MPI type \"${MPI_MODE}\" selected" echo " Choose from (mpich | no | openmpi)" ${EXIT_CMD} 1 ;; esac # Check if CP2K_VERSION and the selected features are compatible case "${CP2K_VERSION}" in ssmp | ssmp-static) for package in cosma dlaf elpa libfabric libsmeagol mimic openpmd pexsi plumed sirius spla; do if [[ "${CMAKE_FEATURE_FLAGS}" == *" -DCP2K_USE_${package^^}=ON"* ]]; then echo -e "ERROR: The feature ${package^^} is not available for building serial CP2K binaries (${CP2K_VERSION})\n" ${EXIT_CMD} 1 fi done # Further exclusions are needed for statically linked serial CP2K binaries if [[ "${CP2K_VERSION}" == "ssmp-static" ]]; then for package in ace deepmd greenx hdf5 libgint libtorch trexio; do if [[ "${CMAKE_FEATURE_FLAGS}" == *" -DCP2K_USE_${package^^}=ON"* ]]; then echo -e "ERROR: The feature ${package^^} is not available for building statically linked serial CP2K binaries (${CP2K_VERSION})\n" ${EXIT_CMD} 1 fi done fi ;; esac # Perform CUDA GPU related settings if ((CUDA_SM_CODE > 0)); then if command -v nvcc &> /dev/null; then CUDA_VERSION=$(nvcc -V | sed -n 's/.*release \([0-9.]*\).*/\1/p') NVCC_VERSION=$(awk -v x="${CUDA_VERSION}" 'BEGIN{print 10*x}') else echo -e "\nERROR: No CUDA toolkit installation found (nvcc compiler not found)\n" ${EXIT_CMD} 1 fi # Check if the selected CUDA SM code is valid when the nvidia-smi command is available if command -v nvidia-smi &> /dev/null; then echo -e "NVIDIA driver installation found:\n" nvidia-smi HOST_CUDA_SM_CODE=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader | tail -n 1 | awk '{print 10*$1}') if ((CUDA_SM_CODE > HOST_CUDA_SM_CODE)); then echo "" echo "ERROR: The requested CUDA SM code (${CUDA_SM_CODE}) is larger than the maximum" echo " CUDA SM code (${HOST_CUDA_SM_CODE}) supported by the host system" echo "" ${EXIT_CMD} 1 fi else echo "INFO: No NVIDIA driver installation found (nvidia-smi not found)" fi # Check GPU support by the CUDA SDK if ((NVCC_VERSION < 128)) && ((CUDA_SM_CODE > 90)); then echo "" echo "ERROR: The CUDA SDK version ${NVCC_VERSION} does not support GPUs with a" echo " CUDA SM code larger than 90 (found ${CUDA_SM_CODE})" echo "" ${EXIT_CMD} 1 fi if ((NVCC_VERSION > 129)) && ((CUDA_SM_CODE < 75)); then echo "" echo "ERROR: The CUDA SDK version ${NVCC_VERSION} does not support GPUs with a" echo " CUDA SM code smaller than 75 (found ${CUDA_SM_CODE})" echo "" ${EXIT_CMD} 1 fi CMAKE_CUDA_FLAGS="-DCP2K_USE_ACCEL=CUDA" CMAKE_CUDA_FLAGS+=" -DCP2K_WITH_GPU=${GPU_MODEL}" CMAKE_CUDA_FLAGS+=" -DCMAKE_CUDA_ARCHITECTURES=${CUDA_SM_CODE}" CMAKE_CUDA_FLAGS+=" ${CMAKE_FEATURE_FLAGS_GPU}" out=() for flag in ${CMAKE_CUDA_FLAGS}; do [[ ${seen[${flag}]+_} ]] || { seen[${flag}]=1 out+=("${flag}") } done CMAKE_CUDA_FLAGS="$(printf '%s\n' "${out[*]}")" echo -e "\nCMAKE_CUDA_FLAGS = ${CMAKE_CUDA_FLAGS}" [[ -n "${CUDA_VERSION:-}" ]] && echo -e "\nCUDA_VERSION = ${CUDA_VERSION} (nvcc compiler)" [[ -n "${CUDA_HOME:-}" ]] && echo -e "\nCUDA_HOME = ${CUDA_HOME}" echo "" else CMAKE_CUDA_FLAGS="-DCP2K_USE_ACCEL=OFF" fi export CMAKE_CUDA_FLAGS # Retrieve and print available resources free -h echo "" ulimit -c 0 -s unlimited ulimit -a echo "" ### Build CP2K dependencies with Spack if needed or requested ### # Spack version export SPACK_VERSION="${SPACK_VERSION:-1.2.1}" export SPACK_BUILD_PATH="${BUILD_PATH}/spack" export SPACK_ROOT="${SPACK_BUILD_PATH}/spack" # Isolate user configuration for spack export SPACK_DISABLE_LOCAL_CONFIG=true export SPACK_USER_CONFIG_PATH="${SPACK_BUILD_PATH}" export SPACK_USER_CACHE_PATH="${SPACK_BUILD_PATH}/cache" # Define the CP2K spack configuration file export CP2K_CONFIG_FILE="${SPACK_BUILD_PATH}/cp2k_deps_${CP2K_VERSION:0:1}${CP2K_VERSION:4}.yaml" # If requested, remove the spack folder for (re)building all CP2K dependencies if [[ "${BUILD_DEPS}" == "always" ]]; then for folder in ${SPACK_BUILD_PATH} ${BUILD_PATH}/build ${INSTALL_PREFIX}; do if [[ -d "${folder}" ]]; then echo "Removing folder \"${folder}\"" rm -rf "${folder}" fi done fi # If requested, remove the build folder for (re)building CP2K if [[ "${REBUILD_CP2K}" == "yes" ]]; then for folder in ${BUILD_PATH}/build ${INSTALL_PREFIX}; do if [[ -d "${folder}" ]]; then echo "Removing folder \"${folder}\"" rm -rf "${folder}" fi done fi # An incomplete build already contains the Spack installation, source cache, # environment, and every successfully installed dependency. Re-enter the # setup/install path until the completion marker is written. if [[ ! -f "${SPACK_BUILD_PATH}/BUILD_DEPENDENCIES_COMPLETED" ]]; then if [[ -d "${SPACK_BUILD_PATH}" ]]; then echo "INFO: Resuming incomplete CP2K dependency build in ${SPACK_BUILD_PATH}" else echo "INFO: Creating local Spack build directory ${SPACK_BUILD_PATH}" fi mkdir -p "${SPACK_BUILD_PATH}" cd "${SPACK_BUILD_PATH}" || ${EXIT_CMD} 1 # Reset the spack environment unset SPACK_ENV # Install Spack only when the local bootstrap is absent. wget --continue # also retains a partially downloaded release archive across interruptions. if [[ ! -d "${SPACK_ROOT}" ]]; then echo "Installing Spack ${SPACK_VERSION}" if ! wget -q -c "https://github.com/spack/spack/archive/v${SPACK_VERSION}.tar.gz"; then echo "ERROR: Downloading Spack ${SPACK_VERSION} failed" ${EXIT_CMD} 1 fi if ! tar -xzf "v${SPACK_VERSION}.tar.gz"; then echo "ERROR: Extracting Spack ${SPACK_VERSION} failed" ${EXIT_CMD} 1 fi if ! mv -f "${SPACK_BUILD_PATH}/spack-${SPACK_VERSION}" "${SPACK_ROOT}"; then echo "ERROR: Installing Spack ${SPACK_VERSION} failed" ${EXIT_CMD} 1 fi rm -f "v${SPACK_VERSION}.tar.gz" fi export PATH="${SPACK_ROOT}/bin:${PATH}" # Create cache folder for user configuration mkdir -p "${SPACK_USER_CACHE_PATH}" # Set Spack cache (folder is the default) export SPACK_CACHE="${SPACK_CACHE:-file://${CP2K_ROOT}/spack_cache}" # Prepare for package caching if [[ "${USE_CACHE}" == @("folder"|"minio") ]]; then # Create the venv only once, then reuse it on a resumed dependency build. if [[ ! -x "${SPACK_BUILD_PATH}/venv/bin/python3" ]]; then if command -v python3 -m venv --help &> /dev/null; then echo "Installing virtual environment for Python packages" if ! python3 -m venv "${SPACK_BUILD_PATH}/venv"; then echo "ERROR: The creation of a virtual environment (venv) for Python packages failed" ${EXIT_CMD} 1 fi else echo "ERROR: python3 -m venv was not found" ${EXIT_CMD} 1 fi fi export PATH="${SPACK_BUILD_PATH}/venv/bin:${PATH}" # Avoid contacting PyPI again when the previously prepared venv is intact. if ! python3 -c 'from importlib.metadata import version; assert version("boto3") == "1.38.11"; assert version("google-cloud-storage") == "3.1.0"' &> /dev/null; then if ! python3 -m pip --version &> /dev/null; then echo "ERROR: python3 -m pip was not found" ${EXIT_CMD} 1 fi if ! python3 -m pip install "${VERBOSE_FLAG}" --upgrade pip \ boto3==1.38.11 google-cloud-storage==3.1.0; then echo "ERROR: The installation of Python packages for the Spack cache failed" ${EXIT_CMD} 1 fi fi fi # Prepare for using an MinIO object storage as cache if [[ "${USE_CACHE}" == "minio" ]]; then if [[ "${IN_CONTAINER}" == "yes" ]]; then echo "ERROR: An external MinIO object storage container cannot be used as cache within a container" echo " Use \"folder\" or \"no\" caching instead of \"MinIO\"" ${EXIT_CMD} 1 fi # MinIO requires podman if command -v podman &> /dev/null; then # Check podman version ((VERBOSE > 0)) && podman version PODMAN_VERSION=$(podman version --format '{{.Client.Version}}' | awk -F'[.-]' '{print $1}') if ((PODMAN_VERSION < 4)); then echo "WARNING: Outdated podman version $(podman version --format '{{.Client.Version}}') found" fi export SPACK_CACHE="${SPACK_CACHE:-s3://spack-cache --s3-endpoint-url=http://localhost:9000}" if ! "${CP2K_ROOT}"/tools/docker/spack_cache_start.sh; then echo "ERROR: Could not start (new) spack cache" echo "" echo "An error message starting with \"Error: initial journal cursor: ...\" indicates that the" echo "journald logging does not work. Try to switch podman (3.x) to file-based logs by creating" echo "the file \"~/.config/containers/containers.conf\" with the following two lines:" echo "[containers]" echo "log_driver = \"k8s-file\"" ${EXIT_CMD} 1 fi else echo "INFO: podman was not found" echo " Install the package podman to use an MinIO object storage as cache" echo " This accelerates a rebuild of the CP2K dependencies, significantly" echo " The folder ${SPACK_CACHE} will be used as cache" USE_CACHE="folder" fi fi # Initialize Spack shell hooks # shellcheck source=/dev/null source "${SPACK_ROOT}/share/spack/setup-env.sh" # Add spack cache as mirror if possible if [[ "${USE_CACHE}" == @("folder"|"minio") ]]; then echo "SPACK_CACHE = \"${SPACK_CACHE}\"" spack mirror list if ! spack mirror list | grep -q "local-cache"; then echo "Setting up spack cache" if ((VERBOSE > 0)); then "${CP2K_ROOT}"/tools/docker/scripts/setup_spack_cache.sh else "${CP2K_ROOT}"/tools/docker/scripts/setup_spack_cache.sh &> /dev/null fi fi else echo "INFO: A spack cache is NOT used" fi # Prepare the CP2K spack configuration file CP2K_DEPS_FILE="${CP2K_ROOT}/tools/spack/cp2k_deps_${CP2K_VERSION:0:1}${CP2K_VERSION:4}.yaml" if [[ -f "${CP2K_DEPS_FILE}" ]]; then sed -E \ -e "s|root: /opt/spack|root: ${SPACK_ROOT}/opt/spack|" \ -e "/\"build_type=/s|build_type=[^\"]*|build_type=${DEPS_BUILD_TYPE}|" \ "${CP2K_DEPS_FILE}" > "${CP2K_CONFIG_FILE}" else echo -e "\nERROR: The spack configuration file ${CP2K_DEPS_FILE} was not found\n" ${EXIT_CMD} 1 fi # Apply selected MPI type if needed # MPICH is selected by default for psmp and no change needed for ssmp if [[ "${MPI_MODE}" == "openmpi" ]]; then sed -E \ -e '/\s*-\s+"mpich@/ s/^ /#/' \ -e '/\s*#\s*-\s+"openmpi@/ s/#/ /' \ -e '/\s*-\s+mpich/ s/mpich$/openmpi/' \ -i "${CP2K_CONFIG_FILE}" fi # Activate CUDA in the spack configuration file if requested if ((CUDA_SM_CODE > 0)); then sed -E \ -e "0,/~cuda/s//+cuda cuda_arch=${CUDA_SM_CODE}/" \ -e 's/"~cuda\s+~gpu_direct"/"\+cuda \+gpu_direct"/' \ -e '/\s*#\s*-\s+"fabrics=efa,ucx"/ s/#/ /' \ -e '/\s*#\s*-\s+"libxstream@/ s/#/ /' \ -i "${CP2K_CONFIG_FILE}" # Building libfabric with CUDA causes problems # sed -E -e 's/"~cuda\s+~gdrcopy"/"\+cuda \+gdrcopy"/' -i "${CP2K_CONFIG_FILE}" sed -E -e 's/"~cuda\s+~gdrcopy"/"\~cuda"/' -i "${CP2K_CONFIG_FILE}" if [[ -n "${CUDA_VERSION:-}" ]]; then # Set CUDA SM code sed -E -e "s/spec:\s+cuda@[.0-9]*/spec: cuda@${CUDA_VERSION}/" -i "${CP2K_CONFIG_FILE}" fi if [[ -n "${CUDA_HOME:-}" ]]; then sed -E -e "s|prefix: /usr/local/cuda|prefix: ${CUDA_HOME}|" -i "${CP2K_CONFIG_FILE}" fi else sed -E -e 's/"~cuda\s+~gdrcopy"/"\~cuda"/' -i "${CP2K_CONFIG_FILE}" fi # CUDA is required for libgint is requested if [[ "${CMAKE_CUDA_FLAGS}" == *"-DCP2K_USE_ACCEL=CUDA"* ]]; then if [[ "${CMAKE_FEATURE_FLAGS}" == *"-DCP2K_USE_EVERYTHING=ON"* ]] || [[ "${CMAKE_FEATURE_FLAGS}" == *"-DCP2K_USE_LIBGINT=ON"* ]]; then sed -E \ -e '/\s*#\s*-\s+"libgint@/ s/#/ /' \ -i "${CP2K_CONFIG_FILE}" fi fi # Activate OpenCL support if requested if [[ "${USE_OPENCL}" == "yes" ]]; then sed -E \ -e 's/"~opencl"/"+opencl"/' \ -e '/\s*#\s*-\s+"libxstream@/ s/#/ /' \ -i "${CP2K_CONFIG_FILE}" fi # Apply Cray specific adaptation of the spack configuration if requested (CSCS) if [[ "${CRAY}" == "yes" ]]; then sed -E \ -e '/\s*#\s*-\s+"netmod=ofi"/ s/#/ /' \ -e 's/~xpmem/+xpmem/' \ -e 's/"libfabric@[.0-9]*"/"libfabric@1.22.0"/' \ -i "${CP2K_CONFIG_FILE}" fi # Apply feature selection to spack configuration file if [[ -n "${SED_PATTERN_LIST}" ]]; then eval sed -E "${SED_PATTERN_LIST}" -i "${CP2K_CONFIG_FILE}" fi # Find all compilers echo "Searching for GCC compilers" if ! spack compiler find &> /dev/null; then echo "ERROR: The compiler detection of spack failed" ${EXIT_CMD} 1 fi spack compiler list # Retrieve the newest compiler version found by spack GCC_VERSION_NEWEST="$(spack compilers | sed -nE 's/.*gcc@([0-9]+(\.[0-9]+)*).*/\1/p' | sort -V | tail -n 1)" echo "The newest GCC compiler version found by spack is ${GCC_VERSION_NEWEST}" GCC_VERSION_NEWEST="$(echo "${GCC_VERSION_NEWEST}" | sed -E -e 's/.*@([0-9]+).*/\1/' | cut -d. -f1)" # Check if the newest compiler version found on the host system is new enough GCC_VERSION_MINIMUM="10" if ((GCC_VERSION_NEWEST < GCC_VERSION_MINIMUM)); then echo "INFO: The newest GCC compiler version ${GCC_VERSION_NEWEST} is too old," echo " because at least version ${GCC_VERSION_MINIMUM} is required" GCC_VERSION="14" echo "INFO: The lastest stable GCC version ${GCC_VERSION} will be built and used by spack" fi # Add a specific GCC version to the spack configuration if requested if [[ "${GCC_VERSION}" == "auto" ]]; then echo "Spack will automatically select the GCC version which is not necessarily the newest one found" else sed -E -e "s/gcc@10:/gcc@${GCC_VERSION}/" -i "${CP2K_CONFIG_FILE}" fi # Disable PEXSI because of an issue with SuperLU using GCC version 15 if ((CUDA_SM_CODE > 0)) || ((GCC_VERSION_NEWEST > 14)); then sed -E -e '/\s*-\s+"pexsi@/ s/^ /#/' -i "${CP2K_CONFIG_FILE}" echo "INFO: PEXSI has been disabled because CUDA or GCC 15 is used" fi # Create CP2K environment if needed if spack env list | grep -q "${CP2K_ENV}"; then echo "The Spack environment \"${CP2K_ENV}\" exists already" else cat "${CP2K_CONFIG_FILE}" echo "The Spack environment \"${CP2K_ENV}\" does NOT exist" if spack env create "${CP2K_ENV}" "${CP2K_CONFIG_FILE}" &> /dev/null; then echo "The Spack environment \"${CP2K_ENV}\" has been created" else echo "ERROR: The creation of the Spack environment \"${CP2K_ENV}\" failed" ${EXIT_CMD} 1 fi fi # Activate CP2K environment if needed if spack env activate "${CP2K_ENV}" &> /dev/null; then echo "The Spack environment \"${CP2K_ENV}\" has been activated" else echo "ERROR: The activation of the Spack environment \"${CP2K_ENV}\" failed" ${EXIT_CMD} 1 fi # Update the repo builtin if ! spack repo update; then echo "ERROR: The update of the repo builtin failed" ${EXIT_CMD} 1 fi # Add the local CP2K development Spack repository when missing export CP2K_REPO="cp2k_dev" if ! spack repo list | grep -q "${CP2K_REPO}"; then spack repo add --scope "env:${CP2K_ENV}" "${CP2K_ROOT}/tools/spack/spack_repo/${CP2K_REPO}" else echo "The CP2K development repo ${CP2K_REPO} is already present ... skipping add" fi spack -e ${CP2K_ENV} repo list # Find all external packages if [[ "${USE_EXTERNALS}" == "yes" ]]; then if ! spack -C "${SPACK_USER_CONFIG_PATH}" external find; then echo -e "\nERROR: The detection of externals by spack failed" ${EXIT_CMD} 1 fi # Concretize CP2K dependencies if ! spack -e "${CP2K_ENV}" concretize --fresh --jobs "${NUM_PROCS}"; then echo -e "\nERROR: The spack concretize for environment \"${CP2K_ENV}\" failed" echo "" echo "HINT: The (-ue | --use_externals) flags can cause conflicts with outdated" echo " packages on the host system, e.g. old python or gcc versions" echo "" ${EXIT_CMD} 1 fi else # If the installation of a specific GCC version for building CP2K is requested, # then an installation of the same GCC version on the host system has to be removed # from the configuration for a static build of CP2K if [[ "${CP2K_VERSION}" == *"-static" ]]; then if spack compilers | grep -q "gcc@${GCC_VERSION}"; then echo "INFO: A static build of CP2K with GCC ${GCC_VERSION} is requested without using" echo " any externals which requires to build that GCC version with spack" echo " while removing a gcc@${GCC_VERSION} installed on the host from the spack" echo " configuration at the same time" if ! spack compiler remove "gcc@${GCC_VERSION}"; then echo -e "\nERROR: Removing the gcc@${GCC_VERSION} compiler failed" ${EXIT_CMD} 1 else echo -e "\nINFO: gcc@${GCC_VERSION} compiler removed" fi spack compiler list fi fi if ! spack -e "${CP2K_ENV}" concretize --fresh --jobs "${NUM_PROCS}"; then echo -e "\nERROR: The spack concretize for environment \"${CP2K_ENV}\" failed" ${EXIT_CMD} 1 fi fi ((VERBOSE > 0)) && spack find -c # Install CP2K dependencies via Spack if ! spack -e "${CP2K_ENV}" install -j "${NUM_PROCS}" -p "${NUM_PACKAGES}" "${VERBOSE_SPACK}"; then echo "ERROR: Building the CP2K dependencies with spack failed" if [[ "${USE_EXTERNALS}" == "yes" ]]; then echo "HINT: Try to re-run the build without the (-ue | --use_externals) flag which avoids" echo " errors or conflicts caused by externals from the host system" fi ${EXIT_CMD} 1 fi # Find all compilers if ! spack compiler find; then echo "ERROR: The compiler detection of spack failed" ${EXIT_CMD} 1 fi # Fix Libs list in elpa pkg-config file when CUDA is used if ((CUDA_SM_CODE > 0)); then ELPA_PKG_CONFIG_FILE="$(find -L "${SPACK_ROOT}/opt/spack/view" -name "elpa*.pc")" if [[ -f "${ELPA_PKG_CONFIG_FILE}" ]]; then sed -E -e 's|Libs: |Libs: -L/usr/local/cuda/lib64 |' -i "${ELPA_PKG_CONFIG_FILE}" fi fi # Return from spack folder after all installations are done cd "${CP2K_ROOT}" || ${EXIT_CMD} 1 # Make a note of the successful build touch "${SPACK_BUILD_PATH}/BUILD_DEPENDENCIES_COMPLETED" echo -e '\n*** Installation of CP2K dependencies completed ***\n' else # Initialize Spack shell hooks # shellcheck source=/dev/null source "${SPACK_ROOT}"/share/spack/setup-env.sh fi # Quit after (re)building all CP2K dependencies if requested if [[ "${BUILD_DEPS_ONLY}" == "yes" ]]; then ${EXIT_CMD} fi ### End of build CP2K dependencies ### ### Build CP2K ### if spack env list | grep -q "${CP2K_ENV}"; then spack env list else echo "ERROR: No Spack environment \"${CP2K_ENV}\" found" ${EXIT_CMD} 1 fi # Activate spack environment eval "$(spack env activate --sh ${CP2K_ENV})" spack env status # CMake configuration step export CMAKE_BUILD_PATH="${BUILD_PATH}/build" # PyTorch's TorchConfig.cmake is buried in the Python site-packages directory Torch_DIR="$(dirname "$(find "${SPACK_ROOT}" ! -type l -name TorchConfig.cmake | tail -n 1)")" export Torch_DIR # Check if PEXSI was built if [[ "${MPI_MODE}" != "no" ]]; then CP2K_USE_PEXSI="$(grep -Eq '\s*#\s*-\s+"pexsi@' "${CP2K_CONFIG_FILE}" && echo OFF || echo ON)" else CP2K_USE_PEXSI="ON" fi export CP2K_USE_PEXSI if [[ ! -d "${CMAKE_BUILD_PATH}" ]]; then mkdir -p "${CMAKE_BUILD_PATH}" case "${CP2K_VERSION}" in pdbg | psmp) # shellcheck disable=SC2086 cmake -S "${CP2K_ROOT}" -B "${CMAKE_BUILD_PATH}" \ -GNinja \ -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ -DCMAKE_BUILD_TYPE="${CP2K_BUILD_TYPE}" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ -DCMAKE_INSTALL_MESSAGE="${INSTALL_MESSAGE}" \ -DCMAKE_SKIP_RPATH="ON" \ -DCMAKE_VERBOSE_MAKEFILE="${VERBOSE_MAKEFILE}" \ ${CMAKE_FEATURE_FLAGS} \ -DCP2K_USE_PEXSI="${CP2K_USE_PEXSI}" \ ${CMAKE_CUDA_FLAGS} \ -Werror=dev |& tee "${CMAKE_BUILD_PATH}/cmake.log" EXIT_CODE=$? ;; sdbg | ssmp) # shellcheck disable=SC2086 cmake -S "${CP2K_ROOT}" -B "${CMAKE_BUILD_PATH}" \ -GNinja \ -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} \ -DCMAKE_BUILD_TYPE="${CP2K_BUILD_TYPE}" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ -DCMAKE_INSTALL_MESSAGE="${INSTALL_MESSAGE}" \ -DCMAKE_SKIP_RPATH="ON" \ -DCMAKE_VERBOSE_MAKEFILE="${VERBOSE_MAKEFILE}" \ ${CMAKE_FEATURE_FLAGS} \ ${CMAKE_CUDA_FLAGS} \ -Werror=dev |& tee "${CMAKE_BUILD_PATH}/cmake.log" EXIT_CODE=$? ;; ssmp-static) # Find some static libraries in advance LIBOPENBLAS=$(find -L "${SPACK_ROOT}"/opt/spack/view -name libopenblas.a) LIBM="$(find /usr -name libm.a 2> /dev/null)" # shellcheck disable=SC2086 cmake -S "${CP2K_ROOT}" -B "${CMAKE_BUILD_PATH}" \ -GNinja \ -DBUILD_SHARED_LIBS="OFF" \ -DCMAKE_BUILD_TYPE="${CP2K_BUILD_TYPE}" \ -DCMAKE_EXE_LINKER_FLAGS="-static" \ -DCMAKE_FIND_LIBRARY_SUFFIXES=".a" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ -DCMAKE_INSTALL_MESSAGE="${INSTALL_MESSAGE}" \ -DCMAKE_SKIP_RPATH="ON" \ -DCMAKE_VERBOSE_MAKEFILE="${VERBOSE_MAKEFILE}" \ -DCP2K_BLAS_LINK_LIBRARIES="${LIBOPENBLAS};${LIBM}" \ -DCP2K_LAPACK_LINK_LIBRARIES="${LIBOPENBLAS};${LIBM}" \ ${CMAKE_FEATURE_FLAGS} \ -Werror=dev |& tee "${CMAKE_BUILD_PATH}/cmake.log" EXIT_CODE=$? # It is almost impossible to avoid that shared libraries are pulled in # when the CP2K dependencies are built and thus just change all shared # to static libraries hoping that these are also available sed -E -e "s/\.so/.a/g" -i build/build.ninja ;; *) echo "ERROR: Unknown CP2K version ${CP2K_VERSION} specified" ${EXIT_CMD} 1 ;; esac if ((EXIT_CODE != 0)); then echo "ERROR: The CMake configuration step failed with the error code ${EXIT_CODE}" echo " You can try to remove the build folder with 'rm -rf build' and re-run" echo " or even start the whole CP2K installation from scratch with the \"-bd\" flag" ${EXIT_CMD} "${EXIT_CODE}" fi fi # CMake build step echo -e '\n*** Compiling CP2K ***\n' cmake --build "${CMAKE_BUILD_PATH}" --parallel "${NUM_PROCS}" -- "${VERBOSE_FLAG}" |& tee "${CMAKE_BUILD_PATH}"/ninja.log EXIT_CODE=${PIPESTATUS[0]} if ((EXIT_CODE != 0)); then echo "ERROR: The CMake build step failed with the error code ${EXIT_CODE}" ${EXIT_CMD} "${EXIT_CODE}" fi # CMake install step echo -e '\n*** Installing CP2K ***\n' cmake --install "${CMAKE_BUILD_PATH}" |& tee "${CMAKE_BUILD_PATH}"/install.log EXIT_CODE=${PIPESTATUS[0]} if ((EXIT_CODE != 0)); then echo -e "\nERROR: The CMake installation step failed with the error code ${EXIT_CODE}" ${EXIT_CMD} "${EXIT_CODE}" fi # Install Skala resource files if needed export GAUXC_SKALA_MODEL="(not available)" if spack location -i gauxc &> /dev/null; then GAUXC_PATH="share/gauxc/onedft_models" GAUXC_PREFIX="$(spack location -i gauxc)" GAUXC_MODEL_SOURCE_PATH="${GAUXC_PREFIX%/}/${GAUXC_PATH}" if [[ -d "${GAUXC_MODEL_SOURCE_PATH}" ]]; then GAUXC_MODEL_TARGET_PATH="${INSTALL_PREFIX%/}/${GAUXC_PATH}" mkdir -p "${GAUXC_MODEL_TARGET_PATH}" if compgen -G "${GAUXC_MODEL_SOURCE_PATH}/*.fun" > /dev/null; then cp "${GAUXC_MODEL_SOURCE_PATH}"/*.fun "${GAUXC_MODEL_TARGET_PATH}/" else echo -e "\nERROR: No GauXC model files found in source folder ${GAUXC_MODEL_SOURCE_PATH}" ${EXIT_CMD} 1 fi shopt -s nullglob MATCHES=("${GAUXC_MODEL_TARGET_PATH}"/skala*) shopt -u nullglob if ((${#MATCHES[@]} > 0)); then export GAUXC_SKALA_MODEL="${MATCHES[${#MATCHES[@]} - 1]}" else echo -e "\nERROR: Failed to resolve GAUXC_SKALA_MODEL in target path ${GAUXC_MODEL_TARGET_PATH}" ${EXIT_CMD} 1 fi fi fi echo -e "\nGAUXC_SKALA_MODEL = ${GAUXC_SKALA_MODEL}" # Collect and compress all log files when building within a container if [[ "${IN_CONTAINER}" == "yes" ]]; then if ! cat "${CMAKE_BUILD_PATH}"/cmake.log \ "${CMAKE_BUILD_PATH}"/ninja.log \ "${CMAKE_BUILD_PATH}"/install.log | gzip > "${CP2K_ROOT}"/install/build_cp2k.log.gz; then echo -e "\nERROR: The compressed log file generation failed" ${EXIT_CMD} 1 fi fi # Cut extension from the CP2K version (e.g. ssmp-static -> ssmp) export VERSION=${CP2K_VERSION%%-*} # Add CP2K lib folder to the LD_LIBRARY_PATH export LD_LIBRARY_PATH="${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH}" # Assemble search paths for libraries search_paths="${SPACK_ROOT}/opt/spack/view ${INSTALL_PREFIX}/lib" # Retrieve paths to all libraries needed by the CP2k binary for library in $(readelf -d "${INSTALL_PREFIX}/bin/cp2k.${VERSION}" "${INSTALL_PREFIX}"/lib/libcp2k.* | awk '/NEEDED/{print $5}' | tr -d '[]' | sort | uniq); do # Search for missing library path if ! ldconfig -p | grep -qE "/${library}$"; then # shellcheck disable=SC2086 library_with_path=$(find -L ${search_paths} -name "${library}" | tail -n 1) if [[ -n "${library_with_path}" ]]; then library_path="$(dirname "${library_with_path}")" case ":${LD_LIBRARY_PATH}:" in *":${library_path}:"*) ((VERBOSE > 1)) && echo "The library path ${library_path} is already present ... skipping" ;; *) LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${library_path}" ((VERBOSE > 0)) && echo "The library path ${library_path} was appended to LD_LIBRARY_PATH" ;; esac fi fi done export LD_LIBRARY_PATH echo -e "\nLD_LIBRARY_PATH = \"${LD_LIBRARY_PATH}\"" # Create an ld configuration file for CP2K because LD_LIBRARY_PATH is fragile if [[ "${IN_CONTAINER}" == "yes" ]]; then CP2K_LD_CONF_FILE="/etc/ld.so.conf.d/cp2k.conf" else CP2K_LD_CONF_FILE="${INSTALL_PREFIX}/bin/cp2k.conf" fi # Either read LD_LIBRARY_PATH from an existing configuration file or write a new one if [[ -f "${CP2K_LD_CONF_FILE}" ]]; then # Load LD_LIBRARY_PATH from an existing configuration file LD_LIBRARY_PATH="$(grep -E '^/' "${CP2K_LD_CONF_FILE}" | paste -sd ':' -)" else # Write LD_LIBRARY_PATH to a new configuration file echo "${LD_LIBRARY_PATH}" | tr ':' '\n' | grep '^/' > "${CP2K_LD_CONF_FILE}" fi export LD_LIBRARY_PATH # Create links to CP2K binaries cd "${INSTALL_PREFIX}"/bin || ${EXIT_CMD} 1 for binary in *."${VERSION}"; do if ! ln -sf "${binary}" "${binary%%."${VERSION}"}"; then echo "ERROR: The creation of a symbolic link for the binary ${binary} failed" ${EXIT_CMD} fi done ln -sf cp2k."${VERSION}" cp2k_shell cd "${CP2K_ROOT}" || ${EXIT_CMD} 1 # Configure Open MPI environment for local CP2K runs if [[ "${MPI_MODE}" == "openmpi" ]]; then OMPI_VARS="export OMPI_MCA_plm_rsh_agent=/bin/false PRTE_MCA_hwloc_default_binding_policy=none" if [[ "${IN_CONTAINER}" == "yes" ]]; then OMPI_VARS="${OMPI_VARS} OMPI_ALLOW_RUN_AS_ROOT=1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1" OMPI_VARS="${OMPI_VARS} OMPI_MCA_mpi_yield_when_idle=1 OMPI_MCA_btl=self,sm OMPI_MCA_pml=ob1" fi else OMPI_VARS="" fi export OMPI_VARS # MPICH and OpenMPI have different flags for exporting environment variables to MPI ranks if [[ "${MPI_MODE}" == "openmpi" ]]; then ENV_VAR_FLAG="-x" else ENV_VAR_FLAG="-genv" fi export ENV_VAR_FLAG # Install LSAN suppressions (only needed for dbg binaries) cp "${CP2K_ROOT}"/tools/spack/lsan.supp "${INSTALL_PREFIX}"/bin # Assemble flags for running the regression tests TESTOPTS="--cp2kdatadir ${INSTALL_PREFIX}/share/cp2k/data --maxtasks ${NUM_PROCS} --workbasedir ${INSTALL_PREFIX}/regtesting ${TESTOPTS}" export TESTOPTS # Create launch script for environment setup LAUNCH_SCRIPT="${INSTALL_PREFIX}"/bin/launch export LAUNCH_SCRIPT cat << *** > "${LAUNCH_SCRIPT}" #!/bin/bash ulimit -c 0 -s unlimited export ASAN_OPTIONS="detect_leaks=1" export LSAN_OPTIONS="suppressions=${INSTALL_PREFIX}/bin/lsan.supp" export PATH=${INSTALL_PREFIX}/bin:${PATH} export LD_LIBRARY_PATH=${LD_LIBRARY_PATH} export OMP_NUM_THREADS=\${OMP_NUM_THREADS:-2} export OMP_STACKSIZE=256M ${OMPI_VARS} export GAUXC_SKALA_MODEL=${GAUXC_SKALA_MODEL} exec "\$@" *** chmod 750 "${LAUNCH_SCRIPT}" # Create shortcut for launching the regression tests cat << *** > "${INSTALL_PREFIX}"/bin/run_tests #!/bin/bash if [[ "${VERSION}" =~ ^(s|p)dbg$ ]]; then echo "ASAN_OPTIONS = \${ASAN_OPTIONS}" echo "LSAN_OPTIONS = \${LSAN_OPTIONS}" fi ldd -- ${INSTALL_PREFIX}/bin/cp2k.${VERSION} 2>&1 | grep -E 'not ' | sort | uniq export GAUXC_SKALA_MODEL=${GAUXC_SKALA_MODEL} ${CP2K_ROOT}/tests/do_regtest.py ${TESTOPTS} \$* ${INSTALL_PREFIX}/bin ${VERSION} *** chmod 750 "${INSTALL_PREFIX}"/bin/run_tests # Set image tag if available export IMAGE_TAG=${IMAGE_TAG:-} # Optionally, launch test run if [[ "${RUN_TEST}" == "yes" ]]; then echo -e "\n*** Launching regression test run using the script ${INSTALL_PREFIX}/bin/run_tests\n" ${LAUNCH_SCRIPT} run_tests EXIT_CODE=$? if ((EXIT_CODE != 0)); then echo "ERROR: The regression test run failed with the error code ${EXIT_CODE}" ${EXIT_CMD} "${EXIT_CODE}" fi else if [[ "${IN_CONTAINER}" == "yes" ]]; then if ((CUDA_SM_CODE > 0)); then DEVICE_FLAG=" --device nvidia.com/gpu=all" else DEVICE_FLAG="" fi echo "" echo "*** A regression test run can be launched with" echo " podman run -it${DEVICE_FLAG} --rm ${IMAGE_TAG} run_tests" echo "" if [[ "${VERSION}" == @(sdbg|ssmp) ]]; then echo "*** A CP2K run using 2 OpenMP threads (default) can be launched with" echo " podman run -it${DEVICE_FLAG} --rm ${IMAGE_TAG} cp2k ${CP2K_ROOT}/benchmarks/CI/H2O-32_md.inp" else echo "*** An MPI-parallel CP2K run using 2 OpenMP threads for each of the 4 MPI ranks can be launched with" echo " podman run -it${DEVICE_FLAG} --rm ${IMAGE_TAG} mpiexec -n 4 ${ENV_VAR_FLAG} OMP_NUM_THREADS=2 cp2k ${CP2K_ROOT}/benchmarks/CI/H2O-32_md.inp" fi echo "" else echo "" echo "*** A regression test run can be launched with" echo " ${LAUNCH_SCRIPT} run_tests" echo "" if [[ "${VERSION}" == @(sdbg|ssmp) ]]; then echo "*** A CP2K run using 2 OpenMP threads (default) can be launched with" echo " ${LAUNCH_SCRIPT} cp2k ${CP2K_ROOT}/benchmarks/CI/H2O-32_md.inp" echo "" echo "*** A CP2K run using only 4 OpenMP threads can be launched with" echo " export OMP_NUM_THREADS=4; ${LAUNCH_SCRIPT} cp2k ${CP2K_ROOT}/benchmarks/CI/H2O-32_md.inp" else echo "*** An MPI-parallel CP2K run using 2 OpenMP threads for each of the 4 MPI ranks can be launched with" echo " export OMP_NUM_THREADS=2; ${LAUNCH_SCRIPT} mpiexec -n 4 cp2k ${CP2K_ROOT}/benchmarks/CI/H2O-32_md.inp" fi echo "" fi fi