mirror of
https://git.yoctoproject.org/poky
synced 2026-02-12 03:33:02 +01:00
Instead of trying to change the RPATH in every file under the binary directories, check that the file is an ELF first. This means that we don't attempt to change the RPATH on the entire Python standard library, for example. Also return early if the directory to iterate doesn't exist. (From OE-Core rev: 977f4baacf7c8d06d9cfe5c5e39bb8bc19f27028) Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
137 lines
5.0 KiB
Plaintext
137 lines
5.0 KiB
Plaintext
CHRPATH_BIN ?= "chrpath"
|
|
PREPROCESS_RELOCATE_DIRS ?= ""
|
|
|
|
def process_file_linux(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
|
|
import subprocess as sub, oe.qa
|
|
|
|
with oe.qa.ELFFile(fpath) as elf:
|
|
try:
|
|
elf.open()
|
|
except oe.qa.NotELFFileError:
|
|
return
|
|
|
|
p = sub.Popen([cmd, '-l', fpath],stdout=sub.PIPE,stderr=sub.PIPE)
|
|
out, err = p.communicate()
|
|
# If returned successfully, process stdout for results
|
|
if p.returncode != 0:
|
|
return
|
|
|
|
out = out.decode('utf-8')
|
|
|
|
# Handle RUNPATH as well as RPATH
|
|
out = out.replace("RUNPATH=","RPATH=")
|
|
# Throw away everything other than the rpath list
|
|
curr_rpath = out.partition("RPATH=")[2]
|
|
#bb.note("Current rpath for %s is %s" % (fpath, curr_rpath.strip()))
|
|
rpaths = curr_rpath.strip().split(":")
|
|
new_rpaths = []
|
|
modified = False
|
|
for rpath in rpaths:
|
|
# If rpath is already dynamic copy it to new_rpath and continue
|
|
if rpath.find("$ORIGIN") != -1:
|
|
new_rpaths.append(rpath)
|
|
continue
|
|
rpath = os.path.normpath(rpath)
|
|
if baseprefix not in rpath and tmpdir not in rpath:
|
|
# Skip standard search paths
|
|
if rpath in ['/lib', '/usr/lib', '/lib64/', '/usr/lib64']:
|
|
bb.warn("Skipping RPATH %s as is a standard search path for %s" % (rpath, fpath))
|
|
modified = True
|
|
continue
|
|
new_rpaths.append(rpath)
|
|
continue
|
|
new_rpaths.append("$ORIGIN/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/"))))
|
|
modified = True
|
|
|
|
# if we have modified some rpaths call chrpath to update the binary
|
|
if modified:
|
|
if break_hardlinks:
|
|
bb.utils.break_hardlinks(fpath)
|
|
|
|
args = ":".join(new_rpaths)
|
|
#bb.note("Setting rpath for %s to %s" %(fpath, args))
|
|
p = sub.Popen([cmd, '-r', args, fpath],stdout=sub.PIPE,stderr=sub.PIPE)
|
|
out, err = p.communicate()
|
|
if p.returncode != 0:
|
|
bb.fatal("%s: chrpath command failed with exit code %d:\n%s%s" % (d.getVar('PN'), p.returncode, out, err))
|
|
|
|
def process_file_darwin(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
|
|
import subprocess as sub
|
|
|
|
p = sub.Popen([d.expand("${HOST_PREFIX}otool"), '-L', fpath],stdout=sub.PIPE,stderr=sub.PIPE)
|
|
out, err = p.communicate()
|
|
# If returned successfully, process stdout for results
|
|
if p.returncode != 0:
|
|
return
|
|
for l in out.split("\n"):
|
|
if "(compatibility" not in l:
|
|
continue
|
|
rpath = l.partition("(compatibility")[0].strip()
|
|
if baseprefix not in rpath:
|
|
continue
|
|
|
|
if break_hardlinks:
|
|
bb.utils.break_hardlinks(fpath)
|
|
|
|
newpath = "@loader_path/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/")))
|
|
p = sub.Popen([d.expand("${HOST_PREFIX}install_name_tool"), '-change', rpath, newpath, fpath],stdout=sub.PIPE,stderr=sub.PIPE)
|
|
out, err = p.communicate()
|
|
|
|
def process_dir(rootdir, directory, d, break_hardlinks = False):
|
|
bb.debug(2, "Checking %s for binaries to process" % directory)
|
|
if not os.path.exists(directory):
|
|
return
|
|
|
|
import stat
|
|
|
|
rootdir = os.path.normpath(rootdir)
|
|
cmd = d.expand('${CHRPATH_BIN}')
|
|
tmpdir = os.path.normpath(d.getVar('TMPDIR', False))
|
|
baseprefix = os.path.normpath(d.expand('${base_prefix}'))
|
|
hostos = d.getVar("HOST_OS")
|
|
|
|
if "linux" in hostos:
|
|
process_file = process_file_linux
|
|
elif "darwin" in hostos:
|
|
process_file = process_file_darwin
|
|
else:
|
|
# Relocations not supported
|
|
return
|
|
|
|
dirs = os.listdir(directory)
|
|
for file in dirs:
|
|
fpath = directory + "/" + file
|
|
fpath = os.path.normpath(fpath)
|
|
if os.path.islink(fpath):
|
|
# Skip symlinks
|
|
continue
|
|
|
|
if os.path.isdir(fpath):
|
|
process_dir(rootdir, fpath, d, break_hardlinks = break_hardlinks)
|
|
else:
|
|
#bb.note("Testing %s for relocatability" % fpath)
|
|
|
|
# We need read and write permissions for chrpath, if we don't have
|
|
# them then set them temporarily. Take a copy of the files
|
|
# permissions so that we can restore them afterwards.
|
|
perms = os.stat(fpath)[stat.ST_MODE]
|
|
if os.access(fpath, os.W_OK|os.R_OK):
|
|
perms = None
|
|
else:
|
|
# Temporarily make the file writeable so we can chrpath it
|
|
os.chmod(fpath, perms|stat.S_IRWXU)
|
|
|
|
process_file(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = break_hardlinks)
|
|
|
|
if perms:
|
|
os.chmod(fpath, perms)
|
|
|
|
def rpath_replace (path, d):
|
|
bindirs = d.expand("${bindir} ${sbindir} ${base_sbindir} ${base_bindir} ${libdir} ${base_libdir} ${libexecdir} ${PREPROCESS_RELOCATE_DIRS}").split()
|
|
|
|
for bindir in bindirs:
|
|
#bb.note ("Processing directory " + bindir)
|
|
directory = path + "/" + bindir
|
|
process_dir (path, directory, d)
|
|
|