summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-05-17 12:29:56 +0200
committerGitHub <noreply@github.com>2024-05-17 12:29:56 +0200
commit9dbb18219ff0a1696a31bee3f817ff5578af2bf5 (patch)
tree54d1bf1e1690a9bef0ab3100a9c3152ec3387634
parent451a977de0112ddb1deaacaf3dbfdea0c0923fb9 (diff)
downloadspack-9dbb18219ff0a1696a31bee3f817ff5578af2bf5.tar.gz
spack-9dbb18219ff0a1696a31bee3f817ff5578af2bf5.tar.bz2
spack-9dbb18219ff0a1696a31bee3f817ff5578af2bf5.tar.xz
spack-9dbb18219ff0a1696a31bee3f817ff5578af2bf5.zip
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.
-rw-r--r--lib/spack/spack/build_environment.py30
-rw-r--r--lib/spack/spack/test/build_environment.py19
2 files changed, 42 insertions, 7 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 00c1c5ab4f..a74816ef62 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -43,7 +43,7 @@ import types
from collections import defaultdict
from enum import Flag, auto
from itertools import chain
-from typing import List, Set, Tuple
+from typing import Dict, List, Set, Tuple
import llnl.util.tty as tty
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)
-def get_rpath_deps(pkg):
- """Return immediate or transitive RPATHs depending on the package."""
- if pkg.transitive_rpaths:
- return [d for d in pkg.spec.traverse(root=False, deptype=("link"))]
- else:
- return pkg.spec.dependencies(deptype="link")
+def _get_rpath_deps_from_spec(
+ spec: spack.spec.Spec, transitive_rpaths: bool
+) -> List[spack.spec.Spec]:
+ if not transitive_rpaths:
+ return spec.dependencies(deptype=dt.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):
diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py
index cb47ee5977..e053e1bebc 100644
--- a/lib/spack/spack/test/build_environment.py
+++ b/lib/spack/spack/test/build_environment.py
@@ -14,6 +14,7 @@ from llnl.util.filesystem import HeaderList, LibraryList
import spack.build_environment
import spack.config
+import spack.deptypes as dt
import spack.package_base
import spack.spec
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 variable in build_variables:
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