binary_distribution: stop relocating tarballs with relative rpaths (#48488)

This commit is contained in:
Harmen Stoppels 2025-01-10 11:30:18 +01:00 committed by GitHub
parent c1d385ada2
commit 93cd216603
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 31 additions and 550 deletions

View File

@ -2189,7 +2189,12 @@ def relocate_package(spec):
old_spack_prefix = str(buildinfo.get("spackprefix"))
old_rel_prefix = buildinfo.get("relative_prefix")
old_prefix = os.path.join(old_layout_root, old_rel_prefix)
rel = buildinfo.get("relative_rpaths", False)
# Warn about old style tarballs created with the now removed --rel flag.
if buildinfo.get("relative_rpaths", False):
tty.warn(
f"Tarball for {spec} uses relative rpaths, " "which can cause library loading issues."
)
# In the past prefix_to_hash was the default and externals were not dropped, so prefixes
# were not unique.
@ -2267,19 +2272,11 @@ def relocate_package(spec):
tty.debug("Relocating package from", "%s to %s." % (old_layout_root, new_layout_root))
# Old archives maybe have hardlinks repeated.
# Old archives may have hardlinks repeated.
dedupe_hardlinks_if_necessary(workdir, buildinfo)
def is_backup_file(file):
return file.endswith("~")
# Text files containing the prefix text
text_names = list()
for filename in buildinfo["relocate_textfiles"]:
text_name = os.path.join(workdir, filename)
# Don't add backup files generated by filter_file during install step.
if not is_backup_file(text_name):
text_names.append(text_name)
text_names = [os.path.join(workdir, f) for f in buildinfo["relocate_textfiles"]]
# If we are not installing back to the same install tree do the relocation
if old_prefix != new_prefix:
@ -2290,29 +2287,11 @@ def is_backup_file(file):
# do the relocation of path in binaries
platform = spack.platforms.by_name(spec.platform)
if "macho" in platform.binary_formats:
relocate.relocate_macho_binaries(
files_to_relocate,
old_layout_root,
new_layout_root,
prefix_to_prefix_bin,
rel,
old_prefix,
new_prefix,
)
elif "elf" in platform.binary_formats and not rel:
relocate.relocate_macho_binaries(files_to_relocate, prefix_to_prefix_bin)
elif "elf" in platform.binary_formats:
# The new ELF dynamic section relocation logic only handles absolute to
# absolute relocation.
relocate.new_relocate_elf_binaries(files_to_relocate, prefix_to_prefix_bin)
elif "elf" in platform.binary_formats and rel:
relocate.relocate_elf_binaries(
files_to_relocate,
old_layout_root,
new_layout_root,
prefix_to_prefix_bin,
rel,
old_prefix,
new_prefix,
)
relocate.relocate_elf_binaries(files_to_relocate, prefix_to_prefix_bin)
# Relocate links to the new install prefix
links = [os.path.join(workdir, f) for f in buildinfo.get("relocate_links", [])]

View File

@ -54,144 +54,11 @@ def _patchelf() -> Optional[executable.Executable]:
return spack.bootstrap.ensure_patchelf_in_path_or_raise()
def _elf_rpaths_for(path):
"""Return the RPATHs for an executable or a library.
Args:
path (str): full path to the executable or library
Return:
RPATHs as a list of strings. Returns an empty array
on ELF parsing errors, or when the ELF file simply
has no rpaths.
"""
return elf.get_rpaths(path) or []
def _make_relative(reference_file, path_root, paths):
"""Return a list where any path in ``paths`` that starts with
``path_root`` is made relative to the directory in which the
reference file is stored.
After a path is made relative it is prefixed with the ``$ORIGIN``
string.
Args:
reference_file (str): file from which the reference directory
is computed
path_root (str): root of the relative paths
paths: (list) paths to be examined
Returns:
List of relative paths
"""
start_directory = os.path.dirname(reference_file)
pattern = re.compile(path_root)
relative_paths = []
for path in paths:
if pattern.match(path):
rel = os.path.relpath(path, start=start_directory)
path = os.path.join("$ORIGIN", rel)
relative_paths.append(path)
return relative_paths
def _normalize_relative_paths(start_path, relative_paths):
"""Normalize the relative paths with respect to the original path name
of the file (``start_path``).
The paths that are passed to this function existed or were relevant
on another filesystem, so os.path.abspath cannot be used.
A relative path may contain the signifier $ORIGIN. Assuming that
``start_path`` is absolute, this implies that the relative path
(relative to start_path) should be replaced with an absolute path.
Args:
start_path (str): path from which the starting directory
is extracted
relative_paths (str): list of relative paths as obtained by a
call to :ref:`_make_relative`
Returns:
List of normalized paths
"""
normalized_paths = []
pattern = re.compile(re.escape("$ORIGIN"))
start_directory = os.path.dirname(start_path)
for path in relative_paths:
if path.startswith("$ORIGIN"):
sub = pattern.sub(start_directory, path)
path = os.path.normpath(sub)
normalized_paths.append(path)
return normalized_paths
def _decode_macho_data(bytestring):
return bytestring.rstrip(b"\x00").decode("ascii")
def macho_make_paths_relative(path_name, old_layout_root, rpaths, deps, idpath):
"""
Return a dictionary mapping the original rpaths to the relativized rpaths.
This dictionary is used to replace paths in mach-o binaries.
Replace old_dir with relative path from dirname of path name
in rpaths and deps; idpath is replaced with @rpath/libname.
"""
paths_to_paths = dict()
if idpath:
paths_to_paths[idpath] = os.path.join("@rpath", "%s" % os.path.basename(idpath))
for rpath in rpaths:
if re.match(old_layout_root, rpath):
rel = os.path.relpath(rpath, start=os.path.dirname(path_name))
paths_to_paths[rpath] = os.path.join("@loader_path", "%s" % rel)
else:
paths_to_paths[rpath] = rpath
for dep in deps:
if re.match(old_layout_root, dep):
rel = os.path.relpath(dep, start=os.path.dirname(path_name))
paths_to_paths[dep] = os.path.join("@loader_path", "%s" % rel)
else:
paths_to_paths[dep] = dep
return paths_to_paths
def macho_make_paths_normal(orig_path_name, rpaths, deps, idpath):
"""
Return a dictionary mapping the relativized rpaths to the original rpaths.
This dictionary is used to replace paths in mach-o binaries.
Replace '@loader_path' with the dirname of the origname path name
in rpaths and deps; idpath is replaced with the original path name
"""
rel_to_orig = dict()
if idpath:
rel_to_orig[idpath] = orig_path_name
for rpath in rpaths:
if re.match("@loader_path", rpath):
norm = os.path.normpath(
re.sub(re.escape("@loader_path"), os.path.dirname(orig_path_name), rpath)
)
rel_to_orig[rpath] = norm
else:
rel_to_orig[rpath] = rpath
for dep in deps:
if re.match("@loader_path", dep):
norm = os.path.normpath(
re.sub(re.escape("@loader_path"), os.path.dirname(orig_path_name), dep)
)
rel_to_orig[dep] = norm
else:
rel_to_orig[dep] = dep
return rel_to_orig
def macho_find_paths(orig_rpaths, deps, idpath, old_layout_root, prefix_to_prefix):
def macho_find_paths(orig_rpaths, deps, idpath, prefix_to_prefix):
"""
Inputs
original rpaths from mach-o binaries
@ -207,7 +74,6 @@ def macho_find_paths(orig_rpaths, deps, idpath, old_layout_root, prefix_to_prefi
# Sort from longest path to shortest, to ensure we try /foo/bar/baz before /foo/bar
prefix_iteration_order = sorted(prefix_to_prefix, key=len, reverse=True)
for orig_rpath in orig_rpaths:
if orig_rpath.startswith(old_layout_root):
for old_prefix in prefix_iteration_order:
new_prefix = prefix_to_prefix[old_prefix]
if orig_rpath.startswith(old_prefix):
@ -348,9 +214,7 @@ def _set_elf_rpaths_and_interpreter(
return None
def relocate_macho_binaries(
path_names, old_layout_root, new_layout_root, prefix_to_prefix, rel, old_prefix, new_prefix
):
def relocate_macho_binaries(path_names, prefix_to_prefix):
"""
Use macholib python package to get the rpaths, depedent libraries
and library identity for libraries from the MachO object. Modify them
@ -363,77 +227,15 @@ def relocate_macho_binaries(
# Corner case where macho object file ended up in the path name list
if path_name.endswith(".o"):
continue
if rel:
# get the relativized paths
rpaths, deps, idpath = macholib_get_paths(path_name)
# get the file path name in the original prefix
orig_path_name = re.sub(re.escape(new_prefix), old_prefix, path_name)
# get the mapping of the relativized paths to the original
# normalized paths
rel_to_orig = macho_make_paths_normal(orig_path_name, rpaths, deps, idpath)
# replace the relativized paths with normalized paths
modify_macho_object(path_name, rpaths, deps, idpath, rel_to_orig)
# get the normalized paths in the mach-o binary
rpaths, deps, idpath = macholib_get_paths(path_name)
# get the mapping of paths in old prefix to path in new prefix
paths_to_paths = macho_find_paths(
rpaths, deps, idpath, old_layout_root, prefix_to_prefix
)
# replace the old paths with new paths
modify_macho_object(path_name, rpaths, deps, idpath, paths_to_paths)
# get the new normalized path in the mach-o binary
rpaths, deps, idpath = macholib_get_paths(path_name)
# get the mapping of paths to relative paths in the new prefix
paths_to_paths = macho_make_paths_relative(
path_name, new_layout_root, rpaths, deps, idpath
)
# replace the new paths with relativized paths in the new prefix
modify_macho_object(path_name, rpaths, deps, idpath, paths_to_paths)
else:
# get the paths in the old prefix
rpaths, deps, idpath = macholib_get_paths(path_name)
# get the mapping of paths in the old prerix to the new prefix
paths_to_paths = macho_find_paths(
rpaths, deps, idpath, old_layout_root, prefix_to_prefix
)
paths_to_paths = macho_find_paths(rpaths, deps, idpath, prefix_to_prefix)
# replace the old paths with new paths
modify_macho_object(path_name, rpaths, deps, idpath, paths_to_paths)
def _transform_rpaths(orig_rpaths, orig_root, new_prefixes):
"""Return an updated list of RPATHs where each entry in the original list
starting with the old root is relocated to another place according to the
mapping passed as argument.
Args:
orig_rpaths (list): list of the original RPATHs
orig_root (str): original root to be substituted
new_prefixes (dict): dictionary that maps the original prefixes to
where they should be relocated
Returns:
List of paths
"""
new_rpaths = []
for orig_rpath in orig_rpaths:
# If the original RPATH doesn't start with the target root
# append it verbatim and proceed
if not orig_rpath.startswith(orig_root):
new_rpaths.append(orig_rpath)
continue
# Otherwise inspect the mapping and transform + append any prefix
# that starts with a registered key
# avoiding duplicates
for old_prefix, new_prefix in new_prefixes.items():
if orig_rpath.startswith(old_prefix):
new_rpath = re.sub(re.escape(old_prefix), new_prefix, orig_rpath)
if new_rpath not in new_rpaths:
new_rpaths.append(new_rpath)
return new_rpaths
def new_relocate_elf_binaries(binaries, prefix_to_prefix):
def relocate_elf_binaries(binaries, prefix_to_prefix):
"""Take a list of binaries, and an ordered dictionary of
prefix to prefix mapping, and update the rpaths accordingly."""
@ -452,98 +254,6 @@ def new_relocate_elf_binaries(binaries, prefix_to_prefix):
_set_elf_rpaths_and_interpreter(path, rpaths=rpaths, interpreter=interpreter)
def relocate_elf_binaries(
binaries, orig_root, new_root, new_prefixes, rel, orig_prefix, new_prefix
):
"""Relocate the binaries passed as arguments by changing their RPATHs.
Use patchelf to get the original RPATHs and then replace them with
rpaths in the new directory layout.
New RPATHs are determined from a dictionary mapping the prefixes in the
old directory layout to the prefixes in the new directory layout if the
rpath was in the old layout root, i.e. system paths are not replaced.
Args:
binaries (list): list of binaries that might need relocation, located
in the new prefix
orig_root (str): original root to be substituted
new_root (str): new root to be used, only relevant for relative RPATHs
new_prefixes (dict): dictionary that maps the original prefixes to
where they should be relocated
rel (bool): True if the RPATHs are relative, False if they are absolute
orig_prefix (str): prefix where the executable was originally located
new_prefix (str): prefix where we want to relocate the executable
"""
for new_binary in binaries:
orig_rpaths = _elf_rpaths_for(new_binary)
# TODO: Can we deduce `rel` from the original RPATHs?
if rel:
# Get the file path in the original prefix
orig_binary = re.sub(re.escape(new_prefix), orig_prefix, new_binary)
# Get the normalized RPATHs in the old prefix using the file path
# in the orig prefix
orig_norm_rpaths = _normalize_relative_paths(orig_binary, orig_rpaths)
# Get the normalize RPATHs in the new prefix
new_norm_rpaths = _transform_rpaths(orig_norm_rpaths, orig_root, new_prefixes)
# Get the relative RPATHs in the new prefix
new_rpaths = _make_relative(new_binary, new_root, new_norm_rpaths)
# check to see if relative rpaths are changed before rewriting
if sorted(new_rpaths) != sorted(orig_rpaths):
_set_elf_rpaths_and_interpreter(new_binary, new_rpaths)
else:
new_rpaths = _transform_rpaths(orig_rpaths, orig_root, new_prefixes)
_set_elf_rpaths_and_interpreter(new_binary, new_rpaths)
def make_link_relative(new_links, orig_links):
"""Compute the relative target from the original link and
make the new link relative.
Args:
new_links (list): new links to be made relative
orig_links (list): original links
"""
for new_link, orig_link in zip(new_links, orig_links):
target = readlink(orig_link)
relative_target = os.path.relpath(target, os.path.dirname(orig_link))
os.unlink(new_link)
symlink(relative_target, new_link)
def make_macho_binaries_relative(cur_path_names, orig_path_names, old_layout_root):
"""
Replace old RPATHs with paths relative to old_dir in binary files
"""
if not sys.platform == "darwin":
return
for cur_path, orig_path in zip(cur_path_names, orig_path_names):
(rpaths, deps, idpath) = macholib_get_paths(cur_path)
paths_to_paths = macho_make_paths_relative(
orig_path, old_layout_root, rpaths, deps, idpath
)
modify_macho_object(cur_path, rpaths, deps, idpath, paths_to_paths)
def make_elf_binaries_relative(new_binaries, orig_binaries, orig_layout_root):
"""Replace the original RPATHs in the new binaries making them
relative to the original layout root.
Args:
new_binaries (list): new binaries whose RPATHs is to be made relative
orig_binaries (list): original binaries
orig_layout_root (str): path to be used as a base for making
RPATHs relative
"""
for new_binary, orig_binary in zip(new_binaries, orig_binaries):
orig_rpaths = _elf_rpaths_for(new_binary)
if orig_rpaths:
new_rpaths = _make_relative(orig_binary, orig_layout_root, orig_rpaths)
_set_elf_rpaths_and_interpreter(new_binary, new_rpaths)
def warn_if_link_cant_be_relocated(link, target):
if not os.path.isabs(target):
return

View File

@ -77,25 +77,9 @@ def rewire_node(spec, explicit):
]
if bins_to_relocate:
if "macho" in platform.binary_formats:
relocate.relocate_macho_binaries(
bins_to_relocate,
str(spack.store.STORE.layout.root),
str(spack.store.STORE.layout.root),
prefix_to_prefix,
False,
spec.build_spec.prefix,
spec.prefix,
)
relocate.relocate_macho_binaries(bins_to_relocate, prefix_to_prefix)
if "elf" in platform.binary_formats:
relocate.relocate_elf_binaries(
bins_to_relocate,
str(spack.store.STORE.layout.root),
str(spack.store.STORE.layout.root),
prefix_to_prefix,
False,
spec.build_spec.prefix,
spec.prefix,
)
relocate.relocate_elf_binaries(bins_to_relocate, prefix_to_prefix)
relocate.relocate_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix)
shutil.rmtree(tempdir)
install_manifest = os.path.join(

View File

@ -31,13 +31,7 @@
from spack.fetch_strategy import URLFetchStrategy
from spack.installer import PackageInstaller
from spack.paths import mock_gpg_keys_path
from spack.relocate import (
macho_find_paths,
macho_make_paths_normal,
macho_make_paths_relative,
relocate_links,
relocate_text,
)
from spack.relocate import macho_find_paths, relocate_links, relocate_text
from spack.spec import Spec
pytestmark = pytest.mark.not_on_windows("does not run on windows")
@ -301,7 +295,6 @@ def test_replace_paths(tmpdir):
os.path.join(oldlibdir_local, libfile_loco),
],
os.path.join(oldlibdir_cc, libfile_c),
old_spack_dir,
prefix2prefix,
)
assert out_dict == {
@ -325,7 +318,6 @@ def test_replace_paths(tmpdir):
os.path.join(oldlibdir_local, libfile_loco),
],
None,
old_spack_dir,
prefix2prefix,
)
assert out_dict == {
@ -349,7 +341,6 @@ def test_replace_paths(tmpdir):
f"@rpath/{libfile_loco}",
],
None,
old_spack_dir,
prefix2prefix,
)
@ -369,7 +360,6 @@ def test_replace_paths(tmpdir):
[oldlibdir_a, oldlibdir_b, oldlibdir_d, oldlibdir_local],
[f"@rpath/{libfile_a}", f"@rpath/{libfile_b}", f"@rpath/{libfile_loco}"],
None,
old_spack_dir,
prefix2prefix,
)
assert out_dict == {
@ -383,91 +373,6 @@ def test_replace_paths(tmpdir):
}
def test_macho_make_paths():
out = macho_make_paths_relative(
"/Users/Shared/spack/pkgC/lib/libC.dylib",
"/Users/Shared/spack",
("/Users/Shared/spack/pkgA/lib", "/Users/Shared/spack/pkgB/lib", "/usr/local/lib"),
(
"/Users/Shared/spack/pkgA/libA.dylib",
"/Users/Shared/spack/pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib",
),
"/Users/Shared/spack/pkgC/lib/libC.dylib",
)
assert out == {
"/Users/Shared/spack/pkgA/lib": "@loader_path/../../pkgA/lib",
"/Users/Shared/spack/pkgB/lib": "@loader_path/../../pkgB/lib",
"/usr/local/lib": "/usr/local/lib",
"/Users/Shared/spack/pkgA/libA.dylib": "@loader_path/../../pkgA/libA.dylib",
"/Users/Shared/spack/pkgB/libB.dylib": "@loader_path/../../pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib": "/usr/local/lib/libloco.dylib",
"/Users/Shared/spack/pkgC/lib/libC.dylib": "@rpath/libC.dylib",
}
out = macho_make_paths_normal(
"/Users/Shared/spack/pkgC/lib/libC.dylib",
("@loader_path/../../pkgA/lib", "@loader_path/../../pkgB/lib", "/usr/local/lib"),
(
"@loader_path/../../pkgA/libA.dylib",
"@loader_path/../../pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib",
),
"@rpath/libC.dylib",
)
assert out == {
"@rpath/libC.dylib": "/Users/Shared/spack/pkgC/lib/libC.dylib",
"@loader_path/../../pkgA/lib": "/Users/Shared/spack/pkgA/lib",
"@loader_path/../../pkgB/lib": "/Users/Shared/spack/pkgB/lib",
"/usr/local/lib": "/usr/local/lib",
"@loader_path/../../pkgA/libA.dylib": "/Users/Shared/spack/pkgA/libA.dylib",
"@loader_path/../../pkgB/libB.dylib": "/Users/Shared/spack/pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib": "/usr/local/lib/libloco.dylib",
}
out = macho_make_paths_relative(
"/Users/Shared/spack/pkgC/bin/exeC",
"/Users/Shared/spack",
("/Users/Shared/spack/pkgA/lib", "/Users/Shared/spack/pkgB/lib", "/usr/local/lib"),
(
"/Users/Shared/spack/pkgA/libA.dylib",
"/Users/Shared/spack/pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib",
),
None,
)
assert out == {
"/Users/Shared/spack/pkgA/lib": "@loader_path/../../pkgA/lib",
"/Users/Shared/spack/pkgB/lib": "@loader_path/../../pkgB/lib",
"/usr/local/lib": "/usr/local/lib",
"/Users/Shared/spack/pkgA/libA.dylib": "@loader_path/../../pkgA/libA.dylib",
"/Users/Shared/spack/pkgB/libB.dylib": "@loader_path/../../pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib": "/usr/local/lib/libloco.dylib",
}
out = macho_make_paths_normal(
"/Users/Shared/spack/pkgC/bin/exeC",
("@loader_path/../../pkgA/lib", "@loader_path/../../pkgB/lib", "/usr/local/lib"),
(
"@loader_path/../../pkgA/libA.dylib",
"@loader_path/../../pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib",
),
None,
)
assert out == {
"@loader_path/../../pkgA/lib": "/Users/Shared/spack/pkgA/lib",
"@loader_path/../../pkgB/lib": "/Users/Shared/spack/pkgB/lib",
"/usr/local/lib": "/usr/local/lib",
"@loader_path/../../pkgA/libA.dylib": "/Users/Shared/spack/pkgA/libA.dylib",
"@loader_path/../../pkgB/libB.dylib": "/Users/Shared/spack/pkgB/libB.dylib",
"/usr/local/lib/libloco.dylib": "/usr/local/lib/libloco.dylib",
}
@pytest.fixture()
def mock_download(monkeypatch):
"""Mock a failing download strategy."""
@ -561,10 +466,6 @@ def test_macho_relocation_with_changing_projection(relocation_dict):
"""
original_rpath = "/foo/bar/baz/abcdef"
result = macho_find_paths(
[original_rpath],
deps=[],
idpath=None,
old_layout_root="/foo",
prefix_to_prefix=relocation_dict,
[original_rpath], deps=[], idpath=None, prefix_to_prefix=relocation_dict
)
assert result[original_rpath] == "/a/b/c/abcdef"

View File

@ -1,8 +1,6 @@
# Copyright Spack Project Developers. See COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import os.path
import re
import shutil
@ -114,49 +112,6 @@ def _copy_somewhere(orig_binary):
return _copy_somewhere
@pytest.mark.parametrize(
"start_path,path_root,paths,expected",
[
(
"/usr/bin/test",
"/usr",
["/usr/lib", "/usr/lib64", "/opt/local/lib"],
[
os.path.join("$ORIGIN", "..", "lib"),
os.path.join("$ORIGIN", "..", "lib64"),
"/opt/local/lib",
],
)
],
)
def test_make_relative_paths(start_path, path_root, paths, expected):
relatives = spack.relocate._make_relative(start_path, path_root, paths)
assert relatives == expected
@pytest.mark.parametrize(
"start_path,relative_paths,expected",
[
# $ORIGIN will be replaced with os.path.dirname('usr/bin/test')
# and then normalized
(
"/usr/bin/test",
["$ORIGIN/../lib", "$ORIGIN/../lib64", "/opt/local/lib"],
[
os.sep + os.path.join("usr", "lib"),
os.sep + os.path.join("usr", "lib64"),
"/opt/local/lib",
],
),
# Relative path without $ORIGIN
("/usr/bin/test", ["../local/lib"], ["../local/lib"]),
],
)
def test_normalize_relative_paths(start_path, relative_paths, expected):
normalized = spack.relocate._normalize_relative_paths(start_path, relative_paths)
assert normalized == expected
@pytest.mark.requires_executables("patchelf", "gcc")
@skip_unless_linux
def test_relocate_text_bin(binary_with_rpaths, prefix_like):
@ -182,61 +137,13 @@ def test_relocate_elf_binaries_absolute_paths(binary_with_rpaths, copy_binary, p
new_binary = copy_binary(orig_binary)
spack.relocate.relocate_elf_binaries(
binaries=[str(new_binary)],
orig_root=str(orig_binary.dirpath()),
new_root=None, # Not needed when relocating absolute paths
new_prefixes={str(orig_binary.dirpath()): "/foo"},
rel=False,
# Not needed when relocating absolute paths
orig_prefix=None,
new_prefix=None,
binaries=[str(new_binary)], prefix_to_prefix={str(orig_binary.dirpath()): "/foo"}
)
# Some compilers add rpaths so ensure changes included in final result
assert "/foo/lib:/usr/lib64" in rpaths_for(new_binary)
@pytest.mark.requires_executables("patchelf", "gcc")
@skip_unless_linux
def test_relocate_elf_binaries_relative_paths(binary_with_rpaths, copy_binary):
# Create an executable, set some RPATHs, copy it to another location
orig_binary = binary_with_rpaths(rpaths=["lib", "lib64", "/opt/local/lib"])
new_binary = copy_binary(orig_binary)
spack.relocate.relocate_elf_binaries(
binaries=[str(new_binary)],
orig_root=str(orig_binary.dirpath()),
new_root=str(new_binary.dirpath()),
new_prefixes={str(orig_binary.dirpath()): "/foo"},
rel=True,
orig_prefix=str(orig_binary.dirpath()),
new_prefix=str(new_binary.dirpath()),
)
# Some compilers add rpaths so ensure changes included in final result
assert "/foo/lib:/foo/lib64:/opt/local/lib" in rpaths_for(new_binary)
@pytest.mark.requires_executables("patchelf", "gcc")
@skip_unless_linux
def test_make_elf_binaries_relative(binary_with_rpaths, copy_binary, prefix_tmpdir):
orig_binary = binary_with_rpaths(
rpaths=[
str(prefix_tmpdir.mkdir("lib")),
str(prefix_tmpdir.mkdir("lib64")),
"/opt/local/lib",
]
)
new_binary = copy_binary(orig_binary)
spack.relocate.make_elf_binaries_relative(
[str(new_binary)], [str(orig_binary)], str(orig_binary.dirpath())
)
# Some compilers add rpaths so ensure changes included in final result
assert "$ORIGIN/lib:$ORIGIN/lib64:/opt/local/lib" in rpaths_for(new_binary)
@pytest.mark.requires_executables("patchelf", "gcc")
@skip_unless_linux
def test_relocate_text_bin_with_message(binary_with_rpaths, copy_binary, prefix_tmpdir):