Skip to content

Commit d0ba53f

Browse files
committed
Save current RPATHS in buildinfo dictionary. Remove RPATHS from binaries for later addition
1 parent ff89390 commit d0ba53f

File tree

2 files changed

+92
-25
lines changed

2 files changed

+92
-25
lines changed

lib/spack/spack/binary_distribution.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
55

66
import os
7+
import platform
78
import re
89
import tarfile
910
import shutil
@@ -27,7 +28,7 @@
2728
from spack.stage import Stage
2829
from spack.util.gpg import Gpg
2930
from spack.util.web import spider, read_from_url
30-
from spack.util.executable import ProcessError
31+
from spack.util.executable import Executable, ProcessError
3132

3233

3334
_build_cache_relative_path = 'build_cache'
@@ -162,6 +163,18 @@ def write_buildinfo_file(prefix, workdir, rel=False):
162163
rel_path_name = os.path.relpath(path_name, prefix)
163164
text_to_relocate.append(rel_path_name)
164165

166+
patchelf = Executable(relocate.get_patchelf())
167+
old_rpaths = set()
168+
for f in binary_to_relocate:
169+
filename='%s/%s' % (prefix, f)
170+
if platform.system().lower() == 'linux':
171+
rpaths = patchelf('--print-rpath', filename, output=str).strip()
172+
old_rpaths.update(rpaths.split(':'))
173+
if platform.system().lower() == 'darwin':
174+
rpaths, deps, idpath = relocate.macho_get_paths(filename)
175+
old_rpaths.update(rpaths)
176+
177+
165178
# Create buildinfo data and write it to disk
166179
buildinfo = {}
167180
buildinfo['relative_rpaths'] = rel
@@ -172,6 +185,8 @@ def write_buildinfo_file(prefix, workdir, rel=False):
172185
buildinfo['relocate_textfiles'] = text_to_relocate
173186
buildinfo['relocate_binaries'] = binary_to_relocate
174187
buildinfo['relocate_links'] = link_to_relocate
188+
buildinfo['orig_rpaths'] = old_rpaths
189+
tty.debug('buildinfo:\n%s' % buildinfo)
175190
filename = buildinfo_file_name(workdir)
176191
with open(filename, 'w') as outfile:
177192
outfile.write(syaml.dump(buildinfo, default_flow_style=True))
@@ -425,10 +440,10 @@ def make_package_relative(workdir, spec, allow_root):
425440
orig_path_names.append(os.path.join(prefix, filename))
426441
cur_path_names.append(os.path.join(workdir, filename))
427442
if spec.architecture.platform == 'darwin':
428-
relocate.make_macho_binary_relative(cur_path_names, orig_path_names,
443+
relocate.make_macho_binaries_relative(cur_path_names, orig_path_names,
429444
old_path, allow_root)
430445
else:
431-
relocate.make_elf_binary_relative(cur_path_names, orig_path_names,
446+
relocate.make_elf_binaries_relative(cur_path_names, orig_path_names,
432447
old_path, allow_root)
433448
orig_path_names = list()
434449
cur_path_names = list()
@@ -440,15 +455,24 @@ def make_package_relative(workdir, spec, allow_root):
440455

441456
def make_package_placeholder(workdir, spec, allow_root):
442457
"""
443-
Check if package binaries are relocatable
444-
Change links to placeholder links
458+
Remove rpaths in the install root for later replacement.
459+
Check if package binaries are relocatable.
460+
Change links to placeholder links.
445461
"""
446462
prefix = spec.prefix
447463
buildinfo = read_buildinfo_file(workdir)
464+
old_path = buildinfo['buildpath']
448465
cur_path_names = list()
466+
orig_path_names = list()
449467
for filename in buildinfo['relocate_binaries']:
450468
cur_path_names.append(os.path.join(workdir, filename))
451469
relocate.check_files_relocatable(cur_path_names, allow_root)
470+
if spec.architecture.platform == 'darwin':
471+
relocate.make_macho_binaries_clean(cur_path_names, orig_path_names,
472+
old_path, allow_root)
473+
else:
474+
relocate.make_elf_binaries_clean(cur_path_names, orig_path_names,
475+
old_path, allow_root)
452476

453477
cur_path_names = list()
454478
for filename in buildinfo.get('relocate_links', []):
@@ -488,10 +512,10 @@ def relocate_package(workdir, spec, allow_root):
488512
path_name = os.path.join(workdir, filename)
489513
path_names.add(path_name)
490514
if spec.architecture.platform == 'darwin':
491-
relocate.relocate_macho_binaries(path_names, old_path, new_path,
515+
relocate.relocate_macho_binaries(path_names, rpaths, old_path, new_path,
492516
allow_root)
493517
else:
494-
relocate.relocate_elf_binaries(path_names, old_path, new_path,
518+
relocate.relocate_elf_binaries(path_names, rpaths, old_path, new_path,
495519
allow_root)
496520
path_names = set()
497521
for filename in buildinfo.get('relocate_links', []):

lib/spack/spack/relocate.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,8 @@ def modify_macho_object(cur_path, rpaths, deps, idpath,
262262
args.extend(['-id', new_idpath])
263263

264264
for orig, new in zip(deps, new_deps):
265-
args.extend(['-change', orig, new])
266-
265+
if not orig == new:
266+
args.extend(['-change', orig, new])
267267
for orig in list(set(rpaths)):
268268
args.extend(['-delete_rpath', orig])
269269
for new in list(set(new_rpaths)):
@@ -285,6 +285,8 @@ def modify_object_machotools(cur_path, rpaths, deps, idpath,
285285
The old install dir in LC_RPATH is replaced with the new install dir using
286286
using py-machotools
287287
"""
288+
if cur_path.endswith('.o'): return
289+
tty.debug('Running machotools on %s\n' %cur_path)
288290
try:
289291
import machotools
290292
except ImportError as e:
@@ -293,8 +295,9 @@ def modify_object_machotools(cur_path, rpaths, deps, idpath,
293295
if machotools.detect.is_dylib(cur_path):
294296
rewriter.install_name = new_idpath
295297
for orig, new in zip(deps, new_deps):
296-
rewriter.change_dependency(orig, new)
297-
for orig, new in zip(rpaths, new_rpaths):
298+
if not orig == new:
299+
rewriter.change_dependency(orig, new)
300+
for new in list(set(new_rpaths)):
298301
rewriter.append_rpath(new)
299302
rewriter.commit()
300303
return
@@ -393,15 +396,13 @@ def replace(match):
393396
f.truncate()
394397

395398

396-
def relocate_macho_binaries(path_names, old_dir, new_dir, allow_root):
399+
def relocate_macho_binaries(path_names, rpaths, old_dir, new_dir, allow_root):
397400
"""
398401
Change old_dir to new_dir in RPATHs of elf or mach-o files
399402
Account for the case where old_dir is now a placeholder
400403
"""
401404
placeholder = set_placeholder(old_dir)
402-
403405
for path_name in path_names:
404-
rpaths = set()
405406
deps = set()
406407
idpath = ""
407408
if platform.system().lower() == 'darwin':
@@ -431,17 +432,20 @@ def relocate_macho_binaries(path_names, old_dir, new_dir, allow_root):
431432
modify_macho_object(path_name,
432433
rpaths, deps, idpath,
433434
new_rpaths, new_deps, new_idpath)
435+
# only try binary string replacement in mach-o binaries
436+
# on macOS
437+
if len(new_dir) <= len(old_dir):
438+
replace_prefix_bin(path_name, old_dir, new_dir)
439+
else:
440+
tty.warn('Cannot do a binary string replacement'
441+
' with padding for %s'
442+
' because %s is longer than %s' %
443+
(path_name, new_dir, old_dir))
434444
else:
435445
modify_object_machotools(path_name,
436446
rpaths, deps, idpath,
437447
new_rpaths, new_deps, new_idpath)
438-
if len(new_dir) <= len(old_dir):
439-
replace_prefix_bin(path_name, old_dir, new_dir)
440-
else:
441-
tty.warn('Cannot do a binary string replacement'
442-
' with padding for %s'
443-
' because %s is longer than %s' %
444-
(path_name, new_dir, old_dir))
448+
445449

446450

447451
def relocate_elf_binaries(path_names, old_dir, new_dir, allow_root):
@@ -481,7 +485,7 @@ def make_link_relative(cur_path_names, orig_path_names):
481485
os.symlink(new_src, cur_path)
482486

483487

484-
def make_macho_binary_relative(cur_path_names, orig_path_names, old_dir,
488+
def make_macho_binaries_relative(cur_path_names, orig_path_names, old_dir,
485489
allow_root):
486490
"""
487491
Replace old RPATHs with paths relative to old_dir in binary files
@@ -508,11 +512,34 @@ def make_macho_binary_relative(cur_path_names, orig_path_names, old_dir,
508512
new_rpaths, new_deps, new_idpath)
509513

510514
if (not allow_root and
511-
not file_is_relocatable(cur_path, old_dir)):
515+
not file_is_relocatable(cur_path)):
512516
raise InstallRootStringException(cur_path, old_dir)
513517

518+
def make_macho_binaries_clean(cur_path_names, orig_path_names, old_dir,
519+
allow_root):
520+
"""
521+
Remove RPATHs in mach-o binary files for later replacement
522+
"""
523+
for cur_path in cur_path_names:
524+
rpaths = set()
525+
deps = set()
526+
idpath = ""
527+
if platform.system().lower() == 'darwin':
528+
(rpaths, deps, idpath) = macho_get_paths(cur_path)
529+
modify_macho_object(cur_path,
530+
rpaths, deps, idpath,
531+
list(), deps, idpath)
532+
else:
533+
(rpaths, deps, idpath) = machotools_get_paths(cur_path)
534+
modify_object_machotools(cur_path,
535+
rpaths, deps, idpath,
536+
list(), deps, idpath)
537+
538+
if (not allow_root and
539+
not file_is_relocatable(cur_path)):
540+
raise InstallRootStringException(cur_path, old_dir)
514541

515-
def make_elf_binary_relative(cur_path_names, orig_path_names, old_dir,
542+
def make_elf_binaries_relative(cur_path_names, orig_path_names, old_dir,
516543
allow_root):
517544
"""
518545
Replace old RPATHs with paths relative to old_dir in binary files
@@ -524,9 +551,25 @@ def make_elf_binary_relative(cur_path_names, orig_path_names, old_dir,
524551
orig_rpaths)
525552
modify_elf_object(cur_path, new_rpaths)
526553
if (not allow_root and
527-
not file_is_relocatable(cur_path, old_dir)):
554+
not file_is_relocatable(cur_path)):
528555
raise InstallRootStringException(cur_path, old_dir)
529556

557+
def make_elf_binaries_clean(cur_path_names, orig_path_names, old_dir,
558+
allow_root):
559+
"""
560+
Remove RPATHS in elf binary files for later replacement
561+
"""
562+
for cur_path in cur_path_names:
563+
orig_rpaths = get_existing_elf_rpaths(cur_path)
564+
new_rpaths=set()
565+
if orig_rpaths:
566+
for rpath in orig_rpaths:
567+
if not old_dir in rpath:
568+
new_rpaths.add(rpath)
569+
modify_elf_object(cur_path, new_rpaths)
570+
if (not allow_root and
571+
not file_is_relocatable(cur_path)):
572+
raise InstallRootStringException(cur_path, old_dir)
530573

531574
def check_files_relocatable(cur_path_names, allow_root):
532575
"""

0 commit comments

Comments
 (0)