cp2k/tools/toolchain/build_cp2k.sh
SY Wang f577188f47
Toolchain: Replace "scripts/generate_cmake_options.sh" with "build_cp2k.sh" (#5080)
Co-authored-by: HE Zilong <159878975+he-zilong@users.noreply.github.com>
2026-04-26 12:40:37 +02:00

282 lines
10 KiB
Bash
Executable file

#!/bin/bash -e
# shellcheck disable=all
[ "${BASH_SOURCE[0]}" ] && SCRIPT_NAME="${BASH_SOURCE[0]}" || SCRIPT_NAME=$0
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_NAME")" && pwd -P)"
TOOLCHAIN_ROOTDIR="${PWD}"
# Exit this script if it is not called from the ./tools/toolchain directory
if [ "${TOOLCHAIN_ROOTDIR}" != "${SCRIPT_DIR}" ]; then
cat << EOF
ERROR: Incorrect execution location.
The absolute path of the build_cp2k.sh script is at:
${SCRIPT_DIR}
Actual working directory where it is currently called:
${TOOLCHAIN_ROOTDIR}
Please enter the absolute path above before executing the build_cp2k.sh script
so that subsequent scripts can be found and files can be placed correctly.
EOF
exit 1
fi
TOOLCHAIN_SCRIPTS_DIR="${TOOLCHAIN_ROOTDIR}/scripts"
source "${TOOLCHAIN_ROOTDIR}/toolchain_settings"
source "${TOOLCHAIN_SCRIPTS_DIR}/tool_kit.sh"
# ====================== Parameter parsing ======================
CP2K_ROOT=$(cd "${TOOLCHAIN_ROOTDIR}/../.." && pwd)
CMAKE_INSTALL_PREFIX=${CP2K_ROOT}/install
CLEAN_BUILD="__FALSE__"
BUILD_JOBS="$(get_nprocs)"
BUILD_SHARED_LIBS="ON"
DRY_RUN="__FALSE__"
show_help() {
cat << EOF
Usage: $(basename "$0") [OPTIONS]
Generate CMake options from the toolchain configuration and build CP2K.
Options:
-h, --help Show this help message and exit
-j N, -jN Number of parallel build jobs
--prefix Set CMAKE_INSTALL_PREFIX (default is ${CP2K_ROOT}/install)
--dry-run Show generated CMake options only and then exit
--clean Remove the build directory before configuring, which means
rebuilding CP2K entirely
--build-static Set -DBUILD_SHARED_LIBS=OFF (default is ON)
EOF
}
while [ $# -ge 1 ]; do
case "$1" in
--dry-run)
DRY_RUN="__TRUE__"
;;
--clean)
CLEAN_BUILD="__TRUE__"
;;
-j)
BUILD_JOBS="$2"
shift
;;
-j[0-9]*)
BUILD_JOBS="${1#-j}"
;;
--prefix)
if [[ "${2}" != /* ]]; then
report_error "The path for --prefix must be an absolute path."
exit 1
fi
CMAKE_INSTALL_PREFIX="${2}"
shift
;;
--build-static)
BUILD_SHARED_LIBS="OFF"
;;
-h | --help)
show_help
exit 0
;;
*)
echo "ERROR: Unknown option: $1"
show_help
exit 1
;;
esac
shift
done
# ====================== Pre-checks ======================
# Require complete source tree
# A minimum working environment for this script should be as follows (assuming out-of-tree build not required):
# cp2k <- variable ${CP2K_ROOT}; CMake option -S
# ├── CMakeLists.txt <- file to be parsed for generating cmake options
# ├── cmake <- directory containing CMake files
# ├── data <- CP2K data directory; CMake option -DCP2K_DATA_DIR\
# ├── build <- to-be-created; CMake option -B
# ├── install <- to-be-created; CMake option -DCMAKE_INSTALL_PREFIX
# ├── src <- CP2K source code directory
# └── tools
# └── toolchain <- working directory; variable ${TOOLCHAIN_ROOTDIR}
# ├── build_cp2k.sh <- this script
# ├── install_cp2k_toolchain.sh <- script being executed before calling this script
# ├── scripts <- directory with toolchain scripts; ${TOOLCHAIN_SCRIPTS_DIR}
# │ └── tool_kit.sh
# └── install <- directory with installed dependencies; ${TOOLCHAIN_INSTALL_DIR}
# ├── setup <- * file to be used for building CP2K
# ├── toolchain.conf <- * file to be parsed for generating cmake options
# └── toolchain.env <- * file to be parsed for generating cmake options (MPI_F08)
#
if [ -d "${CP2K_ROOT}/src" ]; then
echo "Root directory of CP2K with source code is found as ${CP2K_ROOT}"
echo "(path is exported to variable \${CP2K_ROOT})."
else
report_error ${LINENO} "\${CP2K_ROOT} does not have subdirectory src."
exit 1
fi
if [ -f "${CP2K_ROOT}/CMakeLists.txt" ] && [ -r "${CP2K_ROOT}/CMakeLists.txt" ]; then
echo "\${CP2K_ROOT}/CMakeLists.txt exists; will be parsed for CMake options."
else
report_error ${LINENO} "\${CP2K_ROOT}/CMakeLists.txt cannot be found or read."
exit 1
fi
if [ -d "${CP2K_ROOT}/data" ]; then
echo "Data directory ${CP2K_ROOT}/data is found."
else
report_error ${LINENO} "Data directory \${CP2K_ROOT}/data cannot be found."
exit 1
fi
# Require finished toolchain
if [ ! -f "${TOOLCHAIN_INSTALL_DIR}/setup" ]; then
echo "Error: Toolchain is not installed. Please run ./install_cp2k_toolchain.sh first."
exit 1
fi
# Disallow combination of installing toolchain outside the source tree and CP2K under the source tree
if [ "${TOOLCHAIN_INSTALL_DIR}" != "${TOOLCHAIN_ROOTDIR}"/install ] &&
[[ ${CMAKE_INSTALL_PREFIX} == ${CP2K_ROOT}/* ]]; then
echo
cat << EOF
ERROR: You toolchain installation is outside the source tree but the install
prefix of CP2K is under the source tree, which is disallowed by this script.
The script will now abort; please manually set "--prefix" to a proper path.
EOF
exit 1
fi
# Load toolchain environment (required for with_xxx variables)
source "${TOOLCHAIN_INSTALL_DIR}/setup"
source "${TOOLCHAIN_INSTALL_DIR}/toolchain.conf"
printf "========================== %s =========================\n" \
"Generating CMake options from toolchain"
# Generate cmake options for compiling cp2k
CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}"
if [[ ${CMAKE_INSTALL_PREFIX} == ${CP2K_ROOT}/* ]]; then
CMAKE_OPTIONS+=" -DCP2K_DATA_DIR=${CP2K_ROOT}/data"
fi
if [ -n "$(grep -- "--install-all" "${TOOLCHAIN_INSTALL_DIR}/setup")" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_EVERYTHING=ON -DCP2K_USE_DLAF=OFF -DCP2K_USE_PEXSI=OFF"
for toolchain_option in $(grep -i "dontuse" "${TOOLCHAIN_INSTALL_DIR}/toolchain.conf" |
grep -Evi "gcc|amd|intel" | cut -d'_' -f2 | cut -d'=' -f1); do
var_name="with_${toolchain_option}"
if [ "${!var_name}" != "__DONTUSE__" ]; then
ADDED_CMAKE_OPTION=$(sed -n '/option(/,/)/p' "${CP2K_ROOT}/CMakeLists.txt" |
grep -i "${toolchain_option}" | awk '{print $1}' | cut -d'(' -f2 | head -n 1)
# Use "if-then" below can avoid generating empty "-D=OFF" options
if [ -n "${ADDED_CMAKE_OPTION}" ]; then
CMAKE_OPTIONS+=" -D${ADDED_CMAKE_OPTION}=OFF"
fi
fi
done
else
# If MPI is used, set "CP2K_USE_MPI" to "ON"
if [ "${mpi_mode}" != "no" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_MPI=ON -DCP2K_USE_MPI_F08=ON"
fi
# Some options that should be specially considered:
# Intel MKL includes FFTW
if [ "${with_fftw}" != "__DONTUSE__" ] || [ "${MATH_MODE}" = "mkl" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_FFTW3=ON"
fi
# Mimic-MCL (MiMiC Communication Library)
if [ "${with_mcl}" != "__DONTUSE__" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_MIMIC=ON"
fi
# Detect if any other dependencies is used and add the proper cmake option
# Since "pugixml" and "gsl" are not mentioned in CMakeLists.txt, they will not be considered.
for toolchain_option in $(grep "with" "${TOOLCHAIN_INSTALL_DIR}"/toolchain.conf |
grep -Evi "dontuse|gcc|amd|intel|cmake|fftw|mkl|dbcsr" | cut -d'_' -f2 | cut -d'=' -f1); do
var_name="with_${toolchain_option}"
if [ "${!var_name}" != "__DONTUSE__" ]; then
ADDED_CMAKE_OPTION=$(sed -n '/option(/,/)/p' "${CP2K_ROOT}/CMakeLists.txt" |
grep -i "${toolchain_option}" | awk '{print $1}' | cut -d'(' -f2 | head -n 1)
# Use "if-then" below can avoid generating empty "-D=ON" options
if [ -n "${ADDED_CMAKE_OPTION}" ]; then
CMAKE_OPTIONS+=" -D${ADDED_CMAKE_OPTION}=ON"
fi
fi
done
fi
# If GPU acceleration is used, add the option about GPU acceleration
if [ "${enable_cuda}" = "__TRUE__" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_ACCEL=CUDA -DCP2K_WITH_GPU=${gpu_ver}"
elif [ "${enable_hip}" = "__TRUE__" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_ACCEL=HIP -DCP2K_WITH_GPU=${gpu_ver}"
elif [ "${enable_opencl}" = "__TRUE__" ]; then
CMAKE_OPTIONS+=" -DCP2K_USE_ACCEL=OPENCL"
fi
# Set build directory
BUILD_DIR="${CP2K_ROOT}/build"
# Show CMake options
echo "Generated CMake flags:"
for flag in ${CMAKE_OPTIONS}; do
echo " ${flag}"
done
if [ "${DRY_RUN}" != "__TRUE__" ]; then
# ====================== Optional clean ======================
if [ "${CLEAN_BUILD}" = "__TRUE__" ] && [ -d "${BUILD_DIR}" ]; then
echo "Removing existing build directory: ${BUILD_DIR}"
rm -rf "${BUILD_DIR}"
fi
mkdir -p "${BUILD_DIR}"
# ====================== Configure ======================
echo "================== CMake configuration ==================="
echo "Source dir : ${CP2K_ROOT}"
echo "Build dir : ${BUILD_DIR}"
echo "Install dir: ${CMAKE_INSTALL_PREFIX}"
echo "Shared libs: ${BUILD_SHARED_LIBS}"
echo -n "Configuring ... "
cmake -S "${CP2K_ROOT}" -B "${BUILD_DIR}" ${CMAKE_OPTIONS} > cmake.log 2>&1 || tail_excerpt cmake.log
echo "done."
echo "=========================================================="
# ====================== Build ======================
echo "==================== Building CP2K ======================="
echo "Parallel jobs: ${BUILD_JOBS}"
echo -n "Building CP2K ... "
cmake --build "${BUILD_DIR}" --target install -j "${BUILD_JOBS}" > build.log 2>&1 || tail_excerpt build.log
echo "done."
echo "=========================================================="
# Export variable for CMake options to cp2k_env file
cat << EOF > "${CMAKE_INSTALL_PREFIX}/cp2k_env"
#!/bin/bash
export CP2K_ROOT="${CP2K_ROOT}"
source ${TOOLCHAIN_INSTALL_DIR}/setup
prepend_path PATH "${CP2K_ROOT}/install/bin"
prepend_path LD_LIBRARY_PATH "${CP2K_ROOT}/install/lib"
prepend_path PKG_CONFIG_PATH "${CP2K_ROOT}/install/lib/pkgconfig"
EOF
cat << EOF
Done! Installed binaries are now available in: ${CP2K_ROOT}/install/bin
It's suggested to run regtests after installation:
${CP2K_ROOT}/tests/do_regtest.py ${CMAKE_INSTALL_PREFIX}/bin psmp
Run \`${CP2K_ROOT}/tests/do_regtest.py --help\` for help message.
Please always source this script to load CP2K environment before running CP2K:
source ${CMAKE_INSTALL_PREFIX}/cp2k_env
If you want to clean the build cache (except cached CMake files) after
installation, run:
cmake --build "${BUILD_DIR}" --target clean
EOF
else
cat << EOF
Since you run this script with \"--dry-run\", it now exits.
To build CP2K, drop off this flag and re-run this script.
EOF
fi
#EOF