Skip to content

Commit

Permalink
Generate dependencies for referenced shared libs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Woellchen committed Oct 7, 2022
1 parent 901795f commit bac1a36
Showing 1 changed file with 42 additions and 22 deletions.
64 changes: 42 additions & 22 deletions src/_wheel2deb/debian.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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):
Expand Down Expand Up @@ -257,6 +258,7 @@ def search_shlibs_deps(self):
"""
shlibdeps = set()
missing_libs = set()
external_libs = set()
shlibdeps_file = "shlibdeps.txt"

if (self.root / shlibdeps_file).exists():
Expand All @@ -271,36 +273,30 @@ def search_shlibs_deps(self):
output = shell(args, cwd=self.root)[0]
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 "
"shared libs dependencies: %s",
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])[0]
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))
Expand All @@ -310,6 +306,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])[0]
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):
import configparser

Expand Down

0 comments on commit bac1a36

Please sign in to comment.