concretize.lp: enforce target compatibility through DAG (#29694)
Spack currently allows dependencies to be concretized for an architecture incompatible with the root. This commit adds rules to make this situation impossible by design.
This commit is contained in:
parent
b667be470e
commit
79ba0c50c1
@ -615,17 +615,43 @@ node_os(Package, OS) :- node_os_set(Package, OS), node(Package).
|
||||
% Each node has only one target chosen among the known targets
|
||||
1 { node_target(Package, Target) : target(Target) } 1 :- node(Package), error("Each node must have exactly one target").
|
||||
|
||||
% If a node must satisfy a target constraint the choice is reduced among the targets
|
||||
% that satisfy that constraint
|
||||
1 { node_target(Package, Target) : target_satisfies(Constraint, Target) } 1
|
||||
:- node_target_satisfies(Package, Constraint), error("Each node must have exactly one target").
|
||||
% If a node must satisfy a target constraint, enforce it
|
||||
:- node_target(Package, Target),
|
||||
node_target_satisfies(Package, Constraint),
|
||||
not target_satisfies(Constraint, Target),
|
||||
error("Node targets must satisfy node target constraints").
|
||||
|
||||
|
||||
% If a node has a target and the target satisfies a constraint, then the target
|
||||
% associated with the node satisfies the same constraint
|
||||
node_target_satisfies(Package, Constraint)
|
||||
:- node_target(Package, Target), target_satisfies(Constraint, Target).
|
||||
|
||||
% If a node has a target, all of its dependencies must be compatible with that target
|
||||
:- depends_on(Package, Dependency),
|
||||
node_target(Package, Target),
|
||||
not node_target_compatible(Dependency, Target),
|
||||
error("Dependency node targets must be compatible with dependent targets").
|
||||
|
||||
% Intermediate step for performance reasons
|
||||
% When the integrity constraint above was formulated including this logic
|
||||
% we suffered a substantial performance penalty
|
||||
node_target_compatible(Package, Target)
|
||||
:- node_target(Package, MyTarget),
|
||||
target_compatible(Target, MyTarget).
|
||||
|
||||
% target_compatible(T1, T2) means code for T2 can run on T1
|
||||
% This order is dependent -> dependency in the node DAG, which
|
||||
% is contravariant with the target DAG.
|
||||
target_compatible(Target, Target) :- target(Target).
|
||||
target_compatible(Child, Parent) :- target_parent(Child, Parent).
|
||||
target_compatible(Descendent, Ancestor)
|
||||
:- target_parent(Target, Ancestor),
|
||||
target_compatible(Descendent, Target),
|
||||
target(Target).
|
||||
|
||||
#defined target_satisfies/2.
|
||||
#defined target_parent/2.
|
||||
|
||||
% The target weight is either the default target weight
|
||||
% or a more specific per-package weight if set
|
||||
|
@ -768,7 +768,7 @@ def test_concretize_anonymous_dep(self, spec_str):
|
||||
])
|
||||
def test_compiler_conflicts_in_package_py(self, spec_str, expected_str):
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.skip('Original concretizer cannot work around conflicts')
|
||||
pytest.xfail('Original concretizer cannot work around conflicts')
|
||||
|
||||
s = Spec(spec_str).concretized()
|
||||
assert s.satisfies(expected_str)
|
||||
@ -1103,6 +1103,12 @@ def test_target_ranges_in_conflicts(self):
|
||||
with pytest.raises(spack.error.SpackError):
|
||||
Spec('impossible-concretization').concretized()
|
||||
|
||||
def test_target_compatibility(self):
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.xfail('Known failure of the original concretizer')
|
||||
with pytest.raises(spack.error.SpackError):
|
||||
Spec('libdwarf target=x86_64 ^libelf target=x86_64_v2').concretized()
|
||||
|
||||
@pytest.mark.regression('20040')
|
||||
def test_variant_not_default(self):
|
||||
s = Spec('ecp-viz-sdk').concretized()
|
||||
@ -1369,7 +1375,7 @@ def test_concrete_specs_are_not_modified_on_reuse(
|
||||
self, mutable_database, spec_str, expect_installed, config
|
||||
):
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.skip('Original concretizer cannot reuse specs')
|
||||
pytest.xfail('Original concretizer cannot reuse specs')
|
||||
|
||||
# Test the internal consistency of solve + DAG reconstruction
|
||||
# when reused specs are added to the mix. This prevents things
|
||||
@ -1383,7 +1389,7 @@ def test_concrete_specs_are_not_modified_on_reuse(
|
||||
@pytest.mark.regression('26721,19736')
|
||||
def test_sticky_variant_in_package(self):
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.skip('Original concretizer cannot use sticky variants')
|
||||
pytest.xfail('Original concretizer cannot use sticky variants')
|
||||
|
||||
# Here we test that a sticky variant cannot be changed from its default value
|
||||
# by the ASP solver if not set explicitly. The package used in the test needs
|
||||
@ -1400,7 +1406,7 @@ def test_sticky_variant_in_package(self):
|
||||
|
||||
def test_do_not_invent_new_concrete_versions_unless_necessary(self):
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.skip(
|
||||
pytest.xfail(
|
||||
"Original concretizer doesn't resolve concrete versions to known ones"
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user