summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/solver/asp.py2
-rw-r--r--lib/spack/spack/solver/libc_compatibility.lp12
-rw-r--r--lib/spack/spack/test/concretize.py25
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():