1 |
Author: grobian |
2 |
Date: 2008-09-27 14:52:10 +0000 (Sat, 27 Sep 2008) |
3 |
New Revision: 11565 |
4 |
|
5 |
Modified: |
6 |
main/branches/prefix/bin/misc-functions.sh |
7 |
main/branches/prefix/pym/portage/dbapi/vartree.py |
8 |
Log: |
9 |
Now we have scanmacho, we can eventually do some fast examination of libraries and get all info at once that we need. Get rid of otool, and now also store the arch of objects (enabling theoretical support for FAT objects), hence bump to NEEDED.MACHO.3 |
10 |
|
11 |
Modified: main/branches/prefix/bin/misc-functions.sh |
12 |
=================================================================== |
13 |
--- main/branches/prefix/bin/misc-functions.sh 2008-09-27 05:55:10 UTC (rev 11564) |
14 |
+++ main/branches/prefix/bin/misc-functions.sh 2008-09-27 14:52:10 UTC (rev 11565) |
15 |
@@ -407,53 +407,56 @@ |
16 |
done |
17 |
[[ ${abort} == "yes" ]] && die "soiled libtool library files found" |
18 |
|
19 |
- # Check that we don't get kernel traps at runtime because of broken |
20 |
- # install_names on Darwin, at the same time generate the NEEDED |
21 |
- # entries. As long as we don't have a "scanelf" tool for this, we |
22 |
- # use otool to do the magic. Since this is expensive, we do it |
23 |
- # together with the scan for broken installs. |
24 |
+ # While we generate the NEEDED files, check that we don't get kernel |
25 |
+ # traps at runtime because of broken install_names on Darwin. |
26 |
rm -f "${T}"/.install_name_check_failed |
27 |
- [[ ${CHOST} == *-darwin* ]] && find "${ED}" -type f | while IFS= read f ; do |
28 |
- rm -f "${T}"/.NEEDED.tmp |
29 |
- install_name=$(otool -DX "${f}") |
30 |
- otool -LX "${f}" \ |
31 |
- | grep -v "Archive : " \ |
32 |
- | sed -e 's/^\t//' -e 's/ (compa.*$//' \ |
33 |
- | while read r ; |
34 |
- do |
35 |
- # skip the self reference in libraries |
36 |
- [[ -n ${install_name} && ${install_name} == ${r} ]] && continue |
37 |
+ [[ ${CHOST} == *-darwin* ]] && scanmacho -qyRF '%a;%p;%S;%n' "${D}" | { while IFS= read l ; do |
38 |
+ arch=${l%%;*}; l=${l#*;} |
39 |
+ obj="/${l%%;*}"; l=${l#*;} |
40 |
+ install_name=${l%%;*}; l=${l#*;} |
41 |
+ needed=${l%%;*}; l=${l#*;} |
42 |
|
43 |
- if [[ ! -e ${r} && ! -e ${D}${r} && ${r} != *"@executable_path"* ]] ; then |
44 |
+ # this is ugly, paths with spaces won't work |
45 |
+ reevaluate=0 |
46 |
+ for lib in $(echo ${needed} | tr , ' '); do |
47 |
+ if [[ ! -e ${lib} && ! -e ${D}${lib} && ${lib} != *"@executable_path"* ]] ; then |
48 |
# try to "repair" this if possible, happens because of |
49 |
# gen_usr_ldscript tactics |
50 |
- s=${r%usr/*}${r##*/usr/} |
51 |
+ s=${lib%usr/*}${lib##*/usr/} |
52 |
if [[ -e ${D}${s} ]] ; then |
53 |
- ewarn "correcting install_name from ${r} to ${s} in ${f#${D}}" |
54 |
+ ewarn "correcting install_name from ${lib} to ${s} in ${obj}" |
55 |
install_name_tool -change \ |
56 |
- "${r}" "${s}" "${f}" |
57 |
- r=${s} # for the NEEDED entries |
58 |
+ "${lib}" "${s}" "${D}${obj}" |
59 |
+ reevaluate=1 |
60 |
else |
61 |
- eqawarn "QA Notice: invalid reference to ${r} in ${f}" |
62 |
+ eqawarn "QA Notice: invalid reference to ${lib} in ${obj}" |
63 |
# remember we are in an implicit subshell, that's |
64 |
# why we touch a file here ... ideally we should be |
65 |
# able to die correctly/nicely here |
66 |
touch "${T}"/.install_name_check_failed |
67 |
fi |
68 |
fi |
69 |
- echo -n ",${r}" >> "${T}"/.NEEDED.tmp |
70 |
done |
71 |
- if [[ -f "${T}"/.NEEDED.tmp ]] ; then |
72 |
- needed=$(< "${T}"/.NEEDED.tmp) |
73 |
- echo "/${f#${D}} ${needed#,}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED |
74 |
- echo "/${f#${D}};${install_name};${needed#,}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.MACHO.2 |
75 |
+ if [[ reevaluate == 1 ]]; then |
76 |
+ # install_name(s) have been changed, refresh data so we |
77 |
+ # store the correct meta data |
78 |
+ l=$(scanmacho -qyF '%a;%p;%S;%n' ${D}${obj}) |
79 |
+ arch=${l%%;*}; l=${l#*;} |
80 |
+ obj="/${l%%;*}"; l=${l#*;} |
81 |
+ install_name=${l%%;*}; l=${l#*;} |
82 |
+ needed=${l%%;*}; l=${l#*;} |
83 |
fi |
84 |
- done |
85 |
+ |
86 |
+ # backwards compatability |
87 |
+ echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED |
88 |
+ # what we use |
89 |
+ echo "${arch};${obj};${install_name};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.MACHO.3 |
90 |
+ done } |
91 |
if [[ -f ${T}/.install_name_check_failed ]] ; then |
92 |
# secret switch "allow_broken_install_names" to get |
93 |
# around this and install broken crap (not a good idea) |
94 |
hasq allow_broken_install_names ${FEATURES} || \ |
95 |
- die "invalid install_name found, your application will crash at runtime" |
96 |
+ die "invalid install_name found, your application or library will crash at runtime" |
97 |
fi |
98 |
|
99 |
# Evaluate misc gcc warnings |
100 |
|
101 |
Modified: main/branches/prefix/pym/portage/dbapi/vartree.py |
102 |
=================================================================== |
103 |
--- main/branches/prefix/pym/portage/dbapi/vartree.py 2008-09-27 05:55:10 UTC (rev 11564) |
104 |
+++ main/branches/prefix/pym/portage/dbapi/vartree.py 2008-09-27 14:52:10 UTC (rev 11565) |
105 |
@@ -622,10 +622,6 @@ |
106 |
return hash(self._key) |
107 |
|
108 |
def __eq__(self, other): |
109 |
- if isinstance(other, self.__class__): |
110 |
- other_key = other._key |
111 |
- else: |
112 |
- other_key = other |
113 |
return self._key == other_key |
114 |
|
115 |
def _generate_object_key(self, object): |
116 |
@@ -669,59 +665,39 @@ |
117 |
obj_properties = {} |
118 |
lines = [] |
119 |
for cpv in self._dbapi.cpv_all(): |
120 |
- lines += self._dbapi.aux_get(cpv, ["NEEDED.MACHO.2"])[0].split('\n') |
121 |
+ lines += self._dbapi.aux_get(cpv, ["NEEDED.MACHO.3"])[0].split('\n') |
122 |
# Cache NEEDED.* files avoid doing excessive IO for every rebuild. |
123 |
self._dbapi.flush_cache() |
124 |
|
125 |
if include_file: |
126 |
lines += grabfile(include_file) |
127 |
|
128 |
- # have to call otool for preserved libs here as they aren't |
129 |
- # registered in NEEDED.MACHO.2 files |
130 |
+ # have to call scanmacho for preserved libs here as they aren't |
131 |
+ # registered in NEEDED.MACHO.3 files |
132 |
if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs(): |
133 |
- otool = EPREFIX+"/usr/bin/otool" |
134 |
+ args = [EPREFIX+"/usr/bin/scanmacho", "-qF", "%a;%F;%S;%n"] |
135 |
for items in self._dbapi.plib_registry.getPreservedLibs().values(): |
136 |
- for x in items: |
137 |
- try: |
138 |
- proc = subprocess.Popen([otool, "-DX", x.lstrip(".")], |
139 |
- stdout=subprocess.PIPE) |
140 |
- install_name = proc.communicate()[0].split("\n")[0] |
141 |
- proc = subprocess.Popen([otool, "-LX", x.lstrip(".")], |
142 |
- stdout=subprocess.PIPE) |
143 |
- output = [l.lstrip() for l in proc.communicate()[0].split("\n")] |
144 |
- except OSError: |
145 |
- # if otool can't be found (like in an odcctools |
146 |
- # upgrade -> binutils-config needs to update |
147 |
- # symlinks) just ignore it, don't crash |
148 |
- lines += [x + ";" + x.lstrip(".") + ";\n"] |
149 |
- continue |
150 |
+ args += [x.lstrip(".") for x in items] |
151 |
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE) |
152 |
+ output = [proc.communicate()[0].split("\n")] |
153 |
+ lines += output |
154 |
|
155 |
- n = "" |
156 |
- for l in output: |
157 |
- if l == '': |
158 |
- continue |
159 |
- p = l.rfind(" (compatibility") |
160 |
- if p != -1: |
161 |
- l = l[:p] |
162 |
- n += "," + l |
163 |
- |
164 |
- lines += [x + ";" + install_name + ";" + n.lstrip(",") + "\n"] |
165 |
- |
166 |
for l in lines: |
167 |
if l.strip() == "": |
168 |
continue |
169 |
fields = l.strip("\n").split(";") |
170 |
- if len(fields) < 3: |
171 |
+ if len(fields) < 4: |
172 |
print "Error", fields |
173 |
# insufficient field length |
174 |
continue |
175 |
|
176 |
# Linking an object to a library is registered by recording |
177 |
# the install_name of the library in the object. |
178 |
- obj = fields[0] |
179 |
+ arch = fields[0] |
180 |
+ obj = fields[1] |
181 |
obj_key = self._ObjectKey(obj) |
182 |
- install_name = os.path.normpath(fields[1]) |
183 |
- needed = filter(None, fields[2].split(",")) |
184 |
+ install_name = os.path.normpath(fields[2]) |
185 |
+ needed = filter(None, fields[3].split(",")) |
186 |
|
187 |
# build an internal structure that contains for each |
188 |
# install_name, what libs have that install_name |
189 |
@@ -730,16 +706,19 @@ |
190 |
# reference the install_name |
191 |
if install_name: |
192 |
libs.setdefault(install_name, \ |
193 |
+ {arch: {"providers": set(), "consumers": set()}}) |
194 |
+ libs[install_name].setdefault(arch, \ |
195 |
{"providers": set(), "consumers": set()}) |
196 |
- libs[install_name]["providers"].add(obj_key) |
197 |
+ libs[install_name][arch]["providers"].add(obj_key) |
198 |
for x in needed: |
199 |
libs.setdefault(x, \ |
200 |
- {"providers": set(), "consumers": set()}) |
201 |
- libs[x]["consumers"].add(obj_key) |
202 |
+ {arch: {"providers": set(), "consumers": set()}}) |
203 |
+ libs[x].setdefault(arch, {"providers": set(), "consumers": set()}) |
204 |
+ libs[x][arch]["consumers"].add(obj_key) |
205 |
obj_key_cache.setdefault(obj, obj_key) |
206 |
# All object paths are added into the obj_properties tuple |
207 |
obj_properties.setdefault(obj_key, \ |
208 |
- (needed, install_name, set()))[2].add(obj) |
209 |
+ (arch, needed, install_name, set()))[3].add(obj) |
210 |
|
211 |
self._libs = libs |
212 |
self._obj_properties = obj_properties |
213 |
@@ -798,13 +777,13 @@ |
214 |
if obj_key.file_exists(): |
215 |
# Get the install_name from LinkageMapMachO._obj_properties if |
216 |
# it exists. Otherwise, None. |
217 |
- _, install_name, _ = \ |
218 |
- self._obj_properties.get(obj_key, (None,)*3) |
219 |
+ arch, _, install_name, _ = \ |
220 |
+ self._obj_properties.get(obj_key, (None,)*4) |
221 |
return cache_self.cache.setdefault(obj, \ |
222 |
- (install_name, obj_key, True)) |
223 |
+ (arch, install_name, obj_key, True)) |
224 |
else: |
225 |
return cache_self.cache.setdefault(obj, \ |
226 |
- (None, obj_key, False)) |
227 |
+ (None, None, obj_key, False)) |
228 |
|
229 |
rValue = {} |
230 |
cache = _LibraryCache() |
231 |
@@ -812,7 +791,7 @@ |
232 |
|
233 |
# Iterate over all obj_keys and their providers. |
234 |
for obj_key, install_names in providers.items(): |
235 |
- _, _, objs = self._obj_properties[obj_key] |
236 |
+ arch, _, _, objs = self._obj_properties[obj_key] |
237 |
# Iterate over each needed install_name and the set of |
238 |
# library paths that fulfill the install_name to determine |
239 |
# if the dependency is broken. |
240 |
@@ -823,12 +802,12 @@ |
241 |
# If unsatisfied, objects associated with obj_key must |
242 |
# be emerged. |
243 |
validLibrary = None |
244 |
- cachedInstallname, cachedRealpath, cachedExists = \ |
245 |
+ cachedArch, cachedInstallname, cachedRealpath, cachedExists = \ |
246 |
cache.get(install_name) |
247 |
# Check that the this library provides the needed soname. Doing |
248 |
# this, however, will cause consumers of libraries missing |
249 |
# sonames to be unnecessarily emerged. (eg libmix.so) |
250 |
- if cachedInstallname == install_name: |
251 |
+ if cachedInstallname == install_name and cachedArch == arch: |
252 |
validLibrary = cachedRealpath |
253 |
if debug and cachedRealpath not in libraries: |
254 |
print "Found provider outside of findProviders:", \ |
255 |
@@ -894,7 +873,7 @@ |
256 |
obj_key = self._ObjectKey(obj) |
257 |
if obj_key not in self._obj_properties: |
258 |
raise KeyError("%s (%s) not in object list" % (obj_key, obj)) |
259 |
- install_name = self._obj_properties[obj_key][1] |
260 |
+ install_name = self._obj_properties[obj_key][2] |
261 |
return (len(basename) < len(os.path.basename(install_name))) |
262 |
|
263 |
def listLibraryObjects(self): |
264 |
@@ -911,8 +890,9 @@ |
265 |
if not self._libs: |
266 |
self.rebuild() |
267 |
for install_name in self._libs: |
268 |
- for obj_key in self._libs[install_name]["providers"]: |
269 |
- rValue.extend(self._obj_properties[obj_key][2]) |
270 |
+ for arch in self._libs[install_name]: |
271 |
+ for obj_key in self._libs[install_name][arch]["providers"]: |
272 |
+ rValue.extend(self._obj_properties[obj_key][3]) |
273 |
return rValue |
274 |
|
275 |
def getSoname(self, obj): |
276 |
@@ -929,7 +909,7 @@ |
277 |
self.rebuild() |
278 |
if obj not in self._obj_key_cache: |
279 |
raise KeyError("%s not in object list" % obj) |
280 |
- return self._obj_properties[self._obj_key_cache[obj]][1] |
281 |
+ return self._obj_properties[self._obj_key_cache[obj]][2] |
282 |
|
283 |
def findProviders(self, obj): |
284 |
""" |
285 |
@@ -968,15 +948,15 @@ |
286 |
if obj_key not in self._obj_properties: |
287 |
raise KeyError("%s (%s) not in object list" % (obj_key, obj)) |
288 |
|
289 |
- needed, install_name, _ = self._obj_properties[obj_key] |
290 |
+ arch, needed, install_name, _ = self._obj_properties[obj_key] |
291 |
for install_name in needed: |
292 |
rValue[install_name] = set() |
293 |
- if install_name not in self._libs: |
294 |
+ if install_name not in self._libs or arch not in self._libs[install_name]: |
295 |
continue |
296 |
# For each potential provider of the install_name, add it to |
297 |
# rValue if it exists. (Should be one) |
298 |
- for provider_key in self._libs[install_name]["providers"]: |
299 |
- providers = self._obj_properties[provider_key][2] |
300 |
+ for provider_key in self._libs[install_name][arch]["providers"]: |
301 |
+ providers = self._obj_properties[provider_key][3] |
302 |
for provider in providers: |
303 |
if os.path.exists(provider): |
304 |
rValue[install_name].add(provider) |
305 |
@@ -1012,7 +992,7 @@ |
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][2] |
310 |
+ objs = self._obj_properties[obj_key][3] |
311 |
else: |
312 |
objs = set([obj]) |
313 |
obj_key = self._obj_key_cache.get(obj) |
314 |
@@ -1026,7 +1006,7 @@ |
315 |
# other version, this lib will be shadowed and won't |
316 |
# have any consumers. |
317 |
if not isinstance(obj, self._ObjectKey): |
318 |
- master_link = self._obj_properties[obj_key][1] |
319 |
+ master_link = self._obj_properties[obj_key][2] |
320 |
try: |
321 |
master_st = os.stat(master_link) |
322 |
obj_st = os.stat(obj) |
323 |
@@ -1037,12 +1017,12 @@ |
324 |
(master_st.st_dev, master_st.st_ino): |
325 |
return set() |
326 |
|
327 |
- _, install_name, _ = self._obj_properties[obj_key] |
328 |
- if install_name in self._libs: |
329 |
+ arch, _, install_name, _ = self._obj_properties[obj_key] |
330 |
+ if install_name in self._libs and arch in self._libs[install_name]: |
331 |
# For each potential consumer, add it to rValue if an object from the |
332 |
# arguments resides in the consumer's runpath. |
333 |
- for consumer_key in self._libs[install_name]["consumers"]: |
334 |
- _, _, consumer_objs = \ |
335 |
+ for consumer_key in self._libs[install_name][arch]["consumers"]: |
336 |
+ _, _, _, consumer_objs = \ |
337 |
self._obj_properties[consumer_key] |
338 |
rValue.update(consumer_objs) |
339 |
return rValue |