diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index b5a9ebf77a..2207fa9f9a 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -492,7 +492,9 @@ error(100, "Package '{0}' needs to provide both '{1}' and '{2}' together, but pr pkg_fact(Package, provided_together(ID, SetID, Virtual2)), Virtual1 != Virtual2, attr("virtual_on_incoming_edges", node(X, Package), Virtual1), - not attr("virtual_on_incoming_edges", node(X, Package), Virtual2). + not attr("virtual_on_incoming_edges", node(X, Package), Virtual2), + attr("virtual_node", node(_, Virtual1)), + attr("virtual_node", node(_, Virtual2)). % if a package depends on a virtual, it's not external and we have a % provider for that virtual then it depends on the provider diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 1dd530ac70..915f6ca39b 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -2360,3 +2360,16 @@ def test_condition_triggered_by_edge_property( for not_expected in expected_not_satisfies: assert not s.satisfies(not_expected), str(not_expected) + + def test_virtuals_provided_together_but_only_one_required_in_dag(self): + """Tests that we can use a provider that provides more than one virtual together, + and is providing only one, iff the others are not needed in the DAG. + + o blas-only-client + | [virtual=blas] + o openblas (provides blas and lapack together) + + """ + s = Spec("blas-only-client ^openblas").concretized() + assert s.satisfies("^[virtuals=blas] openblas") + assert not s.satisfies("^[virtuals=blas,lapack] openblas") diff --git a/var/spack/repos/edges.test/packages/blas-only-client/package.py b/var/spack/repos/edges.test/packages/blas-only-client/package.py new file mode 100644 index 0000000000..9e9652a752 --- /dev/null +++ b/var/spack/repos/edges.test/packages/blas-only-client/package.py @@ -0,0 +1,19 @@ +# Copyright 2013-2023 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 BlasOnlyClient(Package): + """This package depends on the 'blas' virtual only, but should be able to use also provider + that provide e.g. 'blas' together with 'lapack'. + """ + + homepage = "http://www.openblas.net" + url = "http://github.com/xianyi/OpenBLAS/archive/v0.2.15.tar.gz" + + version("0.2.16", md5="b1190f3d3471685f17cfd1ec1d252ac9") + + depends_on("blas") diff --git a/var/spack/repos/edges.test/packages/openblas/package.py b/var/spack/repos/edges.test/packages/openblas/package.py new file mode 100644 index 0000000000..d162e069b0 --- /dev/null +++ b/var/spack/repos/edges.test/packages/openblas/package.py @@ -0,0 +1,22 @@ +# Copyright 2013-2023 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 Openblas(Package): + """This package provides two virtuals together, so if one is chosen the other + must be used too if needed. + """ + + homepage = "http://www.openblas.net" + url = "http://github.com/xianyi/OpenBLAS/archive/v0.2.15.tar.gz" + + version("0.2.16", md5="b1190f3d3471685f17cfd1ec1d252ac9") + version("0.2.15", md5="b1190f3d3471685f17cfd1ec1d252ac9") + version("0.2.14", md5="b1190f3d3471685f17cfd1ec1d252ac9") + version("0.2.13", md5="b1190f3d3471685f17cfd1ec1d252ac9") + + provides("blas", "lapack")