From ee524d4972adbbdf561d70b813b9873a2ac7ec3d Mon Sep 17 00:00:00 2001 From: Patrick Schmidt Date: Fri, 22 Oct 2021 16:30:55 +0200 Subject: [PATCH] fix: generate dependencies for shared libs When packaging python packages that contain shared libraries, they usually link against other external shared libraries. This creates a runtime dependency on other Debian packages. This change will scan all libraries for such dependencies and generate the Debian package dependencies for them. --- src/wheel2deb/debian.py | 64 +++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/wheel2deb/debian.py b/src/wheel2deb/debian.py index 4ba52ca..808cce4 100644 --- a/src/wheel2deb/debian.py +++ b/src/wheel2deb/debian.py @@ -32,6 +32,7 @@ DPKG_SHLIBS_RE = re.compile(r"find library (.+\.so[.\d]*) needed") APT_FILE_RE = re.compile(r"(.*lib.+):\s(?:/usr/lib/|/lib/)") +LDD_DEP_RE = re.compile(r"\s+lib.+\s=>\s((?:/usr/lib/|/lib/)\S+)") def platform_to_arch(platform_tag): @@ -265,6 +266,7 @@ def search_shlibs_deps(self): """ shlibdeps = set() missing_libs = set() + external_libs = set() shlibdeps_file = "shlibdeps.txt" if (self.root / shlibdeps_file).exists(): @@ -279,6 +281,11 @@ def search_shlibs_deps(self): output, _ = shell(args, cwd=self.root) missing_libs.update(DPKG_SHLIBS_RE.findall(output, re.MULTILINE)) + for x in self.wheel.record.libs: + lib = str(self.src / x) + output = shell(["ldd", lib], cwd=self.root)[0] + external_libs.update(LDD_DEP_RE.findall(output, re.MULTILINE)) + if missing_libs: logger.info( "dpkg-shlibdeps reported the following missing " @@ -286,29 +293,18 @@ def search_shlibs_deps(self): missing_libs, ) + if external_libs: + logger.info( + "found the following shared libs dependencies: %s", + external_libs, + ) + + if not shlibdeps: # search packages providing those libs - for lib in missing_libs: - output, _ = shell(["apt-file", "search", lib, "-a", self.arch]) - packages = set(APT_FILE_RE.findall(output)) - - # remove dbg packages - packages = [p for p in packages if p[-3:] != "dbg"] - - if not len(packages): - logger.warning("did not find a package providing %s", lib) - else: - # we pick the package with the shortest name - packages = sorted(packages, key=len) - shlibdeps.add(packages[0]) - - if len(packages) > 1: - logger.warning( - "several packages providing %s: %s, picking %s, " - "edit debian/control to use another one.", - lib, - packages, - packages[0], - ) + for lib in missing_libs | external_libs: + pkg = self.find_package_for_lib(lib) + if pkg: + shlibdeps.add(pkg) with open(str(self.root / shlibdeps_file), "w") as f: f.write("\n".join(shlibdeps)) @@ -318,6 +314,30 @@ def search_shlibs_deps(self): self.depends = list(set(self.depends) | shlibdeps) + def find_package_for_lib(self, lib): + output, _ = shell(["apt-file", "search", lib, "-a", self.arch]) + packages = set(APT_FILE_RE.findall(output)) + + # remove dbg packages + packages = [p for p in packages if p[-3:] != "dbg"] + + if not len(packages): + logger.warning("did not find a package providing %s", lib) + return None + + # we pick the package with the shortest name + packages = sorted(packages, key=len) + if len(packages) > 1: + logger.warning( + "several packages providing %s: %s, picking %s, " + "edit debian/control to use another one.", + lib, + packages, + packages[0], + ) + + return packages[0] + def run_install_scripts(self): config = configparser.ConfigParser()