Compiling and Installing SLUG

Compilation is only necessary if you are installing SLUG from source, as described in Getting SLUG. If you are installing from PyPI or a container, you can skip this section.

There are two ways to build a source checkout. The first, described in Configuring and Building below, is to build it in place with CMake. This has no separate installation step: it produces the slug command-line executable directly in the build directory, and the compiled Python extension module lands directly inside the slugpy package in the source tree, alongside its pure-Python code. This is the most flexible option, and the one to use if you plan to modify SLUG. The second, described in Installing a Source Checkout with pip below, is to build and install it into a Python environment with pip, exactly as a PyPI installation would, but compiled on your own system.

Dependencies

Required

  • CMake, version 3.15 or later.

  • A C++23-capable compiler. The following compilers are known to work:

    • GCC 13 or later

    • Clang 17 or later (paired with a libc++ of the same version or newer)

    • Intel’s LLVM-based icpx/oneAPI 2024.2.0+ (requires the flag -fp-model=strict for correct behavior)

    • Other C++23-capable compilers have not been tested.

  • The GNU Scientific Library (GSL).

  • HDF5 (only its C library is needed; HDF5’s optional C++ component is not required).

Bundled (no action needed)

These are vendored as git submodules under src/extern and built automatically as part of the normal build – just make sure they were fetched (see Getting SLUG on cloning with submodules; if you forgot, git submodule update --init --recursive from the repository root fetches them after the fact too):

  • pybind11, used to build the Python bindings (see below).

  • A reference implementation of C++23’s <mdspan> (from the Kokkos mdspan project), used as a last resort if neither the compiler’s own standard library nor an externally installed mdspan package provides one.

    Whether a given compiler provides <mdspan> natively depends on the exact standard-library snapshot it was built against, not just its nominal major version – e.g. Homebrew’s own gcc@16 build on macOS bundles a libstdc++ new enough to have it, while the gcc-16 package from Ubuntu’s ppa:ubuntu-toolchain-r/test (as used in CI) does not, as of when this was last checked, and Apple’s own system Clang/libc++ has no native <mdspan> at all. None of this matters in practice: cmake/Mdspan.cmake detects native support with a real compile check (not a version guess) and falls back automatically, in the order listed above, to an externally-installed mdspan package and then this bundled submodule – see that file’s own comments, or AGENTS.md, for the full detail. Application code always just does #include <mdspan> regardless of which provider actually supplied it.

    One further wrinkle specific to this bundled fallback: its own config.hpp deliberately disables its multi-index operator[] on Clang versions before 17, as a workaround for a documented upstream Clang bug with parameter packs in bracket operators – so a build that falls back to this submodule under Clang 16 or earlier fails with “no viable overloaded operator[]” errors on every mdspan indexing expression, even though Clang itself supports the multidimensional operator[] language feature from an earlier version (see Dependencies above). This is why Clang’s own effective minimum version is 17, one version above where the language feature itself first appears.

Optional

  • OpenMP, for multi-threaded execution. If no OpenMP implementation is found, the build falls back to a single-threaded binary automatically, with a warning at configure time.

  • An MPI implementation (e.g. OpenMPI or MPICH), for multi-process execution across more than one machine – see Running SLUG With MPI. If none is found, the build falls back to a single-process binary automatically, with a warning at configure time, the same way OpenMP does above; the two are independent of each other, so a build can have either, both, or neither. MPI support only applies to the slug command-line executable itself, not the Python bindings.

  • Ninja, as the CMake generator. Not required – CMake falls back to its own platform default (Unix Makefiles on Linux/macOS) – but Ninja parallelizes the build automatically and matches what SLUG’s own CI uses, so local builds behave the same way and incremental rebuilds are noticeably faster.

  • Doxygen (install separately, e.g. via your system package manager or Homebrew), plus the Python packages Sphinx, Breathe, and Exhale:

    pip install sphinx breathe exhale sphinx_rtd_theme
    

    to build this documentation site itself as part of the normal build – see Building this Documentation below. Entirely optional: every other part of the build is unaffected if these aren’t installed.

Python

SLUG’s Python frontend, slugpy (see slugpy), requires Python 3.12 or later, plus astropy, h5py, NumPy, platformdirs, SciPy, tomlkit, tqdm, and urllib3:

pip install astropy h5py numpy platformdirs scipy tomlkit tqdm urllib3

