blob: 26b984c4dbb252f8fa64f57e44ff08eac7b0866c [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001CHRPATH_BIN ?= "chrpath"
2PREPROCESS_RELOCATE_DIRS ?= ""
3
Brad Bishopacc069e2019-09-13 06:48:36 -04004def process_file_linux(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
Andrew Geissler82c905d2020-04-13 13:39:40 -05005 import subprocess, oe.qa
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006
Andrew Geissler82c905d2020-04-13 13:39:40 -05007 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:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016 return
17
18 # Handle RUNPATH as well as RPATH
Patrick Williamsc0f7c042017-02-23 20:41:17 -060019 out = out.replace("RUNPATH=","RPATH=")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050020 # Throw away everything other than the rpath list
Patrick Williamsc0f7c042017-02-23 20:41:17 -060021 curr_rpath = out.partition("RPATH=")[2]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022 #bb.note("Current rpath for %s is %s" % (fpath, curr_rpath.strip()))
Brad Bishop6e60e8b2018-02-01 10:27:11 -050023 rpaths = curr_rpath.strip().split(":")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024 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:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050029 new_rpaths.append(rpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030 continue
31 rpath = os.path.normpath(rpath)
32 if baseprefix not in rpath and tmpdir not in rpath:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033 # 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -050040 new_rpaths.append("$ORIGIN/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/"))))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041 modified = True
42
43 # if we have modified some rpaths call chrpath to update the binary
44 if modified:
Brad Bishopacc069e2019-09-13 06:48:36 -040045 if break_hardlinks:
46 bb.utils.break_hardlinks(fpath)
47
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048 args = ":".join(new_rpaths)
49 #bb.note("Setting rpath for %s to %s" %(fpath, args))
Andrew Geissler82c905d2020-04-13 13:39:40 -050050 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))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055
Brad Bishopacc069e2019-09-13 06:48:36 -040056def process_file_darwin(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050057 import subprocess as sub
58
59 p = sub.Popen([d.expand("${HOST_PREFIX}otool"), '-L', fpath],stdout=sub.PIPE,stderr=sub.PIPE)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060060 out, err = p.communicate()
61 # If returned successfully, process stdout for results
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062 if p.returncode != 0:
63 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -060064 for l in out.split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065 if "(compatibility" not in l:
66 continue
67 rpath = l.partition("(compatibility")[0].strip()
68 if baseprefix not in rpath:
69 continue
70
Brad Bishopacc069e2019-09-13 06:48:36 -040071 if break_hardlinks:
72 bb.utils.break_hardlinks(fpath)
73
Patrick Williamsc124f4f2015-09-15 14:41:29 -050074 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)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076 out, err = p.communicate()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077
Brad Bishopacc069e2019-09-13 06:48:36 -040078def process_dir(rootdir, directory, d, break_hardlinks = False):
Andrew Geissler82c905d2020-04-13 13:39:40 -050079 bb.debug(2, "Checking %s for binaries to process" % directory)
80 if not os.path.exists(directory):
81 return
82
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083 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}'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 hostos = d.getVar("HOST_OS")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090
Patrick Williamsc124f4f2015-09-15 14:41:29 -050091 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):
Brad Bishopacc069e2019-09-13 06:48:36 -0400108 process_dir(rootdir, fpath, d, break_hardlinks = break_hardlinks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109 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)
Brad Bishopacc069e2019-09-13 06:48:36 -0400121
122 process_file(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = break_hardlinks)
123
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124 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