.. highlight:: rest
.. _sec-compiling:
Compiling and Installing SLUG
==============================
Compilation is only necessary if you are installing SLUG from source, as
described in :ref:`sec-getting`. 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
:ref:`sec-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 :ref:`sec-pip-install-source`
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.
.. _sec-dependencies:
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 :ref:`sec-getting` 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 ```` (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 ```` 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 ```` 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 ``
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
:ref:`sec-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 :ref:`sec-running-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
`_:
.. code-block:: bash
pip install sphinx breathe exhale sphinx_rtd_theme
to build this documentation site itself as part of the normal build --
see :ref:`sec-building-docs` below. Entirely optional: every other part
of the build is unaffected if these aren't installed.
Python
~~~~~~~
SLUG's Python frontend, ``slugpy`` (see :ref:`sec-slugpy`), requires Python
3.12 or later, plus `astropy `_, `h5py
`_, `NumPy `_, `platformdirs
`_, `SciPy `_,
`tomlkit `_, `tqdm
`_, and `urllib3 `_:
.. code-block:: bash
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
:ref:`sec-pip-install-source`), ``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:
.. code-block:: bash
pip install pytest pyright ruff
.. _sec-building:
Configuring and Building
--------------------------
SLUG uses an out-of-source CMake build. From the repository root:
.. code-block:: bash
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 :ref:`sec-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 :ref:`sec-dependencies` above for
what that interpreter needs installed.
``-DSLUG_MDSPAN_PROVIDER=AUTO|NATIVE|PACKAGE|SUBMODULE``
Override the automatic ```` 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 :ref:`sec-parameters` for details. For
example, if you cloned the repository into ``/home/user/slug3``, you can do:
.. code-block:: bash
export SLUG_DIR=/home/user/slug3
This step is not necessary if you installed SLUG from PyPI or a container, or if
you have :ref:`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 :ref:`sec-tests` for the full detail).
.. _sec-pip-install-source:
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:
.. code-block:: bash
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 :ref:`sec-getting`); the
Python dependencies listed above are installed automatically. You still need a
C++ compiler, CMake, GSL, and HDF5, as described in :ref:`sec-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``:
.. code-block:: bash
CMAKE_ARGS="-DSLUG_ENABLE_MPI=ON" pip install .
Other CMake options described above can be passed the same way.
.. _sec-building-docs:
Building this Documentation
------------------------------
If Doxygen and the Python packages Sphinx, Breathe, and Exhale (see
:ref:`sec-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:
.. code-block:: bash
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. :ref:`sec-slugpy-full`, imports ``slugpy``,
which fails without it):
.. code-block:: bash
cmake --build build --target slugPython
cd doc/sphinx
make html