diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..4a199b3ea --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +# Git metadata +.git +.gitignore + +# Build artifacts +build/ +dist/ +bin/ +*.o +*.so +*.a + +# Python junk +__pycache__/ +*.pyc +*.pyo +*.egg-info/ + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..d3dd04968 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + build: + image: cytnx:build + build: + context: . + dockerfile: docker/cytnx-cpu.Dockerfile + args: + - USE_OMP=OFF # This overrides everything + target: builder + env_file: + - docker/build_config.env # The base defaults + dev: + image: cytnx:dev + build: + context: . + dockerfile: docker/cytnx-cpu.Dockerfile + args: + - USE_OMP=OFF # This overrides everything + target: runtime + env_file: + - docker/build_config.env # The base defaults diff --git a/docker/build_config.env b/docker/build_config.env new file mode 100644 index 000000000..818376692 --- /dev/null +++ b/docker/build_config.env @@ -0,0 +1,18 @@ +CMAKE_INSTALL_PREFIX="/opt/conda" +BUILD_PYTHON="ON" +USE_ICPC="" +USE_MKL="" +USE_OMP="" +USE_CUDA="" +USE_HPTT="" +HPTT_ENABLE_FINE_TUNE="" +HPTT_ENABLE_AVX="" +HPTT_ENABLE_ARM="" +HPTT_ENABLE_IBM="" +USE_CUTENSOR="" +USE_CUQUANTUM="" +RUN_TESTS="" +RUN_BENCHMARKS="" +USE_DEBUG="" +BUILD_DOC="" +DEV_MODE="" diff --git a/docker/cytest-conda.Dockerfile b/docker/cytest-conda.Dockerfile new file mode 100644 index 000000000..9b07c48a4 --- /dev/null +++ b/docker/cytest-conda.Dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:latest +WORKDIR /opt + +ARG PY_VER="3.9" + +# --- 1. System Dependencies & Download (Separate RUNs for caching) +RUN apt-get update && apt-get install -y curl wget vim bash +RUN curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" + +# --- 2. Conda Installation, Environment Setup, and Package Install (Crucially, one combined RUN) +RUN bash Miniforge3-$(uname)-$(uname -m).sh -p /opt/conda -b && \ + rm Miniforge3-$(uname)-$(uname -m).sh && \ + \ + # Initialize the shell for Conda (using the profile script) + . /opt/conda/etc/profile.d/conda.sh && \ + \ + # Create the environment + conda create -n cytnx python=${PY_VER} _openmp_mutex=*=*_llvm -y && \ + \ + # Activate and install (must be in the same RUN command) + conda activate cytnx && \ + conda install -c kaihsinwu cytnx=1 -y && \ + # Clean up Conda files to keep the image small + conda clean --all -f -y && \ + conda install -c conda-forge gxx=14 make cmake -y + +# --- 3. Final Environment Configuration +# Set the PATH to include the Conda environment binaries +ENV PATH="/opt/conda/envs/cytnx/bin:/opt/conda/bin:$PATH" + +WORKDIR /work + +CMD ["/bin/bash"] diff --git a/docker/cytnx-cpu.Dockerfile b/docker/cytnx-cpu.Dockerfile new file mode 100644 index 000000000..5bc6391b5 --- /dev/null +++ b/docker/cytnx-cpu.Dockerfile @@ -0,0 +1,74 @@ +### Generator Stage +FROM python:3.12-slim AS generator +WORKDIR /build + +# Use conda cytnx package or build from source +ARG cytnx_conda="OFF" + +# Conda packages version config +ARG cytnx_ver="1" +ARG py_ver="3.12" +ARG compilers_ver="" +ARG make_ver="" +ARG cmake_ver="" + +# Pass to environment +ENV cytnx_conda=${cytnx_conda} +ENV cy_ver=${cy_ver} +ENV py_ver=${py_ver} +ENV compilers_ver=${compilers_ver} +ENV make_ver=${make_ver} +ENV cmake_ver=${cmake_ver} + +# Set Cytnx compilation build config for build script +COPY docker/build_config.env . +RUN export $(cat build_config.env | xargs) + +COPY docker/generate_conda_deps.py docker/generate_build_cytnx.py . +RUN python3 generate_conda_deps.py +RUN python3 generate_build_cytnx.py + + +### Build stage +FROM continuumio/miniconda3:v25.11.1 AS builder +WORKDIR /opt + +# Run conda dependency install script +COPY --from=generator /build/install_conda_deps.sh /build/build_cytnx.sh . +RUN bash install_conda_deps.sh && conda install -y -c conda-forge conda-pack + +# Copy cytnx source code +# Dockerfile should be built from the root of the repo!! +COPY . ./Cytnx + +# CMake configure, build and install Cytnx +RUN bash build_cytnx.sh + +CMD ["/bin/bash"] + +# 2. Pack the environment into a standalone archive +# RUN conda-pack -p /opt/conda -o /tmp/env.tar.gz && \ +# mkdir /runtime && cd /runtime && tar -xzf /tmp/env.tar.gz && \ +# rm /tmp/env.tar.gz + + +### Runtime Stage +# FROM debian:bookworm-slim AS runtime +# WORKDIR /app +# +# # Install minimal system libraries (OpenMP, etc. required by C++ apps) +# RUN apt-get update && apt-get install -y --no-install-recommends \ +# libgomp1 \ +# && rm -rf /var/lib/apt/lists/* +# +# # Copy the packed environment from the builder +# COPY --from=builder /runtime /opt/venv +# +# # Set environment paths so Python and Cytnx are found +# ENV PATH="/opt/venv/bin:$PATH" +# ENV LD_LIBRARY_PATH="/opt/venv/lib:$LD_LIBRARY_PATH" +# +# # Test if it works +# # RUN python3 -c "import cytnx; print('Cytnx version:', cytnx.__version__)" +# +# CMD [ "/bin/bash" ] diff --git a/docker/generate_build_cytnx.py b/docker/generate_build_cytnx.py new file mode 100644 index 000000000..b9b420282 --- /dev/null +++ b/docker/generate_build_cytnx.py @@ -0,0 +1,47 @@ +import os + +def generate_build_cytnx(): + # Handle CMake Build Flags + # This list maps the Docker ARG names to the desired Shell ENV names + flags = [ + "CMAKE_INSTALL_PREFIX", "BUILD_PYTHON", "USE_ICPC", "USE_MKL", + "USE_OMP", "USE_CUDA", "USE_HPTT", "USE_CUTENSOR", "USE_CUQUANTUM" + ] + + with open("build_cytnx.sh", "w") as f: + f.write("#!/bin/bash\n") + for flag in flags: + # Hierarchy: Build Arg (env var) > Default Value ("OFF") + val = os.environ.get(flag, "") + if val: + f.write(f'export {flag}="{val}"\n') + + # If install Cytnx from conda, skip CMake build + install_cytnx_conda = os.environ.get("cytnx_conda", "OFF") + if install_cytnx_conda == "ON": + print("cytnx_conda=ON, skipping CMake build of Cytnx.") + return + + # CMake configure and build Cytnx + # Assuming source code mounted at ./Cytnx + with open("build_cytnx.sh", "a") as f: + f.write("\n") + f.write("cd Cytnx\n") + f.write("mkdir build\n") + f.write("cd build\n") + f.write("cmake .. \\\n") + for flag in flags: + val = os.environ.get(flag, "") + if val: + f.write(f' -D{flag}="${{{flag}}}" \\\n') + # f.write(" -DCMAKE_BUILD_TYPE=Release\n") + # f.write("make -j$(nproc)\n") + f.write("make\n") + f.write("make install\n") + + with open("build_cytnx.sh", "r") as f: + print(f.read()) + +if __name__ == "__main__": + generate_build_cytnx() + diff --git a/docker/generate_conda_deps.py b/docker/generate_conda_deps.py new file mode 100644 index 000000000..6e43a8651 --- /dev/null +++ b/docker/generate_conda_deps.py @@ -0,0 +1,41 @@ +import os + +def generate_conda_deps(): + # Handle Conda Dependencies + # Pin to latest versions as of 2026-02-05 + conda_deps = { + "python": os.environ.get("py_ver", "3.12"), + "compilers": os.environ.get("compilers_ver", ""), + "make": os.environ.get("make_ver", ""), + # "cmake": os.environ.get("cmake_ver", "3.26"), + "cmake": os.environ.get("cmake_ver", ""), + "numpy": os.environ.get("numpy_ver", ""), # Empty string means latest + "boost": os.environ.get("boost_ver", ""), + "libboost": os.environ.get("libboost_ver", ""), + "pybind11": os.environ.get("pybind11_ver", ""), + "openblas": os.environ.get("openblas_ver", ""), + "arpack": os.environ.get("arpack_ver", ""), + } + + # Standard deps without specific version args in your Dockerfile + extra_deps = ["git", "beartype", "gtest", "benchmark"] + + conda_cmd = ["conda", "install", "-y", "-c", "conda-forge"] + for pkg, ver in conda_deps.items(): + conda_cmd.append(f"{pkg}={ver}" if ver else pkg) + conda_cmd.extend(extra_deps) + + # Directly install conda cytnx package if cytnx_conda="ON" + install_cytnx_conda = os.environ.get("cytnx_conda", "OFF") + if install_cytnx_conda == "ON": + cytnx_ver = os.environ.get("cytnx_ver", "1.0.0") + conda_cmd = ["conda", "install", "-y", "-c", "kaihsinwu", f"cytnx={cytnx_ver}"] + elif install_cytnx_conda != "OFF": + raise ValueError(f"Invalid value for cytnx_conda: {install_cytnx_conda}") + + with open("install_conda_deps.sh", "w") as f: + f.write("#!/bin/bash\n") + f.write(" ".join(conda_cmd) + "\n") + +if __name__ == "__main__": + generate_conda_deps()