summaryrefslogtreecommitdiff
path: root/lib/spack/docs/packaging_guide.rst
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/docs/packaging_guide.rst')
-rw-r--r--lib/spack/docs/packaging_guide.rst168
1 files changed, 168 insertions, 0 deletions
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index 1c78a396e3..641bb74fea 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -1077,6 +1077,174 @@ Go cannot be used to fetch a particular commit or branch, it always
downloads the head of the repository. This download method is untrusted,
and is not recommended. Use another fetch strategy whenever possible.
+--------
+Variants
+--------
+
+Many software packages can be configured to enable optional
+features, which often come at the expense of additional dependencies or
+longer build-times. To be flexible enough and support a wide variety of
+use cases, Spack permits to expose to the end-user the ability to choose
+which features should be activated in a package at the time it is installed.
+The mechanism to be employed is the :py:func:`spack.directives.variant` directive.
+
+^^^^^^^^^^^^^^^^
+Boolean variants
+^^^^^^^^^^^^^^^^
+
+In their simplest form variants are boolean options specified at the package
+level:
+
+ .. code-block:: python
+
+ class Hdf5(AutotoolsPackage):
+ ...
+ variant(
+ 'shared', default=True, description='Builds a shared version of the library'
+ )
+
+with a default value and a description of their meaning / use in the package.
+*Variants can be tested in any context where a spec constraint is expected.*
+In the example above the ``shared`` variant is tied to the build of shared dynamic
+libraries. To pass the right option at configure time we can branch depending on
+its value:
+
+ .. code-block:: python
+
+ def configure_args(self):
+ ...
+ if '+shared' in self.spec:
+ extra_args.append('--enable-shared')
+ else:
+ extra_args.append('--disable-shared')
+ extra_args.append('--enable-static-exec')
+
+As explained in :ref:`basic-variants` the constraint ``+shared`` means
+that the boolean variant is set to ``True``, while ``~shared`` means it is set
+to ``False``.
+Another common example is the optional activation of an extra dependency
+which requires to use the variant in the ``when`` argument of
+:py:func:`spack.directives.depends_on`:
+
+ .. code-block:: python
+
+ class Hdf5(AutotoolsPackage):
+ ...
+ variant('szip', default=False, description='Enable szip support')
+ depends_on('szip', when='+szip')
+
+as shown in the snippet above where ``szip`` is modeled to be an optional
+dependency of ``hdf5``.
+
+^^^^^^^^^^^^^^^^^^^^^
+Multi-valued variants
+^^^^^^^^^^^^^^^^^^^^^
+
+If need be, Spack can go beyond Boolean variants and permit an arbitrary
+number of allowed values. This might be useful when modeling
+options that are tightly related to each other.
+The values in this case are passed to the :py:func:`spack.directives.variant`
+directive as a tuple:
+
+ .. code-block:: python
+
+ class Blis(Package):
+ ...
+ variant(
+ 'threads', default='none', description='Multithreading support',
+ values=('pthreads', 'openmp', 'none'), multi=False
+ )
+
+In the example above the argument ``multi`` is set to ``False`` to indicate
+that only one among all the variant values can be active at any time. This
+constraint is enforced by the parser and an error is emitted if a user
+specifies two or more values at the same time:
+
+ .. code-block:: console
+
+ $ spack spec blis threads=openmp,pthreads
+ Input spec
+ --------------------------------
+ blis threads=openmp,pthreads
+
+ Concretized
+ --------------------------------
+ ==> Error: multiple values are not allowed for variant "threads"
+
+Another useful note is that *Python's* ``None`` *is not allowed as a default value*
+and therefore it should not be used to denote that no feature was selected.
+Users should instead select another value, like ``'none'``, and handle it explicitly
+within the package recipe if need be:
+
+ .. code-block:: python
+
+ if self.spec.variants['threads'].value == 'none':
+ options.append('--no-threads')
+
+In cases where multiple values can be selected at the same time ``multi`` should
+be set to ``True``:
+
+ .. code-block:: python
+
+ class Gcc(AutotoolsPackage):
+ ...
+ variant(
+ 'languages', default='c,c++,fortran',
+ values=('ada', 'brig', 'c', 'c++', 'fortran',
+ 'go', 'java', 'jit', 'lto', 'objc', 'obj-c++'),
+ multi=True,
+ description='Compilers and runtime libraries to build'
+ )
+
+Within a package recipe a multi-valued variant is tested using a ``key=value`` syntax:
+
+ .. code-block:: python
+
+ if 'languages=jit' in spec:
+ options.append('--enable-host-shared')
+
+"""""""""""""""""""""""""""""""""""""""""""
+Complex validation logic for variant values
+"""""""""""""""""""""""""""""""""""""""""""
+To cover complex use cases, the :py:func:`spack.directives.variant` directive
+could accept as the ``values`` argument a full-fledged object which has
+``default`` and other arguments of the directive embedded as attributes.
+
+An example, already implemented in Spack's core, is :py:class:`spack.variant.DisjointSetsOfValues`.
+This class is used to implement a few convenience functions, like
+:py:func:`spack.variant.any_combination_of`:
+
+ .. code-block:: python
+
+ class Adios(AutotoolsPackage):
+ ...
+ variant(
+ 'staging',
+ values=any_combination_of('flexpath', 'dataspaces'),
+ description='Enable dataspaces and/or flexpath staging transports'
+ )
+
+that allows any combination of the specified values, and also allows the
+user to specify ``'none'`` (as a string) to choose none of them.
+The objects returned by these functions can be modified at will by chaining
+method calls to change the default value, customize the error message or
+other similar operations:
+
+ .. code-block:: python
+
+ class Mvapich2(AutotoolsPackage):
+ ...
+ variant(
+ 'process_managers',
+ description='List of the process managers to activate',
+ values=disjoint_sets(
+ ('auto',), ('slurm',), ('hydra', 'gforker', 'remshell')
+ ).prohibit_empty_set().with_error(
+ "'slurm' or 'auto' cannot be activated along with "
+ "other process managers"
+ ).with_default('auto').with_non_feature_values('auto'),
+ )
+
------------------------------------
Resources (expanding extra tarballs)
------------------------------------