Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ RUN apt-get update && \
gnupg \
build-essential \
cmake \
ccache \
clang \
pkg-config \
python3 \
Expand All @@ -54,6 +55,11 @@ RUN apt-get update && \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install the memory-/core-aware build parallelism helper. It is used during
# dependency installation and may also be sourced by development scripts and
# interactive shells.
COPY .devcontainer/scripts/parallelism.sh /usr/local/share/qdk/parallelism.sh

# Install C++ dependencies
COPY .devcontainer/scripts/install_cpp_dependencies.sh /tmp/install_cpp_dependencies.sh
COPY cpp/manifest/qdk-chemistry/cgmanifest.json /tmp/cpp_cgmanifest.json
Expand All @@ -62,7 +68,7 @@ COPY external/macis/manifest/cgmanifest.json /tmp/macis_cgmanifest.json
# Delete build directory after installation
ENV KEEP_BUILD_DIR=0
RUN bash /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json && \
rm /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json
rm /tmp/install_cpp_dependencies.sh /tmp/cpp_cgmanifest.json /tmp/macis_cgmanifest.json

# Create/align the non-root user and group (safe for repeated builds)
RUN if getent group "$USER_GID" >/dev/null; then \
Expand All @@ -89,3 +95,23 @@ USER $USERNAME

# Setup bash prompt
RUN echo 'export PS1="\[\033[1;34m\]\u@qdk-dev:\w$ \[\033[0m\]"' >> ~/.bashrc

# Create the Python virtual environment and pre-install workspace-independent
# Python dev dependencies.
ENV VIRTUAL_ENV=/home/$USERNAME/qdk_chemistry_venv \
PATH=/home/$USERNAME/qdk_chemistry_venv/bin:$PATH

RUN python -m venv "$VIRTUAL_ENV" \
&& pip install --no-cache-dir --upgrade pip setuptools wheel \
&& pip install --no-cache-dir \
"ipykernel>=6.0" \
"pandas>=2.0.0" \
"pre-commit>=4.6,<5" \
"rdkit" \
&& echo "source $VIRTUAL_ENV/bin/activate" >> ~/.bashrc
Comment thread
eimrek marked this conversation as resolved.

# Set the safe CMAKE_BUILD_PARALLEL_LEVEL for interactive shells
RUN echo "source /usr/local/share/qdk/parallelism.sh" >> ~/.bashrc

# Make user-local C++ installations discoverable
ENV CMAKE_PREFIX_PATH=/home/$USERNAME/.local
19 changes: 19 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"features": {
"ghcr.io/devcontainers/features/git:1": {
"version": "1.3.5",
"resolved": "ghcr.io/devcontainers/features/git@sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251",
"integrity": "sha256:27905dc196c01f77d6ba8709cb82eeaf330b3b108772e2f02d1cd0d826de1251"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "1.7.1",
"resolved": "ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6",
"integrity": "sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6"
},
"ghcr.io/devcontainers/features/rust:1": {
"version": "1.5.0",
"resolved": "ghcr.io/devcontainers/features/rust@sha256:0c55e65f2e3df736e478f26ee4d5ed41bae6b54dac1318c443e31444c8ed283c",
"integrity": "sha256:0c55e65f2e3df736e478f26ee4d5ed41bae6b54dac1318c443e31444c8ed283c"
}
}
}
24 changes: 17 additions & 7 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
"ms-toolsai.jupyter"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.defaultInterpreterPath": "${containerEnv:VIRTUAL_ENV}/bin/python",
"python.formatting.provider": "none",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": true,
"source.organizeImports.ruff": true
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
Comment thread
eimrek marked this conversation as resolved.
Outdated
},
"python.linting.enabled": true,
"python.linting.lintOnSave": true,
Expand Down Expand Up @@ -55,16 +55,26 @@
"C_Cpp.codeAnalysis.clangTidy.runAutomatically": true,
"C_Cpp.formatting": "clangFormat",
"C_Cpp.clang_format_style": "file",
"C_Cpp.clang_format_fallbackStyle": "Google"
"C_Cpp.clang_format_fallbackStyle": "Google",
"C_Cpp.default.cppStandard": "c++20",
"cmake.buildType": "Debug"
}
}
},
"features": {
"ghcr.io/devcontainers/features/git:1": {}
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "lts"
},
"ghcr.io/devcontainers/features/rust:1": {
"version": "stable",
"profile": "default"
}
},
"remoteEnv": {
"CPATH": "${containerEnv:CPATH}:/usr/include/hdf5/serial:/usr/include/eigen3"
"CPATH": "${containerEnv:CPATH}:/usr/include/hdf5/serial:/usr/include/eigen3",
"CMAKE_BUILD_TYPE": "Debug"
},
"postCreateCommand": "bash .devcontainer/scripts/venv.sh",
"postCreateCommand": "bash .devcontainer/scripts/post_create.sh",
"remoteUser": "vscode"
}
26 changes: 21 additions & 5 deletions .devcontainer/scripts/install_cpp_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,30 @@ BUILD_DIR="${BUILD_DIR:-/tmp/qdk_deps_build}"
INSTALL_PREFIX="${INSTALL_PREFIX:-/usr/local}"
BUILD_TYPE="${BUILD_TYPE:-Release}"
BUILD_SHARED_LIBS="${BUILD_SHARED_LIBS:-OFF}" # Default to static
LIBINT_JOBS=${LIBINT_JOBS:-4} # Limit libint build jobs to 4 due to high memory usage

KEEP_BUILD_DIR="${KEEP_BUILD_DIR:-0}"
if command -v nproc >/dev/null 2>&1; then
JOBS=$(nproc) # Linux

PARALLELISM_HELPER="/usr/local/share/qdk/parallelism.sh"
if [ -f "$PARALLELISM_HELPER" ]; then
# shellcheck source=/dev/null
source "$PARALLELISM_HELPER"
fi

