diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index 03f2f38189..acb2af1a62 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -33,7 +33,6 @@ class OpenMpi(Package): import functools import os.path import re -import warnings from typing import Any, Callable, List, Optional, Set, Tuple, Union import llnl.util.lang @@ -69,7 +68,6 @@ class OpenMpi(Package): "resource", "build_system", "requires", - "vendors", ] #: These are variant names used by Spack internally; packages can't use them @@ -520,20 +518,8 @@ def _execute_conflicts(pkg): if not when_spec: return - # TODO: (remove after v0.21) - conflict_key = conflict_spec - s = spack.spec.Spec(conflict_spec) - if s.name and s.name != pkg.name: - warning_msg = ( - f"the conflict in package '{pkg.name}' on '{conflict_spec}' should " - f"start with a '^' sigil. Not using it is deprecated as of v0.21 and" - f" will be disallowed in v0.22" - ) - warnings.warn(warning_msg) - conflict_key = "^" + conflict_spec - # Save in a list the conflicts and the associated custom messages - when_spec_list = pkg.conflicts.setdefault(conflict_key, []) + when_spec_list = pkg.conflicts.setdefault(conflict_spec, []) msg_with_name = f"{pkg.name}: {msg}" if msg is not None else msg when_spec_list.append((when_spec, msg_with_name)) @@ -917,29 +903,6 @@ def _execute_requires(pkg): 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 f29a22a2b1..3ca4824be1 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1030,7 +1030,10 @@ def conflict_rules(self, pkg): no_constraint_msg = "{0}: conflicts with '{1}'" for trigger, constraints in pkg.conflicts.items(): trigger_msg = "conflict trigger %s" % str(trigger) - trigger_id = self.condition(spack.spec.Spec(trigger), name=pkg.name, msg=trigger_msg) + trigger_spec = spack.spec.Spec(trigger) + trigger_id = self.condition( + trigger_spec, name=trigger_spec.name or pkg.name, msg=trigger_msg + ) for constraint, conflict_msg in constraints: if conflict_msg is None: @@ -1045,15 +1048,6 @@ def conflict_rules(self, pkg): ) 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.""" @@ -1203,9 +1197,6 @@ def pkg_rules(self, pkg, tests): # conflicts self.conflict_rules(pkg) - # vendoring - self.vendor_rules(pkg) - # default compilers for this package self.package_compiler_defaults(pkg) @@ -1224,19 +1215,20 @@ def pkg_rules(self, pkg, tests): self.package_requirement_rules(pkg) # trigger and effect tables - self.trigger_rules(pkg.name) + self.trigger_rules() self.effect_rules(pkg.name) - def trigger_rules(self, name): + def trigger_rules(self): self.gen.h2("Trigger conditions") - cache = self._trigger_cache[name] - for spec_str, (trigger_id, requirements) in cache.items(): - self.gen.fact(fn.pkg_fact(name, fn.trigger_id(trigger_id))) - self.gen.fact(fn.pkg_fact(name, fn.trigger_msg(spec_str))) - for predicate in requirements: - self.gen.fact(fn.condition_requirement(trigger_id, *predicate.args)) - self.gen.newline() - cache.clear() + for name in self._trigger_cache: + cache = self._trigger_cache[name] + for spec_str, (trigger_id, requirements) in cache.items(): + self.gen.fact(fn.pkg_fact(name, fn.trigger_id(trigger_id))) + self.gen.fact(fn.pkg_fact(name, fn.trigger_msg(spec_str))) + for predicate in requirements: + self.gen.fact(fn.condition_requirement(trigger_id, *predicate.args)) + self.gen.newline() + self._trigger_cache.clear() def effect_rules(self, name): self.gen.h2("Imposed requirements") @@ -1488,7 +1480,7 @@ def provider_requirements(self): virtual_str, requirements, kind=RequirementKind.VIRTUAL ) self.emit_facts_from_requirement_rules(rules) - self.trigger_rules(virtual_str) + self.trigger_rules() self.effect_rules(virtual_str) def emit_facts_from_requirement_rules(self, rules: List[RequirementRule]): @@ -1607,7 +1599,7 @@ def external_packages(self): self.possible_versions[spec.name].add(spec.version) self.gen.newline() - self.trigger_rules(pkg_name) + self.trigger_rules() def preferred_variants(self, pkg_name): """Facts on concretization preferences, as read from packages.yaml""" @@ -2434,7 +2426,7 @@ def setup(self, driver, specs, reuse=None): # Inject dev_path from environment for ds in dev_specs: self.condition(spack.spec.Spec(ds.name), ds, msg="%s is a develop spec" % ds.name) - self.trigger_rules(ds.name) + self.trigger_rules() self.effect_rules(ds.name) self.gen.h1("Spec Constraints") diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 1fd0966f04..bc24514115 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -441,21 +441,14 @@ error(10, "'{0}' is not a valid dependency for any package in the DAG", Package) error(1, Msg) :- attr("node", node(ID, Package)), pkg_fact(Package, conflict(TriggerID, ConstraintID, Msg)), - condition_holds(TriggerID, node(ID, Package)), - condition_holds(ConstraintID, node(ID, Package)), + % node(ID1, TriggerPackage) is node(ID2, Package) in most, but not all, cases + condition_holds(TriggerID, node(ID1, TriggerPackage)), + condition_holds(ConstraintID, node(ID2, Package)), + unification_set(X, node(ID2, Package)), + unification_set(X, node(ID1, TriggerPackage)), not external(node(ID, Package)), % ignore conflicts for externals 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 23c429de16..203fa72d70 100644 --- a/lib/spack/spack/test/env.py +++ b/lib/spack/spack/test/env.py @@ -561,10 +561,12 @@ def test_environment_config_scheme_used(tmp_path, unify_in_config): ("vendorsb@=1.1", True, None), ], ) -def test_vendors_directive( +def test_conflicts_with_packages_that_are_not_dependencies( spec_str, expected_raise, expected_spec, tmp_path, mock_packages, config ): - """Tests that we cannot concretize two specs together, if one vendors the other.""" + """Tests that we cannot concretize two specs together, if one conflicts with the other, + even though they don't have a dependency relation. + """ if spack.config.get("config:concretizer") == "original": pytest.xfail("Known failure of the original concretizer") diff --git a/var/spack/repos/builtin.mock/packages/vendorsb/package.py b/var/spack/repos/builtin.mock/packages/vendorsb/package.py index 73fe9ad1cf..fbf14236a1 100644 --- a/var/spack/repos/builtin.mock/packages/vendorsb/package.py +++ b/var/spack/repos/builtin.mock/packages/vendorsb/package.py @@ -7,7 +7,7 @@ class Vendorsb(Package): - """A package that vendors another""" + """A package that vendors another, and thus conflicts with it""" homepage = "http://www.example.com" url = "http://www.example.com/b-1.0.tar.gz" @@ -15,4 +15,5 @@ class Vendorsb(Package): version("1.1", md5="0123456789abcdef0123456789abcdef") version("1.0", md5="0123456789abcdef0123456789abcdef") - vendors("b", when="@=1.1") + # b is not a dependency + conflicts("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 12a0e18fd6..f51740f48e 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 # . - vendors("jemalloc") + conflicts("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 6eb8d87936..f7345f168f 100644 --- a/var/spack/repos/builtin/packages/palace/package.py +++ b/var/spack/repos/builtin/packages/palace/package.py @@ -95,8 +95,8 @@ class Palace(CMakePackage): depends_on("arpack-ng~shared", when="~shared") # Palace always builds its own internal MFEM, GSLIB - vendors("mfem") - vendors("gslib") + conflicts("mfem") + conflicts("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 3a1e03cbbd..b009aec43d 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 - vendors("metis", when="+metis") - vendors("parmetis", when="+metis") + conflicts("metis", when="+metis") + conflicts("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 629c9eb0ad..db9d260f86 100644 --- a/var/spack/repos/builtin/packages/votca/package.py +++ b/var/spack/repos/builtin/packages/votca/package.py @@ -29,9 +29,9 @@ class Votca(CMakePackage): ) variant("xtp", default=True, description="Build xtp parts of votca") - vendors("votca-tools") - vendors("votca-csg") - vendors("votca-xtp") + conflicts("votca-tools") + conflicts("votca-csg") + conflicts("votca-xtp") depends_on("cmake@3.13:", type="build") depends_on("expat")