This fixes a bug in creating rpaths relative to $ORIGIN on linux. (#5726)

* This fixes a bug in creating rpaths relative to  on linux.

* fix for macOS as well

* found in testing

* flake8

* fix testing on macOS

* flake8
This commit is contained in:
Patrick Gartung 2017-10-13 21:13:07 -05:00 committed by Todd Gamblin
parent 4d3424a5d4
commit 2e1aa0a5e9
3 changed files with 34 additions and 29 deletions

View File

@ -240,24 +240,24 @@ def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
else: else:
raise NoOverwriteException(str(specfile_path)) raise NoOverwriteException(str(specfile_path))
# make a copy of the install directory to work with # make a copy of the install directory to work with
prefix = join_path(outdir, os.path.basename(spec.prefix)) workdir = join_path(outdir, os.path.basename(spec.prefix))
if os.path.exists(prefix): if os.path.exists(workdir):
shutil.rmtree(prefix) shutil.rmtree(workdir)
install_tree(spec.prefix, prefix) install_tree(spec.prefix, workdir)
# create info for later relocation and create tar # create info for later relocation and create tar
write_buildinfo_file(prefix) write_buildinfo_file(workdir)
# optinally make the paths in the binaries relative to each other # optinally make the paths in the binaries relative to each other
# in the spack install tree before creating tarball # in the spack install tree before creating tarball
if rel: if rel:
make_package_relative(prefix) make_package_relative(workdir, spec.prefix)
# create compressed tarball of the install prefix # create compressed tarball of the install prefix
with closing(tarfile.open(tarfile_path, 'w:gz')) as tar: with closing(tarfile.open(tarfile_path, 'w:gz')) as tar:
tar.add(name='%s' % prefix, tar.add(name='%s' % workdir,
arcname='%s' % os.path.basename(prefix)) arcname='%s' % os.path.basename(workdir))
# remove copy of install directory # remove copy of install directory
shutil.rmtree(prefix) shutil.rmtree(workdir)
# get the sha256 checksum of the tarball # get the sha256 checksum of the tarball
checksum = checksum_tarball(tarfile_path) checksum = checksum_tarball(tarfile_path)
@ -327,15 +327,16 @@ def download_tarball(spec):
return None return None
def make_package_relative(prefix): def make_package_relative(workdir, prefix):
""" """
Change paths in binaries to relative paths Change paths in binaries to relative paths
""" """
buildinfo = read_buildinfo_file(prefix) buildinfo = read_buildinfo_file(workdir)
old_path = buildinfo['buildpath'] old_path = buildinfo['buildpath']
for filename in buildinfo['relocate_binaries']: for filename in buildinfo['relocate_binaries']:
path_name = os.path.join(prefix, filename) orig_path_name = os.path.join(prefix, filename)
relocate.make_binary_relative(path_name, old_path) cur_path_name = os.path.join(workdir, filename)
relocate.make_binary_relative(cur_path_name, orig_path_name, old_path)
def relocate_package(prefix): def relocate_package(prefix):

View File

@ -158,7 +158,8 @@ def macho_replace_paths(old_dir, new_dir, rpaths, deps, idpath):
return nrpaths, ndeps, id return nrpaths, ndeps, id
def modify_macho_object(path_name, old_dir, new_dir, relative): def modify_macho_object(cur_path_name, orig_path_name, old_dir, new_dir,
relative):
""" """
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.
@ -170,14 +171,14 @@ def modify_macho_object(path_name, old_dir, new_dir, relative):
install_name_tool -rpath old new binary install_name_tool -rpath old new binary
""" """
# avoid error message for libgcc_s # avoid error message for libgcc_s
if 'libgcc_' in path_name: if 'libgcc_' in cur_path_name:
return return
rpaths, deps, idpath = macho_get_paths(path_name) rpaths, deps, idpath = macho_get_paths(cur_path_name)
id = None id = None
nrpaths = [] nrpaths = []
ndeps = [] ndeps = []
if relative: if relative:
nrpaths, ndeps, id = macho_make_paths_relative(path_name, nrpaths, ndeps, id = macho_make_paths_relative(orig_path_name,
old_dir, rpaths, old_dir, rpaths,
deps, idpath) deps, idpath)
else: else:
@ -185,13 +186,13 @@ def modify_macho_object(path_name, old_dir, new_dir, relative):
deps, idpath) deps, idpath)
install_name_tool = Executable('install_name_tool') install_name_tool = Executable('install_name_tool')
if id: if id:
install_name_tool('-id', id, path_name, output=str, err=str) install_name_tool('-id', id, cur_path_name, output=str, err=str)
for orig, new in zip(deps, ndeps): for orig, new in zip(deps, ndeps):
install_name_tool('-change', orig, new, path_name) install_name_tool('-change', orig, new, cur_path_name)
for orig, new in zip(rpaths, nrpaths): for orig, new in zip(rpaths, nrpaths):
install_name_tool('-rpath', orig, new, path_name) install_name_tool('-rpath', orig, new, cur_path_name)
return return
@ -256,17 +257,18 @@ def relocate_binary(path_name, old_dir, new_dir):
tty.die("Relocation not implemented for %s" % platform.system()) tty.die("Relocation not implemented for %s" % platform.system())
def make_binary_relative(path_name, old_dir): def make_binary_relative(cur_path_name, orig_path_name, old_dir):
""" """
Make RPATHs relative to old_dir in given elf or mach-o file path_name Make RPATHs relative to old_dir in given elf or mach-o file path_name
""" """
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
new_dir = '' new_dir = ''
modify_macho_object(path_name, old_dir, new_dir, relative=True) modify_macho_object(cur_path_name, orig_path_name, old_dir, new_dir,
relative=True)
elif platform.system() == 'Linux': elif platform.system() == 'Linux':
orig_rpaths = get_existing_elf_rpaths(path_name) orig_rpaths = get_existing_elf_rpaths(cur_path_name)
new_rpaths = get_relative_rpaths(path_name, old_dir, orig_rpaths) new_rpaths = get_relative_rpaths(orig_path_name, old_dir, orig_rpaths)
modify_elf_object(path_name, orig_rpaths, new_rpaths) modify_elf_object(cur_path_name, orig_rpaths, new_rpaths)
else: else:
tty.die("Prelocation not implemented for %s" % platform.system()) tty.die("Prelocation not implemented for %s" % platform.system())

