1 |
Make LinkageMapELF safely discard NEEDED.ELF.2 data when possible, |
2 |
in a manner consistent with PROVIDES_EXCLUDE and REQUIRES_EXCLUDE. |
3 |
Achieve this by intersection with PROVIDES and REQUIRES, which is |
4 |
equivalent to evaluating PROVIDES_EXCLUDE and REQUIRES_EXCLUDE, |
5 |
but simpler to do. Do not apply PROVIDES_EXCLUDE for entries that |
6 |
have non-empty needed (after REQUIRES_EXCLUDE has been applied), |
7 |
since that will require a significant number of additional changes |
8 |
to LinkageMapELF. |
9 |
|
10 |
X-Gentoo-Bug: 565792 |
11 |
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=565792 |
12 |
--- |
13 |
pym/portage/util/_dyn_libs/LinkageMapELF.py | 45 +++++++++++++++++++++++++---- |
14 |
pym/portage/util/_dyn_libs/NeededEntry.py | 24 +++++++++++++++ |
15 |
2 files changed, 64 insertions(+), 5 deletions(-) |
16 |
|
17 |
diff --git a/pym/portage/util/_dyn_libs/LinkageMapELF.py b/pym/portage/util/_dyn_libs/LinkageMapELF.py |
18 |
index 63e2213..24d03a5 100644 |
19 |
--- a/pym/portage/util/_dyn_libs/LinkageMapELF.py |
20 |
+++ b/pym/portage/util/_dyn_libs/LinkageMapELF.py |
21 |
@@ -11,6 +11,8 @@ from portage import _os_merge |
22 |
from portage import _unicode_decode |
23 |
from portage import _unicode_encode |
24 |
from portage.cache.mappings import slot_dict_class |
25 |
+from portage.dep.soname.parse import parse_soname_deps |
26 |
+from portage.dep.soname.SonameAtom import SonameAtom |
27 |
from portage.exception import CommandNotFound, InvalidData |
28 |
from portage.localization import _ |
29 |
from portage.util import getlibpaths |
30 |
@@ -225,7 +227,7 @@ class LinkageMapELF(object): |
31 |
for line in grabfile(include_file): |
32 |
lines.append((None, include_file, line)) |
33 |
|
34 |
- aux_keys = [self._needed_aux_key] |
35 |
+ aux_keys = [self._needed_aux_key, 'PROVIDES', 'REQUIRES'] |
36 |
can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK) |
37 |
if can_lock: |
38 |
self._dbapi.lock() |
39 |
@@ -233,10 +235,26 @@ class LinkageMapELF(object): |
40 |
for cpv in self._dbapi.cpv_all(): |
41 |
if exclude_pkgs is not None and cpv in exclude_pkgs: |
42 |
continue |
43 |
+ metadata = dict(zip(aux_keys, self._dbapi.aux_get(cpv, aux_keys))) |
44 |
+ soname_deps = {} |
45 |
+ |
46 |
+ for k in ('PROVIDES', 'REQUIRES'): |
47 |
+ try: |
48 |
+ soname_deps[k] = frozenset(parse_soname_deps(metadata[k])) |
49 |
+ except InvalidData as e: |
50 |
+ soname_deps[k] = None |
51 |
+ location = self._dbapi.getpath(cpv, filename=k) |
52 |
+ writemsg_level(_("\nInvalid data in %s: %s\n\n") % |
53 |
+ (location, e), level=logging.ERROR, noiselevel=-1) |
54 |
+ |
55 |
+ provides = soname_deps['PROVIDES'] |
56 |
+ requires = soname_deps['REQUIRES'] |
57 |
+ |
58 |
needed_file = self._dbapi.getpath(cpv, |
59 |
filename=self._needed_aux_key) |
60 |
+ |
61 |
for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines(): |
62 |
- lines.append((cpv, needed_file, line)) |
63 |
+ lines.append((cpv, provides, requires, needed_file, line)) |
64 |
finally: |
65 |
if can_lock: |
66 |
self._dbapi.unlock() |
67 |
@@ -290,7 +308,8 @@ class LinkageMapELF(object): |
68 |
continue |
69 |
fields[1] = fields[1][root_len:] |
70 |
owner = plibs.pop(fields[1], None) |
71 |
- lines.append((owner, "scanelf", ";".join(fields))) |
72 |
+ lines.append((owner, None, None, |
73 |
+ "scanelf", ";".join(fields))) |
74 |
proc.wait() |
75 |
proc.stdout.close() |
76 |
|
77 |
@@ -302,13 +321,14 @@ class LinkageMapELF(object): |
78 |
# is important in order to prevent findConsumers from raising |
79 |
# an unwanted KeyError. |
80 |
for x, cpv in plibs.items(): |
81 |
- lines.append((cpv, "plibs", ";".join(['', x, '', '', '']))) |
82 |
+ lines.append((cpv, None, None, |
83 |
+ "plibs", ";".join(['', x, '', '', '']))) |
84 |
|
85 |
# Share identical frozenset instances when available, |
86 |
# in order to conserve memory. |
87 |
frozensets = {} |
88 |
|
89 |
- for owner, location, l in lines: |
90 |
+ for owner, provides, requires, location, l in lines: |
91 |
l = l.rstrip("\n") |
92 |
if not l: |
93 |
continue |
94 |
@@ -335,6 +355,21 @@ class LinkageMapELF(object): |
95 |
if arch is None: |
96 |
arch = _approx_multilib_categories.get( |
97 |
entry.arch, entry.arch) |
98 |
+ # initialize multilib_category for intersect_requires |
99 |
+ entry.multilib_category = arch |
100 |
+ |
101 |
+ if requires is not None: |
102 |
+ # Apply REQUIRES_EXCLUDE. |
103 |
+ entry = entry.intersect_requires(requires) |
104 |
+ |
105 |
+ if provides is not None: |
106 |
+ # Apply PROVIDES_EXCLUDE. Don't exclude entries with |
107 |
+ # non-empty entry.needed, since we want to ensure that |
108 |
+ # entry.needed is satisfied. TODO: Apply PROVIDES_EXCLUDE |
109 |
+ # to entries with non-empty entry.needed. |
110 |
+ if not entry.needed and SonameAtom( |
111 |
+ entry.multilib_category, entry.soname) not in provides: |
112 |
+ continue |
113 |
|
114 |
obj = entry.filename |
115 |
soname = entry.soname |
116 |
diff --git a/pym/portage/util/_dyn_libs/NeededEntry.py b/pym/portage/util/_dyn_libs/NeededEntry.py |
117 |
index c52cfce..824f94c 100644 |
118 |
--- a/pym/portage/util/_dyn_libs/NeededEntry.py |
119 |
+++ b/pym/portage/util/_dyn_libs/NeededEntry.py |
120 |
@@ -6,6 +6,7 @@ from __future__ import unicode_literals |
121 |
import sys |
122 |
|
123 |
from portage import _encodings, _unicode_encode |
124 |
+from portage.dep.soname.SonameAtom import SonameAtom |
125 |
from portage.exception import InvalidData |
126 |
from portage.localization import _ |
127 |
|
128 |
@@ -57,6 +58,29 @@ class NeededEntry(object): |
129 |
|
130 |
return obj |
131 |
|
132 |
+ def intersect_requires(self, requires): |
133 |
+ """ |
134 |
+ Return a new instance, filtering out data that does not intersect |
135 |
+ with the given requires data. This is a convenient way to account |
136 |
+ for REQUIRES_EXCLUDE, since the intersection operation will filter |
137 |
+ out anything that REQUIRES_EXCLUDE would exclude. |
138 |
+ |
139 |
+ @param requires: required soname atoms |
140 |
+ @type requires: frozenset |
141 |
+ """ |
142 |
+ obj = self.__class__() |
143 |
+ obj.arch = self.arch |
144 |
+ obj.filename = self.filename |
145 |
+ obj.multilib_category = self.multilib_category |
146 |
+ obj.soname = self.soname |
147 |
+ obj.runpaths = self.runpaths |
148 |
+ filtered_needed = [] |
149 |
+ for soname in self.needed: |
150 |
+ if SonameAtom(self.multilib_category, soname) in requires: |
151 |
+ filtered_needed.append(soname) |
152 |
+ obj.needed = tuple(filtered_needed) |
153 |
+ return obj |
154 |
+ |
155 |
def __str__(self): |
156 |
""" |
157 |
Format this entry for writing to a NEEDED.ELF.2 file. |
158 |
-- |
159 |
2.4.9 |