Relocate mach-o binaries using macholib on linux. (#12946)
Changes deps and rpaths for bins and libs, changes id for libs.
This commit is contained in:
parent
950338aa92
commit
7dae058f91
@ -573,20 +573,19 @@ def extract_tarball(spec, filename, allow_root=False, unsigned=False,
|
|||||||
# so the pathname should be the same now that the directory layout
|
# so the pathname should be the same now that the directory layout
|
||||||
# is confirmed
|
# is confirmed
|
||||||
workdir = os.path.join(tmpdir, os.path.basename(spec.prefix))
|
workdir = os.path.join(tmpdir, os.path.basename(spec.prefix))
|
||||||
|
install_tree(workdir, spec.prefix, symlinks=True)
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
os.remove(tarfile_path)
|
os.remove(tarfile_path)
|
||||||
os.remove(specfile_path)
|
os.remove(specfile_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
relocate_package(workdir, spec, allow_root)
|
relocate_package(spec.prefix, spec, allow_root)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
shutil.rmtree(workdir)
|
shutil.rmtree(spec.prefix)
|
||||||
tty.die(e)
|
tty.die(e)
|
||||||
# Delay creating spec.prefix until verification is complete
|
# Delay creating spec.prefix until verification is complete
|
||||||
# and any relocation has been done.
|
# and any relocation has been done.
|
||||||
else:
|
|
||||||
install_tree(workdir, spec.prefix, symlinks=True)
|
|
||||||
finally:
|
finally:
|
||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
@ -41,20 +41,20 @@ def __init__(self, file_path, old_len, new_len):
|
|||||||
(file_path, old_len, new_len))
|
(file_path, old_len, new_len))
|
||||||
|
|
||||||
|
|
||||||
class MissingMachotoolsException(spack.error.SpackError):
|
class MissingMacholibException(spack.error.SpackError):
|
||||||
"""
|
"""
|
||||||
Raised when the size of the file changes after binary path substitution.
|
Raised when the size of the file changes after binary path substitution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, error):
|
def __init__(self, error):
|
||||||
super(MissingMachotoolsException, self).__init__(
|
super(MissingMacholibException, self).__init__(
|
||||||
"%s\n"
|
"%s\n"
|
||||||
"Python package machotools needs to be avaiable to list\n"
|
"Python package macholib needs to be avaiable to list\n"
|
||||||
"and modify a mach-o binary's rpaths, deps and id.\n"
|
"and modify a mach-o binary's rpaths, deps and id.\n"
|
||||||
"Use virtualenv with pip install machotools or\n"
|
"Use virtualenv with pip install macholib or\n"
|
||||||
"use spack to install the py-machotools package\n"
|
"use spack to install the py-macholib package\n"
|
||||||
"spack install py-machotools\n"
|
"spack install py-macholib\n"
|
||||||
"spack activate py-machotools\n"
|
"spack activate py-macholib\n"
|
||||||
"spack load python\n"
|
"spack load python\n"
|
||||||
% error)
|
% error)
|
||||||
|
|
||||||
@ -275,55 +275,50 @@ def modify_macho_object(cur_path, rpaths, deps, idpath,
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def modify_object_machotools(cur_path, rpaths, deps, idpath,
|
def modify_object_macholib(cur_path, old_dir, new_dir):
|
||||||
new_rpaths, new_deps, new_idpath):
|
|
||||||
"""
|
"""
|
||||||
Modify MachO binary path_name by replacing old_dir with new_dir
|
Modify MachO binary path_name by replacing old_dir with new_dir
|
||||||
or the relative path to spack install root.
|
or the relative path to spack install root.
|
||||||
The old install dir in LC_ID_DYLIB is replaced with the new install dir
|
The old install dir in LC_ID_DYLIB is replaced with the new install dir
|
||||||
using py-machotools
|
using py-macholib
|
||||||
The old install dir in LC_LOAD_DYLIB is replaced with the new install dir
|
The old install dir in LC_LOAD_DYLIB is replaced with the new install dir
|
||||||
using py-machotools
|
using py-macholib
|
||||||
The old install dir in LC_RPATH is replaced with the new install dir using
|
The old install dir in LC_RPATH is replaced with the new install dir using
|
||||||
using py-machotools
|
using py-macholib
|
||||||
"""
|
"""
|
||||||
if cur_path.endswith('.o'):
|
if cur_path.endswith('.o'):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
import machotools
|
from macholib.MachO import MachO
|
||||||
|
from macholib.mach_o import LC_RPATH
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise MissingMachotoolsException(e)
|
raise MissingMacholibException(e)
|
||||||
rewriter = machotools.rewriter_factory(cur_path)
|
|
||||||
if machotools.detect.is_dylib(cur_path):
|
|
||||||
if not new_idpath == idpath:
|
|
||||||
rewriter.install_name = new_idpath
|
|
||||||
for orig, new in zip(deps, new_deps):
|
|
||||||
if not orig == new:
|
|
||||||
rewriter.change_dependency(orig, new)
|
|
||||||
rewriter.commit()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
def match_func(cpath):
|
||||||
|
return str(cpath).replace(old_dir, new_dir)
|
||||||
|
|
||||||
|
dll = MachO(cur_path)
|
||||||
|
dll.rewriteLoadCommands(match_func)
|
||||||
|
for header in dll.headers:
|
||||||
|
for (idx, (lc, cmd, data)) in enumerate(header.commands):
|
||||||
|
if lc.cmd == LC_RPATH:
|
||||||
|
rpath = data
|
||||||
|
rpath = rpath.strip('\x00')
|
||||||
|
new_rpath = match_func(rpath)
|
||||||
|
header.rewriteDataForCommand(idx, new_rpath)
|
||||||
|
|
||||||
def machotools_get_paths(path_name):
|
|
||||||
"""
|
|
||||||
Examines the output of otool -l path_name for these three fields:
|
|
||||||
LC_ID_DYLIB, LC_LOAD_DYLIB, LC_RPATH and parses out the rpaths,
|
|
||||||
dependiencies and library id.
|
|
||||||
Returns these values.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
import machotools
|
f = open(dll.filename, 'rb+')
|
||||||
except ImportError as e:
|
for header in dll.headers:
|
||||||
raise MissingMachotoolsException(e)
|
f.seek(0)
|
||||||
idpath = None
|
dll.write(f)
|
||||||
rpaths = list()
|
f.seek(0, 2)
|
||||||
deps = list()
|
f.flush()
|
||||||
rewriter = machotools.rewriter_factory(path_name)
|
f.close()
|
||||||
if machotools.detect.is_dylib(path_name):
|
except Exception:
|
||||||
idpath = rewriter.install_name
|
pass
|
||||||
rpaths = rewriter.rpaths
|
|
||||||
deps = rewriter.dependencies
|
return
|
||||||
return rpaths, deps, idpath
|
|
||||||
|
|
||||||
|
|
||||||
def strings_contains_installroot(path_name, root_dir):
|
def strings_contains_installroot(path_name, root_dir):
|
||||||
@ -405,15 +400,12 @@ def relocate_macho_binaries(path_names, old_dir, new_dir, allow_root):
|
|||||||
"""
|
"""
|
||||||
placeholder = set_placeholder(old_dir)
|
placeholder = set_placeholder(old_dir)
|
||||||
for path_name in path_names:
|
for path_name in path_names:
|
||||||
deps = set()
|
|
||||||
idpath = None
|
|
||||||
if platform.system().lower() == 'darwin':
|
|
||||||
if path_name.endswith('.o'):
|
if path_name.endswith('.o'):
|
||||||
continue
|
continue
|
||||||
else:
|
if new_dir == old_dir:
|
||||||
|
continue
|
||||||
|
if platform.system().lower() == 'darwin':
|
||||||
rpaths, deps, idpath = macho_get_paths(path_name)
|
rpaths, deps, idpath = macho_get_paths(path_name)
|
||||||
else:
|
|
||||||
rpaths, deps, idpath = machotools_get_paths(path_name)
|
|
||||||
# one pass to replace placeholder
|
# one pass to replace placeholder
|
||||||
(n_rpaths,
|
(n_rpaths,
|
||||||
n_deps,
|
n_deps,
|
||||||
@ -430,16 +422,12 @@ def relocate_macho_binaries(path_names, old_dir, new_dir, allow_root):
|
|||||||
n_rpaths,
|
n_rpaths,
|
||||||
n_deps,
|
n_deps,
|
||||||
n_idpath)
|
n_idpath)
|
||||||
if platform.system().lower() == 'darwin':
|
|
||||||
modify_macho_object(path_name,
|
modify_macho_object(path_name,
|
||||||
rpaths, deps, idpath,
|
rpaths, deps, idpath,
|
||||||
new_rpaths, new_deps, new_idpath)
|
new_rpaths, new_deps, new_idpath)
|
||||||
else:
|
else:
|
||||||
modify_object_machotools(path_name,
|
modify_object_macholib(path_name, placeholder, new_dir)
|
||||||
rpaths, deps, idpath,
|
modify_object_macholib(path_name, old_dir, new_dir)
|
||||||
new_rpaths, new_deps, new_idpath)
|
|
||||||
|
|
||||||
if not new_dir == old_dir:
|
|
||||||
if len(new_dir) <= len(old_dir):
|
if len(new_dir) <= len(old_dir):
|
||||||
replace_prefix_bin(path_name, old_dir, new_dir)
|
replace_prefix_bin(path_name, old_dir, new_dir)
|
||||||
else:
|
else:
|
||||||
@ -498,21 +486,13 @@ def make_macho_binaries_relative(cur_path_names, orig_path_names, old_dir,
|
|||||||
idpath = None
|
idpath = None
|
||||||
if platform.system().lower() == 'darwin':
|
if platform.system().lower() == 'darwin':
|
||||||
(rpaths, deps, idpath) = macho_get_paths(cur_path)
|
(rpaths, deps, idpath) = macho_get_paths(cur_path)
|
||||||
else:
|
|
||||||
(rpaths, deps, idpath) = machotools_get_paths(cur_path)
|
|
||||||
(new_rpaths,
|
(new_rpaths,
|
||||||
new_deps,
|
new_deps,
|
||||||
new_idpath) = macho_make_paths_relative(orig_path, old_dir,
|
new_idpath) = macho_make_paths_relative(orig_path, old_dir,
|
||||||
rpaths, deps, idpath)
|
rpaths, deps, idpath)
|
||||||
if platform.system().lower() == 'darwin':
|
|
||||||
modify_macho_object(cur_path,
|
modify_macho_object(cur_path,
|
||||||
rpaths, deps, idpath,
|
rpaths, deps, idpath,
|
||||||
new_rpaths, new_deps, new_idpath)
|
new_rpaths, new_deps, new_idpath)
|
||||||
else:
|
|
||||||
modify_object_machotools(cur_path,
|
|
||||||
rpaths, deps, idpath,
|
|
||||||
new_rpaths, new_deps, new_idpath)
|
|
||||||
|
|
||||||
if (not allow_root and
|
if (not allow_root and
|
||||||
not file_is_relocatable(cur_path)):
|
not file_is_relocatable(cur_path)):
|
||||||
raise InstallRootStringException(cur_path, old_dir)
|
raise InstallRootStringException(cur_path, old_dir)
|
||||||
|
Loading…
Reference in New Issue
Block a user