Files
poky/meta/classes/chrpath.bbclass
Ross Burton 7785c41d0b chrpath: do less work
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>
2019-12-28 23:25:41 +00:00

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)