summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/build_environment.py95
1 files changed, 44 insertions, 51 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index cf771a10ac..73f5d438a2 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -523,63 +523,52 @@ def set_wrapper_variables(pkg, env):
env.set("CCACHE_DISABLE", "1")
# Gather information about various types of dependencies
- link_deps = set(pkg.spec.traverse(root=False, deptype=("link")))
- rpath_deps = get_rpath_deps(pkg)
+ rpath_hashes = set(s.dag_hash() for s in get_rpath_deps(pkg))
+ link_deps = pkg.spec.traverse(root=False, order="topo", deptype=dt.LINK)
+ external_link_deps, nonexternal_link_deps = stable_partition(link_deps, lambda d: d.external)
link_dirs = []
include_dirs = []
rpath_dirs = []
- def _prepend_all(list_to_modify, items_to_add):
- # Update the original list (creating a new list would be faster but
- # may not be convenient)
- for item in reversed(list(items_to_add)):
- list_to_modify.insert(0, item)
-
- def update_compiler_args_for_dep(dep):
- if dep in link_deps and (not is_system_path(dep.prefix)):
- query = pkg.spec[dep.name]
- dep_link_dirs = []
- try:
- # In some circumstances (particularly for externals) finding
- # libraries packages can be time consuming, so indicate that
- # we are performing this operation (and also report when it
- # finishes).
- tty.debug(f"Collecting libraries for {dep.name}")
- dep_link_dirs.extend(query.libs.directories)
- tty.debug(f"Libraries for {dep.name} have been collected.")
- except NoLibrariesError:
- tty.debug(f"No libraries found for {dep.name}")
-
- for default_lib_dir in ["lib", "lib64"]:
- default_lib_prefix = os.path.join(dep.prefix, default_lib_dir)
- if os.path.isdir(default_lib_prefix):
- dep_link_dirs.append(default_lib_prefix)
-
- _prepend_all(link_dirs, dep_link_dirs)
- if dep in rpath_deps:
- _prepend_all(rpath_dirs, dep_link_dirs)
-
- try:
- _prepend_all(include_dirs, query.headers.directories)
- except NoHeadersError:
- tty.debug(f"No headers found for {dep.name}")
-
- for dspec in pkg.spec.traverse(root=False, order="post"):
- if dspec.external:
- update_compiler_args_for_dep(dspec)
-
- # Just above, we prepended entries for -L/-rpath for externals. We
- # now do this for non-external packages so that Spack-built packages
- # are searched first for libraries etc.
- for dspec in pkg.spec.traverse(root=False, order="post"):
- if not dspec.external:
- update_compiler_args_for_dep(dspec)
+ for dep in chain(external_link_deps, nonexternal_link_deps):
+ # TODO: is_system_path is wrong, but even if we knew default -L, -I flags from the compiler
+ # and default search dirs from the dynamic linker, it's not obvious how to avoid a possibly
+ # expensive search in `query.libs.directories` and `query.headers.directories`, which is
+ # what this branch is trying to avoid.
+ if is_system_path(dep.prefix):
+ continue
+ # TODO: as of Spack 0.22, multiple instances of the same package may occur among the link
+ # deps, so keying by name is wrong. In practice it is not problematic: we obtain the same
+ # gcc-runtime / glibc here, and repeatedly add the same dirs that are later deduped.
+ query = pkg.spec[dep.name]
+ dep_link_dirs = []
+ try:
+ # Locating libraries can be time consuming, so log start and finish.
+ tty.debug(f"Collecting libraries for {dep.name}")
+ dep_link_dirs.extend(query.libs.directories)
+ tty.debug(f"Libraries for {dep.name} have been collected.")
+ except NoLibrariesError:
+ tty.debug(f"No libraries found for {dep.name}")
+
+ for default_lib_dir in ("lib", "lib64"):
+ default_lib_prefix = os.path.join(dep.prefix, default_lib_dir)
+ if os.path.isdir(default_lib_prefix):
+ dep_link_dirs.append(default_lib_prefix)
+
+ link_dirs[:0] = dep_link_dirs
+ if dep.dag_hash() in rpath_hashes:
+ rpath_dirs[:0] = dep_link_dirs
- # The top-level package is always RPATHed. It hasn't been installed yet
- # so the RPATHs are added unconditionally (e.g. even though lib64/ may
- # not be created for the install).
- for libdir in ["lib64", "lib"]:
+ try:
+ tty.debug(f"Collecting headers for {dep.name}")
+ include_dirs[:0] = query.headers.directories
+ tty.debug(f"Headers for {dep.name} have been collected.")
+ except NoHeadersError:
+ tty.debug(f"No headers found for {dep.name}")
+
+ # The top-level package is heuristically rpath'ed.
+ for libdir in ("lib64", "lib"):
lib_path = os.path.join(pkg.prefix, libdir)
rpath_dirs.insert(0, lib_path)
@@ -587,11 +576,15 @@ def set_wrapper_variables(pkg, env):
pkg.compiler.default_dynamic_linker
)
+ # TODO: filter_system_paths is again wrong (and probably unnecessary due to the is_system_path
+ # branch above). link_dirs should be filtered with entries from _parse_link_paths.
link_dirs = list(dedupe(filter_system_paths(link_dirs)))
include_dirs = list(dedupe(filter_system_paths(include_dirs)))
rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))
rpath_dirs = filter_default_dynamic_linker_search_paths(rpath_dirs)
+ # TODO: implicit_rpaths is prefiltered by is_system_path, that should be removed in favor of
+ # just this filter.
implicit_rpaths = filter_default_dynamic_linker_search_paths(pkg.compiler.implicit_rpaths())
if implicit_rpaths:
env.set("SPACK_COMPILER_IMPLICIT_RPATHS", ":".join(implicit_rpaths))