cp2k/tools/docker/generate_dockerfiles.py
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

1000 lines
31 KiB
Python
Executable file

#!/usr/bin/env python3
# author: Ole Schuett
import argparse
import io
from pathlib import Path
from typing import Any
# ======================================================================================
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--check", action="store_true")
args = parser.parse_args()
for version in "sdbg", "ssmp", "pdbg", "psmp":
with OutputFile(f"Dockerfile.test_{version}", args.check) as f:
mpi_mode = "mpich" if version.startswith("p") else "no"
f.write(install_deps_toolchain(mpi_mode=mpi_mode))
f.write(regtest("toolchain", version))
with OutputFile(f"Dockerfile.test_psmp_4ranks", args.check) as f:
testopts = f"--ompthreads=1 --mpiranks=4"
f.write(install_deps_toolchain())
f.write(regtest("toolchain", "psmp", testopts=testopts))
with OutputFile(f"Dockerfile.test_generic_psmp", args.check) as f:
f.write(install_deps_toolchain(target_cpu="generic"))
f.write(regtest("toolchain_generic", "psmp"))
with OutputFile(f"Dockerfile.test_openmpi-psmp", args.check) as f:
f.write(install_deps_toolchain(mpi_mode="openmpi"))
f.write(regtest("toolchain", "psmp"))
with OutputFile(f"Dockerfile.test_fedora-psmp", args.check) as f:
f.write(install_deps_toolchain(base_image="fedora:41"))
f.write(regtest("toolchain", "psmp"))
for version in "ssmp", "psmp":
mpi_mode = "intelmpi" if version.startswith("p") else "no"
f.write(install_deps_toolchain(mpi_mode=mpi_mode))
with OutputFile(f"Dockerfile.test_intel-ifort-{version}", args.check) as f:
base_image = "intel/hpckit:2024.2.1-0-devel-ubuntu22.04"
f.write(install_deps_toolchain_intel(base_image, mpi_mode, with_ifx="no"))
f.write(regtest("toolchain_intel", version))
with OutputFile(f"Dockerfile.test_intel-ifx-{version}", args.check) as f:
base_image = "intel/oneapi-hpckit:2025.2.2-0-devel-ubuntu24.04"
f.write(install_deps_toolchain_intel(base_image, mpi_mode, with_ifx="yes"))
f.write(regtest("toolchain_intel", version))
with OutputFile(f"Dockerfile.test_minimal", args.check) as f:
f.write(install_deps_ubuntu())
f.write(regtest("minimal", "ssmp"))
# Spack/CMake based testers
testopts = f"--keepalive"
with OutputFile(f"Dockerfile.test_spack_pdbg", args.check) as f:
f.write(
install_cp2k_spack(
version="pdbg",
mpi_mode="mpich",
feature_flags="-ef openpmd",
testopts="",
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
for gcc_version in 10, 11, 12, 14, 15:
with OutputFile(
f"Dockerfile.test_spack_psmp-gcc{gcc_version}", args.check
) as f:
base_image = "ubuntu:26.04" if gcc_version > 14 else "ubuntu:24.04"
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
gcc_version=gcc_version,
base_image=base_image,
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_ssmp-rawhide", args.check) as f:
f.write(
install_cp2k_spack(
version="ssmp",
mpi_mode="no",
base_image="fedora:rawhide",
gcc_version=16,
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-rawhide", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
base_image="fedora:rawhide",
gcc_version=16,
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-fedora", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
base_image="fedora:latest",
gcc_version=15,
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-opensuse", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
base_image="opensuse/leap:15.6",
gcc_version=14,
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-rockylinux", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
base_image="docker.io/rockylinux/rockylinux:10",
gcc_version=14,
feature_flags="-df libxsmm -ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-4x2", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
feature_flags="-ef openpmd",
testopts=f"--keepalive --mpiranks=4 --ompthreads=2",
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_openmpi-psmp", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="openmpi",
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_sdbg", args.check) as f:
f.write(install_cp2k_spack(version="sdbg", mpi_mode="no", testopts=""))
with OutputFile(f"Dockerfile.test_spack_ssmp", args.check) as f:
f.write(
install_cp2k_spack(
version="ssmp", mpi_mode="no", testopts=testopts, image_tag=f.image_tag
)
)
with OutputFile(f"Dockerfile.test_spack_ssmp-static", args.check) as f:
f.write(
install_cp2k_spack(
version="ssmp-static",
mpi_mode="no",
gcc_version=14,
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_ssmp-P100", args.check) as f:
f.write(
install_cp2k_spack(
version="ssmp",
mpi_mode="no",
base_image="docker.io/nvidia/cuda:12.9.1-devel-ubuntu24.04",
gcc_version=13,
gpu_model="P100",
testopts=testopts,
image_tag=f.image_tag,
)
)
with OutputFile(f"Dockerfile.test_spack_psmp-P100", args.check) as f:
f.write(
install_cp2k_spack(
version="psmp",
mpi_mode="mpich",
base_image="docker.io/nvidia/cuda:12.9.1-devel-ubuntu24.04",
gcc_version=13,
gpu_model="P100",
feature_flags="-ef openpmd",
testopts=testopts,
image_tag=f.image_tag,
)
)
# End Spack/CMake based tester
with OutputFile(f"Dockerfile.test_asan-psmp", args.check) as f:
f.write(install_deps_toolchain())
f.write(regtest("toolchain_asan", "psmp"))
with OutputFile(f"Dockerfile.test_coverage", args.check) as f:
f.write(install_deps_toolchain())
f.write(coverage())
for gcc_version in 8, 9, 10, 11, 12, 13, 14, 15:
with OutputFile(f"Dockerfile.test_gcc{gcc_version}", args.check) as f:
# Skip some tests due to bug in LDA_C_PMGB06 functional in libxc <5.2.0.
testopts = "--skipdir=QS/regtest-rs-dhft" if gcc_version == 8 else ""
f.write(install_deps_ubuntu(gcc_version=gcc_version))
f.write(regtest("ubuntu", "ssmp", testopts=testopts))
with OutputFile("Dockerfile.test_arm64-psmp", args.check) as f:
base_img = "arm64v8/ubuntu:24.04"
f.write(install_deps_toolchain(base_img, with_libtorch="no", with_deepmd="no"))
f.write(regtest("toolchain_arm64", "psmp"))
with OutputFile(f"Dockerfile.test_performance", args.check) as f:
f.write(install_deps_toolchain())
f.write(performance("toolchain"))
for gpu_ver in "P100", "V100", "A100":
with OutputFile(f"Dockerfile.test_cuda_{gpu_ver}", args.check) as f:
f.write(install_deps_toolchain_cuda(gpu_ver=gpu_ver))
f.write(regtest(f"toolchain_cuda_{gpu_ver}", "psmp"))
with OutputFile(f"Dockerfile.test_performance_cuda_{gpu_ver}", args.check) as f:
f.write(install_deps_toolchain_cuda(gpu_ver=gpu_ver))
f.write(performance(f"toolchain_cuda_{gpu_ver}"))
for gpu_ver in "Mi50", "Mi100":
with OutputFile(f"Dockerfile.build_hip_rocm_{gpu_ver}", args.check) as f:
f.write(install_deps_toolchain_hip_rocm(gpu_ver=gpu_ver))
f.write(test_build(f"toolchain_hip_{gpu_ver}", "psmp"))
with OutputFile(f"Dockerfile.test_conventions", args.check) as f:
f.write(install_deps_toolchain())
f.write(conventions())
with OutputFile(f"Dockerfile.test_manual", args.check) as f:
f.write(install_deps_toolchain())
f.write(manual())
with OutputFile(f"Dockerfile.test_precommit", args.check) as f:
f.write(precommit())
for name in "ase", "aiida", "i-pi", "phonopy", "gromacs":
with OutputFile(f"Dockerfile.test_{name}", args.check) as f:
f.write(install_deps_toolchain(mpi_mode="no"))
f.write(test_3rd_party(name))
for name in "misc", "doxygen":
with OutputFile(f"Dockerfile.test_{name}", args.check) as f:
f.write(test_without_build(name))
# ======================================================================================
def regtest(profile: str, version: str, testopts: str = "") -> str:
return install_cp2k(profile=profile, version=version) + rf"""
# Run regression tests.
ARG TESTOPTS="{testopts}"
COPY ./tests ./tests
COPY ./tools/docker/scripts/test_regtest.sh ./
RUN /bin/bash -o pipefail -c " \
TESTOPTS='${{TESTOPTS}}' \
./test_regtest.sh {profile} {version} |& tee report.log && \
rm -rf regtesting"
""" + print_cached_report()
# ======================================================================================
def test_build(profile: str, version: str) -> str:
return install_cp2k(profile=profile, version=version) + rf"""
# Run build test.
COPY ./tools/docker/scripts/test_build.sh .
RUN ./test_build.sh "{profile}" "{version}" 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def performance(profile: str) -> str:
return install_cp2k(profile=profile, version="psmp") + rf"""
# Run performance test for {profile}.
COPY ./benchmarks ./benchmarks
COPY ./tools/regtesting ./tools/regtesting
COPY ./tools/docker/scripts/test_performance.sh \
./tools/docker/scripts/plot_performance.py \
./
RUN ./test_performance.sh "{profile}" 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def coverage() -> str:
return (
install_cp2k(profile="toolchain_coverage", version="psmp", revision=True)
+ rf"""
# Run coverage test.
COPY ./tests ./tests
COPY ./tools/docker/scripts/test_coverage.sh .
RUN ./test_coverage.sh 2>&1 | tee report.log
"""
+ print_cached_report()
)
# ======================================================================================
def conventions() -> str:
return (
f"""
COPY ./tools/conventions/redirect_gfortran_output.py /usr/bin/
"""
+ install_cp2k(profile="toolchain_conventions", version="psmp")
+ f"""
# Run test for conventions.
COPY ./tools/conventions ./tools/conventions
RUN /bin/bash -ec "./tools/conventions/test_conventions.sh |& tee report.log"
"""
+ print_cached_report()
)
# ======================================================================================
def manual() -> str:
return install_cp2k(profile="toolchain", version="pdbg", revision=True) + rf"""
# Generate manual.
COPY ./docs ./docs
COPY ./tools/input_editing ./tools/input_editing
COPY ./tools/docker/scripts/test_manual.sh .
ARG ADD_EDIT_LINKS=yes
RUN ./test_manual.sh "${{ADD_EDIT_LINKS}}" 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def precommit() -> str:
return rf"""
FROM ubuntu:24.04
# Install dependencies.
WORKDIR /opt/cp2k-precommit
COPY ./tools/precommit/ /opt/cp2k-precommit/
RUN ./install_requirements.sh
ENV PATH="/opt/venv/bin:/opt/cp2k-precommit:$PATH"
# Install sources.
WORKDIR /opt/cp2k
COPY ./ ./
# Run precommit test.
RUN ./tools/docker/scripts/test_precommit.sh 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def test_3rd_party(name: str) -> str:
return install_cp2k(profile="toolchain", version="ssmp") + rf"""
# Run test for {name}.
COPY ./tests ./tests
COPY ./tools/docker/scripts/test_{name}.sh ./
RUN ./test_{name}.sh 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def test_without_build(name: str) -> str:
return rf"""
FROM ubuntu:24.04
# Install dependencies.
WORKDIR /opt/cp2k
COPY ./tools/docker/scripts/install_{name}.sh .
COPY ./tools/pao-ml/requirements.txt pao-ml-requirements.txt
RUN ./install_{name}.sh
ENV PATH="/opt/venv/bin:$PATH"
# Install sources.
ARG GIT_COMMIT_SHA
COPY ./src ./src
COPY ./exts ./exts
COPY ./data ./data
COPY ./docs ./docs
COPY ./tools ./tools
COPY ./tests ./tests
COPY ./cmake ./cmake
COPY ./CMakeLists.txt .
RUN bash -c "if [ -n "${{GIT_COMMIT_SHA}}" ] ; then echo "git:\${{GIT_COMMIT_SHA::7}}" > REVISION; fi"
# Run test for {name}.
COPY ./tools/docker/scripts/test_{name}.sh .
RUN ./test_{name}.sh 2>&1 | tee report.log
""" + print_cached_report()
# ======================================================================================
def print_cached_report() -> str:
return r"""
# Output the report if the image is old and was therefore pulled from the build cache.
CMD cat $(find ./report.log -mmin +10) | sed '/^Summary:/ s/$/ (cached)/'
ENTRYPOINT []
#EOF
"""
# ======================================================================================
def install_cp2k(profile: str, version: str, revision: bool = False) -> str:
output = ""
if revision:
output += "\n"
output += "ARG GIT_COMMIT_SHA\n"
output += "ENV GIT_COMMIT_SHA=${GIT_COMMIT_SHA}\n"
output += rf"""
# Install CP2K sources.
WORKDIR /opt/cp2k
COPY ./src ./src
COPY ./data ./data
COPY ./tools/build_utils ./tools/build_utils
COPY ./cmake ./cmake
COPY ./CMakeLists.txt .
# Compile CP2K.
COPY ./tools/docker/scripts/build_cp2k.sh .
RUN ./build_cp2k.sh {profile} {version}
"""
return output
# ======================================================================================
def install_deps_toolchain(
base_image: str = "ubuntu:24.04",
mpi_mode: str = "mpich",
with_dbcsr: str = "", # enabled by default
with_gcc: str = "system",
**kwargs: str,
) -> str:
output = f"\nFROM {base_image}\n\n"
output += install_toolchain(
base_image=base_image,
install_all="",
mpi_mode=mpi_mode,
with_dbcsr=with_dbcsr,
with_gcc=with_gcc,
**kwargs,
)
return output
# ======================================================================================
def install_deps_ubuntu(gcc_version: int = 13) -> str:
if gcc_version > 14:
base_image = "ubuntu:26.04"
elif gcc_version > 8:
base_image = "ubuntu:24.04"
else:
base_image = "ubuntu:20.04"
output = f"\nFROM {base_image}\n"
if gcc_version > 13:
output += rf"""
# Add Ubuntu universe repository.
RUN apt-get update -qq && apt-get install -qq --no-install-recommends software-properties-common
RUN add-apt-repository universe
"""
output += rf"""
# Install Ubuntu packages.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true && \
apt-get update -qq && apt-get install -qq --no-install-recommends \
cmake \
less \
nano \
make \
ninja-build \
wget \
python3 \
ca-certificates \
gcc-{gcc_version} \
g++-{gcc_version} \
gfortran-{gcc_version} \
libfftw3-dev \
libopenblas-dev \
libint2-dev \
libxc-dev \
libhdf5-dev \
{"libxsmm-dev" if gcc_version > 8 else ""} \
{"libspglib-f08-dev" if gcc_version > 8 else ""} \
&& rm -rf /var/lib/apt/lists/*
# Create links in /usr/local/bin to overrule links in /usr/bin.
RUN ln -sf /usr/bin/gcc-{gcc_version} /usr/local/bin/gcc && \
ln -sf /usr/bin/g++-{gcc_version} /usr/local/bin/g++ && \
ln -sf /usr/bin/gfortran-{gcc_version} /usr/local/bin/gfortran
# Use toolchain to install DBCSR{"" if gcc_version > 8 else " and CMake"}.
""" + install_toolchain(
base_image=base_image,
mpi_mode="no",
with_dbcsr="",
with_gcc="system",
with_cmake="system" if gcc_version > 8 else "",
with_ninja="system",
with_openblas="system",
with_libxc="no",
with_libint="no",
with_fftw="no",
with_libxsmm="no",
with_spglib="no",
with_libvori="no",
)
return output
# ======================================================================================
def install_deps_toolchain_intel(base_image: str, mpi_mode: str, with_ifx: str) -> str:
return rf"""
FROM {base_image}
""" + install_toolchain(
base_image="ubuntu",
install_all="",
mpi_mode=mpi_mode,
with_ifx=with_ifx,
with_mkl="",
with_libsmeagol="",
with_libtorch="no",
with_deepmd="no",
)
# ======================================================================================
def install_deps_toolchain_cuda(gpu_ver: str, **kwargs: str) -> str:
deps = rf"""
FROM nvidia/cuda:12.9.1-devel-ubuntu24.04
# Setup CUDA environment.
ENV CUDA_PATH /usr/local/cuda
ENV LD_LIBRARY_PATH /usr/local/cuda/lib64
# Disable JIT cache as there seems to be an issue with file locking on overlayfs.
# See also https://github.com/cp2k/cp2k/pull/2337
ENV CUDA_CACHE_DISABLE 1
# Install Ubuntu packages.
RUN apt-get update -qq && apt-get install -qq --no-install-recommends \
gfortran \
&& rm -rf /var/lib/apt/lists/*
""" + install_toolchain(
base_image="ubuntu",
with_mpich="install",
mpi_mode="mpich",
enable_cuda="yes",
gpu_ver=gpu_ver,
**kwargs,
)
return deps
# ======================================================================================
def install_deps_toolchain_hip_rocm(gpu_ver: str) -> str:
return rf"""
FROM rocm/dev-ubuntu-24.04:7.2-complete
# Install some Ubuntu packages.
RUN apt-get update -qq && apt-get install -qq --no-install-recommends \
hipblas \
gfortran \
mpich \
libmpich-dev \
&& rm -rf /var/lib/apt/lists/*
# Remove LTO from Ubuntu's MPICH
RUN sed -i -e 's/-flto=auto//g' -e 's/-ffat-lto-objects//g' \
/usr/lib/x86_64-linux-gnu/pkgconfig/mpich.pc \
/usr/bin/*.mpich
# Setup HIP environment.
ENV ROCM_PATH /opt/rocm
ENV PATH ${{PATH}}:${{ROCM_PATH}}/bin
ENV LD_LIBRARY_PATH ${{LD_LIBRARY_PATH}}:${{ROCM_PATH}}/lib
ENV HIP_PLATFORM amd
RUN hipconfig
""" + install_toolchain(
base_image="ubuntu",
mpi_mode="mpich",
enable_hip="yes",
gpu_ver=gpu_ver,
with_dbcsr="",
)
# ======================================================================================
def install_toolchain(base_image: str, **kwargs: str) -> str:
install_args = []
for k, v in kwargs.items():
k = k.replace("_", "-")
if v != "":
install_args.append(f" --{k}={v} \\")
else:
install_args.append(f" --{k} \\")
install_args_str = "\n".join(install_args)
return rf"""
# Install requirements for the toolchain.
WORKDIR /opt/cp2k-toolchain
COPY ./tools/toolchain/install_requirements*.sh ./
RUN ./install_requirements.sh {base_image}
# Install the toolchain.
RUN mkdir scripts
COPY ./tools/toolchain/scripts/VERSION \
./tools/toolchain/scripts/parse_if.py \
./tools/toolchain/scripts/tool_kit.sh \
./tools/toolchain/scripts/common_vars.sh \
./tools/toolchain/scripts/signal_trap.sh \
./tools/toolchain/scripts/get_openblas_arch.sh \
./scripts/
COPY ./tools/toolchain/install_cp2k_toolchain.sh .
RUN ./install_cp2k_toolchain.sh \
{install_args_str}
--dry-run
# Dry-run leaves behind config files for the followup install scripts.
# This breaks up the lengthy installation into smaller build steps.
COPY ./tools/toolchain/scripts/stage0/ ./scripts/stage0/
RUN ./scripts/stage0/install_stage0.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage1/ ./scripts/stage1/
RUN ./scripts/stage1/install_stage1.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage2/ ./scripts/stage2/
RUN ./scripts/stage2/install_stage2.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage3/ ./scripts/stage3/
RUN ./scripts/stage3/install_stage3.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage4/ ./scripts/stage4/
RUN ./scripts/stage4/install_stage4.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage5/ ./scripts/stage5/
RUN ./scripts/stage5/install_stage5.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage6/ ./scripts/stage6/
RUN ./scripts/stage6/install_stage6.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage7/ ./scripts/stage7/
RUN ./scripts/stage7/install_stage7.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage8/ ./scripts/stage8/
RUN ./scripts/stage8/install_stage8.sh && rm -rf ./build
COPY ./tools/toolchain/scripts/stage9/ ./scripts/stage9/
RUN ./scripts/stage9/install_stage9.sh && rm -rf ./build
""".lstrip()
# ======================================================================================
def install_cp2k_spack(
version: str,
mpi_mode: str,
base_image: str = "ubuntu:24.04",
gcc_version: int = 13,
gpu_model: str = "none",
feature_flags: str = "",
testopts: str = "",
image_tag: str = "",
) -> str:
# Ubuntu 24.04 provides no gcc-15 package whereas GCC 15 is the default for fedora:43
if gcc_version == 15 or "fedora" in base_image:
gcc_compilers = "g++ gcc gfortran"
elif "opensuse/leap" in base_image:
gcc_compilers = f"gcc gcc{gcc_version} gcc-c++ gcc{gcc_version}-c++ gcc-fortran gcc{gcc_version}-fortran"
elif "rockylinux" in base_image:
gcc_compilers = f"gcc gcc-c++ gcc-fortran"
else:
gcc_compilers = f"g++ g++-{gcc_version} gcc gcc-{gcc_version} gfortran gfortran-{gcc_version}"
# Static CP2K builds use the GCC compiler built with spack
if version.endswith("-static"):
use_externals = ""
# The default GCC 13 compiler is used for static builds
# A spack build of the same GCC version as the default one
# of the host system and ignoring all externals at the same
# time is not supported
gcc_compilers = "g++ gcc gfortran"
else:
use_externals = "-ue"
# Assemble docker file
output = (
install_base_image(
base_image=rf"{base_image}", gcc_compilers=gcc_compilers, stage="build"
)
+ rf"""
ARG IMAGE_TAG
ENV IMAGE_TAG=${{IMAGE_TAG:-{image_tag}}}
ARG SPACK_CACHE="s3://spack-cache --s3-endpoint-url=http://localhost:9000"
# Copy CP2K repository into container
WORKDIR /opt
COPY . cp2k/
# Build CP2K dependencies
WORKDIR /opt/cp2k
RUN ./make_cp2k.sh -bd_only -cv {version} -gpu {gpu_model} -gv {gcc_version} -mpi {mpi_mode} {use_externals} {feature_flags}
###### Stage 2: Build CP2K ######
FROM build_deps AS build_cp2k
RUN ./make_cp2k.sh -cv {version} -gv {gcc_version} -gpu {gpu_model} -mpi {mpi_mode} {feature_flags}
"""
)
output += (
install_base_image(
base_image=rf"{base_image}", gcc_compilers=gcc_compilers, stage="install"
)
+ rf"""
WORKDIR /opt/cp2k
# Install CP2K dependencies built with spack
COPY --from=build_cp2k /opt/cp2k/spack/spack/opt/spack ./spack/spack/opt/spack
# Install CP2K
COPY --from=build_cp2k /opt/cp2k/install ./install
# Install CP2K regression tests
COPY --from=build_cp2k /opt/cp2k/tests ./tests
COPY --from=build_cp2k /opt/cp2k/src/grid/sample_tasks ./src/grid/sample_tasks
# Install CP2K/Quickstep CI benchmarks
COPY --from=build_cp2k /opt/cp2k/benchmarks/CI ./benchmarks/CI
# Do not rely only on LD_LIBRARY_PATH because it is fragile
COPY --from=build_cp2k /etc/ld.so.conf.d/cp2k.conf /etc/ld.so.conf.d/cp2k.conf
RUN ldconfig
# Run CP2K regression test
RUN /opt/cp2k/install/bin/launch /opt/cp2k/install/bin/run_tests {testopts}
# Create entrypoint and finalise container build
WORKDIR /mnt
ENTRYPOINT ["/opt/cp2k/install/bin/launch"]
CMD ["cp2k", "--help", "--version"]
"""
)
return output
# ======================================================================================
def install_base_image(
base_image: str,
gcc_compilers: str,
stage: str,
) -> str:
if stage == "build":
output = rf"""
ARG BASE_IMAGE="{base_image}"
###### Stage 1: Build CP2K dependencies ######
FROM "${{BASE_IMAGE}}" AS build_deps
"""
if "fedora" in base_image:
output += rf"""
RUN dnf -qy install \
cmake \
{gcc_compilers} \
git \
libtool \
make \
patch \
perl-core \
pkg-config \
python3 \
python3-devel \
unzip \
wget \
zlib-devel \
zlib-static \
&& dnf clean -q all
"""
elif "opensuse/leap" in base_image:
output += rf"""
RUN zypper --non-interactive --quiet ref && \
zypper --non-interactive --quiet in --no-recommends \
bzip2 \
cmake \
{gcc_compilers} \
git \
gzip \
libssh-devel \
libopenssl-devel \
libtool \
lsb-release \
make \
patch \
pkgconf \
python311 \
python311-devel \
unzip \
wget \
xz \
zstd \
&& zypper --non-interactive --quiet clean --all
RUN ln -sf /usr/bin/python3.11 /usr/local/bin/python3 && \
ln -sf /usr/bin/python3.11 /usr/local/bin/python
"""
elif "rockylinux" in base_image:
output += rf"""
RUN dnf -y install dnf-plugins-core && \
dnf --enablerepo=crb -qy install \
bzip2 \
cmake \
{gcc_compilers} \
git \
libtool \
openssl-devel \
patch \
python3 \
python3-devel \
python3-pip \
unzip \
wget \
xz \
zlib-devel \
zlib-static \
&& dnf clean -q all
"""
elif "ubuntu" in base_image:
output += rf"""
RUN apt-get update -qq && apt-get install -qq --no-install-recommends \
bzip2 \
ca-certificates \
cmake \
{gcc_compilers} \
git \
gnupg \
libssh-dev \
libssl-dev \
libtool \
libtool-bin \
lsb-release \
make \
patch \
pkgconf \
python3 \
python3-dev \
python3-pip \
python3-venv \
unzip \
wget \
xxd \
xz-utils \
zstd \
&& rm -rf /var/lib/apt/lists/*
"""
else:
print(f"\nERROR: Unknown base image {base_image} specified\n")
if "nvidia" in base_image:
output += rf"""
# Setup CUDA environment
ENV LD_LIBRARY_PATH /usr/local/cuda/lib64
# Disable JIT cache as there seems to be an issue with file locking on overlayfs
# See also https://github.com/cp2k/cp2k/pull/2337
ENV CUDA_CACHE_DISABLE 1
"""
elif stage == "install":
output = rf"""
###### Stage 3: Install CP2K ######
FROM "${{BASE_IMAGE}}" AS install_cp2k
"""
if "fedora" in base_image:
output += rf"""
RUN dnf -qy install \
{gcc_compilers} \
python3 \
&& dnf clean -q all
"""
elif "opensuse/leap" in base_image:
output += rf"""
RUN zypper --non-interactive --quiet ref && \
zypper --non-interactive --quiet in --no-recommends \
{gcc_compilers} \
python311 \
&& zypper --non-interactive --quiet clean --all
RUN ln -sf /usr/bin/python3.11 /usr/local/bin/python3 && \
ln -sf /usr/bin/python3.11 /usr/local/bin/python
"""
elif "rockylinux" in base_image:
output += rf"""
RUN dnf -y install dnf-plugins-core && \
dnf --enablerepo=crb -qy install \
{gcc_compilers} \
python3 \
python3-pip \
&& dnf clean -q all
"""
elif "ubuntu" in base_image:
output += rf"""
RUN apt-get update -qq && apt-get install -qq --no-install-recommends \
{gcc_compilers} \
python3 \
&& rm -rf /var/lib/apt/lists/*
"""
else:
print(f"\nERROR: Unknown base image {base_image} specified\n")
if "nvidia" in base_image:
output += rf"""
# Setup CUDA environment
ENV LD_LIBRARY_PATH /usr/local/cuda/lib64
# Disable JIT cache as there seems to be an issue with file locking on overlayfs
# See also https://github.com/cp2k/cp2k/pull/2337
ENV CUDA_CACHE_DISABLE 1
"""
else:
print(f"\nERROR: Unknown stage {stage} specified\n")
return output
# ======================================================================================
class OutputFile:
def __init__(self, filename: str, check: bool) -> None:
self.filename = filename
self.check = check
self.content = io.StringIO()
self.content.write(f"#\n")
self.content.write(f"# This file was created by generate_dockerfiles.py.\n")
if "_spack_" in filename:
self.image_tag = filename.removeprefix("Dockerfile.test_")
usage = f"./spack_cache_start.sh; podman build --network=host --shm-size=1g -t {self.image_tag} -f ./{filename} ../../"
else:
self.image_tag = ""
usage = f"podman build --shm-size=1g -f ./{filename} ../../"
self.content.write(f"# Usage: {usage}\n#\n")
def __enter__(self) -> "OutputFile":
return self
def write(self, text: str) -> None:
self.content.write(text)
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
output_path = Path(__file__).parent / self.filename
if self.check:
assert output_path.read_text(encoding="utf8") == self.content.getvalue()
print(f"File {output_path} is consistent with generator script.")
else:
output_path.write_text(self.content.getvalue(), encoding="utf8")
print(f"Wrote {output_path}")
# ======================================================================================
main()
# EOF