summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2019-10-07 15:14:09 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2020-11-17 10:04:13 -0800
commit1cab1b19949791028db0bdb5d4361fd780686faa (patch)
treea1c2d55e60d8811b43ef49060eecb85770559ddd /lib
parent51af590e64f6045fb8e72195d4adcd8d50c984bb (diff)
downloadspack-1cab1b19949791028db0bdb5d4361fd780686faa.tar.gz
spack-1cab1b19949791028db0bdb5d4361fd780686faa.tar.bz2
spack-1cab1b19949791028db0bdb5d4361fd780686faa.tar.xz
spack-1cab1b19949791028db0bdb5d4361fd780686faa.zip
concretizer: support conditional dependencies
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/solver/asp.py67
-rw-r--r--lib/spack/spack/solver/concretize.lp12
2 files changed, 63 insertions, 16 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 74bdeb69a3..f8417434e6 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -283,16 +283,52 @@ class AspGenerator(object):
# dependencies
for name, conditions in pkg.dependencies.items():
for cond, dep in conditions.items():
- self.fact(fn.declared_dependency(dep.pkg.name, dep.spec.name))
+ decl = fn.declared_dependency(dep.pkg.name, dep.spec.name)
+ if cond == spack.spec.Spec():
+ self.fact(decl)
+ else:
+ named_cond = cond.copy()
+ if not named_cond.name:
+ named_cond.name = pkg.name
+ self.rule(
+ decl,
+ self._and(*self.spec_clauses(named_cond, body=True))
+ )
- def spec_clauses(self, spec):
- """Return a list of clauses the spec mandates are true.
+ def spec_clauses(self, spec, body=False):
+ """Return a list of clauses for a spec mandates are true.
Arguments:
spec (Spec): the spec to analyze
+ body (bool): if True, generate clauses to be used in rule bodies
+ (final values) instead of rule heads (setters).
"""
clauses = []
+ # TODO: do this with consistent suffixes.
+ class Head(object):
+ node = fn.node
+ arch_platform = fn.arch_platform_set
+ arch_os = fn.arch_os_set
+ arch_target = fn.arch_target_set
+ variant = fn.variant_set
+ node_compiler = fn.node_compiler_set
+ node_compiler_version = fn.node_compiler_version_set
+
+ class Body(object):
+ node = fn.node
+ arch_platform = fn.arch_platform
+ arch_os = fn.arch_os
+ arch_target = fn.arch_target
+ variant = fn.variant_value
+ node_compiler = fn.node_compiler
+ node_compiler_version = fn.node_compiler_version
+
+ f = Body if body else Head
+
+ if spec.name:
+ clauses.append(f.node(spec.name))
+
clauses.extend(self.spec_versions(spec))
# seed architecture at the root (we'll propagate later)
@@ -300,23 +336,25 @@ class AspGenerator(object):
arch = spec.architecture
if arch:
if arch.platform:
- clauses.append(fn.arch_platform_set(spec.name, arch.platform))
+ clauses.append(f.arch_platform(spec.name, arch.platform))
if arch.os:
- clauses.append(fn.arch_os_set(spec.name, arch.os))
+ clauses.append(f.arch_os(spec.name, arch.os))
if arch.target:
- clauses.append(fn.arch_target_set(spec.name, arch.target))
+ clauses.append(f.arch_target(spec.name, arch.target))
# variants
for vname, variant in spec.variants.items():
- clauses.append(fn.variant_set(spec.name, vname, variant.value))
+ clauses.append(f.variant(spec.name, vname, variant.value))
# compiler and compiler version
if spec.compiler:
- clauses.append(fn.node_compiler_set(spec.name, spec.compiler.name))
+ clauses.append(f.node_compiler(spec.name, spec.compiler.name))
if spec.compiler.concrete:
- clauses.append(fn.node_compiler_version_set(
+ clauses.append(f.node_compiler_version(
spec.name, spec.compiler.name, spec.compiler.version))
+# if spec.dependencies:
+
# TODO
# dependencies
# external_path
@@ -475,11 +513,20 @@ class ResultParser(object):
answer = next(stream)
tty.debug("Answer: %d" % answer_number, answer)
- self._specs = {}
+ # parse functions out of ASP output
+ functions = []
for m in re.finditer(r'(\w+)\(([^)]*)\)', answer):
name, arg_string = m.groups()
args = re.findall(r'"([^"]*)"', arg_string)
+ functions.append((name, args))
+
+ # Functions don't seem to be in particular order in output.
+ # Sort them here so that nodes are created before directives
+ # that need them, (depends_on(), etc.)
+ functions.sort(key=lambda f: f[0] != "node")
+ self._specs = {}
+ for name, args in functions:
action = getattr(self, name)
assert action and callable(action)
action(*args)
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 19ae3a2417..2a8be91382 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -44,18 +44,18 @@ node(D) :- node(P), depends_on(P, D).
% if a variant is set to anything, it is considered 'set'.
variant_set(P, V) :- variant_set(P, V, _).
-% suppress wranings about this atom being unset. It's only set if some
-% spec or some package sets it, and without this, clingo will give
-% warnings like 'info: atom does not occur in any rule head'.
-#defined variant_set/3.
-#defined variant_single_value/2.
-
% variant_set is an explicitly set variant value. If it's not 'set',
% we revert to the default value. If it is set, we force the set value
variant_value(P, V, X) :- node(P), variant(P, V), variant_set(P, V, X).
variant_value(P, V, X) :- node(P), variant(P, V), not variant_set(P, V),
variant_default_value(P, V, X).
+% suppress wranings about this atom being unset. It's only set if some
+% spec or some package sets it, and without this, clingo will give
+% warnings like 'info: atom does not occur in any rule head'.
+#defined variant_set/3.
+#defined variant_single_value/2.
+
%-----------------------------------------------------------------------------
% Architecture semantics
%-----------------------------------------------------------------------------