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.
This commit is contained in:
parent
e6641065af
commit
8dd3797d32
3 changed files with 74 additions and 1 deletions
|
@ -696,6 +696,7 @@ def __init__(self):
|
|||
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 @@ def spec_versions(self, spec):
|
|||
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 Body(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()):
|
||||
|
@ -1437,6 +1448,45 @@ def define_compiler_version_constraints(self):
|
|||
)
|
||||
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.
|
||||
|
||||
|
@ -1560,6 +1610,9 @@ def setup(self, driver, specs, tests=False):
|
|||
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))
|
||||
|
|
|
@ -938,3 +938,8 @@ def test_compiler_match_is_preferred_to_newer_version(self):
|
|||
|
||||
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()
|
||||
|
|
|
@ -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:')
|
Loading…
Reference in a new issue