Skip to content

Commit fe9d520

Browse files
committed
Add toolchain tester dockerfiles
1 parent ff23741 commit fe9d520

5 files changed

Lines changed: 453 additions & 0 deletions

File tree

docker/Dockerfile.gnu-mpich

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#
2+
# This file was created by generate_dockerfiles.py.
3+
# Do not edit this file directly.
4+
# Usage: podman build --shm-size=1g -f ./Dockerfile.gnu-mpich ..
5+
#
6+
7+
FROM ubuntu:24.04
8+
9+
# Install requirements for the toolchain.
10+
WORKDIR /opt/abacus-toolchain
11+
COPY ./toolchain/root_requirements/install_requirements*.sh ./
12+
RUN ./install_requirements.sh ubuntu:24.04
13+
14+
# Configure the toolchain.
15+
RUN mkdir scripts
16+
COPY ./toolchain/scripts/VERSION \
17+
./toolchain/scripts/package_versions.sh \
18+
./toolchain/scripts/tool_kit.sh \
19+
./toolchain/scripts/common_vars.sh \
20+
./toolchain/scripts/signal_trap.sh \
21+
./toolchain/scripts/get_openblas_arch.sh \
22+
./toolchain/scripts/parse_if.py \
23+
./scripts/
24+
COPY ./toolchain/scripts/lib/ ./scripts/lib/
25+
COPY ./toolchain/install_abacus_toolchain_new.sh .
26+
RUN ./install_abacus_toolchain_new.sh \
27+
--mpi-mode=mpich \
28+
--math-mode=openblas \
29+
--with-gcc=system \
30+
--with-mpich=install \
31+
--with-openblas=install \
32+
--with-libtorch=install \
33+
--with-libnpy=install \
34+
--with-dftd4=install \
35+
--with-nep=install \
36+
--skip-system-checks \
37+
--dry-run
38+
39+
# The dry run leaves the configuration files consumed by each stage script.
40+
# Split the installation into stages so Docker can cache completed work.
41+
COPY ./toolchain/scripts/stage0/ ./scripts/stage0/
42+
RUN ./scripts/stage0/install_stage0.sh && rm -rf ./build
43+
44+
COPY ./toolchain/scripts/stage1/ ./scripts/stage1/
45+
RUN ./scripts/stage1/install_stage1.sh && rm -rf ./build
46+
47+
COPY ./toolchain/scripts/stage2/ ./scripts/stage2/
48+
RUN ./scripts/stage2/install_stage2.sh && rm -rf ./build
49+
50+
COPY ./toolchain/scripts/stage3/ ./scripts/stage3/
51+
RUN ./scripts/stage3/install_stage3.sh && rm -rf ./build
52+
53+
COPY ./toolchain/scripts/stage4/ ./scripts/stage4/
54+
RUN ./scripts/stage4/install_stage4.sh && rm -rf ./build
55+
56+
# Additional prerequisites for building and testing
57+
RUN apt-get -qq update && apt-get install -qq ninja-build bc python3-numpy
58+
59+
# Install ABACUS sources.
60+
WORKDIR /opt/abacus
61+
COPY ./source ./source
62+
COPY ./tests ./tests
63+
COPY ./cmake ./cmake
64+
COPY ./CMakeLists.txt .
65+
66+
# Compile and install ABACUS.
67+
COPY ./docker/scripts/build_abacus.sh ./build_abacus.sh
68+
RUN ./build_abacus.sh
69+
70+
# Test ABACUS.
71+
COPY ./docker/scripts/test_abacus.sh ./test_abacus.sh
72+
RUN /bin/bash -o pipefail -c "./test_abacus.sh |& tee report.log"
73+
74+
# Output the report if the image is old and was therefore pulled from the build cache.
75+
CMD cat $(find ./report.log -mmin +10) | sed '/^Summary:/ s/$/ (cached)/'
76+
ENTRYPOINT []
77+
78+
# EOF

