summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <gamblin2@llnl.gov>2022-12-02 09:56:18 -0800
committerGitHub <noreply@github.com>2022-12-02 18:56:18 +0100
commit87562042dfb509e1a937a716ba920406a126088a (patch)
treed405b1ed6c5a9439e52b43d069ad030b9544a4a1
parent10d10b612a89a4df406573f5514a889f8f69822d (diff)
downloadspack-87562042dfb509e1a937a716ba920406a126088a.tar.gz
spack-87562042dfb509e1a937a716ba920406a126088a.tar.bz2
spack-87562042dfb509e1a937a716ba920406a126088a.tar.xz
spack-87562042dfb509e1a937a716ba920406a126088a.zip
concretizer: use only `attr()` for Spec attributes (#31202)
All Spec attributes are now represented as `attr(attribute_name, ... args ...)`, e.g. `attr(node, "hdf5")` instead of `node("hdf5")`, as we *have* to maintain the `attr()` form anyway, and it simplifies the encoding to just maintain one form of the Spec information. Background ---------- In #20644, we unified the way conditionals are done in the concretizer, but this introduced a nasty aspect to the encoding: we have to maintain everything we want in general conditions in two forms: `predicate(...)` and `attr("predicate", ...)`. For example, here's the start of the table of spec attributes we had to maintain: ```prolog node(Package) :- attr("node", Package). virtual_node(Virtual) :- attr("virtual_node", Virtual). hash(Package, Hash) :- attr("hash", Package, Hash). version(Package, Version) :- attr("version", Package, Version). ... ``` ```prolog attr("node", Package) :- node(Package). attr("virtual_node", Virtual) :- virtual_node(Virtual). attr("hash", Package, Hash) :- hash(Package, Hash). attr("version", Package, Version) :- version(Package, Version). ... ``` This adds cognitive load to understanding how the concretizer works, as you have to understand the equivalence between the two forms of spec attributes. It also makes the general condition logic in #20644 hard to explain, and it's easy to forget to add a new equivalence to this list when adding new spec attributes (at least two people have been bitten by this). Solution -------- - [x] remove the equivalence list from `concretize.lp` - [x] simplify `spec_clauses()`, `condition()`, and other functions in `asp.py` that need to deal with `Spec` attributes. - [x] Convert all old-form spec attributes in `concretize.lp` to the `attr()` form - [x] Simplify `display.lp`, where we also had to maintain a list of spec attributes. Now we only need to show `attr/2`, `attr/3`, and `attr/4`. - [x] Simplify model extraction logic in `asp.py`. Performance ----------- This seems to result in a smaller grounded problem (as there are no longer duplicated `attr("foo", ...)` / `foo(...)` predicates in the program), but it also adds a slight performance overhead vs. develop. Ultimately, simplifying the encoding will be a win, particularly for improving error messages. Notes ----- This will simplify future node refactors in `concretize.lp` (e.g., not identifying nodes by package name, which we need for separate build dependencies). I'm still not entirely used to reading `attr()` notation, but I thnk it's ultimately clearer than what we did before. We need more uniform naming, and it's now clear what is part of a solution. We should probably continue making the encoding of `concretize.lp` simpler and more self-explanatory. It may make sense to rename `attr` to something like `node_attr` and to simplify the names of node attributes. It also might make sense to do something similar for other types of predicates in `concretize.lp`.
-rw-r--r--lib/spack/spack/cmd/diff.py18
-rw-r--r--lib/spack/spack/solver/asp.py237
-rw-r--r--lib/spack/spack/solver/concretize.lp557
-rw-r--r--lib/spack/spack/solver/display.lp27
4 files changed, 409 insertions, 430 deletions
diff --git a/lib/spack/spack/cmd/diff.py b/lib/spack/spack/cmd/diff.py
index 703fa5c69c..013bb693db 100644
--- a/lib/spack/spack/cmd/diff.py
+++ b/lib/spack/spack/cmd/diff.py
@@ -46,6 +46,14 @@ def setup_parser(subparser):
)
+def shift(asp_function):
+ """Transforms ``attr("foo", "bar")`` into ``foo("bar")``."""
+ if not asp_function.args:
+ raise ValueError(f"Can't shift ASP function with no arguments: {str(asp_function)}")
+ first, *rest = asp_function.args
+ return asp.AspFunction(first, rest)
+
+
def compare_specs(a, b, to_string=False, color=None):
"""
Generate a comparison, including diffs (for each side) and an intersection.
@@ -71,22 +79,24 @@ def compare_specs(a, b, to_string=False, color=None):
# get facts for specs, making sure to include build dependencies of concrete
# specs and to descend into dependency hashes so we include all facts.
a_facts = set(
- t
- for t in setup.spec_clauses(
+ shift(func)
+ for func in setup.spec_clauses(
a,
body=True,
expand_hashes=True,
concrete_build_deps=True,
)
+ if func.name == "attr"
)
b_facts = set(
- t
- for t in setup.spec_clauses(
+ shift(func)
+ for func in setup.spec_clauses(
b,
body=True,
expand_hashes=True,
concrete_build_deps=True,
)
+ if func.name == "attr"
)
# We want to present them to the user as simple key: values
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 1a22cf5c6f..8809121e1d 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -145,17 +145,14 @@ build_priority_offset = 200
fixed_priority_offset = 100
-def build_criteria_names(costs, tuples):
+def build_criteria_names(costs, arg_tuples):
"""Construct an ordered mapping from criteria names to costs."""
# pull optimization criteria names out of the solution
priorities_names = []
num_fixed = 0
num_high_fixed = 0
- for pred, args in tuples:
- if pred != "opt_criterion":
- continue
-
+ for args in arg_tuples:
priority, name = args[:2]
priority = int(priority)
@@ -255,13 +252,33 @@ def _id(thing):
class AspFunction(AspObject):
def __init__(self, name, args=None):
self.name = name
- self.args = () if args is None else args
+ self.args = () if args is None else tuple(args)
def _cmp_key(self):
return (self.name, self.args)
def __call__(self, *args):
- return AspFunction(self.name, args)
+ """Return a new instance of this function with added arguments.
+
+ Note that calls are additive, so you can do things like::
+
+ >>> attr = AspFunction("attr")
+ attr()
+
+ >>> attr("version")
+ attr("version")
+
+ >>> attr("version")("foo")
+ attr("version", "foo")
+
+ >>> v = AspFunction("attr", "version")
+ attr("version")
+
+ >>> v("foo", "bar")
+ attr("version", "foo", "bar")
+
+ """
+ return AspFunction(self.name, self.args + args)
def symbol(self, positive=True):
def argify(arg):
@@ -537,6 +554,36 @@ def bootstrap_clingo():
from clingo import parse_files
+def stringify(sym):
+ """Stringify symbols from clingo models.
+
+ This will turn a ``clingo.Symbol`` into a string, or a sequence of ``clingo.Symbol``
+ objects into a tuple of strings.
+
+ """
+ # TODO: simplify this when we no longer have to support older clingo versions.
+ if isinstance(sym, (list, tuple)):
+ return tuple(stringify(a) for a in sym)
+
+ if clingo_cffi:
+ # Clingo w/ CFFI will throw an exception on failure
+ try:
+ return sym.string
+ except RuntimeError:
+ return str(sym)
+ else:
+ return sym.string or str(sym)
+
+
+def extract_args(model, predicate_name):
+ """Extract the arguments to predicates with the provided name from a model.
+
+ Pull out all the predicates with name ``predicate_name`` from the model, and return
+ their stringified arguments as tuples.
+ """
+ return [stringify(sym.arguments) for sym in model if sym.name == predicate_name]
+
+
class PyclingoDriver(object):
def __init__(self, cores=True):
"""Driver for the Python clingo interface.
@@ -592,6 +639,20 @@ class PyclingoDriver(object):
if choice:
self.assumptions.append(atom)
+ def handle_error(self, msg, *args):
+ """Handle an error state derived by the solver."""
+ msg = msg.format(*args)
+
+ # For variant formatting, we sometimes have to construct specs
+ # to format values properly. Find/replace all occurances of
+ # Spec(...) with the string representation of the spec mentioned
+ specs_to_construct = re.findall(r"Spec\(([^)]*)\)", msg)
+ for spec_str in specs_to_construct:
+ msg = msg.replace("Spec(%s)" % spec_str, str(spack.spec.Spec(spec_str)))
+
+ # TODO: this raises early -- we should handle multiple errors if there are any.
+ raise UnsatisfiableSpecError(msg)
+
def solve(self, setup, specs, reuse=None, output=None, control=None):
"""Set up the input and solve for dependencies of ``specs``.
@@ -687,26 +748,27 @@ class PyclingoDriver(object):
# once done, construct the solve result
result.satisfiable = solve_result.satisfiable
- def stringify(x):
- if clingo_cffi:
- # Clingo w/ CFFI will throw an exception on failure
- try:
- return x.string
- except RuntimeError:
- return str(x)
- else:
- return x.string or str(x)
-
if result.satisfiable:
- # build spec from the best model
+ # get the best model
builder = SpecBuilder(specs, hash_lookup=setup.reusable_and_possible)
min_cost, best_model = min(models)
- tuples = [(sym.name, [stringify(a) for a in sym.arguments]) for sym in best_model]
- answers = builder.build_specs(tuples)
+
+ # first check for errors
+ error_args = extract_args(best_model, "error")
+ errors = sorted((int(priority), msg, args) for priority, msg, *args in error_args)
+ for _, msg, args in errors:
+ self.handle_error(msg, *args)
+
+ # build specs from spec attributes in the model
+ spec_attrs = [(name, tuple(rest)) for name, *rest in extract_args(best_model, "attr")]
+ answers = builder.build_specs(spec_attrs)
# add best spec to the results
result.answers.append((list(min_cost), 0, answers))
- result.criteria = build_criteria_names(min_cost, tuples)
+
+ # get optimization criteria
+ criteria_args = extract_args(best_model, "opt_criterion")
+ result.criteria = build_criteria_names(min_cost, criteria_args)
# record the number of models the solver considered
result.nmodels = len(models)
@@ -714,6 +776,13 @@ class PyclingoDriver(object):
# record the possible dependencies in the solve
result.possible_dependencies = setup.pkgs
+ # print any unknown functions in the model
+ for sym in best_model:
+ if sym.name not in ("attr", "error", "opt_criterion"):
+ tty.debug(
+ "UNKNOWN SYMBOL: %s(%s)" % (sym.name, ", ".join(stringify(sym.arguments)))
+ )
+
elif cores:
result.control = self.control
result.cores.extend(cores)
@@ -836,14 +905,14 @@ class SpackSolverSetup(object):
assert spec.name, msg
if spec.concrete:
- return [fn.version(spec.name, spec.version)]
+ return [fn.attr("version", spec.name, spec.version)]
if spec.versions == spack.version.ver(":"):
return []
# record all version constraints for later
self.version_constraints.add((spec.name, spec.versions))
- return [fn.node_version_satisfies(spec.name, spec.versions)]
+ return [fn.attr("node_version_satisfies", spec.name, spec.versions)]
def target_ranges(self, spec, single_target_fn):
target = spec.architecture.target
@@ -853,7 +922,7 @@ class SpackSolverSetup(object):
return [single_target_fn(spec.name, target)]
self.target_constraints.add(target)
- return [fn.node_target_satisfies(spec.name, target)]
+ return [fn.attr("node_target_satisfies", spec.name, target)]
def conflict_rules(self, pkg):
default_msg = "{0} '{1}' conflicts with '{2}'"
@@ -1097,7 +1166,7 @@ class SpackSolverSetup(object):
# requirements trigger the condition
requirements = self.spec_clauses(named_cond, body=True, required_from=name)
for pred in requirements:
- self.gen.fact(fn.condition_requirement(condition_id, pred.name, *pred.args))
+ self.gen.fact(fn.condition_requirement(condition_id, *pred.args))
if imposed_spec:
self.impose(condition_id, imposed_spec, node=node, name=name)
@@ -1108,9 +1177,9 @@ class SpackSolverSetup(object):
imposed_constraints = self.spec_clauses(imposed_spec, body=body, required_from=name)
for pred in imposed_constraints:
# imposed "node"-like conditions are no-ops
- if not node and pred.name in ("node", "virtual_node"):
+ if not node and pred.args[0] in ("node", "virtual_node"):
continue
- self.gen.fact(fn.imposed_constraint(condition_id, pred.name, *pred.args))
+ self.gen.fact(fn.imposed_constraint(condition_id, *pred.args))
def package_provider_rules(self, pkg):
for provider_name in sorted(set(s.name for s in pkg.provided.keys())):
@@ -1367,30 +1436,30 @@ class SpackSolverSetup(object):
# TODO: do this with consistent suffixes.
class Head(object):
- node = fn.node
- virtual_node = fn.virtual_node
- node_platform = fn.node_platform_set
- node_os = fn.node_os_set
- node_target = fn.node_target_set
- variant_value = fn.variant_set
- node_compiler = fn.node_compiler_set
- node_compiler_version = fn.node_compiler_version_set
- node_flag = fn.node_flag_set
- node_flag_propagate = fn.node_flag_propagate
- variant_propagate = fn.variant_propagate
+ node = fn.attr("node")
+ virtual_node = fn.attr("virtual_node")
+ node_platform = fn.attr("node_platform_set")
+ node_os = fn.attr("node_os_set")
+ node_target = fn.attr("node_target_set")
+ variant_value = fn.attr("variant_set")
+ node_compiler = fn.attr("node_compiler_set")
+ node_compiler_version = fn.attr("node_compiler_version_set")
+ node_flag = fn.attr("node_flag_set")
+ node_flag_propagate = fn.attr("node_flag_propagate")
+ variant_propagate = fn.attr("variant_propagate")
class Body(object):
- node = fn.node
- virtual_node = fn.virtual_node
- node_platform = fn.node_platform
- node_os = fn.node_os
- node_target = fn.node_target
- variant_value = fn.variant_value
- node_compiler = fn.node_compiler
- node_compiler_version = fn.node_compiler_version
- node_flag = fn.node_flag
- node_flag_propagate = fn.node_flag_propagate
- variant_propagate = fn.variant_propagate
+ node = fn.attr("node")
+ virtual_node = fn.attr("virtual_node")
+ node_platform = fn.attr("node_platform")
+ node_os = fn.attr("node_os")
+ node_target = fn.attr("node_target")
+ variant_value = fn.attr("variant_value")
+ node_compiler = fn.attr("node_compiler")
+ node_compiler_version = fn.attr("node_compiler_version")
+ node_flag = fn.attr("node_flag")
+ node_flag_propagate = fn.attr("node_flag_propagate")
+ variant_propagate = fn.attr("variant_propagate")
f = Body if body else Head
@@ -1457,8 +1526,11 @@ class SpackSolverSetup(object):
elif spec.compiler.versions:
clauses.append(
- fn.node_compiler_version_satisfies(
- spec.name, spec.compiler.name, spec.compiler.versions
+ fn.attr(
+ "node_compiler_version_satisfies",
+ spec.name,
+ spec.compiler.name,
+ spec.compiler.versions,
)
)
self.compiler_version_constraints.add(spec.compiler)
@@ -1474,8 +1546,8 @@ class SpackSolverSetup(object):
if spec.concrete:
# older specs do not have package hashes, so we have to do this carefully
if getattr(spec, "_package_hash", None):
- clauses.append(fn.package_hash(spec.name, spec._package_hash))
- clauses.append(fn.hash(spec.name, spec.dag_hash()))
+ clauses.append(fn.attr("package_hash", spec.name, spec._package_hash))
+ clauses.append(fn.attr("hash", spec.name, spec.dag_hash()))
# add all clauses from dependencies
if transitive:
@@ -1489,18 +1561,18 @@ class SpackSolverSetup(object):
for dtype in dspec.deptypes:
# skip build dependencies of already-installed specs
if concrete_build_deps or dtype != "build":
- clauses.append(fn.depends_on(spec.name, dep.name, dtype))
+ clauses.append(fn.attr("depends_on", spec.name, dep.name, dtype))
# Ensure Spack will not coconcretize this with another provider
# for the same virtual
for virtual in dep.package.virtuals_provided:
- clauses.append(fn.virtual_node(virtual.name))
+ clauses.append(fn.attr("virtual_node", virtual.name))
clauses.append(fn.provider(dep.name, virtual.name))
# imposing hash constraints for all but pure build deps of
# already-installed concrete specs.
if concrete_build_deps or dspec.deptypes != ("build",):
- clauses.append(fn.hash(dep.name, dep.dag_hash()))
+ clauses.append(fn.attr("hash", dep.name, dep.dag_hash()))
# if the spec is abstract, descend into dependencies.
# if it's concrete, then the hashes above take care of dependency
@@ -2057,12 +2129,13 @@ class SpackSolverSetup(object):
self.gen.h2("Spec: %s" % str(spec))
self.gen.fact(fn.literal(idx))
- root_fn = fn.virtual_root(spec.name) if spec.virtual else fn.root(spec.name)
- self.gen.fact(fn.literal(idx, root_fn.name, *root_fn.args))
+ self.gen.fact(fn.literal(idx, "virtual_root" if spec.virtual else "root", spec.name))
for clause in self.spec_clauses(spec):
- self.gen.fact(fn.literal(idx, clause.name, *clause.args))
- if clause.name == "variant_set":
- self.gen.fact(fn.literal(idx, "variant_default_value_from_cli", *clause.args))
+ self.gen.fact(fn.literal(idx, *clause.args))
+ if clause.args[0] == "variant_set":
+ self.gen.fact(
+ fn.literal(idx, "variant_default_value_from_cli", *clause.args[1:])
+ )
if self.concretize_everything:
self.gen.fact(fn.concretize_everything())
@@ -2071,8 +2144,20 @@ class SpackSolverSetup(object):
class SpecBuilder(object):
"""Class with actions to rebuild a spec from ASP results."""
- #: Attributes that don't need actions
- ignored_attributes = ["opt_criterion"]
+ #: Regex for attributes that don't need actions b/c they aren't used to construct specs.
+ ignored_attributes = re.compile(
+ "|".join(
+ [
+ r"^.*_propagate$",
+ r"^.*_satisfies$",
+ r"^.*_set$",
+ r"^package_hash$",
+ r"^root$",
+ r"^virtual_node$",
+ r"^virtual_root$",
+ ]
+ )
+ )
def __init__(self, specs, hash_lookup=None):
self._specs = {}
@@ -2109,17 +2194,6 @@ class SpecBuilder(object):
def node_target(self, pkg, target):
self._arch(pkg).target = target
- def error(self, priority, msg, *args):
- msg = msg.format(*args)
-
- # For variant formatting, we sometimes have to construct specs
- # to format values properly. Find/replace all occurances of
- # Spec(...) with the string representation of the spec mentioned
- specs_to_construct = re.findall(r"Spec\(([^)]*)\)", msg)
- for spec_str in specs_to_construct:
- msg = msg.replace("Spec(%s)" % spec_str, str(spack.spec.Spec(spec_str)))
- raise UnsatisfiableSpecError(msg)
-
def variant_value(self, pkg, name, value):
# FIXME: is there a way not to special case 'dev_path' everywhere?
if name == "dev_path":
@@ -2244,10 +2318,7 @@ class SpecBuilder(object):
@staticmethod
def sort_fn(function_tuple):
name = function_tuple[0]
- if name == "error":
- priority = function_tuple[1][0]
- return (-5, priority)
- elif name == "hash":
+ if name == "hash":
return (-4, 0)
elif name == "node":
return (-3, 0)
@@ -2262,18 +2333,18 @@ class SpecBuilder(object):
# Functions don't seem to be in particular order in output. Sort
# them here so that directives that build objects (like node and
# node_compiler) are called in the right order.
- self.function_tuples = function_tuples
- self.function_tuples.sort(key=self.sort_fn)
+ self.function_tuples = sorted(set(function_tuples), key=self.sort_fn)
self._specs = {}
- for name, args in function_tuples:
- if name in SpecBuilder.ignored_attributes:
+ for name, args in self.function_tuples:
+ if SpecBuilder.ignored_attributes.match(name):
continue
action = getattr(self, name, None)
+
# print out unknown actions so we can display them for debugging
if not action:
- msg = "%s(%s)" % (name, ", ".join(str(a) for a in args))
+ msg = 'UNKNOWN SYMBOL: attr("%s", %s)' % (name, ", ".join(str(a) for a in args))
tty.debug(msg)
continue
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index ab40d28bd9..e2ff08889d 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -28,28 +28,11 @@ opt_criterion(300, "number of input specs not concretized").
#minimize { 1@300,ID : literal_not_solved(ID) }.
% Map constraint on the literal ID to the correct PSID
-attr(Name, A1) :- literal(LiteralID, Name, A1), literal_solved(LiteralID).
-attr(Name, A1, A2) :- literal(LiteralID, Name, A1, A2), literal_solved(LiteralID).
-attr(Name, A1, A2, A3) :- literal(LiteralID, Name, A1, A2, A3), literal_solved(LiteralID).
+attr(Name, A1) :- literal(LiteralID, Name, A1), literal_solved(LiteralID).
+attr(Name, A1, A2) :- literal(LiteralID, Name, A1, A2), literal_solved(LiteralID).
+attr(Name, A1, A2, A3) :- literal(LiteralID, Name, A1, A2, A3), literal_solved(LiteralID).
attr(Name, A1, A2, A3, A4) :- literal(LiteralID, Name, A1, A2, A3, A4), literal_solved(LiteralID).
-% For these two atoms we only need implications in one direction
-root(Package) :- attr("root", Package).
-virtual_root(Package) :- attr("virtual_root", Package).
-
-node_platform_set(Package, Platform) :- attr("node_platform_set", Package, Platform).
-node_os_set(Package, OS) :- attr("node_os_set", Package, OS).
-node_target_set(Package, Target) :- attr("node_target_set", Package, Target).
-node_flag_set(Package, Flag, Value) :- attr("node_flag_set", Package, Flag, Value).
-
-node_compiler_version_set(Package, Compiler, Version)
- :- attr("node_compiler_version_set", Package, Compiler, Version).
-node_compiler_set(Package, Compiler)
- :- attr("node_compiler_set", Package, Compiler).
-
-variant_default_value_from_cli(Package, Variant, Value)
- :- attr("variant_default_value_from_cli", Package, Variant, Value).
-
#defined concretize_everything/0.
#defined literal/1.
#defined literal/3.
@@ -73,9 +56,9 @@ version_declared(Package, Version, Weight) :- version_declared(Package, Version,
% We cannot use a version declared for an installed package if we end up building it
:- version_declared(Package, Version, Weight, "installed"),
- version(Package, Version),
+ attr("version", Package, Version),
version_weight(Package, Weight),
- not hash(Package, _),
+ not attr("hash", Package, _),
internal_error("Reuse version weight used for built package").
% versions are declared w/priority -- declared with priority implies declared
@@ -92,34 +75,36 @@ version_satisfies(Package, Constraint, HashVersion) :- version_satisfies(Package
% is not precisely one version chosen. Error facts are heavily optimized
% against to ensure they cannot be inferred when a non-error solution is
% possible
-{ version(Package, Version) : version_declared(Package, Version) }
- :- node(Package).
+{ attr("version", Package, Version) : version_declared(Package, Version) }
+ :- attr("node", Package).
error(2, "No version for '{0}' satisfies '@{1}' and '@{2}'", Package, Version1, Version2)
- :- node(Package),
- version(Package, Version1),
- version(Package, Version2),
+ :- attr("node", Package),
+ attr("version", Package, Version1),
+ attr("version", Package, Version2),
Version1 < Version2. % see[1]
error(2, "No versions available for package '{0}'", Package)
- :- node(Package), not version(Package, _).
+ :- attr("node", Package), not attr("version", Package, _).
% A virtual package may or may not have a version, but never has more than one
error(2, "No version for '{0}' satisfies '@{1}' and '@{2}'", Virtual, Version1, Version2)
- :- virtual_node(Virtual),
- version(Virtual, Version1),
- version(Virtual, Version2),
+ :- attr("virtual_node", Virtual),
+ attr("version", Virtual, Version1),
+ attr("version", Virtual, Version2),
Version1 < Version2. % see[1]
% If we select a deprecated version, mark the package as deprecated
-deprecated(Package, Version) :- version(Package, Version), deprecated_version(Package, Version).
+attr("deprecated", Package, Version) :-
+ attr("version", Package, Version),
+ deprecated_version(Package, Version).
possible_version_weight(Package, Weight)
- :- version(Package, Version),
+ :- attr("version", Package, Version),
version_declared(Package, Version, Weight).
% we can't use the weight for an external version if we don't use the
% corresponding external spec.
-:- version(Package, Version),
+:- attr("version", Package, Version),
version_weight(Package, Weight),
version_declared(Package, Version, Weight, "external"),
not external(Package),
@@ -127,44 +112,45 @@ possible_version_weight(Package, Weight)
% we can't use a weight from an installed spec if we are building it
% and vice-versa
-:- version(Package, Version),
+:- attr("version", Package, Version),
version_weight(Package, Weight),
version_declared(Package, Version, Weight, "installed"),
build(Package),
internal_error("Reuse version weight used for build package").
-:- version(Package, Version),
+:- attr("version", Package, Version),
version_weight(Package, Weight),
not version_declared(Package, Version, Weight, "installed"),
not build(Package),
internal_error("Build version weight used for reused package").
1 { version_weight(Package, Weight) : version_declared(Package, Version, Weight) } 1
- :- version(Package, Version),
- node(Package).
+ :- attr("version", Package, Version),
+ attr("node", Package).
% node_version_satisfies implies that exactly one of the satisfying versions
% is the package's version, and vice versa.
% While this choice rule appears redundant with the initial choice rule for
% versions, virtual nodes with version constraints require this rule to be
% able to choose versions
-{ version(Package, Version) : version_satisfies(Package, Constraint, Version) }
- :- node_version_satisfies(Package, Constraint).
+{ attr("version", Package, Version) : version_satisfies(Package, Constraint, Version) }
+ :- attr("node_version_satisfies", Package, Constraint).
% If there is at least a version that satisfy the constraint, impose a lower
% bound on the choice rule to avoid false positives with the error below
-1 { version(Package, Version) : version_satisfies(Package, Constraint, Version) }
- :- node_version_satisfies(Package, Constraint), version_satisfies(Package, Constraint, _).
+1 { attr("version", Package, Version) : version_satisfies(Package, Constraint, Version) }
+ :- attr("node_version_satisfies", Package, Constraint),
+ version_satisfies(Package, Constraint, _).
% More specific error message if the version cannot satisfy some constraint
% Otherwise covered by `no_version_error` and `versions_conflict_error`.
error(1, "No valid version for '{0}' satisfies '@{1}'", Package, Constraint)
- :- node_version_satisfies(Package, Constraint),
- C = #count{ Version : version(Package, Version), version_satisfies(Package, Constraint, Version)},
+ :- attr("node_version_satisfies", Package, Constraint),
+ C = #count{ Version : attr("version", Package, Version), version_satisfies(Package, Constraint, Version)},
C < 1.
-node_version_satisfies(Package, Constraint)
- :- version(Package, Version), version_satisfies(Package, Constraint, Version).
+attr("node_version_satisfies", Package, Constraint)
+ :- attr("version", Package, Version), version_satisfies(Package, Constraint, Version).
#defined version_satisfies/3.
#defined deprecated_version/2.
@@ -199,14 +185,14 @@ attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A
attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3, A4).
% we cannot have additional variant values when we are working with concrete specs
-:- node(Package), hash(Package, Hash),
- variant_value(Package, Variant, Value),
+:- attr("node", Package), attr("hash", Package, Hash),
+ attr("variant_value", Package, Variant, Value),
not imposed_constraint(Hash, "variant_value", Package, Variant, Value),
internal_error("imposed hash without imposing all variant values").
% we cannot have additional flag values when we are working with concrete specs
-:- node(Package), hash(Package, Hash),
- node_flag(Package, FlagType, Flag),
+:- attr("node", Package), attr("hash", Package, Hash),
+ attr("node_flag", Package, FlagType, Flag),
not imposed_constraint(Hash, "node_flag", Package, FlagType, Flag),
internal_error("imposed hash without imposing all flag values").
@@ -224,13 +210,13 @@ attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A
% Concrete specs
%-----------------------------------------------------------------------------
% if a package is assigned a hash, it's concrete.
-concrete(Package) :- hash(Package, _), node(Package).
+concrete(Package) :- attr("hash", Package, _), attr("node", Package).
%-----------------------------------------------------------------------------
% Dependency semantics
%-----------------------------------------------------------------------------
% Dependencies of any type imply that one package "depends on" another
-depends_on(Package, Dependency) :- depends_on(Package, Dependency, _).
+depends_on(Package, Dependency) :- attr("depends_on", Package, Dependency, _).
% a dependency holds if its condition holds and if it is not external or
% concrete. We chop off dependencies for externals, and dependencies of
@@ -252,23 +238,23 @@ do_not_impose(ID) :-
% declared dependencies are real if they're not virtual AND
% the package is not an external.
% They're only triggered if the associated dependnecy condition holds.
-depends_on(Package, Dependency, Type)
+attr("depends_on", Package, Dependency, Type)
:- dependency_holds(Package, Dependency, Type),
not virtual(Dependency).
% every root must be a node
-node(Package) :- root(Package).
+attr("node", Package) :- attr("root", Package).
% dependencies imply new nodes
-node(Dependency) :- node(Package), depends_on(Package, Dependency).
+attr("node", Dependency) :- attr("node", Package), depends_on(Package, Dependency).
% all nodes in the graph must be reachable from some root
% this ensures a user can't say `zlib ^libiconv` (neither of which have any
% dependencies) and get a two-node unconnected graph
-needed(Package) :- root(Package).
+needed(Package) :- attr("root", Package).
needed(Dependency) :- needed(Package), depends_on(Package, Dependency).
error(1, "'{0}' is not a valid dependency for any package in the DAG", Package)
- :- node(Package),
+ :- attr("node", Package),
not needed(Package).
% Avoid cycles in the DAG
@@ -286,12 +272,12 @@ error(2, "Cyclic dependency detected between '{0}' and '{1}'\n Consider chang
%-----------------------------------------------------------------------------
% Conflicts
%-----------------------------------------------------------------------------
-error(0, Msg) :- node(Package),
+error(0, Msg) :- attr("node", Package),
conflict(Package, TriggerID, ConstraintID, Msg),
condition_holds(TriggerID),
condition_holds(ConstraintID),
not external(Package), % ignore conflicts for externals
- not hash(Package, _). % ignore conflicts for installed packages
+ not attr("hash", Package, _). % ignore conflicts for installed packages
#defined conflict/4.
@@ -301,43 +287,43 @@ error(0, Msg) :- node(Package),
% if a package depends on a virtual, it's not external and we have a
% provider for that virtual then it depends on the provider
-depends_on(Package, Provider, Type)
+attr("depends_on", Package, Provider, Type)
:- dependency_holds(Package, Virtual, Type),
provider(Provider, Virtual),
not external(Package).
% dependencies on virtuals also imply that the virtual is a virtual node
-virtual_node(Virtual)
+attr("virtual_node", Virtual)
:- dependency_holds(Package, Virtual, Type),
virtual(Virtual), not external(Package).
% If there's a virtual node, we must select one and only one provider.
% The provider must be selected among the possible providers.
{ provider(Package, Virtual) : possible_provider(Package, Virtual) }
- :- virtual_node(Virtual).
+ :- attr("virtual_node", Virtual).
error(2, "Cannot find valid provider for virtual {0}", Virtual)
- :- virtual_node(Virtual),
+ :- attr("virtual_node", Virtual),
P = #count{ Package : provider(Package, Virtual)},
P < 1.
error(2, "Spec cannot include multiple providers for virtual '{0}'\n Requested '{1}' and '{2}'", Virtual, P1, P2)
- :- virtual_node(Virtual),
+ :- attr("virtual_node", Virtual),
provider(P1, Virtual),
provider(P2, Virtual),
P1 < P2.
% virtual roots imply virtual nodes, and that one provider is a root
-virtual_node(Virtual) :- virtual_root(Virtual).
+attr("virtual_node", Virtual) :- attr("virtual_root", Virtual).
% If we asked for a virtual root and we have a provider for that,
% then the provider is the root package.
-root(Package) :- virtual_root(Virtual), provider(Package, Virtual).
+attr("root", Package) :- attr("virtual_root", Virtual), provider(Package, Virtual).
% If we asked for a root package and that root provides a virtual,
% the root is a provider for that virtual. This rule is mostly relevant
% for environments that are concretized together (e.g. where we
% asks to install "mpich" and "hdf5+mpi" and we want "mpich" to
% be the mpi provider)
-provider(Package, Virtual) :- node(Package), virtual_condition_holds(Package, Virtual).
+provider(Package, Virtual) :- attr("node", Package), virtual_condition_holds(Package, Virtual).
% The provider provides the virtual if some provider condition holds.
virtual_condition_holds(Provider, Virtual) :-
@@ -387,73 +373,15 @@ possible_provider_weight(Dependency, Virtual, Weight, "default")
% Any provider can use 100 as a weight, which is very high and discourage its use
possible_provider_weight(Dependency, Virtual, 100, "fallback") :- provider(Dependency, Virtual).
+% do not warn if generated program contains none of these.
#defined possible_provider/2.
#defined provider_condition/3.
#defined required_provider_condition/3.
#defined required_provider_condition/4.
#defined required_provider_condition/5.
#defined required_provider_condition/6.
-
-%-----------------------------------------------------------------------------
-% Spec Attributes
-%-----------------------------------------------------------------------------
-% Equivalencies of the form:
-%
-% name(Arg1, Arg2, ...) :- attr("name", Arg1, Arg2, ...).
-% attr("name", Arg1, Arg2, ...) :- name(Arg1, Arg2, ...).
-%
-% These allow us to easily define conditional dependency and conflict rules
-% without enumerating all spec attributes every time.
-node(Package) :- attr("node", Package).
-virtual_node(Virtual) :- attr("virtual_node", Virtual).
-hash(Package, Hash) :- attr("hash", Package, Hash).
-version(Package, Version) :- attr("version", Package, Version).
-node_version_satisfies(Package, Constraint) :- attr("node_version_satisfies", Package, Constraint).
-node_platform(Package, Platform) :- attr("node_platform", Package, Platform).
-node_os(Package, OS) :- attr("node_os", Package, OS).
-node_target(Package, Target) :- attr("node_target", Package, Target).
-node_target_satisfies(Package, Target) :- attr("node_target_satisfies", Package, Target).
-variant_value(Package, Variant, Value) :- attr("variant_value", Package, Variant, Value).
-variant_set(Package, Variant, Value) :- attr("variant_set", Package, Variant, Value).
-variant_propagate(Package, Variant, Value, Source) :- attr("variant_propagate", Package, Variant, Value, Source).
-node_flag(Package, FlagType, Flag) :- attr("node_flag", Package, FlagType, Flag).
-node_compiler(Package, Compiler) :- attr("node_compiler", Package, Compiler).
-depends_on(Package, Dependency, Type) :- attr("depends_on", Package, Dependency, Type).
-node_compiler_version(Package, Compiler, Version)
- :- attr("node_compiler_version", Package, Compiler, Version).
-node_compiler_version_satisfies(Package, Compiler, Version)
- :- attr("node_compiler_version_satisfies", Package, Compiler, Version).
-node_flag_propagate(Package, FlagType)
- :- attr("node_flag_propagate", Package, FlagType).
-
-attr("node", Package) :- node(Package).
-attr("virtual_node", Virtual) :- virtual_node(Virtual).
-attr("hash", Package, Hash) :- hash(Package, Hash).
-attr("version", Package, Version) :- version(Package, Version).
-attr("node_version_satisfies", Package, Constraint) :- node_version_satisfies(Package, Constraint).
-attr("node_platform", Package, Platform) :- node_platform(Package, Platform).
-attr("node_os", Package, OS) :- node_os(Package, OS).
-attr("node_target", Package, Target) :- node_target(Package, Target).
-attr("node_target_satisfies", Package, Target) :- node_target_satisfies(Package, Target).
-attr("variant_value", Package, Variant, Value) :- variant_value(Package, Variant, Value).
-attr("variant_set", Package, Variant, Value) :- variant_set(Package, Variant, Value).
-attr("variant_propagate", Package, Variant, Value, Source) :- variant_propagate(Package, Variant, Value, Source).
-attr("node_flag", Package, FlagType, Flag) :- node_flag(Package, FlagType, Flag).
-attr("node_compiler", Package, Compiler) :- node_compiler(Package, Compiler).
-attr("depends_on", Package, Dependency, Type) :- depends_on(Package, Dependency, Type).
-attr("node_compiler_version", Package, Compiler, Version)
- :- node_compiler_version(Package, Compiler, Version).
-attr("node_compiler_version_satisfies", Package, Compiler, Version)
- :- node_compiler_version_satisfies(Package, Compiler, Version).
-attr("node_flag_propagate", Package, FlagType)
- :- node_flag_propagate(Package, FlagType).
-
-% do not warn if generated program contains none of these.
-#defined depends_on/3.
#defined declared_dependency/3.
#defined virtual/1.
-#defined virtual_node/1.
-#defined virtual_root/1.
#defined virtual_condition_holds/2.
#defined external/1.
#defined external_spec/2.
@@ -461,9 +389,6 @@ attr("node_flag_propagate", Package, FlagType)
#defined buildable_false/1.
#defined pkg_provider_preference/4.
#defined default_provider_preference/3.
-#defined node_version_satisfies/2.
-#defined node_compiler_version_satisfies/3.
-#defined root/1.
%-----------------------------------------------------------------------------
% External semantics
@@ -483,32 +408,32 @@ error(2, "Attempted to use external for '{0}' which does not satisfy any configu
(Version1, Weight1) < (Version2, Weight2). % see[1]
version_weight(Package, Weight) :- external_version(Package, Version, Weight).
-version(Package, Version) :- external_version(Package, Version, Weight).
+attr("version", Package, Version) :- external_version(Package, Version, Weight).
% if a package is not buildable, only externals or hashed specs are allowed
external(Package) :- buildable_false(Package),
- node(Package),
- not hash(Package, _).
+ attr("node", Package),
+ not attr("hash", Package, _).
% a package is a real_node if it is not external
-real_node(Package) :- node(Package), not external(Package).
+real_node(Package) :- attr("node", Package), not external(Package).
% a package is external if we are using an external spec for it
-external(Package) :- external_spec_selected(Package, _).
+external(Package) :- attr("external_spec_selected", Package, _).
% we can't use the weight for an external version if we don't use the
% corresponding external spec.
-:- version(Package, Version),
+:- attr("version", Package, Version),
version_weight(Package, Weight),
version_declared(Package, Version, Weight, "external"),
not external(Package),
internal_error("External weight used for internal spec").
% determine if an external spec has been selected
-external_spec_selected(Package, LocalIndex) :-
+attr("external_spec_selected", Package, LocalIndex) :-
external_conditions_hold(Package, LocalIndex),
- node(Package),
- not hash(Package, _).
+ attr("node", Package),
+ not attr("hash", Package, _).
external_conditions_hold(Package, LocalIndex) :-
possible_external(ID, Package, LocalIndex), condition_holds(ID).
@@ -530,8 +455,8 @@ error(2, "Attempted to use external for '{0}' which does not satisfy any configu
% Config required semantics
%-----------------------------------------------------------------------------
-activate_requirement_rules(Package) :- node(Package).
-activate_requirement_rules(Package) :- virtual_node(Package).
+activate_requirement_rules(Package) :- attr("node", Package).
+activate_requirement_rules(Package) :- attr("virtual_node", Package).
requirement_group_satisfied(Package, X) :-
1 { condition_holds(Y) : requirement_group_member(Y, Package, X) } 1,
@@ -581,77 +506,77 @@ error(2, "Cannot satisfy the requirements in packages.yaml for the '{0}' package
variant(Package, Variant) :- variant_condition(ID, Package, Variant),
condition_holds(ID).
-variant_propagate(Package, Variant, Value, Source) :-
- node(Package),
+attr("variant_propagate", Package, Variant, Value, Source) :-
+ attr("node", Package),
depends_on(Parent, Package),
- variant_propagate(Parent, Variant, Value, Source),
- not variant_set(Package, Variant).
+ attr("variant_propagate", Parent, Variant, Value, Source),
+ not attr("variant_set", Package, Variant).
-variant_value(Package, Variant, Value) :-
- node(Package),
+attr("variant_value", Package, Variant, Value) :-
+ attr("node", Package),
variant(Package, Variant),
- variant_propagate(Package, Variant, Value, _),
+ attr("variant_propagate", Package, Variant, Value, _),
variant_possible_value(Package, Variant, Value).
error(2, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
- variant_propagate(Package, Variant, Value1, Source1),
- variant_propagate(Package, Variant, Value2, Source2),
+ attr("variant_propagate", Package, Variant, Value1, Source1),
+ attr("variant_propagate", Package, Variant, Value2, Source2),
variant(Package, Variant),
Value1 != Value2.
% a variant cannot be set if it is not a variant on the package
error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
- :- variant_set(Package, Variant),
+ :- attr("variant_set", Package, Variant),
not variant(Package, Variant),
build(Package).
% a variant cannot take on a value if it is not a variant of the package
error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
- :- variant_value(Package, Variant, _),
+ :- attr("variant_value", Package, Variant, _),
not variant(Package, Variant),
build(Package).
% if a variant is sticky and not set its value is the default value
-variant_value(Package, Variant, Value) :-
+attr("variant_value", Package, Variant, Value) :-
variant(Package, Variant),
- not variant_set(Package, Variant),
+ not attr("variant_set", Package, Variant),
variant_sticky(Package, Variant),
variant_default_value(Package, Variant, Value),
build(Package).
% at most one variant value for single-valued variants.
{
- variant_value(Package, Variant, Value)
+ attr("variant_value", Package, Variant, Value)
: variant_possible_value(Package, Variant, Value)
}
- :- node(Package),
+ :- attr("node", Package),
variant(Package, Variant),
build(Package).
error(2, "'{0}' required multiple values for single-valued variant '{1}'\n Requested 'Spec({1}={2})' and 'Spec({1}={3})'", Package, Variant, Value1, Value2)
- :- node(Package),
+ :- attr("node", Package),
variant(Package, Variant),
variant_single_value(Package, Variant),
build(Package),
- variant_value(Package, Variant, Value1),
- variant_value(Package, Variant, Value2),
+ attr("variant_value", Package, Variant, Value1),
+ attr("variant_value", Package, Variant, Value2),
Value1 < Value2. % see[1]
error(2, "No valid value for variant '{1}' of package '{0}'", Package, Variant)
- :- node(Package),
+ :- attr("node", Package),
variant(Package, Variant),
build(Package),
- C = #count{ Value : variant_value(Package, Variant, Value) },
+ C = #count{ Value : attr("variant_value", Package, Variant, Value) },
C < 1.
% if a variant is set to anything, it is considered 'set'.
-variant_set(Package, Variant) :- variant_set(Package, Variant, _).
+attr("variant_set", Package, Variant) :- attr("variant_set", Package, Variant, _).
% A variant cannot have a value that is not also a possible value
% This only applies to packages we need to build -- concrete packages may
% have been built w/different variants from older/different package versions.
error(1, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package, Variant, Value)
- :- variant_value(Package, Variant, Value),
+ :- attr("variant_value", Package, Variant, Value),
not variant_possible_value(Package, Variant, Value),
build(Package).
@@ -659,8 +584,8 @@ error(1, "'Spec({1}={2})' is not a valid value for '{0}' variant '{1}'", Package
% Ensure that we respect that constraint and we don't pick values from more
% than one set at once
error(2, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come from disjoing value sets", Package, Variant, Value1, Value2)
- :- variant_value(Package, Variant, Value1),
- variant_value(Package, Variant, Value2),
+ :- attr("variant_value", Package, Variant, Value1),
+ attr("variant_value", Package, Variant, Value2),
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
variant_value_from_disjoint_sets(Package, Variant, Value2, Set2),
Set1 < Set2, % see[1]
@@ -668,41 +593,41 @@ error(2, "{0} variant '{1}' cannot have values '{2}' and '{3}' as they come from
% 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(Package, Variant, Value)
- :- node(Package),
+attr("variant_value", Package, Variant, Value)
+ :- attr("node", Package),
variant(Package, Variant),
- variant_set(Package, Variant, Value).
+ attr("variant_set", Package, Variant, Value).
% The rules below allow us to prefer default values for variants
% whenever possible. If a variant is set in a spec, or if it is
% specified in an external, we score it as if it was a default value.
variant_not_default(Package, Variant, Value)
- :- variant_value(Package, Variant, Value),
+ :- attr("variant_value", Package, Variant, Value),
not variant_default_value(Package, Variant, Value),
% variants set explicitly on the CLI don't count as non-default
- not variant_set(Package, Variant, Value),
+ not attr("variant_set", Package, Variant, Value),
% variant values forced by propagation don't count as non-default
- not variant_propagate(Package, Variant, Value, _),
+ not attr("variant_propagate", Package, Variant, Value, _),
% variants set on externals that we could use don't count as non-default
% this makes spack prefer to use an external over rebuilding with the
% default configuration
not external_with_variant_set(Package, Variant, Value),
- node(Package).
+ attr("node", Package).
% A default variant value that is not used
variant_default_not_used(Package, Variant, Value)
:- variant_default_value(Package, Variant, Value),
- not variant_value(Package, Variant, Value),
- node(Package).
+ not attr("variant_value", Package, Variant, Value),
+ attr("node", Package).
% The variant is set in an external spec
external_with_variant_set(Package, Variant, Value)
- :- variant_value(Package, Variant, Value),
+ :- attr("variant_value", Package, Variant, Value),
condition_requirement(ID, "variant_value", Package, Variant, Value),
possible_external(ID, Package, _),
external(Package),
- node(Package).
+ attr("node", Package).
% The default value for a variant in a package is what is prescribed:
%
@@ -714,19 +639,20 @@ external_with_variant_set(Package, Variant, Value)
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_package_py(Package, Variant, Value),
not variant_default_value_from_packages_yaml(Package, Variant, _),
- not variant_default_value_from_cli(Package, Variant, _).
+ not attr("variant_default_value_from_cli", Package, Variant, _).
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_packages_yaml(Package, Variant, Value),
- not variant_default_value_from_cli(Package, Variant, _).
+ not attr("variant_default_value_from_cli", Package, Variant, _).
-variant_default_value(Package, Variant, Value) :- variant_default_value_from_cli(Package, Variant, Value).
+variant_default_value(Package, Variant, Value) :-
+ attr("variant_default_value_from_cli", Package, Variant, Value).
% Treat 'none' in a special way - it cannot be combined with other
% values even if the variant is multi-valued
error(2, "{0} variant '{1}' cannot have values '{2}' and 'none'", Package, Variant, Value)
- :- variant_value(Package, Variant, Value),
- variant_value(Package, Variant, "none"),
+ :- attr("variant_value", Package, Variant, Value),
+ attr("variant_value", Package, Variant, "none"),
Value != "none",
build(Package).
@@ -736,16 +662,15 @@ error(2, "{0} variant '{1}' cannot have values '{2}' and 'none'", Package, Varia
auto_variant("dev_path").
auto_variant("patches").
variant(Package, Variant)
- :- variant_set(Package, Variant, _), auto_variant(Variant).
+ :- attr("variant_set", Package, Variant, _), auto_variant(Variant).
variant_single_value(Package, "dev_path")
- :- variant_set(Package, "dev_path", _).
+ :- attr("variant_set", Package, "dev_path", _).
% suppress warnings 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/2.
#defined variant_sticky/2.
-#defined variant_propagate/4.
#defined variant_set/3.
#defined variant_condition/3.
#defined variant_single_value/2.
@@ -761,32 +686,30 @@ variant_single_value(Package, "dev_path")
%-----------------------------------------------------------------------------
% if no platform is set, fall back to the default
-node_platform(Package, Platform)
- :- node(Package),
- not node_platform_set(Package),
+attr("node_platform", Package, Platform)
+ :- attr("node", Package),
+ not attr("node_platform_set", Package),
node_platform_default(Platform).
% setting platform on a node is a hard constraint
-node_platform(Package, Platform)
- :- node(Package), node_platform_set(Package, Platform).
+attr("node_platform", Package, Platform)
+ :- attr("node", Package), attr("node_platform_set", Package, Platform).
% platform is set if set to anything
-node_platform_set(Package) :- node_platform_set(Package, _).
+attr("node_platform_set", Package) :- attr("node_platform_set", Package, _).
% each node must have a single platform
error(2, "No valid platform found for {0}", Package)
- :- node(Package),
- C = #count{ Platform : node_platform(Package, Platform)},
+ :- attr("node", Package),
+ C = #count{ Platform : attr("node_platform", Package, Platform)},
C < 1.
error(2, "Cannot concretize {0} with multiple platforms\n Requested 'platform={1}' and 'platform={2}'", Package, Platform1, Platform2)
- :- node(Package),
- node_platform(Package, Platform1),
- node_platform(Package, Platform2),
+ :- attr("node", Package),
+ attr("node_platform", Package, Platform1),
+ attr("node_platform", Package, Platform2),
Platform1 < Platform2. % see[1]
-#defined node_platform_set/2. % avoid warnings
-
%-----------------------------------------------------------------------------
% OS semantics
%-----------------------------------------------------------------------------
@@ -794,42 +717,42 @@ error(2, "Cannot concretize {0} with multiple platforms\n Requested 'platform
os(OS) :- os(OS, _).
% one os per node
-{ node_os(Package, OS) : os(OS) } :- node(Package).
+{ attr("node_os", Package, OS) : os(OS) } :- attr("node", Package).
error(2, "Cannot find valid operating system for '{0}'", Package)
- :- node(Package),
- C = #count{ OS : node_os(Package, OS)},
+ :- attr("node", Package),
+ C = #count{ OS : attr("node_os", Package, OS)},
C < 1.
error(2, "Cannot concretize {0} with multiple operating systems\n Requested 'os={1}' and 'os={2}'", Package, OS1, OS2)
- :- node(Package),
- node_os(Package, OS1),
- node_os(Package, OS2),
+ :- attr("node", Package),
+ attr("node_os", Package, OS1),
+ attr("node_os", Package, OS2),
OS1 < OS2. %see [1]
% can't have a non-buildable OS on a node we need to build
error(2, "Cannot concretize '{0} os={1}'. Operating system '{1}' is not buildable", Package, OS)
:- build(Package),
- node_os(Package, OS),
+ attr("node_os", Package, OS),
not buildable_os(OS).
% can't have dependencies on incompatible OS's
error(2, "{0} and dependency {1} have incompatible operating systems 'os={2}' and 'os={3}'", Package, Dependency, PackageOS, DependencyOS)
:- depends_on(Package, Dependency),
- node_os(Package, PackageOS),
- node_os(Dependency, DependencyOS),
+ attr("node_os", Package, PackageOS),
+ attr("node_os", Dependency, DependencyOS),
not os_compatible(PackageOS, DependencyOS),
build(Package).
% give OS choice weights according to os declarations
node_os_weight(Package, Weight)
- :- node(Package),
- node_os(Package, OS),
+ :- attr("node", Package),
+ attr("node_os", Package, OS),
os(OS, Weight).
% match semantics for OS's
node_os_match(Package, Dependency) :-
- depends_on(Package, Dependency), node_os(Package, OS), node_os(Dependency, OS).
+ depends_on(Package, Dependency), attr("node_os", Package, OS), attr("node_os", Dependency, OS).
node_os_mismatch(Package, Dependency) :-
depends_on(Package, Dependency), not node_os_match(Package, Dependency).
@@ -843,13 +766,12 @@ os_compatible(OS1, OS3) :- os_compatible(OS1, OS2), os_compatible(OS2, OS3).
% for which we can build software. We need a cardinality constraint
% since we might have more than one "buildable_os(OS)" fact.
:- not 1 { os_compatible(CurrentOS, ReusedOS) : buildable_os(CurrentOS) },
- node_os(Package, ReusedOS),
+ attr("node_os", Package, ReusedOS),
internal_error("Reused OS incompatible with build OS").
% If an OS is set explicitly respect the value
-node_os(Package, OS) :- node_os_set(Package, OS), node(Package).
+attr("node_os", Package, OS) :- attr("node_os_set", Package, OS), attr("node", Package).
-#defined node_os_set/2.
#defined os_compatible/2.
%-----------------------------------------------------------------------------
@@ -857,41 +779,41 @@ node_os(Package, OS) :- node_os_set(Package, OS), node(Package).
%-----------------------------------------------------------------------------
% Each node has only one target chosen among the known targets
-{ node_target(Package, Target) : target(Target) } :- node(Package).
+{ attr("node_target", Package, Target) : target(Target) } :- attr("node", Package).
error(2, "Cannot find valid target for '{0}'", Package)
- :- node(Package),
- C = #count{Target : node_target(Package, Target)},
+ :- attr("node", Package),
+ C = #count{Target : attr("node_target", Package, Target)},
C < 1.
error(2, "Cannot concretize '{0}' with multiple targets\n Requested 'target={1}' and 'target={2}'", Package, Target1, Target2)
- :- node(Package),
- node_target(Package, Target1),
- node_target(Package, Target2),
+ :- attr("node", Package),
+ attr("node_target", Package, Target1),
+ attr("node_target", Package, Target2),
Target1 < Target2. % see[1]
% If a node must satisfy a target constraint, enforce it
error(1, "'{0} target={1}' cannot satisfy constraint 'target={2}'", Package, Target, Constraint)
- :- node_target(Package, Target),
- node_target_satisfies(Package, Constraint),
+ :- attr("node_target", Package, Target),
+ attr("node_target_satisfies", Package, Constraint),
not target_satisfies(Constraint, Target).
% If a node has a target and the target satisfies a constraint, then the target
% associated with the node satisfies the same constraint
-node_target_satisfies(Package, Constraint)
- :- node_target(Package, Target), target_satisfies(Constraint, Target).
+attr("node_target_satisfies", Package, Constraint)
+ :- attr("node_target", Package, Target), target_satisfies(Constraint, Target).
% If a node has a target, all of its dependencies must be compatible with that target
error(2, "Cannot find compatible targets for {0} and {1}", Package, Dependency)
:- depends_on(Package, Dependency),
- node_target(Package, Target),
+ attr("node_target", Package, Target),
not node_target_compatible(Dependency, Target).
% Intermediate step for performance reasons
% When the integrity constraint above was formulated including this logic
% we suffered a substantial performance penalty
node_target_compatible(Package, Target)
- :- node_target(Package, MyTarget),
+ :- attr("node_target", Package, MyTarget),
target_compatible(Target, MyTarget).
% target_compatible(T1, T2) means code for T2 can run on T1
@@ -909,27 +831,27 @@ target_compatible(Descendent, Ancestor)
% can't use targets on node if the compiler for the node doesn't support them
error(2, "{0} compiler '{2}@{3}' incompatible with 'target={1}'", Package, Target, Compiler, Version)
- :- node_target(Package, Target),
+ :- attr("node_target", Package, Target),
not compiler_supports_target(Compiler, Version, Target),
- node_compiler(Package, Compiler),
- node_compiler_version(Package, Compiler, Version),
+ attr("node_compiler", Package, Compiler),
+ attr("node_compiler_version", Package, Compiler, Version),
build(Package).
% if a target is set explicitly, respect it
-node_target(Package, Target)
- :- node(Package), node_target_set(Package, Target).
+attr("node_target", Package, Target)
+ :- attr("node", Package), attr("node_target_set", Package, Target).
% each node has the weight of its assigned target
node_target_weight(Package, Weight)
- :- node(Package),
- node_target(Package, Target),
+ :- attr("node", Package),
+ attr("node_target", Package, Target),
target_weight(Package, Target, Weight).
% compatibility rules for targets among nodes
node_target_match(Parent, Dependency)
:- depends_on(Parent, Dependency),
- node_target(Parent, Target),
- node_target(Dependency, Target).
+ attr("node_target", Parent, Target),
+ attr("node_target", Dependency, Target).
node_target_mismatch(Parent, Dependency)
:- depends_on(Parent, Dependency),
@@ -937,11 +859,10 @@ node_target_mismatch(Parent, Dependency)
% disallow reusing concrete specs that don't have a compatible target
error(2, "'{0} target={1}' is not compatible with this machine", Package, Target)
- :- node(Package),
- node_target(Package, Target),
+ :- attr("node", Package),
+ attr("node_target", Package, Target),
not target(Target).
-#defined node_target_set/2.
#defined package_target_weight/3.
%-----------------------------------------------------------------------------
@@ -951,67 +872,68 @@ compiler(Compiler) :- compiler_version(Compiler, _).
% There must be only one compiler set per built node. The compiler
% is chosen among available versions.
-{ node_compiler_version(Package, Compiler, Version) : compiler_version(Compiler, Version) } :-
- node(Package),
+{ attr("node_compiler_version", Package, Compiler, Version) : compiler_version(Compiler, Version) } :-
+ attr("node", Package),
build(Package).
error(2, "No valid compiler version found for '{0}'", Package)
- :- node(Package),
- C = #count{ Version : node_compiler_version(Package, _, Version)},
+ :- attr("node", Package),
+ C = #count{ Version : attr("node_compiler_version", Package, _, Version)},
C < 1.
error(2, "'{0}' compiler constraints '%{1}@{2}' and '%{3}@{4}' are incompatible", Package, Compiler1, Version1, Compiler2, Version2)
- :- node(Package),
- node_compiler_version(Package, Compiler1, Version1),
- node_compiler_version(Package, Compiler2, Version2),
+ :- attr("node", Package),
+ attr("node_compiler_version", Package, Compiler1, Version1),
+ attr("node_compiler_version", Package, Compiler2, Version2),
(Compiler1, Version1) < (Compiler2, Version2). % see[1]
% Sometimes we just need to know the compiler and not the version
-node_compiler(Package, Compiler) :- node_compiler_version(Package, Compiler, _).
+attr("node_compiler", Package, Compiler) :- attr("node_compiler_version", Package, Compiler, _).
% We can't have a compiler be enforced and select the version from another compiler
error(2, "Cannot concretize {0} with two compilers {1}@{2} and {3}@{4}", Package, C1, V1, C2, V2)
- :- node_compiler_version(Package, C1, V1),
- node_compiler_version(Package, C2, V2),
+ :- attr("node_compiler_version", Package, C1, V1),
+ attr("node_compiler_version", Package, C2, V2),
(C1, V1) != (C2, V2).
error(2, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Compiler1, Compiler2, Version)
- :- node_compiler(Package, Compiler1),
- node_compiler_version(Package, Compiler2, Version),
+ :- attr("node_compiler", Package, Compiler1),
+ attr("node_compiler_version", Package, Compiler2, Version),
Compiler1 != Compiler2.
% If the compiler of a node cannot be satisfied, raise
error(1, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler)
- :- node(Package),
- node_compiler_version_satisfies(Package, Compiler, ":"),
- C = #count{ Version : node_compiler_version(Package, Compiler, Version), compiler_version_satisfies(Compiler, ":", Version) },
+ :- attr("node", Package),
+ attr("node_compiler_version_satisfies", Package, Compiler, ":"),
+ C = #count{ Version : attr("node_compiler_version", Package, Compiler, Version), compiler_version_satisfies(Compiler, ":", Version) },
C < 1.
% If the compiler of a node must satisfy a constraint, then its version
% must be chosen among the ones that satisfy said constraint
error(2, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
- :- node(Package),
- node_compiler_version_satisfies(Package, Compiler, Constraint),
- C = #count{ Version : node_compiler_version(Package, Compiler, Version), compiler_version_satisfies(Compiler, Constraint, Version) },
+ :- attr("node", Package),
+ attr("node_compiler_version_satisfies", Package, Compiler, Constraint),
+ C = #count{ Version : attr("node_compiler_version", Package, Compiler, Version), compiler_version_satisfies(Compiler, Constraint, Version) },
C < 1.
% If the node is associated with a compiler and the compiler satisfy a constraint, then
% the compiler associated with the node satisfy the same constraint
-node_compiler_version_satisfies(Package, Compiler, Constraint)
- :- node_compiler_version(Package, Compiler, Version),
+attr("node_compiler_version_satisfies", Package, Compiler, Constraint)
+ :- attr("node_compiler_version", Package, Compiler, Version),
compiler_version_satisfies(Compiler, Constraint, Version).
#defined compiler_version_satisfies/3.
% If the compiler version was set from the command line,
% respect it verbatim
-node_compiler_version(Package, Compiler, Version) :- node_compiler_version_set(Package, Compiler, Version).
+attr("node_compiler_version", Package, Compiler, Version) :-
+ attr("node_compiler_version_set", Package, Compiler, Version).
% Cannot select a compiler if it is not supported on the OS
% Compilers that are explicitly marked as allowed
% are excluded from this check
error(2, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler, Version, OS)
- :- node_compiler_version(Package, Compiler, Version),
- node_os(Package, OS),
+ :- attr("node_compiler_version", Package, Compiler, Version),
+ attr("node_os", Package, OS),
not compiler_supports_os(Compiler, Version, OS),
not allow_compiler(Compiler, Version),
build(Package).
@@ -1020,40 +942,38 @@ error(2, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler
% same compiler there's a mismatch.
compiler_match(Package, Dependency)
:- depends_on(Package, Dependency),
- node_compiler_version(Package, Compiler, Version),
- node_compiler_version(Dependency, Compiler, Version).
+ attr("node_compiler_version", Package, Compiler, Version),
+ attr("node_compiler_version", Dependency, Compiler, Version).
compiler_mismatch(Package, Dependency)
:- depends_on(Package, Dependency),
- not node_compiler_set(Dependency, _),
+ not attr("node_compiler_set", Dependency, _),
not compiler_match(Package, Dependency).
compiler_mismatch_required(Package, Dependency)
:- depends_on(Package, Dependency),
- node_compiler_set(Dependency, _),
+ attr("node_compiler_set", Dependency, _),
not compiler_match(Package, Dependency).
-#defined node_compiler_set/2.
-#defined node_compiler_version_set/3.
#defined compiler_supports_os/3.
#defined allow_compiler/2.
% compilers weighted by preference according to packages.yaml
compiler_weight(Package, Weight)
- :- node_compiler_version(Package, Compiler, V),
+ :- attr("node_compiler_version", Package, Compiler, V),
node_compiler_preference(Package, Compiler, V, Weight).
compiler_weight(Package, Weight)
- :- node_compiler_version(Package, Compiler, V),
+ :- attr("node_compiler_version", Package, Compiler, V),
not node_compiler_preference(Package, Compiler, V, _),
default_compiler_preference(Compiler, V, Weight).
compiler_weight(Package, 100)
- :- node_compiler_version(Package, Compiler, Version),
+ :- attr("node_compiler_version", Package, Compiler, Version),
not node_compiler_preference(Package, Compiler, Version, _),
not default_compiler_preference(Compiler, Version, _).
% For the time being, be strict and reuse only if the compiler match one we have on the system
error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
- :- node_compiler_version(Package, Compiler, Version), not compiler_version(Compiler, Version).
+ :- attr("node_compiler_version", Package, Compiler, Version), not compiler_version(Compiler, Version).
#defined node_compiler_preference/4.
#defined default_compiler_preference/3.
@@ -1065,85 +985,82 @@ error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missin
% propagate flags when compiler match
can_inherit_flags(Package, Dependency, FlagType)
:- depends_on(Package, Dependency),
- node_compiler(Package, Compiler),
- node_compiler(Dependency, Compiler),
- not node_flag_set(Dependency, FlagType, _),
+ attr("node_compiler", Package, Compiler),
+ attr("node_compiler", Dependency, Compiler),
+ not attr("node_flag_set", Dependency, FlagType, _),
compiler(Compiler), flag_type(FlagType).
node_flag_inherited(Dependency, FlagType, Flag)
- :- node_flag_set(Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType),
- node_flag_propagate(Package, FlagType).
+ :- attr("node_flag_set", Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType),
+ attr("node_flag_propagate", Package, FlagType).
% Ensure propagation
:- node_flag_inherited(Package, FlagType, Flag),
can_inherit_flags(Package, Dependency, FlagType),
- node_flag_propagate(Package, FlagType).
+ attr("node_flag_propagate", Package, FlagType).
error(2, "{0} and {1} cannot both propagate compiler flags '{2}' to {3}", Source1, Source2, Package, FlagType) :-
depends_on(Source1, Package),
depends_on(Source2, Package),
- node_flag_propagate(Source1, FlagType),
- node_flag_propagate(Source2, FlagType),
+ attr("node_flag_propagate", Source1, FlagType),
+ attr("node_flag_propagate", Source2, FlagType),
can_inherit_flags(Source1, Package, FlagType),
can_inherit_flags(Source2, Package, FlagType),
Source1 != Source2.
% remember where flags came from
-node_flag_source(Package, FlagType, Package) :- node_flag_set(Package, FlagType, _).
-node_flag_source(Dependency, FlagType, Q)
- :- node_flag_source(Package, FlagType, Q), node_flag_inherited(Dependency, FlagType, _),
- node_flag_propagate(Package, FlagType).
+attr("node_flag_source", Package, FlagType, Package) :- attr("node_flag_set", Package, FlagType, _).
+attr("node_flag_source", Dependency, FlagType, Q)
+ :- attr("node_flag_source", Package, FlagType, Q), node_flag_inherited(Dependency, FlagType, _),
+ attr("node_flag_propagate", Package, FlagType).
% compiler flags from compilers.yaml are put on nodes if compiler matches
-node_flag(Package, FlagType, Flag)
+attr("node_flag", Package, FlagType, Flag)
:- compiler_version_flag(Compiler, Version, FlagType, Flag),
- node_compiler_version(Package, Compiler, Version),
+ attr("node_compiler_version", Package, Compiler, Version),
flag_type(FlagType),
compiler(Compiler),
compiler_version(Compiler, Version).
-node_flag_compiler_default(Package)
- :- not node_flag_set(Package, FlagType, _),
+attr("node_flag_compiler_default", Package)
+ :- not attr("node_flag_set", Package, FlagType, _),
compiler_version_flag(Compiler, Version, FlagType, Flag),
- node_compiler_version(Package, Compiler, Version),
+ attr("node_compiler_version", Package, Compiler, Version),
flag_type(FlagType),
compiler(Compiler),
compiler_version(Compiler, Version).
% if a flag is set to something or inherited, it's included
-node_flag(Package, FlagType, Flag) :- node_flag_set(Package, FlagType, Flag).
-node_flag(Package, FlagType, Flag)
+attr("node_flag", Package, FlagType, Flag) :- attr("node_flag_set", Package, FlagType, Flag).
+attr("node_flag", Package, FlagType, Flag)
:- node_flag_inherited(Package, FlagType, Flag).
% if no node flags are set for a type, there are no flags.
-no_flags(Package, FlagType)
- :- not node_flag(Package, FlagType, _), node(Package), flag_type(FlagType).
+attr("no_flags", Package, FlagType)
+ :- not attr("node_flag", Package, FlagType, _), attr("node", Package), flag_type(FlagType).
#defined compiler_version_flag/4.
-#defined node_flag/3.
-#defined node_flag_set/3.
-#defined node_flag_propagate/2.
%-----------------------------------------------------------------------------
% Installed packages
%-----------------------------------------------------------------------------
% the solver is free to choose at most one installed hash for each package
-{ hash(Package, Hash) : installed_hash(Package, Hash) } 1
- :- node(Package), internal_error("Package must resolve to at most one hash").
+{ attr("hash", Package, Hash) : installed_hash(Package, Hash) } 1
+ :- attr("node", Package), internal_error("Package must resolve to at most one hash").
% you can't choose an installed hash for a dev spec
-:- hash(Package, Hash), variant_value(Package, "dev_path", _).
+:- attr("hash", Package, Hash), attr("variant_value", Package, "dev_path", _).
% You can't install a hash, if it is not installed
-:- hash(Package, Hash), not installed_hash(Package, Hash).
+:- attr("hash", Package, Hash), not installed_hash(Package, Hash).
% This should be redundant given the constraint above
-:- hash(Package, Hash1), hash(Package, Hash2), Hash1 != Hash2.
+:- attr("hash", Package, Hash1), attr("hash", Package, Hash2), Hash1 != Hash2.
% if a hash is selected, we impose all the constraints that implies
-impose(Hash) :- hash(Package, Hash).
+impose(Hash) :- attr("hash", Package, Hash).
% if we haven't selected a hash for a package, we'll be building it
-build(Package) :- not hash(Package, _), node(Package).
+build(Package) :- not attr("hash", Package, _), attr("node", Package).
% Minimizing builds is tricky. We want a minimizing criterion
@@ -1160,11 +1077,11 @@ build(Package) :- not hash(Package, _), node(Package).
% 200+ Shifted priorities for build nodes; correspond to priorities 0 - 99.
% 100 - 199 Unshifted priorities. Currently only includes minimizing #builds.
% 0 - 99 Priorities for non-built nodes.
-build_priority(Package, 200) :- build(Package), node(Package), optimize_for_reuse().
-build_priority(Package, 0) :- not build(Package), node(Package), optimize_for_reuse().
+build_priority(Package, 200) :- build(Package), attr("node", Package), optimize_for_reuse().
+build_priority(Package, 0) :- not build(Package), attr("node", Package), optimize_for_reuse().
% don't adjust build priorities if reuse is not enabled
-build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
+build_priority(Package, 0) :- attr("node", Package), not optimize_for_reuse().
% don't assign versions from installed packages unless reuse is enabled
% NOTE: that "installed" means the declared version was only included because
@@ -1177,7 +1094,7 @@ build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
% currently *won't* force versions for `bar`'s build dependencies -- `--fresh`
% will instead build the latest bar. When we actually include transitive
% build deps in the solve, consider using them as a preference to resolve this.
-:- version(Package, Version),
+:- attr("version", Package, Version),
version_weight(Package, Weight),
version_declared(Package, Version, Weight, "installed"),
not optimize_for_reuse().
@@ -1233,20 +1150,20 @@ opt_criterion(73, "deprecated versions used").
#minimize{ 0@73: #true }.
#minimize{
1@73+Priority,Package
- : deprecated(Package, _),
+ : attr("deprecated", Package, _),
build_priority(Package, Priority)
}.
% Minimize the:
% 1. Version weight
% 2. Number of variants with a non default value, if not set
-% for the root(Package)
+% for the root package.
opt_criterion(70, "version weight").
#minimize{ 0@270: #true }.
#minimize{ 0@70: #true }.
#minimize {
Weight@70+Priority
- : root(Package),version_weight(Package, Weight),
+ : attr("root", Package), version_weight(Package, Weight),
build_priority(Package, Priority)
}.
@@ -1256,7 +1173,7 @@ opt_criterion(65, "number of non-default variants (roots)").
#minimize {
1@65+Priority,Package,Variant,Value
: variant_not_default(Package, Variant, Value),
- root(Package),
+ attr("root", Package),
build_priority(Package, Priority)
}.
@@ -1266,7 +1183,7 @@ opt_criterion(60, "preferred providers for roots").
#minimize{
Weight@60+Priority,Provider,Virtual
: provider_weight(Provider, Virtual, Weight),
- root(Provider),
+ attr("root", Provider),
build_priority(Provider, Priority)
}.
@@ -1276,7 +1193,7 @@ opt_criterion(55, "default values of variants not being used (roots)").
#minimize{
1@55+Priority,Package,Variant,Value
: variant_default_not_used(Package, Variant, Value),
- root(Package),
+ attr("root", Package),
build_priority(Package, Priority)
}.
@@ -1287,7 +1204,7 @@ opt_criterion(50, "number of non-default variants (non-roots)").
#minimize {
1@50+Priority,Package,Variant,Value
: variant_not_default(Package, Variant, Value),
- not root(Package),
+ not attr("root", Package),
build_priority(Package, Priority)
}.
@@ -1298,7 +1215,7 @@ opt_criterion(45, "preferred providers (non-roots)").
#minimize{ 0@45: #true }.
#minimize{
Weight@45+Priority,Provider,Virtual
- : provider_weight(Provider, Virtual, Weight), not root(Provider),
+ : provider_weight(Provider, Virtual, Weight), not attr("root", Provider),
build_priority(Provider, Priority)
}.
@@ -1357,7 +1274,7 @@ opt_criterion(20, "default values of variants not being used (non-roots)").
#minimize{
1@20+Priority,Package,Variant,Value
: variant_default_not_used(Package, Variant, Value),
- not root(Package),
+ not attr("root", Package),
build_priority(Package, Priority)
}.
@@ -1394,14 +1311,14 @@ opt_criterion(5, "non-preferred targets").
%-----------------
% Domain heuristic
%-----------------
-#heuristic version(Package, Version) : version_declared(Package, Version, 0), node(Package). [10, true]
-#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), node(Package). [10, true]
-#heuristic node_target(Package, Target) : package_target_weight(Target, Package, 0), node(Package). [10, true]
-#heuristic node_target_weight(Package, 0) : node(Package). [10, true]
-#heuristic variant_value(Package, Variant, Value) : variant_default_value(Package, Variant, Value), node(Package). [10, true]
-#heuristic provider(Package, Virtual) : possible_provider_weight(Package, Virtual, 0, _), virtual_node(Virtual). [10, true]
-#heuristic node(Package) : possible_provider_weight(Package, Virtual, 0, _), virtual_node(Virtual). [10, true]
-#heuristic node_os(Package, OS) : buildable_os(OS). [10, true]
+#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("node", Package). [10, true]
+#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("node", Package). [10, true]
+#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("node", Package). [10, true]
+#heuristic node_target_weight(Package, 0) : attr("node", Package). [10, true]
+#heuristic attr("variant_value", Package, Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", Package). [10, true]
+#heuristic provider(Package, Virtual) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [10, true]
+#heuristic attr("node", Package) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [10, true]
+#heuristic attr("node_os", Package, OS) : buildable_os(OS). [10, true]
%-----------
% Notes
diff --git a/lib/spack/spack/solver/display.lp b/lib/spack/spack/solver/display.lp
index 4ba8e9e2cb..320f063e31 100644
--- a/lib/spack/spack/solver/display.lp
+++ b/lib/spack/spack/solver/display.lp
@@ -9,33 +9,14 @@
% This section determines what parts of the model are printed at the end
%==============================================================================
-% Spec-related functions.
-% Used to build the result of the solve.
-#show node/1.
-#show hash/2.
-#show depends_on/3.
-#show version/2.
-#show variant_value/3.
-#show node_platform/2.
-#show node_os/2.
-#show node_target/2.
-#show node_compiler/2.
-#show node_compiler_version/3.
-#show node_flag/3.
-#show node_flag_compiler_default/1.
-#show node_flag_source/3.
-#show no_flags/2.
-#show external_spec_selected/2.
-#show version_equivalent/3.
-
-#show build/1.
+% Spec attributes
+#show attr/2.
+#show attr/3.
+#show attr/4.
% names of optimization criteria
#show opt_criterion/2.
-% deprecated packages
-#show deprecated/2.
-
% error types
#show error/2.
#show error/3.