From 9a98a8d152da8f49f72b13cbb0208763c1a03e23 Mon Sep 17 00:00:00 2001 From: Jannis Maier Date: Thu, 2 Jul 2026 16:44:30 +0200 Subject: [PATCH] Add bootstrap workflow --- README.md | 43 ++++++++++++-- tools/bootstrap.sh | 138 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 5 deletions(-) create mode 100755 tools/bootstrap.sh diff --git a/README.md b/README.md index 94aaa7a..6b69d4a 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,51 @@ pip install rayx > **Note:** The package includes a compiled C++ extension and is distributed as a pre-built wheel. Source builds are not supported via pip. +## Requirements + +For development builds (not needed for the `pip install` above): + +- **uv** — package/environment manager used for development builds. [Install guide](https://docs.astral.sh/uv/getting-started/installation/) +- **Python** — 3.12 is recommended [Download](https://www.python.org/downloads/) +- **HDF5** — required by `rayx-core` for compilation. Install via your system package manager (e.g. `apt install libhdf5-dev` on Debian/Ubuntu, `brew install hdf5` on macOS). See the [HDF5 docs](https://docs.hdfgroup.org/hdf5/develop/_getting_started.html) if you need a different install method. +- **NVIDIA GPU driver** — only required for CUDA-accelerated builds. Verify with `nvidia-smi`. [Download](https://www.nvidia.com/Download/index.aspx) +- **CUDA Toolkit** — only required for CUDA-accelerated builds. Verify with `nvcc --version`. [Download](https://developer.nvidia.com/cuda-downloads) + +If the toolkit is installed but `nvcc` isn't found, its `bin` directory is missing from `PATH`: + +```bash +export PATH=/usr/local/cuda/bin:$PATH +``` + +Make it permanent by adding that line to `~/.bashrc` (or `~/.zshrc`) and reloading. + ## Development The package can be built in two ways: -1. with `cmake` -2. with `uv build` -The 1. option supports build cashing and the build result can be used immediatly without any installation steps. See [example](./examples/metrix.ipynb) -The 2. option builds the package as a wheel. The resulting wheel can be installed in your python environment. +1. **CMake** — supports build caching; the result is usable immediately with no install step. See the [example notebook](./examples/metrix.ipynb). +2. **`uv build`** — builds the package as a wheel, which can then be installed into any Python environment. + +```bash +git submodule update --init --recursive + +# Option 1: build in place with CMake (uv creates/manages the environment) +uv run cmake -S . -B build +uv run cmake --build build -j + +# Option 2: editable install via uv +uv pip install -e . +``` + +`uv run` puts the managed environment's Python first on `PATH`, so CMake's `find_package(Python)` resolves the right interpreter without pinning it manually. + +`uv pip install -e .` only re-links the Python wrapper files. It does **not** rebuild the compiled bindings — if you change `rayx-core` or the nanobind glue in `rayxpy`, rerun the CMake commands (Option 1) to recompile, or the install will keep serving the stale extension. + +A `tools/bootstrap.sh` helper script is also available, wrapping the steps above with CUDA on/off prompting. ### Running tests -To run the tests you need to build the package with cmake. +Tests require a CMake build: ```bash uv run pytest tests diff --git a/tools/bootstrap.sh b/tools/bootstrap.sh new file mode 100755 index 0000000..181145b --- /dev/null +++ b/tools/bootstrap.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +cd "$ROOT_DIR" + +usage() { + cat <<'EOF' +Usage: tools/bootstrap.sh [--with-nvidia|--without-nvidia] + +Options: + --with-nvidia Build with NVIDIA/CUDA support. + --without-nvidia Build without NVIDIA/CUDA support. + -h, --help Show this help message. +EOF +} + +if ! command -v uv >/dev/null 2>&1; then + echo "Error: uv is not installed or not in PATH." >&2 + echo "Install uv from https://docs.astral.sh/uv/getting-started/installation/" >&2 + exit 1 +fi + +PYTHON_SPEC="${PYTHON_SPEC:-3.12}" +USE_NVIDIA="with" +NVIDIA_MODE_SET=0 + +while [ "$#" -gt 0 ]; do + case "$1" in + --with-nvidia|--nvidia) + USE_NVIDIA="with" + NVIDIA_MODE_SET=1 + ;; + --without-nvidia|--no-nvidia) + USE_NVIDIA="without" + NVIDIA_MODE_SET=1 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Error: unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac + shift +done + +if [ "$NVIDIA_MODE_SET" -eq 0 ] && [ -t 0 ] && [ -t 1 ]; then + read -r -p "Build with NVIDIA/CUDA support? [Y/n] " response + case "$response" in + [Nn]|[Nn][Oo]) + USE_NVIDIA="without" + ;; + *) + USE_NVIDIA="with" + ;; + esac +fi + +venv_matches_python_spec() { + if [ ! -x ".venv/bin/python" ]; then + return 1 + fi + local version + version="$(".venv/bin/python" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" + [ "$version" = "$PYTHON_SPEC" ] +} + +have_nvidia_smi=0 +have_nvcc=0 +nvcc_path_hint=0 + +if command -v nvidia-smi >/dev/null 2>&1; then + have_nvidia_smi=1 +fi + +if command -v nvcc >/dev/null 2>&1; then + have_nvcc=1 +elif [ -x "/usr/local/cuda/bin/nvcc" ]; then + nvcc_path_hint=1 +fi + +if [ "$USE_NVIDIA" = "with" ] && { [ "$have_nvidia_smi" -ne 1 ] || [ "$have_nvcc" -ne 1 ]; }; then + echo "Error: CUDA prerequisites are missing." >&2 + + if [ "$have_nvidia_smi" -ne 1 ]; then + echo " - NVIDIA driver not found: install the driver so nvidia-smi works." >&2 + fi + + if [ "$have_nvcc" -ne 1 ]; then + if [ "$nvcc_path_hint" -eq 1 ]; then + echo " - CUDA toolkit found at /usr/local/cuda/bin but not in PATH." >&2 + echo " See README.md for how to add it to your PATH." >&2 + else + echo " - CUDA toolkit not found: install the CUDA toolkit so nvcc works." >&2 + fi + fi + + echo "See: README.md" >&2 + exit 1 +fi + +if [ "$USE_NVIDIA" = "with" ]; then + echo "Bootstrapping with NVIDIA/CUDA support enabled." + BOOTSTRAP_CMAKE_ARGS="-DRAYX_ENABLE_CUDA=ON -DRAYX_REQUIRE_CUDA=ON" +else + echo "Bootstrapping with NVIDIA/CUDA support disabled." + BOOTSTRAP_CMAKE_ARGS="-DRAYX_ENABLE_CUDA=OFF -DRAYX_REQUIRE_CUDA=OFF" +fi + +echo "Updating git submodules" +git submodule update --init --recursive + +if [ -d ".venv" ]; then + if venv_matches_python_spec; then + echo "Using existing virtual environment at .venv (Python ${PYTHON_SPEC})" + else + echo "Existing .venv does not use Python ${PYTHON_SPEC}; recreating." + rm -rf .venv + echo "Creating virtual environment at .venv with Python ${PYTHON_SPEC}" + uv venv --python "${PYTHON_SPEC}" .venv + fi +else + echo "Creating virtual environment at .venv with Python ${PYTHON_SPEC}" + uv venv --python "${PYTHON_SPEC}" .venv +fi + +echo "Installing rayx in editable mode (-e)" +echo "Note: this triggers the CMake/scikit-build-core build — cmake and a C++ compiler must be available." +CMAKE_ARGS="${CMAKE_ARGS:+${CMAKE_ARGS} }${BOOTSTRAP_CMAKE_ARGS}" \ + uv pip install --python .venv/bin/python -e . + +echo "Bootstrap complete." +echo "Activate with: source .venv/bin/activate"