bugfix: pure cxx and fortran deps should display with a compiler. (#49752)

I noticed that `abseil-cpp` was showing in `spack find` with "no compiler", and the only
difference between it and other nodes was that it *only* depends on `cxx` -- others
depend on `c` as well.

It turns out that the `select()` method on `EdgeMap` only takes `Sequence[str]` and doesn't
check whether they're actually just one `str`.  So asking for, e.g., `cxx` is like asking for
`c` or `x` or `x`, as the `str` is treated like a sequence. This causes Spack to miss `cxx`
and `fortran` language virtuals in `DeprecatedCompilerSpec`.

Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
This commit is contained in:
Todd Gamblin 2025-03-28 02:18:18 -07:00 committed by GitHub
parent 37f2683d17
commit 3444d40ae2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 4 deletions

View File

@ -1022,7 +1022,7 @@ def select(
parent: Optional[str] = None,
child: Optional[str] = None,
depflag: dt.DepFlag = dt.ALL,
virtuals: Optional[Sequence[str]] = None,
virtuals: Optional[Union[str, Sequence[str]]] = None,
) -> List[DependencySpec]:
"""Selects a list of edges and returns them.
@ -1062,7 +1062,10 @@ def select(
# Filter by virtuals
if virtuals is not None:
selected = (dep for dep in selected if any(v in dep.virtuals for v in virtuals))
if isinstance(virtuals, str):
selected = (dep for dep in selected if virtuals in dep.virtuals)
else:
selected = (dep for dep in selected if any(v in dep.virtuals for v in virtuals))
return list(selected)
@ -1602,7 +1605,11 @@ def edges_from_dependents(
]
def edges_to_dependencies(
self, name=None, depflag: dt.DepFlag = dt.ALL, *, virtuals: Optional[Sequence[str]] = None
self,
name=None,
depflag: dt.DepFlag = dt.ALL,
*,
virtuals: Optional[Union[str, Sequence[str]]] = None,
) -> List[DependencySpec]:
"""Returns a list of edges connecting this node in the DAG to children.
@ -1644,7 +1651,7 @@ def dependencies(
name=None,
deptype: Union[dt.DepTypes, dt.DepFlag] = dt.ALL,
*,
virtuals: Optional[Sequence[str]] = None,
virtuals: Optional[Union[str, Sequence[str]]] = None,
) -> List["Spec"]:
"""Returns a list of direct dependencies (nodes in the DAG)

View File

@ -1960,6 +1960,23 @@ def test_edge_equality_does_not_depend_on_virtual_order():
assert tuple(sorted(edge2.virtuals)) == edge1.virtuals
def test_virtual_queries_work_for_strings_and_lists():
"""Ensure that ``dependencies()`` works with both virtuals=str and virtuals=[str, ...]."""
parent, child = Spec("parent"), Spec("child")
parent._add_dependency(
child, depflag=dt.BUILD, virtuals=("cxx", "fortran") # multi-char dep names
)
assert not parent.dependencies(virtuals="c") # not in virtuals but shares a char with cxx
for lang in ["cxx", "fortran"]:
assert parent.dependencies(virtuals=lang) # string arg
assert parent.edges_to_dependencies(virtuals=lang) # string arg
assert parent.dependencies(virtuals=[lang]) # list arg
assert parent.edges_to_dependencies(virtuals=[lang]) # string arg
def test_old_format_strings_trigger_error(default_mock_concretization):
s = spack.concretize.concretize_one("pkg-a")
with pytest.raises(SpecFormatStringError):