build_environment.py: deal with rpathing identical packages (#44219)

When multiple gcc-runtime packages exist in the same link sub-dag, only rpath
the latest.
This commit is contained in:
Harmen Stoppels 2024-05-17 12:29:56 +02:00 committed by Harmen Stoppels
parent 47af0159dc
commit 97369776f0
2 changed files with 42 additions and 7 deletions

View file

@ -43,7 +43,7 @@
from collections import defaultdict from collections import defaultdict
from enum import Flag, auto from enum import Flag, auto
from itertools import chain from itertools import chain
from typing import List, Set, Tuple from typing import Dict, List, Set, Tuple
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.string import plural from llnl.string import plural
@ -730,12 +730,28 @@ def _static_to_shared_library(arch, compiler, static_lib, shared_lib=None, **kwa
return compiler(*compiler_args, output=compiler_output) return compiler(*compiler_args, output=compiler_output)
def get_rpath_deps(pkg): def _get_rpath_deps_from_spec(
"""Return immediate or transitive RPATHs depending on the package.""" spec: spack.spec.Spec, transitive_rpaths: bool
if pkg.transitive_rpaths: ) -> List[spack.spec.Spec]:
return [d for d in pkg.spec.traverse(root=False, deptype=("link"))] if not transitive_rpaths:
else: return spec.dependencies(deptype=dt.LINK)
return pkg.spec.dependencies(deptype="link")
by_name: Dict[str, spack.spec.Spec] = {}
for dep in spec.traverse(root=False, deptype=dt.LINK):
lookup = by_name.get(dep.name)
if lookup is None:
by_name[dep.name] = dep
elif lookup.version < dep.version:
by_name[dep.name] = dep
return list(by_name.values())
def get_rpath_deps(pkg: spack.package_base.PackageBase) -> List[spack.spec.Spec]:
"""Return immediate or transitive dependencies (depending on the package) that need to be
rpath'ed. If a package occurs multiple times, the newest version is kept."""
return _get_rpath_deps_from_spec(pkg.spec, pkg.transitive_rpaths)
def get_rpaths(pkg): def get_rpaths(pkg):

View file

@ -14,6 +14,7 @@
import spack.build_environment import spack.build_environment
import spack.config import spack.config
import spack.deptypes as dt
import spack.package_base import spack.package_base
import spack.spec import spack.spec
import spack.util.spack_yaml as syaml import spack.util.spack_yaml as syaml
@ -716,3 +717,21 @@ def test_build_system_globals_only_set_on_root_during_build(default_mock_concret
for depth, spec in root.traverse(depth=True, root=True): for depth, spec in root.traverse(depth=True, root=True):
for variable in build_variables: for variable in build_variables:
assert hasattr(spec.package.module, variable) == should_be_set(depth) assert hasattr(spec.package.module, variable) == should_be_set(depth)
def test_rpath_with_duplicate_link_deps():
"""If we have two instances of one package in the same link sub-dag, only the newest version is
rpath'ed. This is for runtime support without splicing."""
runtime_1 = spack.spec.Spec("runtime@=1.0")
runtime_2 = spack.spec.Spec("runtime@=2.0")
child = spack.spec.Spec("child@=1.0")
root = spack.spec.Spec("root@=1.0")
root.add_dependency_edge(child, depflag=dt.LINK, virtuals=())
root.add_dependency_edge(runtime_2, depflag=dt.LINK, virtuals=())
child.add_dependency_edge(runtime_1, depflag=dt.LINK, virtuals=())
rpath_deps = spack.build_environment._get_rpath_deps_from_spec(root, transitive_rpaths=True)
assert child in rpath_deps
assert runtime_2 in rpath_deps
assert runtime_1 not in rpath_deps