aboutsummaryrefslogtreecommitdiffstats
path: root/classes/chrpath.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'classes/chrpath.bbclass')
-rw-r--r--classes/chrpath.bbclass134
1 files changed, 134 insertions, 0 deletions
diff --git a/classes/chrpath.bbclass b/classes/chrpath.bbclass
new file mode 100644
index 0000000..873a5b5
--- /dev/null
+++ b/classes/chrpath.bbclass
@@ -0,0 +1,134 @@
+CHRPATH_BIN ?= "chrpath"
+PREPROCESS_RELOCATE_DIRS ?= ""
+
+def process_file_linux(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
+ import subprocess, oe.qa
+
+ with oe.qa.ELFFile(fpath) as elf:
+ try:
+ elf.open()
+ except oe.qa.NotELFFileError:
+ return
+
+ try:
+ out = subprocess.check_output([cmd, "-l", fpath], universal_newlines=True)
+ except subprocess.CalledProcessError:
+ return
+
+ # 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))
+ try:
+ subprocess.check_output([cmd, "-r", args, fpath],
+ stderr=subprocess.PIPE, universal_newlines=True)
+ except subprocess.CalledProcessError as e:
+ bb.fatal("chrpath command failed with exit code %d:\n%s\n%s" % (e.returncode, e.stdout, e.stderr))
+
+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, universal_newlines=True)
+ 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)
+