1CHRPATH_BIN ?= "chrpath" 2PREPROCESS_RELOCATE_DIRS ?= "" 3 4def process_file_linux(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False): 5 import subprocess, oe.qa 6 7 with oe.qa.ELFFile(fpath) as elf: 8 try: 9 elf.open() 10 except oe.qa.NotELFFileError: 11 return 12 13 try: 14 out = subprocess.check_output([cmd, "-l", fpath], universal_newlines=True) 15 except subprocess.CalledProcessError: 16 return 17 18 # Handle RUNPATH as well as RPATH 19 out = out.replace("RUNPATH=","RPATH=") 20 # Throw away everything other than the rpath list 21 curr_rpath = out.partition("RPATH=")[2] 22 #bb.note("Current rpath for %s is %s" % (fpath, curr_rpath.strip())) 23 rpaths = curr_rpath.strip().split(":") 24 new_rpaths = [] 25 modified = False 26 for rpath in rpaths: 27 # If rpath is already dynamic copy it to new_rpath and continue 28 if rpath.find("$ORIGIN") != -1: 29 new_rpaths.append(rpath) 30 continue 31 rpath = os.path.normpath(rpath) 32 if baseprefix not in rpath and tmpdir not in rpath: 33 # Skip standard search paths 34 if rpath in ['/lib', '/usr/lib', '/lib64/', '/usr/lib64']: 35 bb.warn("Skipping RPATH %s as is a standard search path for %s" % (rpath, fpath)) 36 modified = True 37 continue 38 new_rpaths.append(rpath) 39 continue 40 new_rpaths.append("$ORIGIN/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/")))) 41 modified = True 42 43 # if we have modified some rpaths call chrpath to update the binary 44 if modified: 45 if break_hardlinks: 46 bb.utils.break_hardlinks(fpath) 47 48 args = ":".join(new_rpaths) 49 #bb.note("Setting rpath for %s to %s" %(fpath, args)) 50 try: 51 subprocess.check_output([cmd, "-r", args, fpath], 52 stderr=subprocess.PIPE, universal_newlines=True) 53 except subprocess.CalledProcessError as e: 54 bb.fatal("chrpath command failed with exit code %d:\n%s\n%s" % (e.returncode, e.stdout, e.stderr)) 55 56def process_file_darwin(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False): 57 import subprocess as sub 58 59 p = sub.Popen([d.expand("${HOST_PREFIX}otool"), '-L', fpath],stdout=sub.PIPE,stderr=sub.PIPE) 60 out, err = p.communicate() 61 # If returned successfully, process stdout for results 62 if p.returncode != 0: 63 return 64 for l in out.split("\n"): 65 if "(compatibility" not in l: 66 continue 67 rpath = l.partition("(compatibility")[0].strip() 68 if baseprefix not in rpath: 69 continue 70 71 if break_hardlinks: 72 bb.utils.break_hardlinks(fpath) 73 74 newpath = "@loader_path/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/"))) 75 p = sub.Popen([d.expand("${HOST_PREFIX}install_name_tool"), '-change', rpath, newpath, fpath],stdout=sub.PIPE,stderr=sub.PIPE) 76 out, err = p.communicate() 77 78def process_dir(rootdir, directory, d, break_hardlinks = False): 79 bb.debug(2, "Checking %s for binaries to process" % directory) 80 if not os.path.exists(directory): 81 return 82 83 import stat 84 85 rootdir = os.path.normpath(rootdir) 86 cmd = d.expand('${CHRPATH_BIN}') 87 tmpdir = os.path.normpath(d.getVar('TMPDIR', False)) 88 baseprefix = os.path.normpath(d.expand('${base_prefix}')) 89 hostos = d.getVar("HOST_OS") 90 91 if "linux" in hostos: 92 process_file = process_file_linux 93 elif "darwin" in hostos: 94 process_file = process_file_darwin 95 else: 96 # Relocations not supported 97 return 98 99 dirs = os.listdir(directory) 100 for file in dirs: 101 fpath = directory + "/" + file 102 fpath = os.path.normpath(fpath) 103 if os.path.islink(fpath): 104 # Skip symlinks 105 continue 106 107 if os.path.isdir(fpath): 108 process_dir(rootdir, fpath, d, break_hardlinks = break_hardlinks) 109 else: 110 #bb.note("Testing %s for relocatability" % fpath) 111 112 # We need read and write permissions for chrpath, if we don't have 113 # them then set them temporarily. Take a copy of the files 114 # permissions so that we can restore them afterwards. 115 perms = os.stat(fpath)[stat.ST_MODE] 116 if os.access(fpath, os.W_OK|os.R_OK): 117 perms = None 118 else: 119 # Temporarily make the file writeable so we can chrpath it 120 os.chmod(fpath, perms|stat.S_IRWXU) 121 122 process_file(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = break_hardlinks) 123 124 if perms: 125 os.chmod(fpath, perms) 126 127def rpath_replace (path, d): 128 bindirs = d.expand("${bindir} ${sbindir} ${base_sbindir} ${base_bindir} ${libdir} ${base_libdir} ${libexecdir} ${PREPROCESS_RELOCATE_DIRS}").split() 129 130 for bindir in bindirs: 131 #bb.note ("Processing directory " + bindir) 132 directory = path + "/" + bindir 133 process_dir (path, directory, d) 134 135