blob: 7135d74837cb02ee022de44eff74b4c6ffa75f57 [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7# Debian package renaming only occurs when a package is built
8# We therefore have to make sure we build all runtime packages
9# before building the current package to make the packages runtime
10# depends are correct
11#
12# Custom library package names can be defined setting
13# DEBIANNAME: + pkgname to the desired name.
14#
15# Better expressed as ensure all RDEPENDS package before we package
16# This means we can't have circular RDEPENDS/RRECOMMENDS
17
18AUTO_LIBNAME_PKGS = "${PACKAGES}"
19
20inherit package
21
22DEBIANRDEP = "do_packagedata"
23do_package_write_ipk[deptask] = "${DEBIANRDEP}"
24do_package_write_deb[deptask] = "${DEBIANRDEP}"
25do_package_write_tar[deptask] = "${DEBIANRDEP}"
26do_package_write_rpm[deptask] = "${DEBIANRDEP}"
27do_package_write_ipk[rdeptask] = "${DEBIANRDEP}"
28do_package_write_deb[rdeptask] = "${DEBIANRDEP}"
29do_package_write_tar[rdeptask] = "${DEBIANRDEP}"
30do_package_write_rpm[rdeptask] = "${DEBIANRDEP}"
31
32python () {
33 if not d.getVar("PACKAGES"):
34 d.setVar("DEBIANRDEP", "")
35}
36
37python debian_package_name_hook () {
38 import glob, copy, stat, errno, re, pathlib, subprocess
39
40 pkgdest = d.getVar("PKGDEST")
41 packages = d.getVar('PACKAGES')
42 so_re = re.compile(r"lib.*\.so")
43
44 def socrunch(s):
45 s = s.lower().replace('_', '-')
46 m = re.match(r"^(.*)(.)\.so\.(.*)$", s)
47 if m is None:
48 return None
49 if m.group(2) in '0123456789':
50 bin = '%s%s-%s' % (m.group(1), m.group(2), m.group(3))
51 else:
52 bin = m.group(1) + m.group(2) + m.group(3)
53 dev = m.group(1) + m.group(2)
54 return (bin, dev)
55
56 def isexec(path):
57 try:
58 s = os.stat(path)
59 except (os.error, AttributeError):
60 return 0
61 return (s[stat.ST_MODE] & stat.S_IEXEC)
62
63 def add_rprovides(pkg, d):
64 newpkg = d.getVar('PKG:' + pkg)
65 if newpkg and newpkg != pkg:
66 provs = (d.getVar('RPROVIDES:' + pkg) or "").split()
67 if pkg not in provs:
68 d.appendVar('RPROVIDES:' + pkg, " " + pkg + " (=" + d.getVar("PKGV") + ")")
69
70 def auto_libname(packages, orig_pkg):
71 p = lambda var: pathlib.PurePath(d.getVar(var))
72 libdirs = (p("base_libdir"), p("libdir"))
73 bindirs = (p("base_bindir"), p("base_sbindir"), p("bindir"), p("sbindir"))
74
75 sonames = []
76 has_bins = 0
77 has_libs = 0
78 for f in pkgfiles[orig_pkg]:
79 # This is .../packages-split/orig_pkg/
80 pkgpath = pathlib.PurePath(pkgdest, orig_pkg)
81 # Strip pkgpath off the full path to a file in the package, re-root
82 # so it is absolute, and then get the parent directory of the file.
83 path = pathlib.PurePath("/") / (pathlib.PurePath(f).relative_to(pkgpath).parent)
84 if path in bindirs:
85 has_bins = 1
86 if path in libdirs:
87 has_libs = 1
88 if so_re.match(os.path.basename(f)):
89 try:
90 cmd = [d.expand("${TARGET_PREFIX}objdump"), "-p", f]
91 output = subprocess.check_output(cmd).decode("utf-8")
92 for m in re.finditer(r"\s+SONAME\s+([^\s]+)", output):
93 if m.group(1) not in sonames:
94 sonames.append(m.group(1))
95 except subprocess.CalledProcessError:
96 pass
97 bb.debug(1, 'LIBNAMES: pkg %s libs %d bins %d sonames %s' % (orig_pkg, has_libs, has_bins, sonames))
98 soname = None
99 if len(sonames) == 1:
100 soname = sonames[0]
101 elif len(sonames) > 1:
102 lead = d.getVar('LEAD_SONAME')
103 if lead:
104 r = re.compile(lead)
105 filtered = []
106 for s in sonames:
107 if r.match(s):
108 filtered.append(s)
109 if len(filtered) == 1:
110 soname = filtered[0]
111 elif len(filtered) > 1:
112 bb.note("Multiple matches (%s) for LEAD_SONAME '%s'" % (", ".join(filtered), lead))
113 else:
114 bb.note("Multiple libraries (%s) found, but LEAD_SONAME '%s' doesn't match any of them" % (", ".join(sonames), lead))
115 else:
116 bb.note("Multiple libraries (%s) found and LEAD_SONAME not defined" % ", ".join(sonames))
117
118 if has_libs and not has_bins and soname:
119 soname_result = socrunch(soname)
120 if soname_result:
121 (pkgname, devname) = soname_result
122 for pkg in packages.split():
123 if (d.getVar('PKG:' + pkg, False) or d.getVar('DEBIAN_NOAUTONAME:' + pkg, False)):
124 add_rprovides(pkg, d)
125 continue
126 debian_pn = d.getVar('DEBIANNAME:' + pkg, False)
127 if debian_pn:
128 newpkg = debian_pn
129 elif pkg == orig_pkg:
130 newpkg = pkgname
131 else:
132 newpkg = pkg.replace(orig_pkg, devname, 1)
133 mlpre=d.getVar('MLPREFIX')
134 if mlpre:
135 if not newpkg.find(mlpre) == 0:
136 newpkg = mlpre + newpkg
137 if newpkg != pkg:
138 bb.note("debian: renaming %s to %s" % (pkg, newpkg))
139 d.setVar('PKG:' + pkg, newpkg)
140 add_rprovides(pkg, d)
141 else:
142 add_rprovides(orig_pkg, d)
143
144 # reversed sort is needed when some package is substring of another
145 # ie in ncurses we get without reverse sort:
146 # DEBUG: LIBNAMES: pkgname libtic5 devname libtic pkg ncurses-libtic orig_pkg ncurses-libtic debian_pn None newpkg libtic5
147 # and later
148 # DEBUG: LIBNAMES: pkgname libtic5 devname libtic pkg ncurses-libticw orig_pkg ncurses-libtic debian_pn None newpkg libticw
149 # so we need to handle ncurses-libticw->libticw5 before ncurses-libtic->libtic5
150 for pkg in sorted((d.getVar('AUTO_LIBNAME_PKGS') or "").split(), reverse=True):
151 auto_libname(packages, pkg)
152}
153
154EXPORT_FUNCTIONS package_name_hook
155
156DEBIAN_NAMES = "1"