aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2020-02-08 11:43:27 -0800
committerZac Medico <zmedico@gentoo.org>2020-02-08 14:49:24 -0800
commit0edb0cd52e25a3ce168f712258ded9ccc6a5bee4 (patch)
tree56b7a0329952676ee7b8d22ac7e80ed4257d3ed3 /lib
parentdep_zapdeps: prefer choices with all in graph (bug 649622) (diff)
downloadportage-0edb0cd52e25a3ce168f712258ded9ccc6a5bee4.tar.gz
portage-0edb0cd52e25a3ce168f712258ded9ccc6a5bee4.tar.bz2
portage-0edb0cd52e25a3ce168f712258ded9ccc6a5bee4.zip
preserve-libs: generate implicit rpath for bundled libs (bug 705736)
In order to account for internal library resolution which a package may implement (useful at least for handling of bundled libraries), generate implicit runpath entries for any needed sonames which are provided by the same owner package. For packages that have bundled versions of system libraries, this will prevent preserve-libs from unecessarily preserving system libraries as reported in bug 705736. For the www-client/firefox-bin-72.0.2 package, this adds an implicit /opt/firefox runpath entry to 15 files. Bug: https://bugs.gentoo.org/705736 Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/portage/util/_dyn_libs/LinkageMapELF.py63
1 files changed, 54 insertions, 9 deletions
diff --git a/lib/portage/util/_dyn_libs/LinkageMapELF.py b/lib/portage/util/_dyn_libs/LinkageMapELF.py
index 92a50b444..70bec116a 100644
--- a/lib/portage/util/_dyn_libs/LinkageMapELF.py
+++ b/lib/portage/util/_dyn_libs/LinkageMapELF.py
@@ -1,7 +1,9 @@
-# Copyright 1998-2019 Gentoo Authors
+# Copyright 1998-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
+import collections
import errno
+import itertools
import logging
import subprocess
import sys
@@ -14,6 +16,7 @@ from portage import _unicode_encode
from portage.cache.mappings import slot_dict_class
from portage.const import EPREFIX
from portage.dep.soname.multilib_category import compute_multilib_category
+from portage.dep.soname.SonameAtom import SonameAtom
from portage.exception import CommandNotFound, InvalidData
from portage.localization import _
from portage.util import getlibpaths
@@ -328,8 +331,13 @@ class LinkageMapELF(object):
# Share identical frozenset instances when available,
# in order to conserve memory.
frozensets = {}
+ owner_entries = collections.defaultdict(list)
- for owner, location, l in lines:
+ while True:
+ try:
+ owner, location, l = lines.pop()
+ except IndexError:
+ break
l = l.rstrip("\n")
if not l:
continue
@@ -352,18 +360,55 @@ class LinkageMapELF(object):
# exists, map e_machine (entry.arch) to an approximate
# multilib category. If all else fails, use e_machine, just
# as older versions of portage did.
- arch = entry.multilib_category
- if arch is None:
- arch = _approx_multilib_categories.get(
+ if entry.multilib_category is None:
+ entry.multilib_category = _approx_multilib_categories.get(
entry.arch, entry.arch)
- obj = entry.filename
- soname = entry.soname
+ entry.filename = normalize_path(entry.filename)
expand = {"ORIGIN": os.path.dirname(entry.filename)}
- path = frozenset(normalize_path(
+ entry.runpaths = frozenset(normalize_path(
varexpand(x, expand, error_leader=lambda: "%s: " % location))
for x in entry.runpaths)
- path = frozensets.setdefault(path, path)
+ entry.runpaths = frozensets.setdefault(entry.runpaths, entry.runpaths)
+ owner_entries[owner].append(entry)
+
+ # In order to account for internal library resolution which a package
+ # may implement (useful at least for handling of bundled libraries),
+ # generate implicit runpath entries for any needed sonames which are
+ # provided by the same owner package.
+ for owner, entries in owner_entries.items():
+ if owner is None:
+ continue
+
+ providers = {}
+ for entry in entries:
+ if entry.soname:
+ providers[SonameAtom(entry.multilib_category, entry.soname)] = entry
+
+ for entry in entries:
+ implicit_runpaths = []
+ for soname in entry.needed:
+ soname_atom = SonameAtom(entry.multilib_category, soname)
+ provider = providers.get(soname_atom)
+ if provider is None:
+ continue
+ provider_dir = os.path.dirname(provider.filename)
+ if provider_dir not in entry.runpaths:
+ implicit_runpaths.append(provider_dir)
+
+ if implicit_runpaths:
+ entry.runpaths = frozenset(
+ itertools.chain(entry.runpaths, implicit_runpaths))
+ entry.runpaths = frozensets.setdefault(
+ entry.runpaths, entry.runpaths)
+
+ for owner, entry in ((owner, entry)
+ for (owner, entries) in owner_entries.items()
+ for entry in entries):
+ arch = entry.multilib_category
+ obj = entry.filename
+ soname = entry.soname
+ path = entry.runpaths
needed = frozenset(entry.needed)
needed = frozensets.setdefault(needed, needed)