1 |
commit: 71a47b1875141b038489ab87b87f7f5eb1e7332b |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Tue Jul 26 17:23:06 2011 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue Jul 26 17:23:06 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=71a47b18 |
7 |
|
8 |
LinkageMapMachO: sync with LinkageMapELF |
9 |
|
10 |
--- |
11 |
pym/portage/util/_dyn_libs/LinkageMapMachO.py | 153 +++++++++++++++++++------ |
12 |
1 files changed, 116 insertions(+), 37 deletions(-) |
13 |
|
14 |
diff --git a/pym/portage/util/_dyn_libs/LinkageMapMachO.py b/pym/portage/util/_dyn_libs/LinkageMapMachO.py |
15 |
index e64a54d..0e7c333 100644 |
16 |
--- a/pym/portage/util/_dyn_libs/LinkageMapMachO.py |
17 |
+++ b/pym/portage/util/_dyn_libs/LinkageMapMachO.py |
18 |
@@ -27,6 +27,18 @@ class LinkageMapMachO(object): |
19 |
_installname_map_class = slot_dict_class( |
20 |
("consumers", "providers"), prefix="") |
21 |
|
22 |
+ class _obj_properies_class(object): |
23 |
+ |
24 |
+ __slots__ = ("arch", "needed", "install_name", "alt_paths", |
25 |
+ "owner",) |
26 |
+ |
27 |
+ def __init__(self, arch, needed, install_name, alt_paths, owner): |
28 |
+ self.arch = arch |
29 |
+ self.needed = needed |
30 |
+ self.install_name = install_name |
31 |
+ self.alt_paths = alt_paths |
32 |
+ self.owner = owner |
33 |
+ |
34 |
def __init__(self, vardbapi): |
35 |
self._dbapi = vardbapi |
36 |
self._root = self._dbapi.settings['ROOT'] |
37 |
@@ -183,7 +195,7 @@ class LinkageMapMachO(object): |
38 |
# overrides any data from previously installed files. |
39 |
if include_file is not None: |
40 |
for line in grabfile(include_file): |
41 |
- lines.append((include_file, line)) |
42 |
+ lines.append((None, include_file, line)) |
43 |
|
44 |
aux_keys = [self._needed_aux_key] |
45 |
can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) |
46 |
@@ -196,16 +208,16 @@ class LinkageMapMachO(object): |
47 |
needed_file = self._dbapi.getpath(cpv, |
48 |
filename=self._needed_aux_key) |
49 |
for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): |
50 |
- lines.append((needed_file, line)) |
51 |
+ lines.append((cpv, needed_file, line)) |
52 |
finally: |
53 |
if can_lock: |
54 |
self._dbapi.unlock() |
55 |
|
56 |
# have to call scanmacho for preserved libs here as they aren't |
57 |
# registered in NEEDED.MACHO.3 files |
58 |
- plibs = set() |
59 |
+ plibs = {} |
60 |
if preserve_paths is not None: |
61 |
- plibs.update(preserve_paths) |
62 |
+ plibs.update((x, None) for x in preserve_paths) |
63 |
if self._dbapi._plib_registry and \ |
64 |
self._dbapi._plib_registry.hasEntries(): |
65 |
for cpv, items in \ |
66 |
@@ -217,7 +229,7 @@ class LinkageMapMachO(object): |
67 |
# already represented via the preserve_paths |
68 |
# parameter. |
69 |
continue |
70 |
- plibs.update(items) |
71 |
+ plibs.update((x, cpv) for x in items) |
72 |
if plibs: |
73 |
args = [EPREFIX+"/usr/bin/scanmacho", "-qF", "%a;%F;%S;%n"] |
74 |
args.extend(os.path.join(root, x.lstrip("." + os.sep)) \ |
75 |
@@ -249,8 +261,8 @@ class LinkageMapMachO(object): |
76 |
level=logging.ERROR, noiselevel=-1) |
77 |
continue |
78 |
fields[1] = fields[1][root_len:] |
79 |
- plibs.discard(fields[1]) |
80 |
- lines.append(("scanmacho", ";".join(fields))) |
81 |
+ owner = plibs.pop(fields[1], None) |
82 |
+ lines.append((owner, "scanmacho", ";".join(fields))) |
83 |
proc.wait() |
84 |
|
85 |
if plibs: |
86 |
@@ -260,33 +272,39 @@ class LinkageMapMachO(object): |
87 |
# assume that every preserved library has an entry in |
88 |
# self._obj_properties. This is important in order to |
89 |
# prevent findConsumers from raising an unwanted KeyError. |
90 |
- for x in plibs: |
91 |
- lines.append(("plibs", ";".join(['', x, '', '', '']))) |
92 |
+ for x, cpv in plibs.items(): |
93 |
+ lines.append((cpv, "plibs", ";".join(['', x, '', '', '']))) |
94 |
|
95 |
- for location, l in lines: |
96 |
+ # Share identical frozenset instances when available, |
97 |
+ # in order to conserve memory. |
98 |
+ frozensets = {} |
99 |
+ |
100 |
+ for owner, location, l in lines: |
101 |
l = l.rstrip("\n") |
102 |
if not l: |
103 |
continue |
104 |
fields = l.split(";") |
105 |
if len(fields) < 4: |
106 |
- writemsg_level("\nWrong number of fields " + \ |
107 |
- "in %s: %s\n\n" % (location, l), |
108 |
+ writemsg_level(_("\nWrong number of fields " \ |
109 |
+ "in %s: %s\n\n") % (location, l), |
110 |
level=logging.ERROR, noiselevel=-1) |
111 |
continue |
112 |
arch = fields[0] |
113 |
obj = fields[1] |
114 |
install_name = os.path.normpath(fields[2]) |
115 |
- needed = filter(None, fields[3].split(",")) |
116 |
+ needed = frozenset(x for x in fields[3].split(",") if x) |
117 |
+ needed = frozensets.setdefault(needed, needed) |
118 |
|
119 |
obj_key = self._obj_key(obj) |
120 |
indexed = True |
121 |
myprops = obj_properties.get(obj_key) |
122 |
if myprops is None: |
123 |
indexed = False |
124 |
- myprops = (arch, needed, install_name, set()) |
125 |
+ myprops = self._obj_properies_class( |
126 |
+ arch, needed, install_name, [], owner) |
127 |
obj_properties[obj_key] = myprops |
128 |
# All object paths are added into the obj_properties tuple. |
129 |
- myprops[3].add(obj) |
130 |
+ myprops.alt_paths.append(obj) |
131 |
|
132 |
# Don't index the same file more that once since only one |
133 |
# set of data can be correct and therefore mixing data |
134 |
@@ -303,17 +321,22 @@ class LinkageMapMachO(object): |
135 |
installname_map = arch_map.get(install_name) |
136 |
if installname_map is None: |
137 |
installname_map = self._installname_map_class( |
138 |
- providers=set(), consumers=set()) |
139 |
+ providers=[], consumers=[]) |
140 |
arch_map[install_name] = installname_map |
141 |
installname_map.providers.add(obj_key) |
142 |
for needed_installname in needed: |
143 |
installname_map = arch_map.get(needed_installname) |
144 |
if installname_map is None: |
145 |
installname_map = self._installname_map_class( |
146 |
- providers=set(), consumers=set()) |
147 |
+ providers=[], consumers=[]) |
148 |
arch_map[needed_installname] = installname_map |
149 |
installname_map.consumers.add(obj_key) |
150 |
|
151 |
+ for arch, install_names in libs.items(): |
152 |
+ for install_name_node in install_names.values(): |
153 |
+ install_name_node.providers = tuple(set(install_name_node.providers)) |
154 |
+ install_name_node.consumers = tuple(set(install_name_node.consumers)) |
155 |
+ |
156 |
def listBrokenBinaries(self, debug=False): |
157 |
""" |
158 |
Find binaries and their needed install_names, which have no providers. |
159 |
@@ -367,8 +390,13 @@ class LinkageMapMachO(object): |
160 |
if obj_key.file_exists(): |
161 |
# Get the install_name from LinkageMapMachO._obj_properties if |
162 |
# it exists. Otherwise, None. |
163 |
- arch = self._obj_properties.get(obj_key, (None,)*4)[0] |
164 |
- install_name = self._obj_properties.get(obj_key, (None,)*4)[2] |
165 |
+ obj_props = self._obj_properties.get(obj_key) |
166 |
+ if obj_props is None: |
167 |
+ arch = None |
168 |
+ install_name = None |
169 |
+ else: |
170 |
+ arch = obj_props.arch |
171 |
+ install_name = obj_props.install_name |
172 |
return cache_self.cache.setdefault(obj, \ |
173 |
(arch, install_name, obj_key, True)) |
174 |
else: |
175 |
@@ -381,8 +409,9 @@ class LinkageMapMachO(object): |
176 |
|
177 |
# Iterate over all obj_keys and their providers. |
178 |
for obj_key, install_names in providers.items(): |
179 |
- arch = self._obj_properties[obj_key][0] |
180 |
- objs = self._obj_properties[obj_key][3] |
181 |
+ obj_props = self._obj_properties[obj_key] |
182 |
+ arch = obj_props.arch |
183 |
+ objs = obj_props.alt_paths |
184 |
# Iterate over each needed install_name and the set of |
185 |
# library paths that fulfill the install_name to determine |
186 |
# if the dependency is broken. |
187 |
@@ -483,7 +512,7 @@ class LinkageMapMachO(object): |
188 |
if obj_key not in self._obj_properties: |
189 |
raise KeyError("%s (%s) not in object list" % (obj_key, obj)) |
190 |
basename = os.path.basename(obj) |
191 |
- install_name = self._obj_properties[obj_key][2] |
192 |
+ install_name = self._obj_properties[obj_key].install_name |
193 |
return (len(basename) < len(os.path.basename(install_name)) and \ |
194 |
basename.endswith(".dylib") and \ |
195 |
os.path.basename(install_name).startswith(basename[:-6])) |
196 |
@@ -504,9 +533,40 @@ class LinkageMapMachO(object): |
197 |
for arch_map in self._libs.values(): |
198 |
for soname_map in arch_map.values(): |
199 |
for obj_key in soname_map.providers: |
200 |
- rValue.extend(self._obj_properties[obj_key][3]) |
201 |
+ rValue.extend(self._obj_properties[obj_key].alt_paths) |
202 |
return rValue |
203 |
|
204 |
+ def getOwners(self, obj): |
205 |
+ """ |
206 |
+ Return the package(s) associated with an object. Raises KeyError |
207 |
+ if the object is unknown. Returns an empty tuple if the owner(s) |
208 |
+ are unknown. |
209 |
+ |
210 |
+ NOTE: For preserved libraries, the owner(s) may have been |
211 |
+ previously uninstalled, but these uninstalled owners can be |
212 |
+ returned by this method since they are registered in the |
213 |
+ PreservedLibsRegistry. |
214 |
+ |
215 |
+ @param obj: absolute path to an object |
216 |
+ @type obj: string (example: '/usr/bin/bar') |
217 |
+ @rtype: tuple |
218 |
+ @return: a tuple of cpv |
219 |
+ """ |
220 |
+ if not self._libs: |
221 |
+ self.rebuild() |
222 |
+ if isinstance(obj, self._ObjectKey): |
223 |
+ obj_key = obj |
224 |
+ else: |
225 |
+ obj_key = self._obj_key_cache.get(obj) |
226 |
+ if obj_key is None: |
227 |
+ raise KeyError("%s not in object list" % obj) |
228 |
+ obj_props = self._obj_properties.get(obj_key) |
229 |
+ if obj_props is None: |
230 |
+ raise KeyError("%s not in object list" % obj_key) |
231 |
+ if obj_props.owner is None: |
232 |
+ return () |
233 |
+ return (obj_props.owner,) |
234 |
+ |
235 |
def getSoname(self, obj): |
236 |
""" |
237 |
Return the soname associated with an object. |
238 |
@@ -523,10 +583,10 @@ class LinkageMapMachO(object): |
239 |
obj_key = obj |
240 |
if obj_key not in self._obj_properties: |
241 |
raise KeyError("%s not in object list" % obj_key) |
242 |
- return self._obj_properties[obj_key][2] |
243 |
+ return self._obj_properties[obj_key].install_name |
244 |
if obj not in self._obj_key_cache: |
245 |
raise KeyError("%s not in object list" % obj) |
246 |
- return self._obj_properties[self._obj_key_cache[obj]][2] |
247 |
+ return self._obj_properties[self._obj_key_cache[obj]].install_name |
248 |
|
249 |
def findProviders(self, obj): |
250 |
""" |
251 |
@@ -566,7 +626,10 @@ class LinkageMapMachO(object): |
252 |
if obj_key not in self._obj_properties: |
253 |
raise KeyError("%s (%s) not in object list" % (obj_key, obj)) |
254 |
|
255 |
- arch, needed, install_name, _ = self._obj_properties[obj_key] |
256 |
+ obj_props = self._obj_properties[obj_key] |
257 |
+ arch = obj_props.arch |
258 |
+ needed = obj_props.needed |
259 |
+ install_name = obj_props.install_name |
260 |
for install_name in needed: |
261 |
rValue[install_name] = set() |
262 |
if arch not in self._libs or install_name not in self._libs[arch]: |
263 |
@@ -574,13 +637,13 @@ class LinkageMapMachO(object): |
264 |
# For each potential provider of the install_name, add it to |
265 |
# rValue if it exists. (Should be one) |
266 |
for provider_key in self._libs[arch][install_name].providers: |
267 |
- providers = self._obj_properties[provider_key][3] |
268 |
+ providers = self._obj_properties[provider_key].alt_paths |
269 |
for provider in providers: |
270 |
if os.path.exists(provider): |
271 |
rValue[install_name].add(provider) |
272 |
return rValue |
273 |
|
274 |
- def findConsumers(self, obj): |
275 |
+ def findConsumers(self, obj, exclude_providers=None): |
276 |
""" |
277 |
Find consumers of an object or object key. |
278 |
|
279 |
@@ -603,8 +666,16 @@ class LinkageMapMachO(object): |
280 |
corresponding libtool archive (*.la) files to detect such consumers |
281 |
(revdep-rebuild is able to detect them). |
282 |
|
283 |
+ The exclude_providers argument is only useful on platforms where |
284 |
+ references to libraries are not full paths, e.g. they are being |
285 |
+ searched for in a path, like ELF. On Mach-O, these references |
286 |
+ are full paths, and hence this argument is ignored, since there |
287 |
+ never will be alternative providers. |
288 |
+ |
289 |
@param obj: absolute path to an object or a key from _obj_properties |
290 |
@type obj: string (example: '/usr/bin/bar') or _ObjectKey |
291 |
+ @param exclude_providers: ignored in LinkageMapMachO |
292 |
+ @type exclude_providers: collection |
293 |
@rtype: set of strings (example: set(['/bin/foo', '/usr/bin/bar'])) |
294 |
@return: The return value is a install_name -> set-of-library-paths, where |
295 |
set-of-library-paths satisfy install_name. |
296 |
@@ -613,8 +684,6 @@ class LinkageMapMachO(object): |
297 |
|
298 |
os = _os_merge |
299 |
|
300 |
- rValue = set() |
301 |
- |
302 |
if not self._libs: |
303 |
self.rebuild() |
304 |
|
305 |
@@ -623,7 +692,7 @@ class LinkageMapMachO(object): |
306 |
obj_key = obj |
307 |
if obj_key not in self._obj_properties: |
308 |
raise KeyError("%s not in object list" % obj_key) |
309 |
- objs = self._obj_properties[obj_key][3] |
310 |
+ objs = self._obj_properties[obj_key].alt_paths |
311 |
else: |
312 |
objs = set([obj]) |
313 |
obj_key = self._obj_key(obj) |
314 |
@@ -635,7 +704,7 @@ class LinkageMapMachO(object): |
315 |
# other version, this lib will be shadowed and won't |
316 |
# have any consumers. |
317 |
if not isinstance(obj, self._ObjectKey): |
318 |
- install_name = self._obj_properties[obj_key][2] |
319 |
+ install_name = self._obj_properties[obj_key].install_name |
320 |
master_link = os.path.join(self._root, |
321 |
install_name.lstrip(os.path.sep)) |
322 |
try: |
323 |
@@ -648,12 +717,22 @@ class LinkageMapMachO(object): |
324 |
(master_st.st_dev, master_st.st_ino): |
325 |
return set() |
326 |
|
327 |
- arch = self._obj_properties[obj_key][0] |
328 |
- install_name = self._obj_properties[obj_key][2] |
329 |
- if arch in self._libs and install_name in self._libs[arch]: |
330 |
+ obj_props = self._obj_properties[obj_key] |
331 |
+ arch = obj_props.arch |
332 |
+ install_name = obj_props.install_name |
333 |
+ |
334 |
+ install_name_node = None |
335 |
+ arch_map = self._libs.get(arch) |
336 |
+ if arch_map is not None: |
337 |
+ install_name_node = arch_map.get(install_name) |
338 |
+ |
339 |
+ |
340 |
+ rValue = set() |
341 |
+ if install_name_node is not None: |
342 |
# For each potential consumer, add it to rValue if an object from the |
343 |
# arguments resides in the consumer's runpath. |
344 |
- for consumer_key in self._libs[arch][install_name].consumers: |
345 |
- consumer_objs = self._obj_properties[consumer_key][3] |
346 |
+ for consumer_key in install_name_node.consumers: |
347 |
+ consumer_props = self._obj_properties[consumer_key] |
348 |
+ consumer_objs = consumer_props.alt_paths |
349 |
rValue.update(consumer_objs) |
350 |
return rValue |