docker/Dockerfile.gnu-openmpi

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#
2+
# This file was created by generate_dockerfiles.py.
3+
# Do not edit this file directly.
4+
# Usage: podman build --shm-size=1g -f ./Dockerfile.gnu-openmpi ..
5+
#
6+
7+
FROM ubuntu:24.04
8+
9+
# Install requirements for the toolchain.
10+
WORKDIR /opt/abacus-toolchain
11+
COPY ./toolchain/root_requirements/install_requirements*.sh ./
12+
RUN ./install_requirements.sh ubuntu:24.04
13+
14+
# Configure the toolchain.
15+
RUN mkdir scripts
16+
COPY ./toolchain/scripts/VERSION \
17+
./toolchain/scripts/package_versions.sh \
18+
./toolchain/scripts/tool_kit.sh \
19+
./toolchain/scripts/common_vars.sh \
20+
./toolchain/scripts/signal_trap.sh \
21+
./toolchain/scripts/get_openblas_arch.sh \
22+
./toolchain/scripts/parse_if.py \
23+
./scripts/
24+
COPY ./toolchain/scripts/lib/ ./scripts/lib/
25+
COPY ./toolchain/install_abacus_toolchain_new.sh .
26+
RUN ./install_abacus_toolchain_new.sh \
27+
--mpi-mode=openmpi \
28+
--math-mode=openblas \
29+
--with-gcc=system \
30+
--with-openmpi=install \
31+
--with-openblas=install \
32+
--with-libtorch=install \
33+
--with-libnpy=install \
34+
--with-dftd4=install \
35+
--with-nep=install \
36+
--skip-system-checks \
37+
--dry-run
38+
39+
# The dry run leaves the configuration files consumed by each stage script.
40+
# Split the installation into stages so Docker can cache completed work.
41+
COPY ./toolchain/scripts/stage0/ ./scripts/stage0/
42+
RUN ./scripts/stage0/install_stage0.sh && rm -rf ./build
43+
44+
COPY ./toolchain/scripts/stage1/ ./scripts/stage1/
45+
RUN ./scripts/stage1/install_stage1.sh && rm -rf ./build
46+
47+
COPY ./toolchain/scripts/stage2/ ./scripts/stage2/
48+
RUN ./scripts/stage2/install_stage2.sh && rm -rf ./build
49+
50+
COPY ./toolchain/scripts/stage3/ ./scripts/stage3/
51+
RUN ./scripts/stage3/install_stage3.sh && rm -rf ./build
52+
53+
COPY ./toolchain/scripts/stage4/ ./scripts/stage4/
54+
RUN ./scripts/stage4/install_stage4.sh && rm -rf ./build
55+
56+
# Additional prerequisites for building and testing
57+
RUN apt-get -qq update && apt-get install -qq ninja-build bc python3-numpy
58+
59+
# Install ABACUS sources.
60+
WORKDIR /opt/abacus
61+
COPY ./source ./source
62+
COPY ./tests ./tests
63+
COPY ./cmake ./cmake
64+
COPY ./CMakeLists.txt .
65+
66+
# Compile and install ABACUS.
67+
COPY ./docker/scripts/build_abacus.sh ./build_abacus.sh
68+
RUN ./build_abacus.sh
69+
70+
# Test ABACUS.
71+
COPY ./docker/scripts/test_abacus.sh ./test_abacus.sh
72+
RUN /bin/bash -o pipefail -c "./test_abacus.sh |& tee report.log"
73+
74+
# Output the report if the image is old and was therefore pulled from the build cache.
75+
CMD cat $(find ./report.log -mmin +10) | sed '/^Summary:/ s/$/ (cached)/'
76+
ENTRYPOINT []
77+
78+
# EOF

