Fix a bug when a required provider is requested for multiple virtuals (#42088)

This commit is contained in:
Massimiliano Culpo 2024-01-16 11:50:33 +01:00
parent 9af5eca9ec
commit b23a829c4c
4 changed files with 60 additions and 3 deletions

View file

@ -1676,9 +1676,10 @@ def provider_requirements(self):
rules = self._rules_from_requirements(
virtual_str, requirements, kind=RequirementKind.VIRTUAL
)
self.emit_facts_from_requirement_rules(rules)
self.trigger_rules()
self.effect_rules()
if rules:
self.emit_facts_from_requirement_rules(rules)
self.trigger_rules()
self.effect_rules()
def emit_facts_from_requirement_rules(self, rules: List[RequirementRule]):
"""Generate facts to enforce requirements.

View file

@ -698,6 +698,18 @@ requirement_group_satisfied(node(ID, Package), X) :-
activate_requirement(node(ID, Package), X),
requirement_group(Package, X).
% When we have a required provider, we need to ensure that the provider/2 facts respect
% the requirement. This is particularly important for packages that could provide multiple
% virtuals independently
required_provider(Provider, Virtual)
:- requirement_group_member(ConditionID, Virtual, RequirementID),
condition_holds(ConditionID, _),
virtual(Virtual),
pkg_fact(Virtual, condition_effect(ConditionID, EffectID)),
imposed_constraint(EffectID, "node", Provider).
:- provider(node(Y, Package), node(X, Virtual)), required_provider(Provider, Virtual), Package != Provider.
% TODO: the following two choice rules allow the solver to add compiler
% flags if their only source is from a requirement. This is overly-specific
% and should use a more-generic approach like in https://github.com/spack/spack/pull/37180

View file

@ -896,3 +896,26 @@ def test_requires_directive(concretize_scope, mock_packages):
# This package can only be compiled with clang
with pytest.raises(spack.error.SpackError, match="can only be compiled with Clang"):
Spec("requires_clang").concretized()
@pytest.mark.regression("42084")
def test_requiring_package_on_multiple_virtuals(concretize_scope, mock_packages):
update_packages_config(
"""
packages:
all:
providers:
scalapack: [netlib-scalapack]
blas:
require: intel-parallel-studio
lapack:
require: intel-parallel-studio
scalapack:
require: intel-parallel-studio
"""
)
s = Spec("dla-future").concretized()
assert s["blas"].name == "intel-parallel-studio"
assert s["lapack"].name == "intel-parallel-studio"
assert s["scalapack"].name == "intel-parallel-studio"

View file

@ -0,0 +1,21 @@
# Copyright 2013-2024 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)
from spack.package import *
class DlaFuture(Package):
"""A package that depends on 3 different virtuals, that might or might not be provided
by the same node.
"""
homepage = "http://www.example.com"
url = "http://www.example.com/dla-1.0.tar.gz"
version("1.0", md5="0123456789abcdef0123456789abcdef")
depends_on("blas")
depends_on("lapack")
depends_on("scalapack")