View File

@ -291,11 +291,13 @@ def test_relocate_macho():
assert (needs_binary_relocation('Mach-O') is True) assert (needs_binary_relocation('Mach-O') is True)
macho_get_paths('/bin/bash') macho_get_paths('/bin/bash')
shutil.copyfile('/bin/bash', 'bash') shutil.copyfile('/bin/bash', 'bash')
modify_macho_object('bash', '/usr', '/opt', False) modify_macho_object('bash', '/bin/bash', '/usr', '/opt', False)
modify_macho_object('bash', '/usr', '/opt', True) modify_macho_object('bash', '/bin/bash', '/usr', '/opt', True)
shutil.copyfile('/usr/lib/libncurses.5.4.dylib', 'libncurses.5.4.dylib') shutil.copyfile('/usr/lib/libncurses.5.4.dylib', 'libncurses.5.4.dylib')
modify_macho_object('libncurses.5.4.dylib', '/usr', '/opt', False) modify_macho_object('libncurses.5.4.dylib',
modify_macho_object('libncurses.5.4.dylib', '/usr', '/opt', True) '/usr/lib/libncurses.5.4.dylib', '/usr', '/opt', False)
modify_macho_object('libncurses.5.4.dylib',
'/usr/lib/libncurses.5.4.dylib', '/usr', '/opt', True)
@pytest.mark.skipif(sys.platform != 'linux2', @pytest.mark.skipif(sys.platform != 'linux2',