extensions: allow multiple "extends" directives (#28853)

* extensions: allow multiple "extends" directives

This will allow multiple extends directives in a package as long as only one of
them is selected as a dependency in the concrete spec.

* document the option to have multiple extends
This commit is contained in:
Tom Scogland 2022-02-16 13:23:12 -08:00 committed by GitHub
parent e8c5f195a7
commit 8f5fcc6e95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 5 deletions

View File

@ -2470,6 +2470,24 @@ Now, the ``py-numpy`` package can be used as an argument to ``spack
activate``. When it is activated, all the files in its prefix will be
symbolically linked into the prefix of the python package.
A package can only extend one other package at a time. To support packages
that may extend one of a list of other packages, Spack supports multiple
``extends`` directives as long as at most one of them is selected as
a dependency during concretization. For example, a lua package could extend
either lua or luajit, but not both:
.. code-block:: python
class LuaLpeg(Package):
...
variant('use_lua', default=True)
extends('lua', when='+use_lua')
extends('lua-luajit', when='~use_lua')
...
Now, a user can install, and activate, the ``lua-lpeg`` package for either
lua or luajit.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Adding additional constraints
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1186,22 +1186,27 @@ def extendee_spec(self):
if not self.extendees:
return None
# TODO: allow more than one extendee.
name = next(iter(self.extendees))
deps = []
# If the extendee is in the spec's deps already, return that.
for dep in self.spec.traverse(deptypes=('link', 'run')):
if name == dep.name:
return dep
if dep.name in self.extendees:
deps.append(dep)
# TODO: allow more than one active extendee.
if deps:
assert len(deps) == 1
return deps[0]
# if the spec is concrete already, then it extends something
# that is an *optional* dependency, and the dep isn't there.
if self.spec._concrete:
return None
else:
# TODO: do something sane here with more than one extendee
# If it's not concrete, then return the spec from the
# extends() directive since that is all we know so far.
spec, kwargs = self.extendees[name]
spec, kwargs = next(iter(self.extendees.items()))
return spec
@property