'with_or_without' accepts bool variants
Fixes #4112 This commit extends the support of the AutotoolsPackage methods `with_or_without` and `enable_or_disable` to bool-valued variants. It also defines for those functions a convenience short-cut if the activation parameter is the prefix of a spec (like in `--with-{pkg}={prefix}`). This commit also includes: * Updates to viennarna and adios accordingly: they have been modified to use `enable_or_disable` and `with_or_without` * Improved docstrings in `autotools.py`. Raise `KeyError` if name is not a variant.
This commit is contained in:
parent
f502de4725
commit
32117c22de
@ -291,49 +291,161 @@ def check(self):
|
|||||||
self._if_make_target_execute('test')
|
self._if_make_target_execute('test')
|
||||||
self._if_make_target_execute('check')
|
self._if_make_target_execute('check')
|
||||||
|
|
||||||
def _activate_or_not(self, active, inactive, name, active_parameters=None):
|
def _activate_or_not(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
activation_word,
|
||||||
|
deactivation_word,
|
||||||
|
activation_value=None
|
||||||
|
):
|
||||||
|
"""This function contains the current implementation details of
|
||||||
|
:py:meth:`~.AutotoolsPackage.with_or_without` and
|
||||||
|
:py:meth:`~.AutotoolsPackage.enable_or_disable`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): name of the variant that is being processed
|
||||||
|
activation_word (str): the default activation word ('with' in the
|
||||||
|
case of ``with_or_without``)
|
||||||
|
deactivation_word (str): the default deactivation word ('without'
|
||||||
|
in the case of ``with_or_without``)
|
||||||
|
activation_value (callable): callable that accepts a single
|
||||||
|
value. This value is either one of the allowed values for a
|
||||||
|
multi-valued variant or the name of a bool-valued variant.
|
||||||
|
Returns the parameter to be used when the value is activated.
|
||||||
|
|
||||||
|
The special value 'prefix' can also be assigned and will return
|
||||||
|
``spec[name].prefix`` as activation parameter.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
Given a package with:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
variant('foo', values=('x', 'y'), description='')
|
||||||
|
variant('bar', default=True, description='')
|
||||||
|
|
||||||
|
calling this function like:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
_activate_or_not(
|
||||||
|
'foo', 'with', 'without', activation_value='prefix'
|
||||||
|
)
|
||||||
|
_activate_or_not('bar', 'with', 'without')
|
||||||
|
|
||||||
|
will generate the following configuration options:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
--with-x=<prefix-to-x> --without-y --with-bar
|
||||||
|
|
||||||
|
for ``<spec-name> foo=x +bar``
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of strings that corresponds to the activation/deactivation
|
||||||
|
of the variant that has been processed
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
KeyError: if name is not among known variants
|
||||||
|
"""
|
||||||
spec = self.spec
|
spec = self.spec
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
|
if activation_value == 'prefix':
|
||||||
|
activation_value = lambda x: spec[x].prefix
|
||||||
|
|
||||||
|
# Defensively look that the name passed as argument is among
|
||||||
|
# variants
|
||||||
|
if name not in self.variants:
|
||||||
|
msg = '"{0}" is not a variant of "{1}"'
|
||||||
|
raise KeyError(msg.format(name, self.name))
|
||||||
|
|
||||||
|
# Create a list of pairs. Each pair includes a configuration
|
||||||
|
# option and whether or not that option is activated
|
||||||
|
if set(self.variants[name].values) == set((True, False)):
|
||||||
|
# BoolValuedVariant carry information about a single option.
|
||||||
|
# Nonetheless, for uniformity of treatment we'll package them
|
||||||
|
# in an iterable of one element.
|
||||||
|
condition = '+{name}'.format(name=name)
|
||||||
|
options = [(name, condition in spec)]
|
||||||
|
else:
|
||||||
|
condition = '{name}={value}'
|
||||||
|
options = [
|
||||||
|
(value, condition.format(name=name, value=value) in spec)
|
||||||
|
for value in self.variants[name].values
|
||||||
|
]
|
||||||
|
|
||||||
# For each allowed value in the list of values
|
# For each allowed value in the list of values
|
||||||
for value in self.variants[name].values:
|
for option_value, activated in options:
|
||||||
# Check if the value is active in the current spec
|
|
||||||
condition = '{name}={value}'.format(name=name, value=value)
|
|
||||||
activated = condition in spec
|
|
||||||
# Search for an override in the package for this value
|
# Search for an override in the package for this value
|
||||||
override_name = '{0}_or_{1}_{2}'.format(active, inactive, value)
|
override_name = '{0}_or_{1}_{2}'.format(
|
||||||
|
activation_word, deactivation_word, option_value
|
||||||
|
)
|
||||||
line_generator = getattr(self, override_name, None)
|
line_generator = getattr(self, override_name, None)
|
||||||
# If not available use a sensible default
|
# If not available use a sensible default
|
||||||
if line_generator is None:
|
if line_generator is None:
|
||||||
def _default_generator(is_activated):
|
def _default_generator(is_activated):
|
||||||
if is_activated:
|
if is_activated:
|
||||||
line = '--{0}-{1}'.format(active, value)
|
line = '--{0}-{1}'.format(
|
||||||
if active_parameters is not None and active_parameters(value): # NOQA=ignore=E501
|
activation_word, option_value
|
||||||
line += '={0}'.format(active_parameters(value))
|
)
|
||||||
|
if activation_value is not None and activation_value(option_value): # NOQA=ignore=E501
|
||||||
|
line += '={0}'.format(
|
||||||
|
activation_value(option_value)
|
||||||
|
)
|
||||||
return line
|
return line
|
||||||
return '--{0}-{1}'.format(inactive, value)
|
return '--{0}-{1}'.format(deactivation_word, option_value)
|
||||||
line_generator = _default_generator
|
line_generator = _default_generator
|
||||||
args.append(line_generator(activated))
|
args.append(line_generator(activated))
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def with_or_without(self, name, active_parameters=None):
|
def with_or_without(self, name, activation_value=None):
|
||||||
"""Inspects the multi-valued variant 'name' and returns the configure
|
"""Inspects a variant and returns the arguments that activate
|
||||||
arguments that activate / deactivate the selected feature.
|
or deactivate the selected feature(s) for the configure options.
|
||||||
|
|
||||||
:param str name: name of a valid multi-valued variant
|
This function works on all type of variants. For bool-valued variants
|
||||||
:param callable active_parameters: if present accepts a single value
|
it will return by default ``--with-{name}`` or ``--without-{name}``.
|
||||||
and returns the parameter to be used leading to an entry of the
|
For other kinds of variants it will cycle over the allowed values and
|
||||||
type '--with-{name}={parameter}
|
return either ``--with-{value}`` or ``--without-{value}``.
|
||||||
|
|
||||||
|
If activation_value is given, then for each possible value of the
|
||||||
|
variant, the option ``--with-{value}=activation_value(value)`` or
|
||||||
|
``--without-{value}`` will be added depending on whether or not
|
||||||
|
``variant=value`` is in the spec.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): name of a valid multi-valued variant
|
||||||
|
activation_value (callable): callable that accepts a single
|
||||||
|
value and returns the parameter to be used leading to an entry
|
||||||
|
of the type ``--with-{name}={parameter}``.
|
||||||
|
|
||||||
|
The special value 'prefix' can also be assigned and will return
|
||||||
|
``spec[name].prefix`` as activation parameter.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of arguments to configure
|
||||||
|
"""
|
||||||
|
return self._activate_or_not(name, 'with', 'without', activation_value)
|
||||||
|
|
||||||
|
def enable_or_disable(self, name, activation_value=None):
|
||||||
|
"""Same as :py:meth:`~.AutotoolsPackage.with_or_without` but substitute
|
||||||
|
``with`` with ``enable`` and ``without`` with ``disable``.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): name of a valid multi-valued variant
|
||||||
|
activation_value (callable): if present accepts a single value
|
||||||
|
and returns the parameter to be used leading to an entry of the
|
||||||
|
type ``--enable-{name}={parameter}``
|
||||||
|
|
||||||
|
The special value 'prefix' can also be assigned and will return
|
||||||
|
``spec[name].prefix`` as activation parameter.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list of arguments to configure
|
||||||
"""
|
"""
|
||||||
return self._activate_or_not(
|
return self._activate_or_not(
|
||||||
'with', 'without', name, active_parameters
|
name, 'enable', 'disable', activation_value
|
||||||
)
|
|
||||||
|
|
||||||
def enable_or_disable(self, name, active_parameters=None):
|
|
||||||
"""Inspects the multi-valued variant 'name' and returns the configure
|
|
||||||
arguments that activate / deactivate the selected feature.
|
|
||||||
"""
|
|
||||||
return self._activate_or_not(
|
|
||||||
'enable', 'disable', name, active_parameters
|
|
||||||
)
|
)
|
||||||
|
|
||||||
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
|
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
|
||||||
|
@ -53,20 +53,23 @@ def test_with_or_without(self):
|
|||||||
pkg = spack.repo.get(s)
|
pkg = spack.repo.get(s)
|
||||||
|
|
||||||
# Called without parameters
|
# Called without parameters
|
||||||
l = pkg.with_or_without('foo')
|
options = pkg.with_or_without('foo')
|
||||||
assert '--with-bar' in l
|
assert '--with-bar' in options
|
||||||
assert '--without-baz' in l
|
assert '--without-baz' in options
|
||||||
assert '--no-fee' in l
|
assert '--no-fee' in options
|
||||||
|
|
||||||
def activate(value):
|
def activate(value):
|
||||||
return 'something'
|
return 'something'
|
||||||
|
|
||||||
l = pkg.with_or_without('foo', active_parameters=activate)
|
options = pkg.with_or_without('foo', activation_value=activate)
|
||||||
assert '--with-bar=something' in l
|
assert '--with-bar=something' in options
|
||||||
assert '--without-baz' in l
|
assert '--without-baz' in options
|
||||||
assert '--no-fee' in l
|
assert '--no-fee' in options
|
||||||
|
|
||||||
l = pkg.enable_or_disable('foo')
|
options = pkg.enable_or_disable('foo')
|
||||||
assert '--enable-bar' in l
|
assert '--enable-bar' in options
|
||||||
assert '--disable-baz' in l
|
assert '--disable-baz' in options
|
||||||
assert '--disable-fee' in l
|
assert '--disable-fee' in options
|
||||||
|
|
||||||
|
options = pkg.with_or_without('bvv')
|
||||||
|
assert '--with-bvv' in options
|
||||||
|
@ -50,6 +50,8 @@ class A(AutotoolsPackage):
|
|||||||
multi=False
|
multi=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
variant('bvv', default=True, description='The good old BV variant')
|
||||||
|
|
||||||
depends_on('b', when='foobar=bar')
|
depends_on('b', when='foobar=bar')
|
||||||
|
|
||||||
def with_or_without_fee(self, activated):
|
def with_or_without_fee(self, activated):
|
||||||
|
@ -61,9 +61,14 @@ class Adios(AutotoolsPackage):
|
|||||||
# transports and serial file converters
|
# transports and serial file converters
|
||||||
variant('hdf5', default=False, description='Enable parallel HDF5 transport and serial bp2h5 converter')
|
variant('hdf5', default=False, description='Enable parallel HDF5 transport and serial bp2h5 converter')
|
||||||
variant('netcdf', default=False, description='Enable netcdf support')
|
variant('netcdf', default=False, description='Enable netcdf support')
|
||||||
variant('flexpath', default=False, description='Enable flexpath transport')
|
|
||||||
variant('dataspaces', default=False, description='Enable dataspaces transport')
|
variant(
|
||||||
variant('staging', default=False, description='Enable dataspaces and flexpath staging transports')
|
'staging',
|
||||||
|
default=None,
|
||||||
|
values=('flexpath', 'dataspaces'),
|
||||||
|
multi=True,
|
||||||
|
description='Enable dataspaces and/or flexpath staging transports'
|
||||||
|
)
|
||||||
|
|
||||||
depends_on('autoconf', type='build')
|
depends_on('autoconf', type='build')
|
||||||
depends_on('automake', type='build')
|
depends_on('automake', type='build')
|
||||||
@ -100,15 +105,27 @@ class Adios(AutotoolsPackage):
|
|||||||
patch('adios_1100.patch', when='@:1.10.0^hdf5@1.10:')
|
patch('adios_1100.patch', when='@:1.10.0^hdf5@1.10:')
|
||||||
|
|
||||||
def validate(self, spec):
|
def validate(self, spec):
|
||||||
"""
|
"""Checks if incompatible variants have been activated at the same time
|
||||||
Checks if incompatible variants have been activated at the same time
|
|
||||||
:param spec: spec of the package
|
Args:
|
||||||
:raises RuntimeError: in case of inconsistencies
|
spec: spec of the package
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: in case of inconsistencies
|
||||||
"""
|
"""
|
||||||
if '+fortran' in spec and not self.compiler.fc:
|
if '+fortran' in spec and not self.compiler.fc:
|
||||||
msg = 'cannot build a fortran variant without a fortran compiler'
|
msg = 'cannot build a fortran variant without a fortran compiler'
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
def with_or_without_hdf5(self, activated):
|
||||||
|
|
||||||
|
if activated:
|
||||||
|
return '--with-phdf5={0}'.format(
|
||||||
|
self.spec['hdf5'].prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
return '--without-phdf5'
|
||||||
|
|
||||||
def configure_args(self):
|
def configure_args(self):
|
||||||
spec = self.spec
|
spec = self.spec
|
||||||
self.validate(spec)
|
self.validate(spec)
|
||||||
@ -118,66 +135,31 @@ def configure_args(self):
|
|||||||
'CFLAGS={0}'.format(self.compiler.pic_flag)
|
'CFLAGS={0}'.format(self.compiler.pic_flag)
|
||||||
]
|
]
|
||||||
|
|
||||||
if '+shared' in spec:
|
extra_args += self.enable_or_disable('shared')
|
||||||
extra_args.append('--enable-shared')
|
extra_args += self.enable_or_disable('fortran')
|
||||||
|
|
||||||
if '+mpi' in spec:
|
if '+mpi' in spec:
|
||||||
env['MPICC'] = spec['mpi'].mpicc
|
env['MPICC'] = spec['mpi'].mpicc
|
||||||
env['MPICXX'] = spec['mpi'].mpicxx
|
env['MPICXX'] = spec['mpi'].mpicxx
|
||||||
extra_args.append('--with-mpi=%s' % spec['mpi'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-mpi')
|
|
||||||
if '+infiniband' in spec:
|
|
||||||
extra_args.append('--with-infiniband')
|
|
||||||
else:
|
|
||||||
extra_args.append('--with-infiniband=no')
|
|
||||||
|
|
||||||
if '+fortran' in spec:
|
extra_args += self.with_or_without('mpi', activation='prefix')
|
||||||
extra_args.append('--enable-fortran')
|
extra_args += self.with_or_without('infiniband')
|
||||||
else:
|
|
||||||
extra_args.append('--disable-fortran')
|
|
||||||
|
|
||||||
# Transforms
|
# Transforms
|
||||||
if '+zlib' in spec:
|
variants = ['zlib', 'bzip2', 'szip', 'zfp', 'sz']
|
||||||
extra_args.append('--with-zlib=%s' % spec['zlib'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-zlib')
|
|
||||||
if '+bzip2' in spec:
|
|
||||||
extra_args.append('--with-bzip2=%s' % spec['bzip2'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-bzip2')
|
|
||||||
if '+szip' in spec:
|
|
||||||
extra_args.append('--with-szip=%s' % spec['szip'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-szip')
|
|
||||||
if '+zfp' in spec:
|
|
||||||
extra_args.append('--with-zfp=%s' % spec['zfp'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-zfp')
|
|
||||||
if '+sz' in spec:
|
|
||||||
extra_args.append('--with-sz=%s' % spec['sz'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-sz')
|
|
||||||
|
|
||||||
# External I/O libraries
|
# External I/O libraries
|
||||||
if '+hdf5' in spec:
|
variants += ['hdf5', 'netcdf']
|
||||||
extra_args.append('--with-phdf5=%s' % spec['hdf5'].prefix)
|
|
||||||
else:
|
for x in variants:
|
||||||
extra_args.append('--without-phdf5')
|
extra_args += self.with_or_without(x, activation='prefix')
|
||||||
if '+netcdf' in spec:
|
|
||||||
extra_args.append('--with-netcdf=%s' % spec['netcdf'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-netcdf')
|
|
||||||
|
|
||||||
# Staging transports
|
# Staging transports
|
||||||
if '+flexpath' in spec or '+staging' in spec:
|
def with_staging(name):
|
||||||
extra_args.append('--with-flexpath=%s' % spec['libevpath'].prefix)
|
if name == 'flexpath':
|
||||||
else:
|
return spec['libevpath'].prefix
|
||||||
extra_args.append('--without-flexpath')
|
return spec[name].prefix
|
||||||
if '+dataspaces' in spec or '+staging' in spec:
|
|
||||||
extra_args.append('--with-dataspaces=%s'
|
extra_args += self.with_or_without('staging', activation=with_staging)
|
||||||
% spec['dataspaces'].prefix)
|
|
||||||
else:
|
|
||||||
extra_args.append('--without-dataspaces')
|
|
||||||
|
|
||||||
return extra_args
|
return extra_args
|
||||||
|
@ -27,8 +27,9 @@
|
|||||||
|
|
||||||
class Viennarna(AutotoolsPackage):
|
class Viennarna(AutotoolsPackage):
|
||||||
"""The ViennaRNA Package consists of a C code library and several
|
"""The ViennaRNA Package consists of a C code library and several
|
||||||
stand-alone programs for the prediction and comparison of RNA secondary
|
stand-alone programs for the prediction and comparison of RNA secondary
|
||||||
structures."""
|
structures.
|
||||||
|
"""
|
||||||
|
|
||||||
homepage = "https://www.tbi.univie.ac.at/RNA/"
|
homepage = "https://www.tbi.univie.ac.at/RNA/"
|
||||||
url = "https://www.tbi.univie.ac.at/RNA/download/sourcecode/2_3_x/ViennaRNA-2.3.5.tar.gz"
|
url = "https://www.tbi.univie.ac.at/RNA/download/sourcecode/2_3_x/ViennaRNA-2.3.5.tar.gz"
|
||||||
@ -49,19 +50,12 @@ def url_for_version(self, version):
|
|||||||
return url.format(version.up_to(2).underscored, version)
|
return url.format(version.up_to(2).underscored, version)
|
||||||
|
|
||||||
def configure_args(self):
|
def configure_args(self):
|
||||||
args = []
|
|
||||||
if '+sse' in self.spec:
|
args = self.enable_or_disable('sse')
|
||||||
args.append('--enable-sse')
|
args += self.with_or_without('python')
|
||||||
else:
|
args += self.with_or_without('perl')
|
||||||
args.append('--disable-sse')
|
|
||||||
if '~python' in self.spec:
|
|
||||||
args.append('--without-python')
|
|
||||||
else:
|
|
||||||
args.append('--with-python')
|
|
||||||
if '~perl' in self.spec:
|
|
||||||
args.append('--without-perl')
|
|
||||||
else:
|
|
||||||
args.append('--with-perl')
|
|
||||||
if 'python@3:' in self.spec:
|
if 'python@3:' in self.spec:
|
||||||
args.append('--with-python3')
|
args.append('--with-python3')
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
Loading…
Reference in New Issue
Block a user