binary_distribution: stop relocating tarballs with relative rpaths (#48488)
This commit is contained in:
parent
c1d385ada2
commit
93cd216603
@ -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", [])]
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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"
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user