summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRicharda Butler <39577672+RikkiButler20@users.noreply.github.com>2023-11-07 12:04:41 -0800
committerGitHub <noreply@github.com>2023-11-07 21:04:41 +0100
commit5774df6b7a295a397e30a843f5ef14b339535b64 (patch)
tree31b116612d7899565e591606b5dd1364c198f7d4 /lib
parent3a5c1eb5f370cc532629f70b28067a6711aa24e3 (diff)
downloadspack-5774df6b7a295a397e30a843f5ef14b339535b64.tar.gz
spack-5774df6b7a295a397e30a843f5ef14b339535b64.tar.bz2
spack-5774df6b7a295a397e30a843f5ef14b339535b64.tar.xz
spack-5774df6b7a295a397e30a843f5ef14b339535b64.zip
Propagate variant across nodes that don't have that variant (#38512)
Before this PR, variant were not propagated to leaf nodes that could accept the propagated value, if some intermediate node couldn't accept it. This PR fixes that issue by marking nodes as "candidate" for propagation and by setting the variant only if it can be accepted by the node. Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/solver/asp.py8
-rw-r--r--lib/spack/spack/solver/concretize.lp29
-rw-r--r--lib/spack/spack/test/concretize.py52
3 files changed, 71 insertions, 18 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 0cca744359..4514bd0e96 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -1922,7 +1922,7 @@ class SpackSolverSetup:
node_flag = fn.attr("node_flag_set")
node_flag_source = fn.attr("node_flag_source")
node_flag_propagate = fn.attr("node_flag_propagate")
- variant_propagate = fn.attr("variant_propagate")
+ variant_propagation_candidate = fn.attr("variant_propagation_candidate")
class Body:
node = fn.attr("node")
@@ -1936,7 +1936,7 @@ class SpackSolverSetup:
node_flag = fn.attr("node_flag")
node_flag_source = fn.attr("node_flag_source")
node_flag_propagate = fn.attr("node_flag_propagate")
- variant_propagate = fn.attr("variant_propagate")
+ variant_propagation_candidate = fn.attr("variant_propagation_candidate")
f = Body if body else Head
@@ -1985,7 +1985,9 @@ class SpackSolverSetup:
clauses.append(f.variant_value(spec.name, vname, value))
if variant.propagate:
- clauses.append(f.variant_propagate(spec.name, vname, value, spec.name))
+ clauses.append(
+ f.variant_propagation_candidate(spec.name, vname, value, spec.name)
+ )
# Tell the concretizer that this is a possible value for the
# variant, to account for things like int/str values where we
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 5e98e5cf11..d5f24ddc3b 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -757,23 +757,36 @@ node_has_variant(node(ID, Package), Variant) :-
pkg_fact(Package, variant(Variant)),
attr("node", node(ID, Package)).
-attr("variant_propagate", PackageNode, Variant, Value, Source) :-
+% Variant propagation is forwarded to dependencies
+attr("variant_propagation_candidate", PackageNode, Variant, Value, Source) :-
attr("node", PackageNode),
depends_on(ParentNode, PackageNode),
- attr("variant_propagate", ParentNode, Variant, Value, Source),
- not attr("variant_set", PackageNode, Variant).
+ attr("variant_value", node(_, Source), Variant, Value),
+ attr("variant_propagation_candidate", ParentNode, Variant, _, Source).
-attr("variant_value", node(ID, Package), Variant, Value) :-
- attr("node", node(ID, Package)),
+% If the node is a candidate, and it has the variant and value,
+% then those variant and value should be propagated
+attr("variant_propagate", node(ID, Package), Variant, Value, Source) :-
+ attr("variant_propagation_candidate", node(ID, Package), Variant, Value, Source),
node_has_variant(node(ID, Package), Variant),
- attr("variant_propagate", node(ID, Package), Variant, Value, _),
- pkg_fact(Package, variant_possible_value(Variant, Value)).
+ pkg_fact(Package, variant_possible_value(Variant, Value)),
+ not attr("variant_set", node(ID, Package), Variant).
+
+% Propagate the value, if there is the corresponding attribute
+attr("variant_value", PackageNode, Variant, Value) :- attr("variant_propagate", PackageNode, Variant, Value, _).
+
+% If a variant is propagated, we cannot have extraneous values (this is for multi valued variants)
+variant_is_propagated(PackageNode, Variant) :- attr("variant_propagate", PackageNode, Variant, _, _).
+:- variant_is_propagated(PackageNode, Variant),
+ attr("variant_value", PackageNode, Variant, Value),
+ not attr("variant_propagate", PackageNode, Variant, Value, _).
+% Cannot receive different values from different sources on the same variant
error(100, "{0} and {1} cannot both propagate variant '{2}' to package {3} with values '{4}' and '{5}'", Source1, Source2, Variant, Package, Value1, Value2) :-
attr("variant_propagate", node(X, Package), Variant, Value1, Source1),
attr("variant_propagate", node(X, Package), Variant, Value2, Source2),
node_has_variant(node(X, Package), Variant),
- Value1 < Value2.
+ Value1 < Value2, Source1 < Source2.
% a variant cannot be set if it is not a variant on the package
error(100, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 0af689ddd5..eba86d14fc 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -349,6 +349,9 @@ class TestConcretize:
spec.concretize()
assert spec.satisfies("cflags=-O2")
+ @pytest.mark.only_clingo(
+ "Optional compiler propagation isn't deprecated for original concretizer"
+ )
def test_concretize_compiler_flag_propagate(self):
spec = Spec("hypre cflags=='-g' ^openblas")
spec.concretize()
@@ -458,19 +461,54 @@ class TestConcretize:
@pytest.mark.only_clingo(
"Optional compiler propagation isn't deprecated for original concretizer"
)
- def test_concretize_propagate_disabled_variant(self):
+ @pytest.mark.parametrize(
+ "spec_str,expected_propagation",
+ [
+ ("hypre~~shared ^openblas+shared", [("hypre", "~shared"), ("openblas", "+shared")]),
+ # Propagates past a node that doesn't have the variant
+ ("hypre~~shared ^openblas", [("hypre", "~shared"), ("openblas", "~shared")]),
+ (
+ "ascent~~shared +adios2",
+ [("ascent", "~shared"), ("adios2", "~shared"), ("bzip2", "~shared")],
+ ),
+ # Propagates below a node that uses the other value explicitly
+ (
+ "ascent~~shared +adios2 ^adios2+shared",
+ [("ascent", "~shared"), ("adios2", "+shared"), ("bzip2", "~shared")],
+ ),
+ (
+ "ascent++shared +adios2 ^adios2~shared",
+ [("ascent", "+shared"), ("adios2", "~shared"), ("bzip2", "+shared")],
+ ),
+ ],
+ )
+ def test_concretize_propagate_disabled_variant(self, spec_str, expected_propagation):
+ """Tests various patterns of boolean variant propagation"""
+ spec = Spec(spec_str).concretized()
+ for key, expected_satisfies in expected_propagation:
+ spec[key].satisfies(expected_satisfies)
+
+ @pytest.mark.only_clingo(
+ "Optional compiler propagation isn't deprecated for original concretizer"
+ )
+ def test_concretize_propagated_variant_is_not_passed_to_dependent(self):
"""Test a package variant value was passed from its parent."""
- spec = Spec("hypre~~shared ^openblas")
+ spec = Spec("ascent~~shared +adios2 ^adios2+shared")
spec.concretize()
- assert spec.satisfies("^openblas~shared")
+ assert spec.satisfies("^adios2+shared")
+ assert spec.satisfies("^bzip2~shared")
- def test_concretize_propagated_variant_is_not_passed_to_dependent(self):
- """Test a package variant value was passed from its parent."""
- spec = Spec("hypre~~shared ^openblas+shared")
+ @pytest.mark.only_clingo(
+ "Optional compiler propagation isn't deprecated for original concretizer"
+ )
+ def test_concretize_propagate_specified_variant(self):
+ """Test that only the specified variant is propagated to the dependencies"""
+ spec = Spec("parent-foo-bar ~~foo")
spec.concretize()
- assert spec.satisfies("^openblas+shared")
+ assert spec.satisfies("~foo") and spec.satisfies("^dependency-foo-bar~foo")
+ assert spec.satisfies("+bar") and not spec.satisfies("^dependency-foo-bar+bar")
@pytest.mark.only_clingo("Original concretizer is allowed to forego variant propagation")
def test_concretize_propagate_multivalue_variant(self):