Skip to content

Commit 9bb5cff

Browse files
alalazotgamblin
authored andcommitted
Change semantic for providers
If a possible provider is not used to satisfy a vdep, then it's not a provider of that vdep.
1 parent 135b44c commit 9bb5cff

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

lib/spack/spack/solver/concretize.lp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,16 @@ error(1, Msg)
455455

456456
% if a package depends on a virtual, it's not external and we have a
457457
% provider for that virtual then it depends on the provider
458-
1 { attr("depends_on", PackageNode, ProviderNode, Type) : provider(ProviderNode, node(VirtualID, Virtual)) } 1
458+
node_depends_on_virtual(PackageNode, Virtual, Type)
459459
:- dependency_holds(PackageNode, Virtual, Type),
460460
virtual(Virtual),
461461
not external(PackageNode).
462462

463+
node_depends_on_virtual(PackageNode, Virtual) :- node_depends_on_virtual(PackageNode, Virtual, Type).
464+
465+
1 { attr("depends_on", PackageNode, ProviderNode, Type) : provider(ProviderNode, node(VirtualID, Virtual)) } 1
466+
:- node_depends_on_virtual(PackageNode, Virtual, Type).
467+
463468
attr("virtual_on_edge", PackageNode, ProviderNode, Virtual)
464469
:- dependency_holds(PackageNode, Virtual, Type),
465470
attr("depends_on", PackageNode, ProviderNode, Type),
@@ -468,9 +473,7 @@ attr("virtual_on_edge", PackageNode, ProviderNode, Virtual)
468473

469474
% dependencies on virtuals also imply that the virtual is a virtual node
470475
1 { attr("virtual_node", node(0..X-1, Virtual)) : max_dupes(Virtual, X) }
471-
:- dependency_holds(PackageNode, Virtual, Type),
472-
virtual(Virtual),
473-
not external(PackageNode).
476+
:- node_depends_on_virtual(PackageNode, Virtual).
474477

475478
% If there's a virtual node, we must select one and only one provider.
476479
% The provider must be selected among the possible providers.
@@ -490,13 +493,24 @@ attr("virtual_node", VirtualNode) :- attr("virtual_root", VirtualNode).
490493
% then the provider is the root package.
491494
attr("root", PackageNode) :- attr("virtual_root", VirtualNode), provider(PackageNode, VirtualNode).
492495

493-
% If we asked for a root package and that root provides a virtual,
494-
% the root is a provider for that virtual. This rule is mostly relevant
495-
% for environments that are concretized together (e.g. where we
496-
% asks to install "mpich" and "hdf5+mpi" and we want "mpich" to
497-
% be the mpi provider)
498-
1 { provider(PackageNode, node(0..X-1, Virtual)) : max_dupes(Virtual, X) } 1 :- attr("node", PackageNode), virtual_condition_holds(PackageNode, Virtual).
499-
:- 2 { provider(PackageNode, VirtualNode) }, attr("virtual_node", VirtualNode).
496+
% The provider is selected among the nodes for which the virtual condition holds
497+
1 { provider(PackageNode, node(X, Virtual)) :
498+
attr("node", PackageNode), virtual_condition_holds(PackageNode, Virtual) } 1
499+
:- attr("virtual_node", node(X, Virtual)).
500+
501+
% If a spec is selected as a provider, it is for all the virtual it could provide
502+
:- provider(PackageNode, node(X, Virtual1)),
503+
virtual_condition_holds(PackageNode, Virtual2),
504+
Virtual2 != Virtual1,
505+
unification_set(SetID, PackageNode),
506+
unification_set(SetID, node(X, Virtual2)),
507+
not provider(PackageNode, node(X, Virtual2)).
508+
509+
% If a spec is a dependency, and could provide a needed virtual, it must be a provider
510+
:- node_depends_on_virtual(PackageNode, Virtual),
511+
depends_on(PackageNode, PossibleProviderNode),
512+
virtual_condition_holds(PossibleProviderNode, Virtual),
513+
not attr("virtual_on_edge", PackageNode, PossibleProviderNode, Virtual).
500514

501515
% The provider provides the virtual if some provider condition holds.
502516
virtual_condition_holds(node(ProviderID, Provider), Virtual) :- virtual_condition_holds(ID, node(ProviderID, Provider), Virtual).

lib/spack/spack/test/env.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,3 +588,35 @@ def test_conflicts_with_packages_that_are_not_dependencies(
588588
else:
589589
e.concretize()
590590
assert any(s.satisfies(expected_spec) for s in e.concrete_roots())
591+
592+
593+
def test_requires_on_virtual_and_potential_providers(tmp_path, mock_packages, config):
594+
"""Tests that in an environment we can add packages explicitly, even though they provide
595+
a virtual package, and we require the provider of the same virtual to be another package,
596+
if they are added explicitly by their name.
597+
"""
598+
if spack.config.get("config:concretizer") == "original":
599+
pytest.xfail("Known failure of the original concretizer")
600+
601+
manifest = tmp_path / "spack.yaml"
602+
manifest.write_text(
603+
"""\
604+
spack:
605+
specs:
606+
- mpich
607+
- mpich2
608+
- mpileaks
609+
packages:
610+
mpi:
611+
require: mpich2
612+
"""
613+
)
614+
with ev.Environment(manifest.parent) as e:
615+
e.concretize()
616+
assert e.matching_spec("mpich")
617+
assert e.matching_spec("mpich2")
618+
619+
mpileaks = e.matching_spec("mpileaks")
620+
assert mpileaks.satisfies("^mpich2")
621+
assert mpileaks["mpi"].satisfies("mpich2")
622+
assert not mpileaks.satisfies("^mpich")

share/spack/gitlab/cloud_pipelines/stacks/e4s-oneapi/spack.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ spack:
148148
- nco
149149
- netlib-scalapack
150150
- omega-h
151-
# - openmpi
151+
- openmpi
152152
- openpmd-api
153153
- papi
154154
- papyrus

0 commit comments

Comments
 (0)