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_spack_prefix = str(buildinfo.get("spackprefix"))
|
||||||
old_rel_prefix = buildinfo.get("relative_prefix")
|
old_rel_prefix = buildinfo.get("relative_prefix")
|
||||||
old_prefix = os.path.join(old_layout_root, old_rel_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
|
# In the past prefix_to_hash was the default and externals were not dropped, so prefixes
|
||||||
# were not unique.
|
# 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))
|
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)
|
dedupe_hardlinks_if_necessary(workdir, buildinfo)
|
||||||
|
|
||||||
def is_backup_file(file):
|
|
||||||
return file.endswith("~")
|
|
||||||
|
|
||||||
# Text files containing the prefix text
|
# Text files containing the prefix text
|
||||||
text_names = list()
|
text_names = [os.path.join(workdir, f) for f in buildinfo["relocate_textfiles"]]
|
||||||
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)
|
|
||||||
|
|
||||||
# If we are not installing back to the same install tree do the relocation
|
# If we are not installing back to the same install tree do the relocation
|
||||||
if old_prefix != new_prefix:
|
if old_prefix != new_prefix:
|
||||||
@ -2290,29 +2287,11 @@ def is_backup_file(file):
|
|||||||
# do the relocation of path in binaries
|
# do the relocation of path in binaries
|
||||||
platform = spack.platforms.by_name(spec.platform)
|
platform = spack.platforms.by_name(spec.platform)
|
||||||
if "macho" in platform.binary_formats:
|
if "macho" in platform.binary_formats:
|
||||||
relocate.relocate_macho_binaries(
|
relocate.relocate_macho_binaries(files_to_relocate, prefix_to_prefix_bin)
|
||||||
files_to_relocate,
|
elif "elf" in platform.binary_formats:
|
||||||
old_layout_root,
|
|
||||||
new_layout_root,
|
|
||||||
prefix_to_prefix_bin,
|
|
||||||
rel,
|
|
||||||
old_prefix,
|
|
||||||
new_prefix,
|
|
||||||
)
|
|
||||||
elif "elf" in platform.binary_formats and not rel:
|
|
||||||
# The new ELF dynamic section relocation logic only handles absolute to
|
# The new ELF dynamic section relocation logic only handles absolute to
|
||||||
# absolute relocation.
|
# absolute relocation.
|
||||||
relocate.new_relocate_elf_binaries(files_to_relocate, prefix_to_prefix_bin)
|
relocate.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 links to the new install prefix
|
# Relocate links to the new install prefix
|
||||||
links = [os.path.join(workdir, f) for f in buildinfo.get("relocate_links", [])]
|
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()
|
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):
|
def _decode_macho_data(bytestring):
|
||||||
return bytestring.rstrip(b"\x00").decode("ascii")
|
return bytestring.rstrip(b"\x00").decode("ascii")
|
||||||
|
|
||||||
|
|
||||||
def macho_make_paths_relative(path_name, old_layout_root, rpaths, deps, idpath):
|
def macho_find_paths(orig_rpaths, deps, idpath, prefix_to_prefix):
|
||||||
"""
|
|
||||||
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):
|
|
||||||
"""
|
"""
|
||||||
Inputs
|
Inputs
|
||||||
original rpaths from mach-o binaries
|
original rpaths from mach-o binaries
|
||||||
@ -207,13 +74,12 @@ 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
|
# 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)
|
prefix_iteration_order = sorted(prefix_to_prefix, key=len, reverse=True)
|
||||||
for orig_rpath in orig_rpaths:
|
for orig_rpath in orig_rpaths:
|
||||||
if orig_rpath.startswith(old_layout_root):
|
for old_prefix in prefix_iteration_order:
|
||||||
for old_prefix in prefix_iteration_order:
|
new_prefix = prefix_to_prefix[old_prefix]
|
||||||
new_prefix = prefix_to_prefix[old_prefix]
|
if orig_rpath.startswith(old_prefix):
|
||||||
if orig_rpath.startswith(old_prefix):
|
new_rpath = re.sub(re.escape(old_prefix), new_prefix, orig_rpath)
|
||||||
new_rpath = re.sub(re.escape(old_prefix), new_prefix, orig_rpath)
|
paths_to_paths[orig_rpath] = new_rpath
|
||||||
paths_to_paths[orig_rpath] = new_rpath
|
break
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
paths_to_paths[orig_rpath] = orig_rpath
|
paths_to_paths[orig_rpath] = orig_rpath
|
||||||
|
|
||||||
@ -348,9 +214,7 @@ def _set_elf_rpaths_and_interpreter(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def relocate_macho_binaries(
|
def relocate_macho_binaries(path_names, prefix_to_prefix):
|
||||||
path_names, old_layout_root, new_layout_root, prefix_to_prefix, rel, old_prefix, new_prefix
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Use macholib python package to get the rpaths, depedent libraries
|
Use macholib python package to get the rpaths, depedent libraries
|
||||||
and library identity for libraries from the MachO object. Modify them
|
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
|
# Corner case where macho object file ended up in the path name list
|
||||||
if path_name.endswith(".o"):
|
if path_name.endswith(".o"):
|
||||||
continue
|
continue
|
||||||
if rel:
|
# get the paths in the old prefix
|
||||||
# get the relativized paths
|
rpaths, deps, idpath = macholib_get_paths(path_name)
|
||||||
rpaths, deps, idpath = macholib_get_paths(path_name)
|
# get the mapping of paths in the old prerix to the new prefix
|
||||||
# get the file path name in the original prefix
|
paths_to_paths = macho_find_paths(rpaths, deps, idpath, prefix_to_prefix)
|
||||||
orig_path_name = re.sub(re.escape(new_prefix), old_prefix, path_name)
|
# replace the old paths with new paths
|
||||||
# get the mapping of the relativized paths to the original
|
modify_macho_object(path_name, rpaths, deps, idpath, paths_to_paths)
|
||||||
# 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
|
|
||||||
)
|
|
||||||
# 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):
|
def relocate_elf_binaries(binaries, prefix_to_prefix):
|
||||||
"""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):
|
|
||||||
"""Take a list of binaries, and an ordered dictionary of
|
"""Take a list of binaries, and an ordered dictionary of
|
||||||
prefix to prefix mapping, and update the rpaths accordingly."""
|
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)
|
_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):
|
def warn_if_link_cant_be_relocated(link, target):
|
||||||
if not os.path.isabs(target):
|
if not os.path.isabs(target):
|
||||||
return
|
return
|
||||||
|
@ -77,25 +77,9 @@ def rewire_node(spec, explicit):
|
|||||||
]
|
]
|
||||||
if bins_to_relocate:
|
if bins_to_relocate:
|
||||||
if "macho" in platform.binary_formats:
|
if "macho" in platform.binary_formats:
|
||||||
relocate.relocate_macho_binaries(
|
relocate.relocate_macho_binaries(bins_to_relocate, prefix_to_prefix)
|
||||||
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,
|
|
||||||
)
|
|
||||||
if "elf" in platform.binary_formats:
|
if "elf" in platform.binary_formats:
|
||||||
relocate.relocate_elf_binaries(
|
relocate.relocate_elf_binaries(bins_to_relocate, prefix_to_prefix)
|
||||||
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_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix)
|
relocate.relocate_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix)
|
||||||
shutil.rmtree(tempdir)
|
shutil.rmtree(tempdir)
|
||||||
install_manifest = os.path.join(
|
install_manifest = os.path.join(
|
||||||
|
@ -31,13 +31,7 @@
|
|||||||
from spack.fetch_strategy import URLFetchStrategy
|
from spack.fetch_strategy import URLFetchStrategy
|
||||||
from spack.installer import PackageInstaller
|
from spack.installer import PackageInstaller
|
||||||
from spack.paths import mock_gpg_keys_path
|
from spack.paths import mock_gpg_keys_path
|
||||||
from spack.relocate import (
|
from spack.relocate import macho_find_paths, relocate_links, relocate_text
|
||||||
macho_find_paths,
|
|
||||||
macho_make_paths_normal,
|
|
||||||
macho_make_paths_relative,
|
|
||||||
relocate_links,
|
|
||||||
relocate_text,
|
|
||||||
)
|
|
||||||
from spack.spec import Spec
|
from spack.spec import Spec
|
||||||
|
|
||||||
pytestmark = pytest.mark.not_on_windows("does not run on windows")
|
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_local, libfile_loco),
|
||||||
],
|
],
|
||||||
os.path.join(oldlibdir_cc, libfile_c),
|
os.path.join(oldlibdir_cc, libfile_c),
|
||||||
old_spack_dir,
|
|
||||||
prefix2prefix,
|
prefix2prefix,
|
||||||
)
|
)
|
||||||
assert out_dict == {
|
assert out_dict == {
|
||||||
@ -325,7 +318,6 @@ def test_replace_paths(tmpdir):
|
|||||||
os.path.join(oldlibdir_local, libfile_loco),
|
os.path.join(oldlibdir_local, libfile_loco),
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
old_spack_dir,
|
|
||||||
prefix2prefix,
|
prefix2prefix,
|
||||||
)
|
)
|
||||||
assert out_dict == {
|
assert out_dict == {
|
||||||
@ -349,7 +341,6 @@ def test_replace_paths(tmpdir):
|
|||||||
f"@rpath/{libfile_loco}",
|
f"@rpath/{libfile_loco}",
|
||||||
],
|
],
|
||||||
None,
|
None,
|
||||||
old_spack_dir,
|
|
||||||
prefix2prefix,
|
prefix2prefix,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -369,7 +360,6 @@ def test_replace_paths(tmpdir):
|
|||||||
[oldlibdir_a, oldlibdir_b, oldlibdir_d, oldlibdir_local],
|
[oldlibdir_a, oldlibdir_b, oldlibdir_d, oldlibdir_local],
|
||||||
[f"@rpath/{libfile_a}", f"@rpath/{libfile_b}", f"@rpath/{libfile_loco}"],
|
[f"@rpath/{libfile_a}", f"@rpath/{libfile_b}", f"@rpath/{libfile_loco}"],
|
||||||
None,
|
None,
|
||||||
old_spack_dir,
|
|
||||||
prefix2prefix,
|
prefix2prefix,
|
||||||
)
|
)
|
||||||
assert out_dict == {
|
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()
|
@pytest.fixture()
|
||||||
def mock_download(monkeypatch):
|
def mock_download(monkeypatch):
|
||||||
"""Mock a failing download strategy."""
|
"""Mock a failing download strategy."""
|
||||||
@ -561,10 +466,6 @@ def test_macho_relocation_with_changing_projection(relocation_dict):
|
|||||||
"""
|
"""
|
||||||
original_rpath = "/foo/bar/baz/abcdef"
|
original_rpath = "/foo/bar/baz/abcdef"
|
||||||
result = macho_find_paths(
|
result = macho_find_paths(
|
||||||
[original_rpath],
|
[original_rpath], deps=[], idpath=None, prefix_to_prefix=relocation_dict
|
||||||
deps=[],
|
|
||||||
idpath=None,
|
|
||||||
old_layout_root="/foo",
|
|
||||||
prefix_to_prefix=relocation_dict,
|
|
||||||
)
|
)
|
||||||
assert result[original_rpath] == "/a/b/c/abcdef"
|
assert result[original_rpath] == "/a/b/c/abcdef"
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# Copyright Spack Project Developers. See COPYRIGHT file for details.
|
# Copyright Spack Project Developers. See COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
@ -114,49 +112,6 @@ def _copy_somewhere(orig_binary):
|
|||||||
return _copy_somewhere
|
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")
|
@pytest.mark.requires_executables("patchelf", "gcc")
|
||||||
@skip_unless_linux
|
@skip_unless_linux
|
||||||
def test_relocate_text_bin(binary_with_rpaths, prefix_like):
|
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)
|
new_binary = copy_binary(orig_binary)
|
||||||
|
|
||||||
spack.relocate.relocate_elf_binaries(
|
spack.relocate.relocate_elf_binaries(
|
||||||
binaries=[str(new_binary)],
|
binaries=[str(new_binary)], prefix_to_prefix={str(orig_binary.dirpath()): "/foo"}
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Some compilers add rpaths so ensure changes included in final result
|
# Some compilers add rpaths so ensure changes included in final result
|
||||||
assert "/foo/lib:/usr/lib64" in rpaths_for(new_binary)
|
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")
|
@pytest.mark.requires_executables("patchelf", "gcc")
|
||||||
@skip_unless_linux
|
@skip_unless_linux
|
||||||
def test_relocate_text_bin_with_message(binary_with_rpaths, copy_binary, prefix_tmpdir):
|
def test_relocate_text_bin_with_message(binary_with_rpaths, copy_binary, prefix_tmpdir):
|
||||||
|
Loading…
Reference in New Issue
Block a user