1 |
commit: 0edb0cd52e25a3ce168f712258ded9ccc6a5bee4 |
2 |
Author: Zac Medico <zmedico <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sat Feb 8 19:43:27 2020 +0000 |
4 |
Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat Feb 8 22:49:24 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=0edb0cd5 |
7 |
|
8 |
preserve-libs: generate implicit rpath for bundled libs (bug 705736) |
9 |
|
10 |
In order to account for internal library resolution which a package |
11 |
may implement (useful at least for handling of bundled libraries), |
12 |
generate implicit runpath entries for any needed sonames which are |
13 |
provided by the same owner package. |
14 |
|
15 |
For packages that have bundled versions of system libraries, this will |
16 |
prevent preserve-libs from unecessarily preserving system libraries as |
17 |
reported in bug 705736. For the www-client/firefox-bin-72.0.2 package, |
18 |
this adds an implicit /opt/firefox runpath entry to 15 files. |
19 |
|
20 |
Bug: https://bugs.gentoo.org/705736 |
21 |
Signed-off-by: Zac Medico <zmedico <AT> gentoo.org> |
22 |
|
23 |
lib/portage/util/_dyn_libs/LinkageMapELF.py | 63 ++++++++++++++++++++++++----- |
24 |
1 file changed, 54 insertions(+), 9 deletions(-) |
25 |
|
26 |
diff --git a/lib/portage/util/_dyn_libs/LinkageMapELF.py b/lib/portage/util/_dyn_libs/LinkageMapELF.py |
27 |
index 92a50b444..70bec116a 100644 |
28 |
--- a/lib/portage/util/_dyn_libs/LinkageMapELF.py |
29 |
+++ b/lib/portage/util/_dyn_libs/LinkageMapELF.py |
30 |
@@ -1,7 +1,9 @@ |
31 |
-# Copyright 1998-2019 Gentoo Authors |
32 |
+# Copyright 1998-2020 Gentoo Authors |
33 |
# Distributed under the terms of the GNU General Public License v2 |
34 |
|
35 |
+import collections |
36 |
import errno |
37 |
+import itertools |
38 |
import logging |
39 |
import subprocess |
40 |
import sys |
41 |
@@ -14,6 +16,7 @@ from portage import _unicode_encode |
42 |
from portage.cache.mappings import slot_dict_class |
43 |
from portage.const import EPREFIX |
44 |
from portage.dep.soname.multilib_category import compute_multilib_category |
45 |
+from portage.dep.soname.SonameAtom import SonameAtom |
46 |
from portage.exception import CommandNotFound, InvalidData |
47 |
from portage.localization import _ |
48 |
from portage.util import getlibpaths |
49 |
@@ -328,8 +331,13 @@ class LinkageMapELF(object): |
50 |
# Share identical frozenset instances when available, |
51 |
# in order to conserve memory. |
52 |
frozensets = {} |
53 |
+ owner_entries = collections.defaultdict(list) |
54 |
|
55 |
- for owner, location, l in lines: |
56 |
+ while True: |
57 |
+ try: |
58 |
+ owner, location, l = lines.pop() |
59 |
+ except IndexError: |
60 |
+ break |
61 |
l = l.rstrip("\n") |
62 |
if not l: |
63 |
continue |
64 |
@@ -352,18 +360,55 @@ class LinkageMapELF(object): |
65 |
# exists, map e_machine (entry.arch) to an approximate |
66 |
# multilib category. If all else fails, use e_machine, just |
67 |
# as older versions of portage did. |
68 |
- arch = entry.multilib_category |
69 |
- if arch is None: |
70 |
- arch = _approx_multilib_categories.get( |
71 |
+ if entry.multilib_category is None: |
72 |
+ entry.multilib_category = _approx_multilib_categories.get( |
73 |
entry.arch, entry.arch) |
74 |
|
75 |
- obj = entry.filename |
76 |
- soname = entry.soname |
77 |
+ entry.filename = normalize_path(entry.filename) |
78 |
expand = {"ORIGIN": os.path.dirname(entry.filename)} |
79 |
- path = frozenset(normalize_path( |
80 |
+ entry.runpaths = frozenset(normalize_path( |
81 |
varexpand(x, expand, error_leader=lambda: "%s: " % location)) |
82 |
for x in entry.runpaths) |
83 |
- path = frozensets.setdefault(path, path) |
84 |
+ entry.runpaths = frozensets.setdefault(entry.runpaths, entry.runpaths) |
85 |
+ owner_entries[owner].append(entry) |
86 |
+ |
87 |
+ # In order to account for internal library resolution which a package |
88 |
+ # may implement (useful at least for handling of bundled libraries), |
89 |
+ # generate implicit runpath entries for any needed sonames which are |
90 |
+ # provided by the same owner package. |
91 |
+ for owner, entries in owner_entries.items(): |
92 |
+ if owner is None: |
93 |
+ continue |
94 |
+ |
95 |
+ providers = {} |
96 |
+ for entry in entries: |
97 |
+ if entry.soname: |
98 |
+ providers[SonameAtom(entry.multilib_category, entry.soname)] = entry |
99 |
+ |
100 |
+ for entry in entries: |
101 |
+ implicit_runpaths = [] |
102 |
+ for soname in entry.needed: |
103 |
+ soname_atom = SonameAtom(entry.multilib_category, soname) |
104 |
+ provider = providers.get(soname_atom) |
105 |
+ if provider is None: |
106 |
+ continue |
107 |
+ provider_dir = os.path.dirname(provider.filename) |
108 |
+ if provider_dir not in entry.runpaths: |
109 |
+ implicit_runpaths.append(provider_dir) |
110 |
+ |
111 |
+ if implicit_runpaths: |
112 |
+ entry.runpaths = frozenset( |
113 |
+ itertools.chain(entry.runpaths, implicit_runpaths)) |
114 |
+ entry.runpaths = frozensets.setdefault( |
115 |
+ entry.runpaths, entry.runpaths) |
116 |
+ |
117 |
+ for owner, entry in ((owner, entry) |
118 |
+ for (owner, entries) in owner_entries.items() |
119 |
+ for entry in entries): |
120 |
+ arch = entry.multilib_category |
121 |
+ obj = entry.filename |
122 |
+ soname = entry.soname |
123 |
+ path = entry.runpaths |
124 |
needed = frozenset(entry.needed) |
125 |
|
126 |
needed = frozensets.setdefault(needed, needed) |