docker/generate_dockerfiles.py

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#!/usr/bin/env python3
2+
3+
"""Generate the GNU, CUDA, and Intel ABACUS Dockerfiles.
4+
5+
The Dockerfiles use the ABACUS toolchain as the single source of dependency
6+
installation logic. The generator only selects the base image, toolchain
7+
configuration, and ABACUS CMake options.
8+
"""
9+
10+
import argparse
11+
import io
12+
from pathlib import Path
13+
from typing import Any
14+
15+
16+
# ======================================================================================
17+
def main() -> None:
18+
parser = argparse.ArgumentParser()
19+
parser.add_argument(
20+
"--check",
21+
action="store_true",
22+
help="check that generated Dockerfiles are up to date",
23+
)
24+
args = parser.parse_args()
25+
26+
with OutputFile("Dockerfile.gnu-openmpi", args.check) as f:
27+
f.write(
28+
install_deps_toolchain(
29+
base_image="ubuntu:24.04",
30+
mpi_mode="openmpi",
31+
math_mode="openblas",
32+
with_gcc="system",
33+
with_openmpi="install",
34+
with_openblas="install",
35+
with_libtorch="install",
36+
with_libnpy="install",
37+
with_dftd4="install",
38+
with_nep="install",
39+
)
40+
)
41+
f.write(install_abacus())
42+
43+
with OutputFile("Dockerfile.gnu-mpich", args.check) as f:
44+
f.write(
45+
install_deps_toolchain(
46+
base_image="ubuntu:24.04",
47+
mpi_mode="mpich",
48+
math_mode="openblas",
49+
with_gcc="system",
50+
with_mpich="install",
51+
with_openblas="install",
52+
with_libtorch="install",
53+
with_libnpy="install",
54+
with_dftd4="install",
55+
with_nep="install",
56+
)
57+
)
58+
f.write(install_abacus())
59+
60+
# TODO: Check and re-generate Intel and CUDA testers
61+
#
62+
# with OutputFile("Dockerfile.cuda", args.check) as f:
63+
# f.write(
64+
# install_deps_toolchain_cuda(
65+
# gpu_ver="80",
66+
# mpi_mode="openmpi",
67+
# math_mode="openblas",
68+
# with_gcc="system",
69+
# with_openmpi="install",
70+
# with_openblas="install",
71+
# with_dftd4="install",
72+
# )
73+
# )
74+
# f.write(install_abacus())
75+
76+
# with OutputFile("Dockerfile.intel", args.check) as f:
77+
# f.write(
78+
# install_deps_toolchain(
79+
# base_image="intel/oneapi-toolkit:2026.1.0-devel-ubuntu24.04",
80+
# mpi_mode="intelmpi",
81+
# math_mode="mkl",
82+
# with_gcc="no",
83+
# with_intel="system",
84+
# with_intelmpi="system",
85+
# with_mkl="system",
86+
# with_ifx="yes",
87+
# with_libtorch="no",
88+
# with_dftd4="install",
89+
# )
90+
# )
91+
# f.write(install_abacus())
92+
93+
94+
# ======================================================================================
95+
def install_deps_toolchain(base_image: str, **kwargs: str) -> str:
96+
return f"FROM {base_image}\n\n" + install_toolchain(base_image, **kwargs)
97+
98+
99+
# ======================================================================================
100+
def install_deps_toolchain_cuda(gpu_ver: str, **kwargs: str) -> str:
101+
return rf"""
102+
FROM nvidia/cuda:12.9.2-devel-ubuntu24.04
103+
104+
ARG GPU_VER={gpu_ver}
105+
106+
# Setup CUDA environment.
107+
ENV CUDA_PATH=/usr/local/cuda
108+
ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64
109+
110+
""".lstrip() + install_toolchain(
111+
"ubuntu",
112+
enable_cuda="",
113+
gpu_ver="${GPU_VER}",
114+
**kwargs,
115+
)
116+
117+
118+
# ======================================================================================
119+
def install_toolchain(base_image: str, **kwargs: str) -> str:
120+
install_args = []
121+
for key, value in kwargs.items():
122+
option = key.replace("_", "-")
123+
if value == "":
124+
install_args.append(f" --{option} \\")
125+
else:
126+
install_args.append(f" --{option}={value} \\")
127+
install_args_str = "\n".join(install_args)
128+
129+
return rf"""
130+
# Install requirements for the toolchain.
131+
WORKDIR /opt/abacus-toolchain
132+
COPY ./toolchain/root_requirements/install_requirements*.sh ./
133+
RUN ./install_requirements.sh {base_image}
134+
135+
# Configure the toolchain.
136+
RUN mkdir scripts
137+
COPY ./toolchain/scripts/VERSION \
138+
./toolchain/scripts/package_versions.sh \
139+
./toolchain/scripts/tool_kit.sh \
140+
./toolchain/scripts/common_vars.sh \
141+
./toolchain/scripts/signal_trap.sh \
142+
./toolchain/scripts/get_openblas_arch.sh \
143+
./toolchain/scripts/parse_if.py \
144+
./scripts/
145+
COPY ./toolchain/scripts/lib/ ./scripts/lib/
146+
COPY ./toolchain/install_abacus_toolchain_new.sh .
147+
RUN ./install_abacus_toolchain_new.sh \
148+
{install_args_str}
149+
--skip-system-checks \
150+
--dry-run
151+
152+
# The dry run leaves the configuration files consumed by each stage script.
153+
# Split the installation into stages so Docker can cache completed work.
154+
COPY ./toolchain/scripts/stage0/ ./scripts/stage0/
155+
RUN ./scripts/stage0/install_stage0.sh && rm -rf ./build
156+
157+
COPY ./toolchain/scripts/stage1/ ./scripts/stage1/
158+
RUN ./scripts/stage1/install_stage1.sh && rm -rf ./build
159+
160+
COPY ./toolchain/scripts/stage2/ ./scripts/stage2/
161+
RUN ./scripts/stage2/install_stage2.sh && rm -rf ./build
162+
163+
COPY ./toolchain/scripts/stage3/ ./scripts/stage3/
164+
RUN ./scripts/stage3/install_stage3.sh && rm -rf ./build
165+
166+
COPY ./toolchain/scripts/stage4/ ./scripts/stage4/
167+
RUN ./scripts/stage4/install_stage4.sh && rm -rf ./build
168+
""".lstrip()
169+
170+
171+
# ======================================================================================
172+
def install_abacus(**cmake_options: str) -> str:
173+
174+
return rf"""
175+
# Additional prerequisites for building and testing
176+
RUN apt-get -qq update && apt-get install -qq ninja-build bc python3-numpy
177+
178+
# Install ABACUS sources.
179+
WORKDIR /opt/abacus
180+
COPY ./source ./source
181+
COPY ./tests ./tests
182+
COPY ./cmake ./cmake
183+
COPY ./CMakeLists.txt .
184+
185+
# Compile and install ABACUS.
186+
COPY ./docker/scripts/build_abacus.sh ./build_abacus.sh
187+
RUN ./build_abacus.sh
188+
189+
# Test ABACUS.
190+
COPY ./docker/scripts/test_abacus.sh ./test_abacus.sh
191+
RUN /bin/bash -o pipefail -c "./test_abacus.sh |& tee report.log"
192+
193+
# Output the report if the image is old and was therefore pulled from the build cache.
194+
CMD cat $(find ./report.log -mmin +10) | sed '/^Summary:/ s/$/ (cached)/'
195+
ENTRYPOINT []
196+
197+
# EOF
198+
"""
199+
200+
201+
# ======================================================================================
202+
class OutputFile:
203+
def __init__(self, filename: str, check: bool) -> None:
204+
self.filename = filename
205+
self.check = check
206+
self.content = io.StringIO()
207+
self.content.write("#\n")
208+
self.content.write("# This file was created by generate_dockerfiles.py.\n")
209+
self.content.write("# Do not edit this file directly.\n")
210+
self.content.write(
211+
f"# Usage: podman build --shm-size=1g -f ./{filename} ..\n"
212+
)
213+
self.content.write("#\n\n")
214+
215+
def __enter__(self) -> "OutputFile":
216+
return self
217+
218+
def write(self, text: str) -> None:
219+
self.content.write(text)
220+
221+
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
222+
if exc_type is not None:
223+
return
224+
225+
output_path = Path(__file__).resolve().parent / self.filename
226+
generated = self.content.getvalue()
227+
228+
if self.check:
229+
assert output_path.read_text(encoding="utf8") == generated
230+
print(f"File {output_path} is consistent with generator script.")
231+
else:
232+
output_path.write_text(generated, encoding="utf8")
233+
print(f"Wrote {output_path}")
234+
235+
236+
# ======================================================================================
237+
if __name__ == "__main__":
238+
main()
239+
240+
# EOF

0 commit comments

Comments
 (0)