blob: 16729dcf611c2f00df7befe3908233eff9e0f5e1 [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007CHRPATH_BIN ?= "chrpath"
8PREPROCESS_RELOCATE_DIRS ?= ""
9
Brad Bishopacc069e2019-09-13 06:48:36 -040010def process_file_linux(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
Andrew Geissler82c905d2020-04-13 13:39:40 -050011 import subprocess, oe.qa
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012
Andrew Geissler82c905d2020-04-13 13:39:40 -050013 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 Williamsc124f4f2015-09-15 14:41:29 -050022 return
23
24 # Handle RUNPATH as well as RPATH
Patrick Williamsc0f7c042017-02-23 20:41:17 -060025 out = out.replace("RUNPATH=","RPATH=")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026 # Throw away everything other than the rpath list
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027 curr_rpath = out.partition("RPATH=")[2]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 #bb.note("Current rpath for %s is %s" % (fpath, curr_rpath.strip()))
Brad Bishop6e60e8b2018-02-01 10:27:11 -050029 rpaths = curr_rpath.strip().split(":")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030 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 Bishop6e60e8b2018-02-01 10:27:11 -050035 new_rpaths.append(rpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036 continue
37 rpath = os.path.normpath(rpath)
38 if baseprefix not in rpath and tmpdir not in rpath:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050039 # 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 Williamsc124f4f2015-09-15 14:41:29 -050045 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -050046 new_rpaths.append("$ORIGIN/" + os.path.relpath(rpath, os.path.dirname(fpath.replace(rootdir, "/"))))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050047 modified = True
48
49 # if we have modified some rpaths call chrpath to update the binary
50 if modified:
Brad Bishopacc069e2019-09-13 06:48:36 -040051 if break_hardlinks:
52 bb.utils.break_hardlinks(fpath)
53
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054 args = ":".join(new_rpaths)
55 #bb.note("Setting rpath for %s to %s" %(fpath, args))
Andrew Geissler82c905d2020-04-13 13:39:40 -050056 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 Williamsc124f4f2015-09-15 14:41:29 -050061
Brad Bishopacc069e2019-09-13 06:48:36 -040062def process_file_darwin(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063 import subprocess as sub
64
Patrick Williams56b44a92024-01-19 08:49:29 -060065 p = sub.Popen([d.expand("${HOST_PREFIX}otool"), '-L', fpath],stdout=sub.PIPE,stderr=sub.PIPE, text=True)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060066 out, err = p.communicate()
67 # If returned successfully, process stdout for results
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 if p.returncode != 0:
69 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -060070 for l in out.split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071 if "(compatibility" not in l:
72 continue
73 rpath = l.partition("(compatibility")[0].strip()
74 if baseprefix not in rpath:
75 continue
76
Brad Bishopacc069e2019-09-13 06:48:36 -040077 if break_hardlinks:
78 bb.utils.break_hardlinks(fpath)
79
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080 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 Williamsc0f7c042017-02-23 20:41:17 -060082 out, err = p.communicate()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083
Brad Bishopacc069e2019-09-13 06:48:36 -040084def process_dir(rootdir, directory, d, break_hardlinks = False):
Andrew Geissler82c905d2020-04-13 13:39:40 -050085 bb.debug(2, "Checking %s for binaries to process" % directory)
86 if not os.path.exists(directory):
87 return
88
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089 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 Bishop6e60e8b2018-02-01 10:27:11 -050095 hostos = d.getVar("HOST_OS")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097 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 Bishopacc069e2019-09-13 06:48:36 -0400114 process_dir(rootdir, fpath, d, break_hardlinks = break_hardlinks)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500115 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 Bishopacc069e2019-09-13 06:48:36 -0400127
128 process_file(cmd, fpath, rootdir, baseprefix, tmpdir, d, break_hardlinks = break_hardlinks)
129
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500130 if perms:
131 os.chmod(fpath, perms)
132
133def 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