From c9677b24651270d1e9c7c3fe37329d460f5544b9 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Fri, 13 Oct 2023 14:59:44 +0200 Subject: Expand multiple build systems section (#39589) Co-authored-by: Massimiliano Culpo --- lib/spack/docs/packaging_guide.rst | 153 ++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 51 deletions(-) (limited to 'lib') diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index d25009532a..acc79ea342 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -3635,7 +3635,8 @@ regardless of the build system. The arguments for the phase are: The arguments ``spec`` and ``prefix`` are passed only for convenience, as they always correspond to ``self.spec`` and ``self.spec.prefix`` respectively. -If the ``package.py`` encodes builders explicitly, the signature for a phase changes slightly: +If the ``package.py`` has build instructions in a separate +:ref:`builder class `, the signature for a phase changes slightly: .. code-block:: python @@ -3645,56 +3646,6 @@ If the ``package.py`` encodes builders explicitly, the signature for a phase cha In this case the package is passed as the second argument, and ``self`` is the builder instance. -.. _multiple_build_systems: - -^^^^^^^^^^^^^^^^^^^^^^ -Multiple build systems -^^^^^^^^^^^^^^^^^^^^^^ - -There are cases where a software actively supports two build systems, or changes build systems -as it evolves, or needs different build systems on different platforms. Spack allows dealing with -these cases natively, if a recipe is written using builders explicitly. - -For instance, software that supports two build systems unconditionally should derive from -both ``*Package`` base classes, and declare the possible use of multiple build systems using -a directive: - -.. code-block:: python - - class ArpackNg(CMakePackage, AutotoolsPackage): - - build_system("cmake", "autotools", default="cmake") - -In this case the software can be built with both ``autotools`` and ``cmake``. Since the package -supports multiple build systems, it is necessary to declare which one is the default. The ``package.py`` -will likely contain some overriding of default builder methods: - -.. code-block:: python - - class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): - def cmake_args(self): - pass - - class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): - def configure_args(self): - pass - -In more complex cases it might happen that the build system changes according to certain conditions, -for instance across versions. That can be expressed with conditional variant values: - -.. code-block:: python - - class ArpackNg(CMakePackage, AutotoolsPackage): - - build_system( - conditional("cmake", when="@0.64:"), - conditional("autotools", when="@:0.63"), - default="cmake", - ) - -In the example the directive impose a change from ``Autotools`` to ``CMake`` going -from ``v0.63`` to ``v0.64``. - ^^^^^^^^^^^^^^^^^^ Mixin base classes ^^^^^^^^^^^^^^^^^^ @@ -3741,6 +3692,106 @@ for instance: In the example above ``Cp2k`` inherits all the conflicts and variants that ``CudaPackage`` defines. +.. _multiple_build_systems: + +---------------------- +Multiple build systems +---------------------- + +There are cases where a package actively supports two build systems, or changes build systems +as it evolves, or needs different build systems on different platforms. Spack allows dealing with +these cases by splitting the build instructions into separate builder classes. + +For instance, software that supports two build systems unconditionally should derive from +both ``*Package`` base classes, and declare the possible use of multiple build systems using +a directive: + +.. code-block:: python + + class Example(CMakePackage, AutotoolsPackage): + + variant("my_feature", default=True) + + build_system("cmake", "autotools", default="cmake") + +In this case the software can be built with both ``autotools`` and ``cmake``. Since the package +supports multiple build systems, it is necessary to declare which one is the default. + +Additional build instructions are split into separate builder classes: + +.. code-block:: python + + class CMakeBuilder(spack.build_systems.cmake.CMakeBuilder): + def cmake_args(self): + return [ + self.define_from_variant("MY_FEATURE", "my_feature") + ] + + class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder): + def configure_args(self): + return self.with_or_without("my-feature", variant="my_feature") + +In this example, ``spack install example +feature build_sytem=cmake`` will +pick the ``CMakeBuilder`` and invoke ``cmake -DMY_FEATURE:BOOL=ON``. + +Similarly, ``spack install example +feature build_system=autotools`` will pick +the ``AutotoolsBuilder`` and invoke ``./configure --with-my-feature``. + +Dependencies are always specified in the package class. When some dependencies +depend on the choice of the build system, it is possible to use when conditions as +usual: + +.. code-block:: python + + class Example(CMakePackage, AutotoolsPackage): + + build_system("cmake", "autotools", default="cmake") + + # Runtime dependencies + depends_on("ncurses") + depends_on("libxml2") + + # Lowerbounds for cmake only apply when using cmake as the build system + with when("build_system=cmake"): + depends_on("cmake@3.18:", when="@2.0:", type="build") + depends_on("cmake@3:", type="build") + + # Specify extra build dependencies used only in the configure script + with when("build_system=autotools"): + depends_on("perl", type="build") + depends_on("pkgconfig", type="build") + +Very often projects switch from one build system to another, or add support +for a new build system from a certain version, which means that the choice +of the build system typically depends on a version range. Those situations can +be handled by using conditional values in the ``build_system`` directive: + +.. code-block:: python + + class Example(CMakePackage, AutotoolsPackage): + + build_system( + conditional("cmake", when="@0.64:"), + conditional("autotools", when="@:0.63"), + default="cmake", + ) + +In the example the directive impose a change from ``Autotools`` to ``CMake`` going +from ``v0.63`` to ``v0.64``. + +The ``build_system`` can be used as an ordinary variant, which also means that it can +be used in ``depends_on`` statements. This can be useful when a package *requires* that +its dependency has a CMake config file, meaning that the dependent can only build when the +dependency is built with CMake, and not Autotools. In that case, you can force the choice +of the build system in the dependent: + +.. code-block:: python + + class Dependent(CMakePackage): + + depends_on("example build_system=cmake") + + .. _install-environment: ----------------------- -- cgit v1.2.3-70-g09d2