CMake builds the compiled _slug extension module against whichever Python interpreter it finds (or the one given explicitly via -DPython_EXECUTABLE, see below), and that same interpreter needs the packages above installed for import slugpy to work afterwards. pyproject.toml lists these same packages (and the optional ones just below) under [project.dependencies]/[project.optional-dependencies]. If you instead install a source checkout with pip (see Installing a Source Checkout with pip), pip installs them automatically.

A further three tools are needed only for specific development tasks, not for using slugpy itself: pytest to run the test suite, pyright to type-check slugpy locally, and ruff to lint it:

pip install pytest pyright ruff

Configuring and Building

SLUG uses an out-of-source CMake build. From the repository root:

cmake -S . -B build -G Ninja
cmake --build build

(omit -G Ninja to use CMake’s own default generator instead, if Ninja isn’t installed – see Dependencies above). This produces the slug command-line executable at build/slug, and builds the compiled Python extension module directly into the slugpy package in the source tree (so import slugpy works from the repository root immediately afterward, with no separate install step).

A few configure-time options worth knowing about:

-DPython_EXECUTABLE=/path/to/python3

Build the Python bindings against a specific Python interpreter, rather than whichever one CMake finds automatically. Needed if you use a virtual environment, conda environment, or other non-default interpreter for slugpy – see Dependencies above for what that interpreter needs installed.

-DSLUG_MDSPAN_PROVIDER=AUTO|NATIVE|PACKAGE|SUBMODULE

Override the automatic <mdspan> provider selection described above – e.g. to require a specific provider and get a hard error if it isn’t available, rather than a silent fallback. Defaults to AUTO.

-DCMAKE_BUILD_TYPE=Debug|Release|RelWithDebInfo

The usual CMake build-type switch. If it is not given, SLUG defaults to Release, an optimized build with assertions disabled; use Debug to turn on SLUG’s internal assertion checks, e.g. when developing or debugging the code. Some of SLUG’s own performance- sensitive targets (e.g. the Python extension module) are always built with optimizations enabled regardless of this setting, since they drive the same interpolation-heavy code any analysis using slugpy depends on.

Setting the Data Path

Once SLUG is built, it is recommended but not required to set the environment variable SLUG_DIR to the repository root directory. This simplifies finding the data files that SLUG needs to run by providing an automatic search path that will be used when parsing the inputs – see The SLUG Input Deck for details. For example, if you cloned the repository into /home/user/slug3, you can do:

export SLUG_DIR=/home/user/slug3

This step is not necessary if you installed SLUG from PyPI or a container, or if you have built and installed with pip, since those installation methods automatically set up the data path for you.

Verifying the Build

Once the build finishes, ctest (run from the build directory) executes SLUG’s own test suite:

cd build
ctest -L quick

The quick label selects tests that run in a few seconds each and need no large data files beyond what’s already committed to the repository; some further, slower end-to-end tests exist but require data files too large to distribute this way (see Tests for the full detail).

Installing a Source Checkout with pip

Instead of building in place, you can build and install a source checkout into the active Python environment by running, from the repository root:

pip install .

This uses the same CMake build, driven by scikit-build-core, to compile SLUG, and then installs the slugpy package, the slug command-line executable, and the small data files distributed with the source code into the environment, exactly as installing from PyPI does (see Getting SLUG); the Python dependencies listed above are installed automatically. You still need a C++ compiler, CMake, GSL, and HDF5, as described in Dependencies. As with a PyPI installation, the large data files are not installed this way; download them with python -m slugpy.download_data, or point the SLUG_DIR environment variable at an existing copy of them (e.g., the repository root of a checkout into which you have already downloaded them).

The installed slug executable is built without MPI support by default, so that it does not depend on any particular MPI library. To build it with MPI support, pass the corresponding CMake option through pip:

CMAKE_ARGS="-DSLUG_ENABLE_MPI=ON" pip install .

Other CMake options described above can be passed the same way.

Building this Documentation

If Doxygen and the Python packages Sphinx, Breathe, and Exhale (see Dependencies above) are all found at configure time, cmake --build build (with no explicit --target) builds this documentation site too, into doc/html, alongside everything else – if they aren’t found, that step is simply skipped, with a note printed at configure time, and every other target is unaffected. To build just the documentation without touching anything else:

cmake --build build --target docs

or, from doc/sphinx directly, without going through CMake at all – though in this case slugPython must already have been built (cmake --build build --target docs above builds it automatically first; this page’s own autodoc-generated content, e.g. The slug Python API, imports slugpy, which fails without it):

cmake --build build --target slugPython
cd doc/sphinx
make html