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