diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/solver/asp.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/solver/concretize.lp | 29 | ||||
-rw-r--r-- | lib/spack/spack/test/concretize.py | 52 |
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): |