Gentoo Archives: gentoo-portage-dev

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