if command -v parallel_jobs_for_memory >/dev/null 2>&1; then
# Use the parallelism helper to determine job counts based on memory
JOBS="${JOBS:-$(parallel_jobs_for_memory 1)}"
LIBINT_JOBS="${LIBINT_JOBS:-$(parallel_jobs_for_memory 4)}"
else
Comment thread
eimrek marked this conversation as resolved.
JOBS=$(sysctl -n hw.logicalcpu) # macOS
# Fallback when helper is unavailable
if command -v nproc >/dev/null 2>&1; then
DEFAULT_JOBS=$(nproc) # Linux
else
DEFAULT_JOBS=$(sysctl -n hw.logicalcpu) # macOS
fi
JOBS="${JOBS:-$DEFAULT_JOBS}"
LIBINT_JOBS="${LIBINT_JOBS:-4}"
fi

MAC_BUILD="OFF"
if [[ "$OSTYPE" == "darwin"* ]]; then
MAC_BUILD="ON"
Expand Down Expand Up @@ -224,7 +241,6 @@ cmake .. -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DBUILD_SHARED_LIBS="$BUILD_SHARED_LIBS"
# libint's compilation is memory intensive so parallel jobs are limited to 4 to prevent OOM errors
make -j"$LIBINT_JOBS"
make install
cd "$BUILD_DIR"
Expand Down
56 changes: 56 additions & 0 deletions .devcontainer/scripts/parallelism.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# shellcheck shell=bash
#
# This file is intended to be sourced.
#
# It provides:
# - parallel_jobs_for_memory()
# - a default CMAKE_BUILD_PARALLEL_LEVEL (unless already set)
#
# parallel_jobs_for_memory <memory_per_job_gb>
#
# Compute a safe parallel job count based on available RAM and CPU cores.
#
# Result:
# min(cpu_cores, floor(total_ram_gb / memory_per_job_gb))
#
# with a minimum value of 1.
#
parallel_jobs_for_memory() {
local memory_per_job_gb="$1"
local cores mem_bytes jobs

if command -v nproc >/dev/null 2>&1; then
# Linux
cores=$(nproc)
mem_bytes=$(awk '/MemTotal/ {print $2 * 1024}' /proc/meminfo)
else
# macOS
cores=$(sysctl -n hw.logicalcpu)
mem_bytes=$(sysctl -n hw.memsize)
fi
Comment thread
eimrek marked this conversation as resolved.
Comment thread
Copilot marked this conversation as resolved.
Outdated

# If running inside a cgroup with a memory limit, respect it.
local cgroup_limit_bytes=""
if [ -r /sys/fs/cgroup/memory.max ]; then
cgroup_limit_bytes="$(cat /sys/fs/cgroup/memory.max)" # cgroup v2
elif [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
cgroup_limit_bytes="$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)" # cgroup v1
fi
if [[ "$cgroup_limit_bytes" =~ ^[0-9]+$ ]] && (( cgroup_limit_bytes > 0 )) && (( cgroup_limit_bytes < mem_bytes )); then
mem_bytes="$cgroup_limit_bytes"
fi

# tiny overhead to get common cases correct (e.g., 15.9GB RAM, 8GB per job -> 2 jobs)
mem_bytes=$(( mem_bytes * 103 / 100 ))

jobs=$(( mem_bytes / (memory_per_job_gb * 1024 * 1024 * 1024) ))
Comment thread
eimrek marked this conversation as resolved.
Comment thread
eimrek marked this conversation as resolved.

(( jobs < 1 )) && jobs=1
(( jobs > cores )) && jobs=$cores

echo "$jobs"
}

if [ -z "${CMAKE_BUILD_PARALLEL_LEVEL:-}" ]; then
export CMAKE_BUILD_PARALLEL_LEVEL="$(parallel_jobs_for_memory 8)"
fi
21 changes: 21 additions & 0 deletions .devcontainer/scripts/post_create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
# Post-create step: install QDK Chemistry from the mounted source.
set -euo pipefail
source "$HOME/qdk_chemistry_venv/bin/activate"
Comment thread
eimrek marked this conversation as resolved.

# Set a memory-/core-aware CMAKE_BUILD_PARALLEL_LEVEL (unless already set) so the
# initial build below does not oversubscribe CPU or OOM on constrained machines.
source /usr/local/share/qdk/parallelism.sh

# Build C++ and install to a user-local prefix.
# Use the in-tree macis (external/macis) per INSTALL.md; prevents a
# full rebuild on reconfigure.
cmake -S cpp -B cpp/build -G Ninja \
-DCMAKE_INSTALL_PREFIX="$HOME/.local" \
-DCMAKE_DISABLE_FIND_PACKAGE_macis=ON
cmake --build cpp/build
cmake --install cpp/build

# Install python library
cd ./python
pip install -v .[all]
Comment thread
eimrek marked this conversation as resolved.
28 changes: 0 additions & 28 deletions .devcontainer/scripts/venv.sh

This file was deleted.

4 changes: 4 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ Alternatively, click the green button in the bottom-left corner of VS Code and s

After the initial build, restart VS Code and reopen in the container to ensure the Python virtual environment is properly loaded.

### Step 4: Develop

The dev container builds the C++ library and links it to the Python package in separate steps, as shown in `.devcontainer/scripts/post_create.sh`. After changing the source code, you need to rebuild and install accordingly.
Comment thread
eimrek marked this conversation as resolved.

Comment thread
eimrek marked this conversation as resolved.
Comment thread
eimrek marked this conversation as resolved.
Comment thread
eimrek marked this conversation as resolved.
**NOTE:**

- The first build can take up to two hours on slower systems.
Expand Down
Loading