summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2020-11-27 20:53:39 +0100
committerTamara Dahlgren <dahlgren1@llnl.gov>2021-02-17 17:07:17 -0800
commitd7ffdd76f6703bc0f85b8c5239f11ac1f389e4e9 (patch)
tree42549af7696bd6814698a60268e6abdb57752545
parentb326d59e10046f75b65c8fcbeb691faa5ea7a71a (diff)
downloadspack-d7ffdd76f6703bc0f85b8c5239f11ac1f389e4e9.tar.gz
spack-d7ffdd76f6703bc0f85b8c5239f11ac1f389e4e9.tar.bz2
spack-d7ffdd76f6703bc0f85b8c5239f11ac1f389e4e9.tar.xz
spack-d7ffdd76f6703bc0f85b8c5239f11ac1f389e4e9.zip
concretizer: treat target ranges in directives correctly (#19988)
fixes #19981 This commit adds support for target ranges in directives, for instance: conflicts('+foo', when='target=x86_64:,aarch64:') If any target in a spec body is not a known target the following clause will be emitted: node_target_satisfies(Package, TargetConstraint) when traversing the spec and a definition of the clause will then be printed at the end similarly to what is done for package and compiler versions.
-rw-r--r--lib/spack/spack/solver/asp.py55
-rw-r--r--lib/spack/spack/test/concretize.py5
-rw-r--r--var/spack/repos/builtin.mock/packages/impossible-concretization/package.py15
3 files changed, 74 insertions, 1 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index 4ea54663be..9c78546455 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -696,6 +696,7 @@ class SpackSolverSetup(object):
self.possible_virtuals = None
self.possible_compilers = []
self.version_constraints = set()
+ self.target_constraints = set()
self.providers_by_vspec_name = collections.defaultdict(list)
self.virtual_constraints = set()
self.compiler_version_constraints = set()
@@ -765,6 +766,16 @@ class SpackSolverSetup(object):
self.version_constraints.add((spec.name, spec.versions))
return [fn.version_satisfies(spec.name, spec.versions)]
+ def target_ranges(self, spec, single_target_fn):
+ target = spec.architecture.target
+
+ # Check if the target is a concrete target
+ if str(target) in archspec.cpu.TARGETS:
+ return [single_target_fn(spec.name, target)]
+
+ self.target_constraints.add((spec.name, target))
+ return [fn.node_target_satisfies(spec.name, target)]
+
def conflict_rules(self, pkg):
for trigger, constraints in pkg.conflicts.items():
for constraint, _ in constraints:
@@ -1167,7 +1178,7 @@ class SpackSolverSetup(object):
if arch.os:
clauses.append(f.node_os(spec.name, arch.os))
if arch.target:
- clauses.append(f.node_target(spec.name, arch.target))
+ clauses.extend(self.target_ranges(spec, f.node_target))
# variants
for vname, variant in sorted(spec.variants.items()):
@@ -1438,6 +1449,45 @@ class SpackSolverSetup(object):
)
self.gen.newline()
+ def define_target_constraints(self):
+
+ def _all_targets_satisfiying(single_constraint):
+ allowed_targets = []
+ t_min, _, t_max = single_constraint.partition(':')
+ for test_target in archspec.cpu.TARGETS.values():
+ # Check lower bound
+ if t_min and not t_min <= test_target:
+ continue
+
+ # Check upper bound
+ if t_max and not t_max >= test_target:
+ continue
+
+ allowed_targets.append(test_target)
+ return allowed_targets
+
+ cache = {}
+ for spec_name, target_constraint in sorted(self.target_constraints):
+
+ # Construct the list of allowed targets for this constraint
+ allowed_targets = []
+ for single_constraint in str(target_constraint).split(','):
+ if single_constraint not in cache:
+ cache[single_constraint] = _all_targets_satisfiying(
+ single_constraint
+ )
+ allowed_targets.extend(cache[single_constraint])
+
+ allowed_targets = [
+ fn.node_target(spec_name, t) for t in allowed_targets
+ ]
+
+ self.gen.one_of_iff(
+ fn.node_target_satisfies(spec_name, target_constraint),
+ allowed_targets,
+ )
+ self.gen.newline()
+
def setup(self, driver, specs, tests=False):
"""Generate an ASP program with relevant constraints for specs.
@@ -1561,6 +1611,9 @@ class SpackSolverSetup(object):
self.gen.h1("Compiler Version Constraints")
self.define_compiler_version_constraints()
+ self.gen.h1("Target Constraints")
+ self.define_target_constraints()
+
def virtual_spec_clauses(self, dep):
assert dep.virtual
self.virtual_constraints.add(str(dep))
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 11c2764822..39799fc1bc 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -938,3 +938,8 @@ class TestConcretize(object):
assert 'openblas@0.2.13' in s
assert s['openblas'].satisfies('%gcc@4.4.0')
+
+ @pytest.mark.regression('19981')
+ def test_target_ranges_in_conflicts(self):
+ with pytest.raises(spack.error.SpackError):
+ Spec('impossible-concretization').concretized()
diff --git a/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py b/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py
new file mode 100644
index 0000000000..bb8ad02b49
--- /dev/null
+++ b/var/spack/repos/builtin.mock/packages/impossible-concretization/package.py
@@ -0,0 +1,15 @@
+# Copyright 2013-2020 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)
+class ImpossibleConcretization(Package):
+ """Package that should be impossible to concretize due to a conflict
+ with target ranges. See Issue 19981.
+ """
+
+ homepage = "http://www.example.com"
+ url = "http://www.example.com/example-1.0.tar.gz"
+
+ version(1.0, 'foobarbaz')
+
+ conflicts('target=x86_64:')