diff options
-rw-r--r-- | lib/spack/spack/solver/asp.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/solver/libc_compatibility.lp | 12 | ||||
-rw-r--r-- | lib/spack/spack/test/concretize.py | 25 |
3 files changed, 35 insertions, 4 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 094ebaf170..49b5c626ce 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -2440,7 +2440,7 @@ class SpackSolverSetup: if using_libc_compatibility(): for libc in self.libcs: - self.gen.fact(fn.allowed_libc(libc.name, libc.version)) + self.gen.fact(fn.host_libc(libc.name, libc.version)) if not allow_deprecated: self.gen.fact(fn.deprecated_versions_not_allowed()) diff --git a/lib/spack/spack/solver/libc_compatibility.lp b/lib/spack/spack/solver/libc_compatibility.lp index 3e2c00e372..6c32493656 100644 --- a/lib/spack/spack/solver/libc_compatibility.lp +++ b/lib/spack/spack/solver/libc_compatibility.lp @@ -24,12 +24,20 @@ has_built_packages() :- build(X), not external(X). % A libc is needed in the DAG :- has_built_packages(), not provider(_, node(0, "libc")). -% The libc must be chosen among available ones +% Non-libc reused specs must be host libc compatible. In case we build packages, we get a +% host compatible libc provider from other rules. If nothing is built, there is no libc provider, +% since it's pruned from reusable specs, meaning we have to explicitly impose reused specs are host +% compatible. +:- attr("hash", node(R, ReusedPackage), Hash), + not provider(node(R, ReusedPackage), node(0, "libc")), + not attr("compatible_libc", node(R, ReusedPackage), _, _). + +% The libc provider must be one that a compiler can target :- has_built_packages(), provider(node(X, LibcPackage), node(0, "libc")), attr("node", node(X, LibcPackage)), attr("version", node(X, LibcPackage), LibcVersion), - not allowed_libc(LibcPackage, LibcVersion). + not host_libc(LibcPackage, LibcVersion). % A built node must depend on libc :- build(PackageNode), diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 0b4ce5b42a..b1cd35bff9 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -28,7 +28,7 @@ import spack.util.libc import spack.variant as vt from spack.concretize import find_spec from spack.spec import CompilerSpec, Spec -from spack.version import Version, ver +from spack.version import Version, VersionList, ver def check_spec(abstract, concrete): @@ -2570,6 +2570,29 @@ class TestConcretize: sombrero = result.specs[0] assert sombrero["externaltool"].dag_hash() == external_spec.dag_hash() + @pytest.mark.only_clingo("Original concretizer cannot reuse") + def test_cannot_reuse_host_incompatible_libc(self): + """Test whether reuse concretization correctly fails to reuse a spec with a host + incompatible libc.""" + if not spack.solver.asp.using_libc_compatibility(): + pytest.skip("This test requires libc nodes") + + # We install b@1 ^glibc@2.30, and b@0 ^glibc@2.28. The former is not host compatible, the + # latter is. + fst = Spec("b@1").concretized() + fst._mark_concrete(False) + fst.dependencies("glibc")[0].versions = VersionList(["=2.30"]) + fst._mark_concrete(True) + snd = Spec("b@0").concretized() + + # The spec b@1 ^glibc@2.30 is "more optimal" than b@0 ^glibc@2.28, but due to glibc + # incompatibility, it should not be reused. + solver = spack.solver.asp.Solver() + setup = spack.solver.asp.SpackSolverSetup() + result, _, _ = solver.driver.solve(setup, [Spec("b")], reuse=[fst, snd]) + assert len(result.specs) == 1 + assert result.specs[0] == snd + @pytest.fixture() def duplicates_test_repository(): |