summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2019-10-13 21:06:54 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2020-11-17 10:04:13 -0800
commitb4e6d9d28ec9025c423b88d211bd16f54694b511 (patch)
tree0478a725959ced83f683232094378be1a567a1ff /lib
parent36ec66d997e91e3afcbd4a3c7b999370b24254a0 (diff)
downloadspack-b4e6d9d28ec9025c423b88d211bd16f54694b511.tar.gz
spack-b4e6d9d28ec9025c423b88d211bd16f54694b511.tar.bz2
spack-b4e6d9d28ec9025c423b88d211bd16f54694b511.tar.xz
spack-b4e6d9d28ec9025c423b88d211bd16f54694b511.zip
concretizer: handle virtual provider preferences from packages.yaml
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/solver/asp.py65
-rw-r--r--lib/spack/spack/solver/concretize.lp29
2 files changed, 83 insertions, 11 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 4033362e74..76798f7fe1 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -19,6 +19,7 @@ import llnl.util.tty.color as color
import spack
import spack.cmd
+import spack.config
import spack.spec
import spack.package
import spack.package_prefs
@@ -61,7 +62,14 @@ class AspObject(object):
def _id(thing):
"""Quote string if needed for it to be a valid identifier."""
- return thing if isinstance(thing, AspObject) else '"%s"' % str(thing)
+ if isinstance(thing, AspObject):
+ return thing
+ elif isinstance(thing, bool):
+ return '"%s"' % str(thing)
+ elif isinstance(thing, int):
+ return str(thing)
+ else:
+ return '"%s"' % str(thing)
class AspFunction(AspObject):
@@ -73,6 +81,10 @@ class AspFunction(AspObject):
self.args[:] = args
return self
+ def __getitem___(self, *args):
+ self.args[:] = args
+ return self
+
def __str__(self):
return "%s(%s)" % (
self.name, ', '.join(_id(arg) for arg in self.args))
@@ -128,6 +140,7 @@ class AspGenerator(object):
self.out = out
self.func = AspFunctionBuilder()
self.possible_versions = {}
+ self.possible_virtuals = None
def title(self, name, char):
self.out.write('\n')
@@ -309,6 +322,33 @@ class AspGenerator(object):
self._and(*self.spec_clauses(named_cond, body=True))
)
+ # virtual preferences
+ self.virtual_preferences(
+ pkg.name,
+ lambda v, p, i: self.fact(
+ fn.pkg_provider_preference(pkg.name, v, p, i)
+ )
+ )
+
+ def virtual_preferences(self, pkg_name, func):
+ """Call func(vspec, provider, i) for each of pkg's provider prefs."""
+ config = spack.config.get("packages")
+ pkg_prefs = config.get(pkg_name, {}).get("providers", {})
+ for vspec, providers in pkg_prefs.items():
+ if vspec not in self.possible_virtuals:
+ continue
+
+ for i, provider in enumerate(providers):
+ func(vspec, provider, i)
+
+ def provider_defaults(self):
+ self.h2("Default virtual providers")
+ assert self.possible_virtuals is not None
+ self.virtual_preferences(
+ "all",
+ lambda v, p, i: self.fact(fn.default_provider_preference(v, p, i))
+ )
+
def spec_clauses(self, spec, body=False):
"""Return a list of clauses for a spec mandates are true.
@@ -358,7 +398,12 @@ class AspGenerator(object):
# variants
for vname, variant in spec.variants.items():
- clauses.append(f.variant(spec.name, vname, variant.value))
+ value = variant.value
+ if isinstance(value, tuple):
+ for v in value:
+ clauses.append(f.variant(spec.name, vname, v))
+ else:
+ clauses.append(f.variant(spec.name, vname, variant.value))
# compiler and compiler version
if spec.compiler:
@@ -397,9 +442,12 @@ class AspGenerator(object):
self.fact(fn.arch_os_default(default_arch.os))
self.fact(fn.arch_target_default(default_arch.target))
- def virtual_providers(self, virtuals):
+ def virtual_providers(self):
self.h2("Virtual providers")
- for vspec in virtuals:
+ assert self.possible_virtuals is not None
+
+ # what provides what
+ for vspec in self.possible_virtuals:
self.fact(fn.virtual(vspec))
for provider in spack.repo.path.providers_for(vspec):
# TODO: handle versioned virtuals
@@ -417,10 +465,12 @@ class AspGenerator(object):
pkg_names = set(spec.fullname for spec in specs)
possible = set()
- virtuals = set()
+ self.possible_virtuals = set()
for name in pkg_names:
pkg = spack.repo.path.get_pkg_class(name)
- possible.update(pkg.possible_dependencies(virtuals=virtuals))
+ possible.update(
+ pkg.possible_dependencies(virtuals=self.possible_virtuals)
+ )
pkgs = set(possible) | set(pkg_names)
@@ -433,7 +483,8 @@ class AspGenerator(object):
self.h1('General Constraints')
self.compiler_defaults()
self.arch_defaults()
- self.virtual_providers(virtuals)
+ self.virtual_providers()
+ self.provider_defaults()
self.h1('Package Constraints')
for pkg in pkgs:
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 041ea76e31..e43feb4ae1 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -28,12 +28,30 @@ depends_on(P, D) :- declared_dependency(P, D), not virtual(D), node(P).
provider(P, V) :- node(P), provides_virtual(P, V).
1 { provider(P, V) : node(P) } 1 :- virtual(V).
+% give dependents the virtuals they want
+provider_weight(D, N)
+ :- virtual(V), depends_on(P, D), provider(D, V),
+ pkg_provider_preference(P, V, D, N).
+provider_weight(D, N)
+ :- virtual(V), depends_on(P, D), provider(D, V),
+ not pkg_provider_preference(P, V, D, _),
+ default_provider_preference(V, D, N).
+
+% if there's no preference for something, it costs 100 to discourage its
+% use with minimization
+provider_weight(D, 100)
+ :- virtual(V), depends_on(P, D), provider(D, V),
+ not pkg_provider_preference(P, V, D, _),
+ not default_provider_preference(V, D, _).
+
+% pick most preferred virtual providers
+#minimize{ N@2,D : provider_weight(D, N) }.
+
% all nodes must be reachable from some root
-% TODO: this doesn't seem to be working yet
-needed(D) :- depends_on(_, D), node(D).
-needed(P) :- root(P).
+needed(D) :- root(D), node(D).
+needed(D) :- root(P), depends_on(P, D).
+needed(D) :- needed(P), depends_on(P, D), node(P).
:- node(P), not needed(P).
-#defined root/1.
% real dependencies imply new nodes.
node(D) :- node(P), depends_on(P, D).
@@ -43,6 +61,9 @@ node(D) :- node(P), depends_on(P, D).
#defined declared_dependency/2.
#defined virtual/1.
#defined provides_virtual/2.
+#defined pkg_provider_preference/4.
+#defined default_provider_preference/3.
+#defined root/1.
%-----------------------------------------------------------------------------
% Variant semantics