summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2023-08-09 16:35:01 +0200
committerTodd Gamblin <tgamblin@llnl.gov>2023-08-15 15:54:37 -0700
commit1db73eb1f222048fbdaf43835000ac17c12694bf (patch)
treea7f221f10b4acafb34f0be7b9896e5a1963f7524
parent2da34de519c847d86f40ac16734ed4ef9e30c0c8 (diff)
downloadspack-1db73eb1f222048fbdaf43835000ac17c12694bf.tar.gz
spack-1db73eb1f222048fbdaf43835000ac17c12694bf.tar.bz2
spack-1db73eb1f222048fbdaf43835000ac17c12694bf.tar.xz
spack-1db73eb1f222048fbdaf43835000ac17c12694bf.zip
Add vendors directive
For the time being this directive prevents the vendored package to be in the same DAG as the one vendoring it.
-rw-r--r--lib/spack/spack/directives.py24
-rw-r--r--lib/spack/spack/solver/asp.py12
-rw-r--r--lib/spack/spack/solver/concretize.lp10
-rw-r--r--lib/spack/spack/test/env.py35
-rw-r--r--var/spack/repos/builtin.mock/packages/vendorsb/package.py18
-rw-r--r--var/spack/repos/builtin/packages/memkind/package.py2
-rw-r--r--var/spack/repos/builtin/packages/palace/package.py6
-rw-r--r--var/spack/repos/builtin/packages/scotch/package.py4
-rw-r--r--var/spack/repos/builtin/packages/votca/package.py7
9 files changed, 109 insertions, 9 deletions
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index 2b7aefca55..03f2f38189 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -69,6 +69,7 @@ __all__ = [
"resource",
"build_system",
"requires",
+ "vendors",
]
#: These are variant names used by Spack internally; packages can't use them
@@ -916,6 +917,29 @@ def requires(*requirement_specs, policy="one_of", when=None, msg=None):
return _execute_requires
+@directive("vendors")
+def vendors(spec, when=None):
+ """Declares that a package has an internal copy of another package.
+
+ Currently, the effect is to forbid having the two packages in the same
+ "unification set".
+
+ Args:
+ spec: spec being vendored
+ when: optional constraint that triggers vendoring
+ """
+
+ def _execute_vendors(pkg):
+ when_spec = make_when_spec(when)
+ if not when_spec:
+ return
+
+ when_spec_list = pkg.vendors.setdefault(spec, [])
+ when_spec_list.append(when_spec)
+
+ return _execute_vendors
+
+
class DirectiveError(spack.error.SpackError):
"""This is raised when something is wrong with a package directive."""
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index e9141d071d..71aa57e1bf 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -1040,6 +1040,15 @@ class SpackSolverSetup:
)
self.gen.newline()
+ def vendor_rules(self, pkg):
+ """Facts about vendored packages."""
+ for vendored_spec_str, constraints in pkg.vendors.items():
+ vendored_spec = spack.spec.Spec(vendored_spec_str)
+ for constraint in constraints:
+ constraint_id = self.condition(constraint, name=pkg.name)
+ self.gen.fact(fn.pkg_fact(pkg.name, fn.vendors(constraint_id, vendored_spec.name)))
+ self.gen.newline()
+
def compiler_facts(self):
"""Facts about available compilers."""
@@ -1189,6 +1198,9 @@ class SpackSolverSetup:
# conflicts
self.conflict_rules(pkg)
+ # vendoring
+ self.vendor_rules(pkg)
+
# default compilers for this package
self.package_compiler_defaults(pkg)
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index eb691225b8..e41539a366 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -450,6 +450,16 @@ error(1, Msg)
not attr("hash", node(ID, Package), _). % ignore conflicts for installed packages
%-----------------------------------------------------------------------------
+% Vendoring
+%-----------------------------------------------------------------------------
+error(1, "{0} vendors an internal copy of {1}, so it cannot be in the same unification set as {1}", Package, VendoredPackage)
+ :- pkg_fact(Package, vendors(ConditionID, VendoredPackage)),
+ attr("node", node(ID, Package)),
+ condition_holds(ConditionID, node(ID, Package)),
+ unification_set(X, node(ID, Package)),
+ unification_set(X, node(_, VendoredPackage)).
+
+%-----------------------------------------------------------------------------
% Virtual dependencies
%-----------------------------------------------------------------------------
diff --git a/lib/spack/spack/test/env.py b/lib/spack/spack/test/env.py
index bcb459f100..23c429de16 100644
--- a/lib/spack/spack/test/env.py
+++ b/lib/spack/spack/test/env.py
@@ -551,3 +551,38 @@ spack:
with spack.config.override("concretizer:unify", unify_in_config):
with ev.Environment(manifest.parent) as e:
assert e.unify == unify_in_config
+
+
+@pytest.mark.parametrize(
+ "spec_str,expected_raise,expected_spec",
+ [
+ # vendorsb vendors "b" only when @=1.1
+ ("vendorsb", False, "vendorsb@=1.0"),
+ ("vendorsb@=1.1", True, None),
+ ],
+)
+def test_vendors_directive(
+ spec_str, expected_raise, expected_spec, tmp_path, mock_packages, config
+):
+ """Tests that we cannot concretize two specs together, if one vendors the other."""
+ if spack.config.get("config:concretizer") == "original":
+ pytest.xfail("Known failure of the original concretizer")
+
+ manifest = tmp_path / "spack.yaml"
+ manifest.write_text(
+ f"""\
+spack:
+ specs:
+ - {spec_str}
+ - b
+ concretizer:
+ unify: true
+"""
+ )
+ with ev.Environment(manifest.parent) as e:
+ if expected_raise:
+ with pytest.raises(spack.solver.asp.UnsatisfiableSpecError):
+ e.concretize()
+ else:
+ e.concretize()
+ assert any(s.satisfies(expected_spec) for s in e.concrete_roots())
diff --git a/var/spack/repos/builtin.mock/packages/vendorsb/package.py b/var/spack/repos/builtin.mock/packages/vendorsb/package.py
new file mode 100644
index 0000000000..73fe9ad1cf
--- /dev/null
+++ b/var/spack/repos/builtin.mock/packages/vendorsb/package.py
@@ -0,0 +1,18 @@
+# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+from spack.package import *
+
+
+class Vendorsb(Package):
+ """A package that vendors another"""
+
+ homepage = "http://www.example.com"
+ url = "http://www.example.com/b-1.0.tar.gz"
+
+ version("1.1", md5="0123456789abcdef0123456789abcdef")
+ version("1.0", md5="0123456789abcdef0123456789abcdef")
+
+ vendors("b", when="@=1.1")
diff --git a/var/spack/repos/builtin/packages/memkind/package.py b/var/spack/repos/builtin/packages/memkind/package.py
index f51740f48e..12a0e18fd6 100644
--- a/var/spack/repos/builtin/packages/memkind/package.py
+++ b/var/spack/repos/builtin/packages/memkind/package.py
@@ -40,7 +40,7 @@ class Memkind(AutotoolsPackage):
# memkind includes a copy of jemalloc; see
# <https://github.com/memkind/memkind#jemalloc>.
- conflicts("jemalloc")
+ vendors("jemalloc")
# https://github.com/spack/spack/issues/37292
parallel = False
diff --git a/var/spack/repos/builtin/packages/palace/package.py b/var/spack/repos/builtin/packages/palace/package.py
index fd06706db1..6eb8d87936 100644
--- a/var/spack/repos/builtin/packages/palace/package.py
+++ b/var/spack/repos/builtin/packages/palace/package.py
@@ -94,9 +94,9 @@ class Palace(CMakePackage):
depends_on("arpack-ng+shared", when="+shared")
depends_on("arpack-ng~shared", when="~shared")
- # Conflicts: Palace always builds its own internal MFEM, GSLIB
- conflicts("^mfem", msg="Palace builds its own internal MFEM")
- conflicts("^gslib", msg="Palace builds its own internal GSLIB")
+ # Palace always builds its own internal MFEM, GSLIB
+ vendors("mfem")
+ vendors("gslib")
# More dependency variant conflicts
conflicts("^hypre+int64", msg="Palace uses HYPRE's mixedint option for 64 bit integers")
diff --git a/var/spack/repos/builtin/packages/scotch/package.py b/var/spack/repos/builtin/packages/scotch/package.py
index 12e81d7b96..3a1e03cbbd 100644
--- a/var/spack/repos/builtin/packages/scotch/package.py
+++ b/var/spack/repos/builtin/packages/scotch/package.py
@@ -70,8 +70,8 @@ class Scotch(CMakePackage, MakefilePackage):
# Vendored dependency of METIS/ParMETIS conflicts with standard
# installations
- conflicts("^metis", when="+metis")
- conflicts("^parmetis", when="+metis")
+ vendors("metis", when="+metis")
+ vendors("parmetis", when="+metis")
parallel = False
diff --git a/var/spack/repos/builtin/packages/votca/package.py b/var/spack/repos/builtin/packages/votca/package.py
index aa5a5d0b3f..629c9eb0ad 100644
--- a/var/spack/repos/builtin/packages/votca/package.py
+++ b/var/spack/repos/builtin/packages/votca/package.py
@@ -28,9 +28,10 @@ class Votca(CMakePackage):
"new-gmx", default=False, description="Build against gromacs>2019 - no tabulated kernels"
)
variant("xtp", default=True, description="Build xtp parts of votca")
- conflicts("votca-tools")
- conflicts("votca-csg")
- conflicts("votca-xtp")
+
+ vendors("votca-tools")
+ vendors("votca-csg")
+ vendors("votca-xtp")
depends_on("cmake@3.13:", type="build")
depends_on("expat")