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