blob: 7a36262eb600059dc21745c0314ca7a661ebb77b [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Packaging process
3#
4# Executive summary: This class iterates over the functions listed in PACKAGEFUNCS
5# Taking D and splitting it up into the packages listed in PACKAGES, placing the
6# resulting output in PKGDEST.
7#
8# There are the following default steps but PACKAGEFUNCS can be extended:
9#
10# a) package_get_auto_pr - get PRAUTO from remote PR service
11#
12# b) perform_packagecopy - Copy D into PKGD
13#
14# c) package_do_split_locales - Split out the locale files, updates FILES and PACKAGES
15#
16# d) split_and_strip_files - split the files into runtime and debug and strip them.
17# Debug files include debug info split, and associated sources that end up in -dbg packages
18#
19# e) fixup_perms - Fix up permissions in the package before we split it.
20#
21# f) populate_packages - Split the files in PKGD into separate packages in PKGDEST/<pkgname>
22# Also triggers the binary stripping code to put files in -dbg packages.
23#
24# g) package_do_filedeps - Collect perfile run-time dependency metadata
25# The data is stores in FILER{PROVIDES,DEPENDS}_file_pkg variables with
26# a list of affected files in FILER{PROVIDES,DEPENDS}FLIST_pkg
27#
28# h) package_do_shlibs - Look at the shared libraries generated and autotmatically add any
Brad Bishop316dfdd2018-06-25 12:45:53 -040029# dependencies found. Also stores the package name so anyone else using this library
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030# knows which package to depend on.
31#
32# i) package_do_pkgconfig - Keep track of which packages need and provide which .pc files
33#
34# j) read_shlibdeps - Reads the stored shlibs information into the metadata
35#
36# k) package_depchains - Adds automatic dependencies to -dbg and -dev packages
37#
38# l) emit_pkgdata - saves the packaging data into PKGDATA_DIR for use in later
39# packaging steps
40
41inherit packagedata
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042inherit chrpath
Brad Bishop96ff1982019-08-19 13:50:42 -040043inherit package_pkgdata
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044
45# Need the package_qa_handle_error() in insane.bbclass
46inherit insane
47
48PKGD = "${WORKDIR}/package"
49PKGDEST = "${WORKDIR}/packages-split"
50
51LOCALE_SECTION ?= ''
52
53ALL_MULTILIB_PACKAGE_ARCHS = "${@all_multilib_tune_values(d, 'PACKAGE_ARCHS')}"
54
55# rpm is used for the per-file dependency identification
Brad Bishop316dfdd2018-06-25 12:45:53 -040056# dwarfsrcfiles is used to determine the list of debug source files
57PACKAGE_DEPENDS += "rpm-native dwarfsrcfiles-native"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
Brad Bishop6e60e8b2018-02-01 10:27:11 -050059
60# If your postinstall can execute at rootfs creation time rather than on
61# target but depends on a native/cross tool in order to execute, you need to
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080062# list that tool in PACKAGE_WRITE_DEPS. Target package dependencies belong
Brad Bishop6e60e8b2018-02-01 10:27:11 -050063# in the package dependencies as normal, this is just for native/cross support
64# tools at rootfs build time.
65PACKAGE_WRITE_DEPS ??= ""
66
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067def legitimize_package_name(s):
68 """
69 Make sure package names are legitimate strings
70 """
71 import re
72
73 def fixutf(m):
74 cp = m.group(1)
75 if cp:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076 return ('\\u%s' % cp).encode('latin-1').decode('unicode_escape')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077
78 # Handle unicode codepoints encoded as <U0123>, as in glibc locale files.
Brad Bishop19323692019-04-05 15:28:33 -040079 s = re.sub(r'<U([0-9A-Fa-f]{1,4})>', fixutf, s)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080
81 # Remaining package name validity fixes
82 return s.lower().replace('_', '-').replace('@', '+').replace(',', '+').replace('/', '-')
83
84def do_split_packages(d, root, file_regex, output_pattern, description, postinst=None, recursive=False, hook=None, extra_depends=None, aux_files_pattern=None, postrm=None, allow_dirs=False, prepend=False, match_path=False, aux_files_pattern_verbatim=None, allow_links=False, summary=None):
85 """
86 Used in .bb files to split up dynamically generated subpackages of a
87 given package, usually plugins or modules.
88
89 Arguments:
90 root -- the path in which to search
91 file_regex -- regular expression to match searched files. Use
92 parentheses () to mark the part of this expression
93 that should be used to derive the module name (to be
94 substituted where %s is used in other function
95 arguments as noted below)
96 output_pattern -- pattern to use for the package names. Must include %s.
97 description -- description to set for each package. Must include %s.
98 postinst -- postinstall script to use for all packages (as a
99 string)
100 recursive -- True to perform a recursive search - default False
101 hook -- a hook function to be called for every match. The
102 function will be called with the following arguments
103 (in the order listed):
104 f: full path to the file/directory match
105 pkg: the package name
106 file_regex: as above
107 output_pattern: as above
108 modulename: the module name derived using file_regex
109 extra_depends -- extra runtime dependencies (RDEPENDS) to be set for
110 all packages. The default value of None causes a
111 dependency on the main package (${PN}) - if you do
112 not want this, pass '' for this parameter.
113 aux_files_pattern -- extra item(s) to be added to FILES for each
114 package. Can be a single string item or a list of
115 strings for multiple items. Must include %s.
116 postrm -- postrm script to use for all packages (as a string)
117 allow_dirs -- True allow directories to be matched - default False
118 prepend -- if True, prepend created packages to PACKAGES instead
119 of the default False which appends them
120 match_path -- match file_regex on the whole relative path to the
121 root rather than just the file name
122 aux_files_pattern_verbatim -- extra item(s) to be added to FILES for
123 each package, using the actual derived module name
124 rather than converting it to something legal for a
125 package name. Can be a single string item or a list
126 of strings for multiple items. Must include %s.
127 allow_links -- True to allow symlinks to be matched - default False
128 summary -- Summary to set for each package. Must include %s;
129 defaults to description if not set.
130
131 """
132
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500133 dvar = d.getVar('PKGD')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500134 root = d.expand(root)
135 output_pattern = d.expand(output_pattern)
136 extra_depends = d.expand(extra_depends)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137
138 # If the root directory doesn't exist, don't error out later but silently do
139 # no splitting.
140 if not os.path.exists(dvar + root):
141 return []
142
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500143 ml = d.getVar("MLPREFIX")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 if ml:
145 if not output_pattern.startswith(ml):
146 output_pattern = ml + output_pattern
147
148 newdeps = []
149 for dep in (extra_depends or "").split():
150 if dep.startswith(ml):
151 newdeps.append(dep)
152 else:
153 newdeps.append(ml + dep)
154 if newdeps:
155 extra_depends = " ".join(newdeps)
156
157
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500158 packages = d.getVar('PACKAGES').split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 split_packages = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500160
161 if postinst:
162 postinst = '#!/bin/sh\n' + postinst + '\n'
163 if postrm:
164 postrm = '#!/bin/sh\n' + postrm + '\n'
165 if not recursive:
166 objs = os.listdir(dvar + root)
167 else:
168 objs = []
169 for walkroot, dirs, files in os.walk(dvar + root):
170 for file in files:
171 relpath = os.path.join(walkroot, file).replace(dvar + root + '/', '', 1)
172 if relpath:
173 objs.append(relpath)
174
175 if extra_depends == None:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500176 extra_depends = d.getVar("PN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500177
178 if not summary:
179 summary = description
180
181 for o in sorted(objs):
182 import re, stat
183 if match_path:
184 m = re.match(file_regex, o)
185 else:
186 m = re.match(file_regex, os.path.basename(o))
187
188 if not m:
189 continue
190 f = os.path.join(dvar + root, o)
191 mode = os.lstat(f).st_mode
192 if not (stat.S_ISREG(mode) or (allow_links and stat.S_ISLNK(mode)) or (allow_dirs and stat.S_ISDIR(mode))):
193 continue
194 on = legitimize_package_name(m.group(1))
195 pkg = output_pattern % on
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600196 split_packages.add(pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197 if not pkg in packages:
198 if prepend:
199 packages = [pkg] + packages
200 else:
201 packages.append(pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500202 oldfiles = d.getVar('FILES_' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203 newfile = os.path.join(root, o)
204 # These names will be passed through glob() so if the filename actually
205 # contains * or ? (rare, but possible) we need to handle that specially
206 newfile = newfile.replace('*', '[*]')
207 newfile = newfile.replace('?', '[?]')
208 if not oldfiles:
209 the_files = [newfile]
210 if aux_files_pattern:
211 if type(aux_files_pattern) is list:
212 for fp in aux_files_pattern:
213 the_files.append(fp % on)
214 else:
215 the_files.append(aux_files_pattern % on)
216 if aux_files_pattern_verbatim:
217 if type(aux_files_pattern_verbatim) is list:
218 for fp in aux_files_pattern_verbatim:
219 the_files.append(fp % m.group(1))
220 else:
221 the_files.append(aux_files_pattern_verbatim % m.group(1))
222 d.setVar('FILES_' + pkg, " ".join(the_files))
223 else:
224 d.setVar('FILES_' + pkg, oldfiles + " " + newfile)
225 if extra_depends != '':
226 d.appendVar('RDEPENDS_' + pkg, ' ' + extra_depends)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500227 if not d.getVar('DESCRIPTION_' + pkg):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500228 d.setVar('DESCRIPTION_' + pkg, description % on)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500229 if not d.getVar('SUMMARY_' + pkg):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230 d.setVar('SUMMARY_' + pkg, summary % on)
231 if postinst:
232 d.setVar('pkg_postinst_' + pkg, postinst)
233 if postrm:
234 d.setVar('pkg_postrm_' + pkg, postrm)
235 if callable(hook):
236 hook(f, pkg, file_regex, output_pattern, m.group(1))
237
238 d.setVar('PACKAGES', ' '.join(packages))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 return list(split_packages)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500240
241PACKAGE_DEPENDS += "file-native"
242
243python () {
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500244 if d.getVar('PACKAGES') != '':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 deps = ""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500246 for dep in (d.getVar('PACKAGE_DEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247 deps += " %s:do_populate_sysroot" % dep
Andrew Geissler82c905d2020-04-13 13:39:40 -0500248 if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
249 deps += ' xz-native:do_populate_sysroot'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250 d.appendVarFlag('do_package', 'depends', deps)
251
252 # shlibs requires any DEPENDS to have already packaged for the *.list files
253 d.appendVarFlag('do_package', 'deptask', " do_packagedata")
254}
255
256# Get a list of files from file vars by searching files under current working directory
257# The list contains symlinks, directories and normal files.
258def files_from_filevars(filevars):
259 import os,glob
260 cpath = oe.cachedpath.CachedPath()
261 files = []
262 for f in filevars:
263 if os.path.isabs(f):
264 f = '.' + f
265 if not f.startswith("./"):
266 f = './' + f
267 globbed = glob.glob(f)
268 if globbed:
269 if [ f ] != globbed:
270 files += globbed
271 continue
272 files.append(f)
273
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600274 symlink_paths = []
275 for ind, f in enumerate(files):
276 # Handle directory symlinks. Truncate path to the lowest level symlink
277 parent = ''
278 for dirname in f.split('/')[:-1]:
279 parent = os.path.join(parent, dirname)
280 if dirname == '.':
281 continue
282 if cpath.islink(parent):
283 bb.warn("FILES contains file '%s' which resides under a "
284 "directory symlink. Please fix the recipe and use the "
285 "real path for the file." % f[1:])
286 symlink_paths.append(f)
287 files[ind] = parent
288 f = parent
289 break
290
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500291 if not cpath.islink(f):
292 if cpath.isdir(f):
293 newfiles = [ os.path.join(f,x) for x in os.listdir(f) ]
294 if newfiles:
295 files += newfiles
296
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 return files, symlink_paths
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500298
299# Called in package_<rpm,ipk,deb>.bbclass to get the correct list of configuration files
300def get_conffiles(pkg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500301 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500302 root = os.path.join(pkgdest, pkg)
303 cwd = os.getcwd()
304 os.chdir(root)
305
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500306 conffiles = d.getVar('CONFFILES_%s' % pkg);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307 if conffiles == None:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500308 conffiles = d.getVar('CONFFILES')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500309 if conffiles == None:
310 conffiles = ""
311 conffiles = conffiles.split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600312 conf_orig_list = files_from_filevars(conffiles)[0]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500313
314 # Remove links and directories from conf_orig_list to get conf_list which only contains normal files
315 conf_list = []
316 for f in conf_orig_list:
317 if os.path.isdir(f):
318 continue
319 if os.path.islink(f):
320 continue
321 if not os.path.exists(f):
322 continue
323 conf_list.append(f)
324
325 # Remove the leading './'
326 for i in range(0, len(conf_list)):
327 conf_list[i] = conf_list[i][1:]
328
329 os.chdir(cwd)
330 return conf_list
331
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500332def checkbuildpath(file, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500333 tmpdir = d.getVar('TMPDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500334 with open(file) as f:
335 file_content = f.read()
336 if tmpdir in file_content:
337 return True
338
339 return False
340
Brad Bishop316dfdd2018-06-25 12:45:53 -0400341def parse_debugsources_from_dwarfsrcfiles_output(dwarfsrcfiles_output):
342 debugfiles = {}
343
344 for line in dwarfsrcfiles_output.splitlines():
345 if line.startswith("\t"):
346 debugfiles[os.path.normpath(line.split()[0])] = ""
347
348 return debugfiles.keys()
349
Brad Bishop19323692019-04-05 15:28:33 -0400350def source_info(file, d, fatal=True):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800351 import subprocess
352
353 cmd = ["dwarfsrcfiles", file]
354 try:
355 output = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT)
356 retval = 0
357 except subprocess.CalledProcessError as exc:
358 output = exc.output
359 retval = exc.returncode
360
Brad Bishop316dfdd2018-06-25 12:45:53 -0400361 # 255 means a specific file wasn't fully parsed to get the debug file list, which is not a fatal failure
362 if retval != 0 and retval != 255:
363 msg = "dwarfsrcfiles failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else "")
364 if fatal:
365 bb.fatal(msg)
366 bb.note(msg)
367
368 debugsources = parse_debugsources_from_dwarfsrcfiles_output(output)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400369
Brad Bishop19323692019-04-05 15:28:33 -0400370 return list(debugsources)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400371
Brad Bishop19323692019-04-05 15:28:33 -0400372def splitdebuginfo(file, dvar, debugdir, debuglibdir, debugappend, debugsrcdir, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500373 # Function to split a single file into two components, one is the stripped
374 # target system binary, the other contains any debugging information. The
375 # two files are linked to reference each other.
376 #
Brad Bishop19323692019-04-05 15:28:33 -0400377 # return a mapping of files:debugsources
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500378
379 import stat
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800380 import subprocess
381
382 src = file[len(dvar):]
383 dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
384 debugfile = dvar + dest
Brad Bishop19323692019-04-05 15:28:33 -0400385 sources = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800386
387 # Split the file...
388 bb.utils.mkdirhier(os.path.dirname(debugfile))
389 #bb.note("Split %s -> %s" % (file, debugfile))
390 # Only store off the hard link reference if we successfully split!
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500391
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500392 dvar = d.getVar('PKGD')
393 objcopy = d.getVar("OBJCOPY")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500394
395 # We ignore kernel modules, we don't generate debug info files.
396 if file.find("/lib/modules/") != -1 and file.endswith(".ko"):
Brad Bishop19323692019-04-05 15:28:33 -0400397 return (file, sources)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500398
399 newmode = None
400 if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
401 origmode = os.stat(file)[stat.ST_MODE]
402 newmode = origmode | stat.S_IWRITE | stat.S_IREAD
403 os.chmod(file, newmode)
404
405 # We need to extract the debug src information here...
406 if debugsrcdir:
Brad Bishop19323692019-04-05 15:28:33 -0400407 sources = source_info(file, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500408
409 bb.utils.mkdirhier(os.path.dirname(debugfile))
410
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800411 subprocess.check_output([objcopy, '--only-keep-debug', file, debugfile], stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500412
413 # Set the debuglink to have the view of the file path on the target
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800414 subprocess.check_output([objcopy, '--add-gnu-debuglink', debugfile, file], stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500415
416 if newmode:
417 os.chmod(file, origmode)
418
Brad Bishop19323692019-04-05 15:28:33 -0400419 return (file, sources)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500420
Andrew Geissler82c905d2020-04-13 13:39:40 -0500421def splitstaticdebuginfo(file, dvar, debugstaticdir, debugstaticlibdir, debugstaticappend, debugsrcdir, d):
422 # Unlike the function above, there is no way to split a static library
423 # two components. So to get similar results we will copy the unmodified
424 # static library (containing the debug symbols) into a new directory.
425 # We will then strip (preserving symbols) the static library in the
426 # typical location.
427 #
428 # return a mapping of files:debugsources
429
430 import stat
431 import shutil
432
433 src = file[len(dvar):]
434 dest = debugstaticlibdir + os.path.dirname(src) + debugstaticdir + "/" + os.path.basename(src) + debugstaticappend
435 debugfile = dvar + dest
436 sources = []
437
438 # Copy the file...
439 bb.utils.mkdirhier(os.path.dirname(debugfile))
440 #bb.note("Copy %s -> %s" % (file, debugfile))
441
442 dvar = d.getVar('PKGD')
443
444 newmode = None
445 if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
446 origmode = os.stat(file)[stat.ST_MODE]
447 newmode = origmode | stat.S_IWRITE | stat.S_IREAD
448 os.chmod(file, newmode)
449
450 # We need to extract the debug src information here...
451 if debugsrcdir:
452 sources = source_info(file, d)
453
454 bb.utils.mkdirhier(os.path.dirname(debugfile))
455
456 # Copy the unmodified item to the debug directory
457 shutil.copy2(file, debugfile)
458
459 if newmode:
460 os.chmod(file, origmode)
461
462 return (file, sources)
463
464def inject_minidebuginfo(file, dvar, debugdir, debuglibdir, debugappend, debugsrcdir, d):
465 # Extract just the symbols from debuginfo into minidebuginfo,
466 # compress it with xz and inject it back into the binary in a .gnu_debugdata section.
467 # https://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html
468
469 import subprocess
470
471 readelf = d.getVar('READELF')
472 nm = d.getVar('NM')
473 objcopy = d.getVar('OBJCOPY')
474
475 minidebuginfodir = d.expand('${WORKDIR}/minidebuginfo')
476
477 src = file[len(dvar):]
478 dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
479 debugfile = dvar + dest
480 minidebugfile = minidebuginfodir + src + '.minidebug'
481 bb.utils.mkdirhier(os.path.dirname(minidebugfile))
482
483 # If we didn't produce debuginfo for any reason, we can't produce minidebuginfo either
484 # so skip it.
485 if not os.path.exists(debugfile):
486 bb.debug(1, 'ELF file {} has no debuginfo, skipping minidebuginfo injection'.format(file))
487 return
488
489 # Find non-allocated PROGBITS, NOTE, and NOBITS sections in the debuginfo.
490 # We will exclude all of these from minidebuginfo to save space.
491 remove_section_names = []
492 for line in subprocess.check_output([readelf, '-W', '-S', debugfile], universal_newlines=True).splitlines():
493 fields = line.split()
494 if len(fields) < 8:
495 continue
496 name = fields[0]
497 type = fields[1]
498 flags = fields[7]
499 # .debug_ sections will be removed by objcopy -S so no need to explicitly remove them
500 if name.startswith('.debug_'):
501 continue
502 if 'A' not in flags and type in ['PROGBITS', 'NOTE', 'NOBITS']:
503 remove_section_names.append(name)
504
505 # List dynamic symbols in the binary. We can exclude these from minidebuginfo
506 # because they are always present in the binary.
507 dynsyms = set()
508 for line in subprocess.check_output([nm, '-D', file, '--format=posix', '--defined-only'], universal_newlines=True).splitlines():
509 dynsyms.add(line.split()[0])
510
511 # Find all function symbols from debuginfo which aren't in the dynamic symbols table.
512 # These are the ones we want to keep in minidebuginfo.
513 keep_symbols_file = minidebugfile + '.symlist'
514 found_any_symbols = False
515 with open(keep_symbols_file, 'w') as f:
516 for line in subprocess.check_output([nm, debugfile, '--format=sysv', '--defined-only'], universal_newlines=True).splitlines():
517 fields = line.split('|')
518 if len(fields) < 7:
519 continue
520 name = fields[0].strip()
521 type = fields[3].strip()
522 if type == 'FUNC' and name not in dynsyms:
523 f.write('{}\n'.format(name))
524 found_any_symbols = True
525
526 if not found_any_symbols:
527 bb.debug(1, 'ELF file {} contains no symbols, skipping minidebuginfo injection'.format(file))
528 return
529
530 bb.utils.remove(minidebugfile)
531 bb.utils.remove(minidebugfile + '.xz')
532
533 subprocess.check_call([objcopy, '-S'] +
534 ['--remove-section={}'.format(s) for s in remove_section_names] +
535 ['--keep-symbols={}'.format(keep_symbols_file), debugfile, minidebugfile])
536
537 subprocess.check_call(['xz', '--keep', minidebugfile])
538
539 subprocess.check_call([objcopy, '--add-section', '.gnu_debugdata={}.xz'.format(minidebugfile), file])
540
Brad Bishop19323692019-04-05 15:28:33 -0400541def copydebugsources(debugsrcdir, sources, d):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400542 # The debug src information written out to sourcefile is further processed
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500543 # and copied to the destination here.
544
545 import stat
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800546 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500547
Brad Bishop19323692019-04-05 15:28:33 -0400548 if debugsrcdir and sources:
549 sourcefile = d.expand("${WORKDIR}/debugsources.list")
550 bb.utils.remove(sourcefile)
551
552 # filenames are null-separated - this is an artefact of the previous use
553 # of rpm's debugedit, which was writing them out that way, and the code elsewhere
554 # is still assuming that.
555 debuglistoutput = '\0'.join(sources) + '\0'
556 with open(sourcefile, 'a') as sf:
557 sf.write(debuglistoutput)
558
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500559 dvar = d.getVar('PKGD')
560 strip = d.getVar("STRIP")
561 objcopy = d.getVar("OBJCOPY")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500562 workdir = d.getVar("WORKDIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500563 workparentdir = os.path.dirname(os.path.dirname(workdir))
564 workbasedir = os.path.basename(os.path.dirname(workdir)) + "/" + os.path.basename(workdir)
565
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500566 # If build path exists in sourcefile, it means toolchain did not use
567 # -fdebug-prefix-map to compile
568 if checkbuildpath(sourcefile, d):
569 localsrc_prefix = workparentdir + "/"
570 else:
571 localsrc_prefix = "/usr/src/debug/"
572
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500573 nosuchdir = []
574 basepath = dvar
575 for p in debugsrcdir.split("/"):
576 basepath = basepath + "/" + p
577 if not cpath.exists(basepath):
578 nosuchdir.append(basepath)
579 bb.utils.mkdirhier(basepath)
580 cpath.updatecache(basepath)
581
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500582 # Ignore files from the recipe sysroots (target and native)
583 processdebugsrc = "LC_ALL=C ; sort -z -u '%s' | egrep -v -z '((<internal>|<built-in>)$|/.*recipe-sysroot.*/)' | "
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500584 # We need to ignore files that are not actually ours
585 # we do this by only paying attention to items from this package
586 processdebugsrc += "fgrep -zw '%s' | "
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500587 # Remove prefix in the source paths
588 processdebugsrc += "sed 's#%s##g' | "
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500589 processdebugsrc += "(cd '%s' ; cpio -pd0mlL --no-preserve-owner '%s%s' 2>/dev/null)"
590
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500591 cmd = processdebugsrc % (sourcefile, workbasedir, localsrc_prefix, workparentdir, dvar, debugsrcdir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800592 try:
593 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
594 except subprocess.CalledProcessError:
595 # Can "fail" if internal headers/transient sources are attempted
596 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597
598 # cpio seems to have a bug with -lL together and symbolic links are just copied, not dereferenced.
599 # Work around this by manually finding and copying any symbolic links that made it through.
Brad Bishop19323692019-04-05 15:28:33 -0400600 cmd = "find %s%s -type l -print0 -delete | sed s#%s%s/##g | (cd '%s' ; cpio -pd0mL --no-preserve-owner '%s%s')" % \
601 (dvar, debugsrcdir, dvar, debugsrcdir, workparentdir, dvar, debugsrcdir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800602 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500603
604 # The copy by cpio may have resulted in some empty directories! Remove these
605 cmd = "find %s%s -empty -type d -delete" % (dvar, debugsrcdir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800606 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500607
608 # Also remove debugsrcdir if its empty
609 for p in nosuchdir[::-1]:
610 if os.path.exists(p) and not os.listdir(p):
611 os.rmdir(p)
612
613#
614# Package data handling routines
615#
616
Andrew Geissler82c905d2020-04-13 13:39:40 -0500617def get_package_mapping (pkg, basepkg, d, depversions=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500618 import oe.packagedata
619
620 data = oe.packagedata.read_subpkgdata(pkg, d)
621 key = "PKG_%s" % pkg
622
623 if key in data:
624 # Have to avoid undoing the write_extra_pkgs(global_variants...)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800625 if bb.data.inherits_class('allarch', d) and not d.getVar('MULTILIB_VARIANTS') \
626 and data[key] == basepkg:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500627 return pkg
Andrew Geissler82c905d2020-04-13 13:39:40 -0500628 if depversions == []:
629 # Avoid returning a mapping if the renamed package rprovides its original name
630 rprovkey = "RPROVIDES_%s" % pkg
631 if rprovkey in data:
632 if pkg in bb.utils.explode_dep_versions2(data[rprovkey]):
633 bb.note("%s rprovides %s, not replacing the latter" % (data[key], pkg))
634 return pkg
635 # Do map to rewritten package name
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500636 return data[key]
637
638 return pkg
639
640def get_package_additional_metadata (pkg_type, d):
641 base_key = "PACKAGE_ADD_METADATA"
642 for key in ("%s_%s" % (base_key, pkg_type.upper()), base_key):
643 if d.getVar(key, False) is None:
644 continue
645 d.setVarFlag(key, "type", "list")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500646 if d.getVarFlag(key, "separator") is None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500647 d.setVarFlag(key, "separator", "\\n")
648 metadata_fields = [field.strip() for field in oe.data.typed_value(key, d)]
649 return "\n".join(metadata_fields).strip()
650
651def runtime_mapping_rename (varname, pkg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500652 #bb.note("%s before: %s" % (varname, d.getVar(varname)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500653
654 new_depends = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500655 deps = bb.utils.explode_dep_versions2(d.getVar(varname) or "")
Andrew Geissler82c905d2020-04-13 13:39:40 -0500656 for depend, depversions in deps.items():
657 new_depend = get_package_mapping(depend, pkg, d, depversions)
658 if depend != new_depend:
659 bb.note("package name mapping done: %s -> %s" % (depend, new_depend))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 new_depends[new_depend] = deps[depend]
661
662 d.setVar(varname, bb.utils.join_deps(new_depends, commasep=False))
663
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500664 #bb.note("%s after: %s" % (varname, d.getVar(varname)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665
666#
667# Package functions suitable for inclusion in PACKAGEFUNCS
668#
669
670python package_get_auto_pr() {
671 import oe.prservice
672 import re
673
674 # Support per recipe PRSERV_HOST
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500675 pn = d.getVar('PN')
676 host = d.getVar("PRSERV_HOST_" + pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677 if not (host is None):
678 d.setVar("PRSERV_HOST", host)
679
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500680 pkgv = d.getVar("PKGV")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500681
682 # PR Server not active, handle AUTOINC
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500683 if not d.getVar('PRSERV_HOST'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684 if 'AUTOINC' in pkgv:
685 d.setVar("PKGV", pkgv.replace("AUTOINC", "0"))
686 return
687
688 auto_pr = None
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500689 pv = d.getVar("PV")
690 version = d.getVar("PRAUTOINX")
691 pkgarch = d.getVar("PACKAGE_ARCH")
692 checksum = d.getVar("BB_TASKHASH")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500693
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500694 if d.getVar('PRSERV_LOCKDOWN'):
695 auto_pr = d.getVar('PRAUTO_' + version + '_' + pkgarch) or d.getVar('PRAUTO_' + version) or None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500696 if auto_pr is None:
697 bb.fatal("Can NOT get PRAUTO from lockdown exported file")
698 d.setVar('PRAUTO',str(auto_pr))
699 return
700
701 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500702 conn = d.getVar("__PRSERV_CONN")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703 if conn is None:
704 conn = oe.prservice.prserv_make_conn(d)
705 if conn is not None:
706 if "AUTOINC" in pkgv:
707 srcpv = bb.fetch2.get_srcrev(d)
708 base_ver = "AUTOINC-%s" % version[:version.find(srcpv)]
709 value = conn.getPR(base_ver, pkgarch, srcpv)
710 d.setVar("PKGV", pkgv.replace("AUTOINC", str(value)))
711
712 auto_pr = conn.getPR(version, pkgarch, checksum)
713 except Exception as e:
714 bb.fatal("Can NOT get PRAUTO, exception %s" % str(e))
715 if auto_pr is None:
716 bb.fatal("Can NOT get PRAUTO from remote PR service")
717 d.setVar('PRAUTO',str(auto_pr))
718}
719
720LOCALEBASEPN ??= "${PN}"
721
722python package_do_split_locales() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500723 if (d.getVar('PACKAGE_NO_LOCALE') == '1'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500724 bb.debug(1, "package requested not splitting locales")
725 return
726
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500727 packages = (d.getVar('PACKAGES') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500728
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500729 datadir = d.getVar('datadir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500730 if not datadir:
731 bb.note("datadir not defined")
732 return
733
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500734 dvar = d.getVar('PKGD')
735 pn = d.getVar('LOCALEBASEPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500736
737 if pn + '-locale' in packages:
738 packages.remove(pn + '-locale')
739
740 localedir = os.path.join(dvar + datadir, 'locale')
741
742 if not cpath.isdir(localedir):
743 bb.debug(1, "No locale files in this package")
744 return
745
746 locales = os.listdir(localedir)
747
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500748 summary = d.getVar('SUMMARY') or pn
749 description = d.getVar('DESCRIPTION') or ""
750 locale_section = d.getVar('LOCALE_SECTION')
751 mlprefix = d.getVar('MLPREFIX') or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500752 for l in sorted(locales):
753 ln = legitimize_package_name(l)
754 pkg = pn + '-locale-' + ln
755 packages.append(pkg)
756 d.setVar('FILES_' + pkg, os.path.join(datadir, 'locale', l))
757 d.setVar('RRECOMMENDS_' + pkg, '%svirtual-locale-%s' % (mlprefix, ln))
758 d.setVar('RPROVIDES_' + pkg, '%s-locale %s%s-translation' % (pn, mlprefix, ln))
759 d.setVar('SUMMARY_' + pkg, '%s - %s translations' % (summary, l))
760 d.setVar('DESCRIPTION_' + pkg, '%s This package contains language translation files for the %s locale.' % (description, l))
761 if locale_section:
762 d.setVar('SECTION_' + pkg, locale_section)
763
764 d.setVar('PACKAGES', ' '.join(packages))
765
766 # Disabled by RP 18/06/07
767 # Wildcards aren't supported in debian
768 # They break with ipkg since glibc-locale* will mean that
769 # glibc-localedata-translit* won't install as a dependency
770 # for some other package which breaks meta-toolchain
771 # Probably breaks since virtual-locale- isn't provided anywhere
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500772 #rdep = (d.getVar('RDEPENDS_%s' % pn) or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500773 #rdep.append('%s-locale*' % pn)
774 #d.setVar('RDEPENDS_%s' % pn, ' '.join(rdep))
775}
776
777python perform_packagecopy () {
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800778 import subprocess
779
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500780 dest = d.getVar('D')
781 dvar = d.getVar('PKGD')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500782
783 # Start by package population by taking a copy of the installed
784 # files to operate on
785 # Preserve sparse files and hard links
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800786 cmd = 'tar -cf - -C %s -p -S . | tar -xf - -C %s' % (dest, dvar)
787 subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500788
789 # replace RPATHs for the nativesdk binaries, to make them relocatable
790 if bb.data.inherits_class('nativesdk', d) or bb.data.inherits_class('cross-canadian', d):
791 rpath_replace (dvar, d)
792}
793perform_packagecopy[cleandirs] = "${PKGD}"
794perform_packagecopy[dirs] = "${PKGD}"
795
796# We generate a master list of directories to process, we start by
797# seeding this list with reasonable defaults, then load from
798# the fs-perms.txt files
799python fixup_perms () {
800 import pwd, grp
801
802 # init using a string with the same format as a line as documented in
803 # the fs-perms.txt file
804 # <path> <mode> <uid> <gid> <walk> <fmode> <fuid> <fgid>
805 # <path> link <link target>
806 #
807 # __str__ can be used to print out an entry in the input format
808 #
809 # if fs_perms_entry.path is None:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400810 # an error occurred
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500811 # if fs_perms_entry.link, you can retrieve:
812 # fs_perms_entry.path = path
813 # fs_perms_entry.link = target of link
814 # if not fs_perms_entry.link, you can retrieve:
815 # fs_perms_entry.path = path
816 # fs_perms_entry.mode = expected dir mode or None
817 # fs_perms_entry.uid = expected uid or -1
818 # fs_perms_entry.gid = expected gid or -1
819 # fs_perms_entry.walk = 'true' or something else
820 # fs_perms_entry.fmode = expected file mode or None
821 # fs_perms_entry.fuid = expected file uid or -1
822 # fs_perms_entry_fgid = expected file gid or -1
823 class fs_perms_entry():
824 def __init__(self, line):
825 lsplit = line.split()
826 if len(lsplit) == 3 and lsplit[1].lower() == "link":
827 self._setlink(lsplit[0], lsplit[2])
828 elif len(lsplit) == 8:
829 self._setdir(lsplit[0], lsplit[1], lsplit[2], lsplit[3], lsplit[4], lsplit[5], lsplit[6], lsplit[7])
830 else:
831 msg = "Fixup Perms: invalid config line %s" % line
832 package_qa_handle_error("perm-config", msg, d)
833 self.path = None
834 self.link = None
835
836 def _setdir(self, path, mode, uid, gid, walk, fmode, fuid, fgid):
837 self.path = os.path.normpath(path)
838 self.link = None
839 self.mode = self._procmode(mode)
840 self.uid = self._procuid(uid)
841 self.gid = self._procgid(gid)
842 self.walk = walk.lower()
843 self.fmode = self._procmode(fmode)
844 self.fuid = self._procuid(fuid)
845 self.fgid = self._procgid(fgid)
846
847 def _setlink(self, path, link):
848 self.path = os.path.normpath(path)
849 self.link = link
850
851 def _procmode(self, mode):
852 if not mode or (mode and mode == "-"):
853 return None
854 else:
855 return int(mode,8)
856
857 # Note uid/gid -1 has special significance in os.lchown
858 def _procuid(self, uid):
859 if uid is None or uid == "-":
860 return -1
861 elif uid.isdigit():
862 return int(uid)
863 else:
864 return pwd.getpwnam(uid).pw_uid
865
866 def _procgid(self, gid):
867 if gid is None or gid == "-":
868 return -1
869 elif gid.isdigit():
870 return int(gid)
871 else:
872 return grp.getgrnam(gid).gr_gid
873
874 # Use for debugging the entries
875 def __str__(self):
876 if self.link:
877 return "%s link %s" % (self.path, self.link)
878 else:
879 mode = "-"
880 if self.mode:
881 mode = "0%o" % self.mode
882 fmode = "-"
883 if self.fmode:
884 fmode = "0%o" % self.fmode
885 uid = self._mapugid(self.uid)
886 gid = self._mapugid(self.gid)
887 fuid = self._mapugid(self.fuid)
888 fgid = self._mapugid(self.fgid)
889 return "%s %s %s %s %s %s %s %s" % (self.path, mode, uid, gid, self.walk, fmode, fuid, fgid)
890
891 def _mapugid(self, id):
892 if id is None or id == -1:
893 return "-"
894 else:
895 return "%d" % id
896
897 # Fix the permission, owner and group of path
898 def fix_perms(path, mode, uid, gid, dir):
899 if mode and not os.path.islink(path):
900 #bb.note("Fixup Perms: chmod 0%o %s" % (mode, dir))
901 os.chmod(path, mode)
902 # -1 is a special value that means don't change the uid/gid
903 # if they are BOTH -1, don't bother to lchown
904 if not (uid == -1 and gid == -1):
905 #bb.note("Fixup Perms: lchown %d:%d %s" % (uid, gid, dir))
906 os.lchown(path, uid, gid)
907
908 # Return a list of configuration files based on either the default
909 # files/fs-perms.txt or the contents of FILESYSTEM_PERMS_TABLES
910 # paths are resolved via BBPATH
911 def get_fs_perms_list(d):
912 str = ""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500913 bbpath = d.getVar('BBPATH')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500914 fs_perms_tables = d.getVar('FILESYSTEM_PERMS_TABLES') or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500915 for conf_file in fs_perms_tables.split():
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800916 confpath = bb.utils.which(bbpath, conf_file)
917 if confpath:
918 str += " %s" % bb.utils.which(bbpath, conf_file)
919 else:
920 bb.warn("cannot find %s specified in FILESYSTEM_PERMS_TABLES" % conf_file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500921 return str
922
923
924
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500925 dvar = d.getVar('PKGD')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500926
927 fs_perms_table = {}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500928 fs_link_table = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500929
930 # By default all of the standard directories specified in
931 # bitbake.conf will get 0755 root:root.
932 target_path_vars = [ 'base_prefix',
933 'prefix',
934 'exec_prefix',
935 'base_bindir',
936 'base_sbindir',
937 'base_libdir',
938 'datadir',
939 'sysconfdir',
940 'servicedir',
941 'sharedstatedir',
942 'localstatedir',
943 'infodir',
944 'mandir',
945 'docdir',
946 'bindir',
947 'sbindir',
948 'libexecdir',
949 'libdir',
950 'includedir',
951 'oldincludedir' ]
952
953 for path in target_path_vars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500954 dir = d.getVar(path) or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500955 if dir == "":
956 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500957 fs_perms_table[dir] = fs_perms_entry(d.expand("%s 0755 root root false - - -" % (dir)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500958
959 # Now we actually load from the configuration files
960 for conf in get_fs_perms_list(d).split():
Brad Bishop64c979e2019-11-04 13:55:29 -0500961 if not os.path.exists(conf):
962 continue
963 with open(conf) as f:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 for line in f:
965 if line.startswith('#'):
966 continue
967 lsplit = line.split()
968 if len(lsplit) == 0:
969 continue
970 if len(lsplit) != 8 and not (len(lsplit) == 3 and lsplit[1].lower() == "link"):
971 msg = "Fixup perms: %s invalid line: %s" % (conf, line)
972 package_qa_handle_error("perm-line", msg, d)
973 continue
974 entry = fs_perms_entry(d.expand(line))
975 if entry and entry.path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500976 if entry.link:
977 fs_link_table[entry.path] = entry
978 if entry.path in fs_perms_table:
979 fs_perms_table.pop(entry.path)
980 else:
981 fs_perms_table[entry.path] = entry
982 if entry.path in fs_link_table:
983 fs_link_table.pop(entry.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500984
985 # Debug -- list out in-memory table
986 #for dir in fs_perms_table:
987 # bb.note("Fixup Perms: %s: %s" % (dir, str(fs_perms_table[dir])))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500988 #for link in fs_link_table:
989 # bb.note("Fixup Perms: %s: %s" % (link, str(fs_link_table[link])))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500990
991 # We process links first, so we can go back and fixup directory ownership
992 # for any newly created directories
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500993 # Process in sorted order so /run gets created before /run/lock, etc.
994 for entry in sorted(fs_link_table.values(), key=lambda x: x.link):
995 link = entry.link
996 dir = entry.path
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500997 origin = dvar + dir
998 if not (cpath.exists(origin) and cpath.isdir(origin) and not cpath.islink(origin)):
999 continue
1000
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001001 if link[0] == "/":
1002 target = dvar + link
1003 ptarget = link
1004 else:
1005 target = os.path.join(os.path.dirname(origin), link)
1006 ptarget = os.path.join(os.path.dirname(dir), link)
1007 if os.path.exists(target):
1008 msg = "Fixup Perms: Unable to correct directory link, target already exists: %s -> %s" % (dir, ptarget)
1009 package_qa_handle_error("perm-link", msg, d)
1010 continue
1011
1012 # Create path to move directory to, move it, and then setup the symlink
1013 bb.utils.mkdirhier(os.path.dirname(target))
1014 #bb.note("Fixup Perms: Rename %s -> %s" % (dir, ptarget))
1015 os.rename(origin, target)
1016 #bb.note("Fixup Perms: Link %s -> %s" % (dir, link))
1017 os.symlink(link, origin)
1018
1019 for dir in fs_perms_table:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001020 origin = dvar + dir
1021 if not (cpath.exists(origin) and cpath.isdir(origin)):
1022 continue
1023
1024 fix_perms(origin, fs_perms_table[dir].mode, fs_perms_table[dir].uid, fs_perms_table[dir].gid, dir)
1025
1026 if fs_perms_table[dir].walk == 'true':
1027 for root, dirs, files in os.walk(origin):
1028 for dr in dirs:
1029 each_dir = os.path.join(root, dr)
1030 fix_perms(each_dir, fs_perms_table[dir].mode, fs_perms_table[dir].uid, fs_perms_table[dir].gid, dir)
1031 for f in files:
1032 each_file = os.path.join(root, f)
1033 fix_perms(each_file, fs_perms_table[dir].fmode, fs_perms_table[dir].fuid, fs_perms_table[dir].fgid, dir)
1034}
1035
1036python split_and_strip_files () {
1037 import stat, errno
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001038 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001039
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001040 dvar = d.getVar('PKGD')
1041 pn = d.getVar('PN')
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001042 hostos = d.getVar('HOST_OS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001043
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001044 oldcwd = os.getcwd()
1045 os.chdir(dvar)
1046
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001047 # We default to '.debug' style
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001048 if d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory':
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001049 # Single debug-file-directory style debug info
1050 debugappend = ".debug"
Andrew Geissler82c905d2020-04-13 13:39:40 -05001051 debugstaticappend = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001052 debugdir = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001053 debugstaticdir = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001054 debuglibdir = "/usr/lib/debug"
Andrew Geissler82c905d2020-04-13 13:39:40 -05001055 debugstaticlibdir = "/usr/lib/debug-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001056 debugsrcdir = "/usr/src/debug"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001057 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-without-src':
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001058 # Original OE-core, a.k.a. ".debug", style debug info, but without sources in /usr/src/debug
1059 debugappend = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001060 debugstaticappend = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001061 debugdir = "/.debug"
Andrew Geissler82c905d2020-04-13 13:39:40 -05001062 debugstaticdir = "/.debug-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001063 debuglibdir = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001064 debugstaticlibdir = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001065 debugsrcdir = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001066 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-with-srcpkg':
1067 debugappend = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001068 debugstaticappend = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001069 debugdir = "/.debug"
Andrew Geissler82c905d2020-04-13 13:39:40 -05001070 debugstaticdir = "/.debug-static"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001071 debuglibdir = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001072 debugstaticlibdir = ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001073 debugsrcdir = "/usr/src/debug"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001074 else:
1075 # Original OE-core, a.k.a. ".debug", style debug info
1076 debugappend = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001077 debugstaticappend = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001078 debugdir = "/.debug"
Andrew Geissler82c905d2020-04-13 13:39:40 -05001079 debugstaticdir = "/.debug-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001080 debuglibdir = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -05001081 debugstaticlibdir = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001082 debugsrcdir = "/usr/src/debug"
1083
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001084 #
1085 # First lets figure out all of the files we may have to process ... do this only once!
1086 #
1087 elffiles = {}
1088 symlinks = {}
1089 kernmods = []
Brad Bishop316dfdd2018-06-25 12:45:53 -04001090 staticlibs = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001091 inodes = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001092 libdir = os.path.abspath(dvar + os.sep + d.getVar("libdir"))
1093 baselibdir = os.path.abspath(dvar + os.sep + d.getVar("base_libdir"))
Brad Bishop316dfdd2018-06-25 12:45:53 -04001094 skipfiles = (d.getVar("INHIBIT_PACKAGE_STRIP_FILES") or "").split()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001095 if (d.getVar('INHIBIT_PACKAGE_STRIP') != '1' or \
1096 d.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT') != '1'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001097 checkelf = {}
1098 checkelflinks = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001099 for root, dirs, files in cpath.walk(dvar):
1100 for f in files:
1101 file = os.path.join(root, f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001102
1103 # Skip debug files
1104 if debugappend and file.endswith(debugappend):
1105 continue
1106 if debugdir and debugdir in os.path.dirname(file[len(dvar):]):
1107 continue
1108
Brad Bishop316dfdd2018-06-25 12:45:53 -04001109 if file in skipfiles:
1110 continue
1111
Andrew Geissler82c905d2020-04-13 13:39:40 -05001112 if file.endswith(".ko") and file.find("/lib/modules/") != -1:
1113 kernmods.append(file)
1114 continue
1115 if oe.package.is_static_lib(file):
1116 staticlibs.append(file)
1117 continue
1118
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001119 try:
1120 ltarget = cpath.realpath(file, dvar, False)
1121 s = cpath.lstat(ltarget)
1122 except OSError as e:
1123 (err, strerror) = e.args
1124 if err != errno.ENOENT:
1125 raise
1126 # Skip broken symlinks
1127 continue
1128 if not s:
1129 continue
Brad Bishop316dfdd2018-06-25 12:45:53 -04001130 # Check its an executable
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001131 if (s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) or (s[stat.ST_MODE] & stat.S_IXOTH) \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001132 or ((file.startswith(libdir) or file.startswith(baselibdir)) and (".so" in f or ".node" in f)):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001133
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134 if cpath.islink(file):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001135 checkelflinks[file] = ltarget
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001136 continue
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001137 # Use a reference of device ID and inode number to identify files
1138 file_reference = "%d_%d" % (s.st_dev, s.st_ino)
1139 checkelf[file] = (file, file_reference)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001140
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001141 results = oe.utils.multiprocess_launch(oe.package.is_elf, checkelflinks.values(), d)
1142 results_map = {}
1143 for (ltarget, elf_file) in results:
1144 results_map[ltarget] = elf_file
1145 for file in checkelflinks:
1146 ltarget = checkelflinks[file]
1147 # If it's a symlink, and points to an ELF file, we capture the readlink target
1148 if results_map[ltarget]:
1149 target = os.readlink(file)
1150 #bb.note("Sym: %s (%d)" % (ltarget, results_map[ltarget]))
1151 symlinks[file] = target
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001152
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001153 results = oe.utils.multiprocess_launch(oe.package.is_elf, checkelf.keys(), d)
Brad Bishop15ae2502019-06-18 21:44:24 -04001154
1155 # Sort results by file path. This ensures that the files are always
1156 # processed in the same order, which is important to make sure builds
1157 # are reproducible when dealing with hardlinks
1158 results.sort(key=lambda x: x[0])
1159
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001160 for (file, elf_file) in results:
1161 # It's a file (or hardlink), not a link
1162 # ...but is it ELF, and is it already stripped?
1163 if elf_file & 1:
1164 if elf_file & 2:
1165 if 'already-stripped' in (d.getVar('INSANE_SKIP_' + pn) or "").split():
1166 bb.note("Skipping file %s from %s for already-stripped QA test" % (file[len(dvar):], pn))
1167 else:
1168 msg = "File '%s' from %s was already stripped, this will prevent future debugging!" % (file[len(dvar):], pn)
1169 package_qa_handle_error("already-stripped", msg, d)
1170 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001171
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001172 # At this point we have an unstripped elf file. We need to:
1173 # a) Make sure any file we strip is not hardlinked to anything else outside this tree
1174 # b) Only strip any hardlinked file once (no races)
1175 # c) Track any hardlinks between files so that we can reconstruct matching debug file hardlinks
1176
1177 # Use a reference of device ID and inode number to identify files
1178 file_reference = checkelf[file][1]
1179 if file_reference in inodes:
1180 os.unlink(file)
1181 os.link(inodes[file_reference][0], file)
1182 inodes[file_reference].append(file)
1183 else:
1184 inodes[file_reference] = [file]
1185 # break hardlink
1186 bb.utils.break_hardlinks(file)
1187 elffiles[file] = elf_file
1188 # Modified the file so clear the cache
1189 cpath.updatecache(file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001190
1191 #
1192 # First lets process debug splitting
1193 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001194 if (d.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT') != '1'):
Brad Bishop19323692019-04-05 15:28:33 -04001195 results = oe.utils.multiprocess_launch(splitdebuginfo, list(elffiles), d, extraargs=(dvar, debugdir, debuglibdir, debugappend, debugsrcdir, d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001196
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001197 if debugsrcdir and not hostos.startswith("mingw"):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001198 if (d.getVar('PACKAGE_DEBUG_STATIC_SPLIT') == '1'):
1199 results = oe.utils.multiprocess_launch(splitstaticdebuginfo, staticlibs, d, extraargs=(dvar, debugstaticdir, debugstaticlibdir, debugstaticappend, debugsrcdir, d))
1200 else:
1201 for file in staticlibs:
1202 results.append( (file,source_info(file, d)) )
Brad Bishop19323692019-04-05 15:28:33 -04001203
1204 sources = set()
1205 for r in results:
1206 sources.update(r[1])
Brad Bishop316dfdd2018-06-25 12:45:53 -04001207
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001208 # Hardlink our debug symbols to the other hardlink copies
1209 for ref in inodes:
1210 if len(inodes[ref]) == 1:
1211 continue
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001212
1213 target = inodes[ref][0][len(dvar):]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001214 for file in inodes[ref][1:]:
1215 src = file[len(dvar):]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001216 dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(target) + debugappend
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001217 fpath = dvar + dest
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001218 ftarget = dvar + debuglibdir + os.path.dirname(target) + debugdir + "/" + os.path.basename(target) + debugappend
1219 bb.utils.mkdirhier(os.path.dirname(fpath))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001220 # Only one hardlink of separated debug info file in each directory
1221 if not os.access(fpath, os.R_OK):
1222 #bb.note("Link %s -> %s" % (fpath, ftarget))
1223 os.link(ftarget, fpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001224
1225 # Create symlinks for all cases we were able to split symbols
1226 for file in symlinks:
1227 src = file[len(dvar):]
1228 dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend
1229 fpath = dvar + dest
1230 # Skip it if the target doesn't exist
1231 try:
1232 s = os.stat(fpath)
1233 except OSError as e:
1234 (err, strerror) = e.args
1235 if err != errno.ENOENT:
1236 raise
1237 continue
1238
1239 ltarget = symlinks[file]
1240 lpath = os.path.dirname(ltarget)
1241 lbase = os.path.basename(ltarget)
1242 ftarget = ""
1243 if lpath and lpath != ".":
1244 ftarget += lpath + debugdir + "/"
1245 ftarget += lbase + debugappend
1246 if lpath.startswith(".."):
1247 ftarget = os.path.join("..", ftarget)
1248 bb.utils.mkdirhier(os.path.dirname(fpath))
1249 #bb.note("Symlink %s -> %s" % (fpath, ftarget))
1250 os.symlink(ftarget, fpath)
1251
1252 # Process the debugsrcdir if requested...
1253 # This copies and places the referenced sources for later debugging...
Brad Bishop19323692019-04-05 15:28:33 -04001254 copydebugsources(debugsrcdir, sources, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001255 #
1256 # End of debug splitting
1257 #
1258
1259 #
1260 # Now lets go back over things and strip them
1261 #
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001262 if (d.getVar('INHIBIT_PACKAGE_STRIP') != '1'):
1263 strip = d.getVar("STRIP")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001264 sfiles = []
1265 for file in elffiles:
1266 elf_file = int(elffiles[file])
1267 #bb.note("Strip %s" % file)
1268 sfiles.append((file, elf_file, strip))
1269 for f in kernmods:
1270 sfiles.append((f, 16, strip))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001271 if (d.getVar('PACKAGE_STRIP_STATIC') == '1' or d.getVar('PACKAGE_DEBUG_STATIC_SPLIT') == '1'):
1272 for f in staticlibs:
1273 sfiles.append((f, 16, strip))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001274
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001275 oe.utils.multiprocess_launch(oe.package.runstrip, sfiles, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001276
Andrew Geissler82c905d2020-04-13 13:39:40 -05001277 # Build "minidebuginfo" and reinject it back into the stripped binaries
1278 if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
1279 oe.utils.multiprocess_launch(inject_minidebuginfo, list(elffiles), d,
1280 extraargs=(dvar, debugdir, debuglibdir, debugappend, debugsrcdir, d))
1281
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001282 #
1283 # End of strip
1284 #
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001285 os.chdir(oldcwd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001286}
1287
1288python populate_packages () {
1289 import glob, re
1290
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001291 workdir = d.getVar('WORKDIR')
1292 outdir = d.getVar('DEPLOY_DIR')
1293 dvar = d.getVar('PKGD')
Brad Bishop19323692019-04-05 15:28:33 -04001294 packages = d.getVar('PACKAGES').split()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001295 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001296
1297 bb.utils.mkdirhier(outdir)
1298 os.chdir(dvar)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001299
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001300 autodebug = not (d.getVar("NOAUTOPACKAGEDEBUG") or False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001301
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001302 split_source_package = (d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-with-srcpkg')
1303
Brad Bishop19323692019-04-05 15:28:33 -04001304 # If debug-with-srcpkg mode is enabled then add the source package if it
1305 # doesn't exist and add the source file contents to the source package.
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001306 if split_source_package:
1307 src_package_name = ('%s-src' % d.getVar('PN'))
Brad Bishop19323692019-04-05 15:28:33 -04001308 if not src_package_name in packages:
1309 packages.append(src_package_name)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001310 d.setVar('FILES_%s' % src_package_name, '/usr/src/debug')
1311
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001312 # Sanity check PACKAGES for duplicates
Brad Bishop316dfdd2018-06-25 12:45:53 -04001313 # Sanity should be moved to sanity.bbclass once we have the infrastructure
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001314 package_dict = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001315
Brad Bishop19323692019-04-05 15:28:33 -04001316 for i, pkg in enumerate(packages):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001317 if pkg in package_dict:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001318 msg = "%s is listed in PACKAGES multiple times, this leads to packaging errors." % pkg
1319 package_qa_handle_error("packages-list", msg, d)
Brad Bishop19323692019-04-05 15:28:33 -04001320 # Ensure the source package gets the chance to pick up the source files
1321 # before the debug package by ordering it first in PACKAGES. Whether it
1322 # actually picks up any source files is controlled by
1323 # PACKAGE_DEBUG_SPLIT_STYLE.
1324 elif pkg.endswith("-src"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001325 package_dict[pkg] = (10, i)
1326 elif autodebug and pkg.endswith("-dbg"):
1327 package_dict[pkg] = (30, i)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001328 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001329 package_dict[pkg] = (50, i)
Brad Bishop19323692019-04-05 15:28:33 -04001330 packages = sorted(package_dict.keys(), key=package_dict.get)
1331 d.setVar('PACKAGES', ' '.join(packages))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001332 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001333
1334 seen = []
1335
1336 # os.mkdir masks the permissions with umask so we have to unset it first
1337 oldumask = os.umask(0)
1338
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001339 debug = []
1340 for root, dirs, files in cpath.walk(dvar):
1341 dir = root[len(dvar):]
1342 if not dir:
1343 dir = os.sep
1344 for f in (files + dirs):
1345 path = "." + os.path.join(dir, f)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001346 if "/.debug/" in path or "/.debug-static/" in path or path.endswith("/.debug"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001347 debug.append(path)
1348
Brad Bishop19323692019-04-05 15:28:33 -04001349 for pkg in packages:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001350 root = os.path.join(pkgdest, pkg)
1351 bb.utils.mkdirhier(root)
1352
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001353 filesvar = d.getVar('FILES_%s' % pkg) or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001354 if "//" in filesvar:
1355 msg = "FILES variable for package %s contains '//' which is invalid. Attempting to fix this but you should correct the metadata.\n" % pkg
1356 package_qa_handle_error("files-invalid", msg, d)
1357 filesvar.replace("//", "/")
1358
1359 origfiles = filesvar.split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001360 files, symlink_paths = files_from_filevars(origfiles)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001361
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001362 if autodebug and pkg.endswith("-dbg"):
1363 files.extend(debug)
1364
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001365 for file in files:
1366 if (not cpath.islink(file)) and (not cpath.exists(file)):
1367 continue
1368 if file in seen:
1369 continue
1370 seen.append(file)
1371
1372 def mkdir(src, dest, p):
1373 src = os.path.join(src, p)
1374 dest = os.path.join(dest, p)
1375 fstat = cpath.stat(src)
Brad Bishop96ff1982019-08-19 13:50:42 -04001376 os.mkdir(dest)
1377 os.chmod(dest, fstat.st_mode)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001378 os.chown(dest, fstat.st_uid, fstat.st_gid)
1379 if p not in seen:
1380 seen.append(p)
1381 cpath.updatecache(dest)
1382
1383 def mkdir_recurse(src, dest, paths):
1384 if cpath.exists(dest + '/' + paths):
1385 return
1386 while paths.startswith("./"):
1387 paths = paths[2:]
1388 p = "."
1389 for c in paths.split("/"):
1390 p = os.path.join(p, c)
1391 if not cpath.exists(os.path.join(dest, p)):
1392 mkdir(src, dest, p)
1393
1394 if cpath.isdir(file) and not cpath.islink(file):
1395 mkdir_recurse(dvar, root, file)
1396 continue
1397
1398 mkdir_recurse(dvar, root, os.path.dirname(file))
1399 fpath = os.path.join(root,file)
1400 if not cpath.islink(file):
1401 os.link(file, fpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001402 continue
1403 ret = bb.utils.copyfile(file, fpath)
1404 if ret is False or ret == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001405 bb.fatal("File population failed")
1406
1407 # Check if symlink paths exist
1408 for file in symlink_paths:
1409 if not os.path.exists(os.path.join(root,file)):
1410 bb.fatal("File '%s' cannot be packaged into '%s' because its "
1411 "parent directory structure does not exist. One of "
1412 "its parent directories is a symlink whose target "
1413 "directory is not included in the package." %
1414 (file, pkg))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001415
1416 os.umask(oldumask)
1417 os.chdir(workdir)
1418
1419 # Handle LICENSE_EXCLUSION
1420 package_list = []
Brad Bishop19323692019-04-05 15:28:33 -04001421 for pkg in packages:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001422 licenses = d.getVar('LICENSE_EXCLUSION-' + pkg)
1423 if licenses:
1424 msg = "Excluding %s from packaging as it has incompatible license(s): %s" % (pkg, licenses)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001425 package_qa_handle_error("incompatible-license", msg, d)
1426 else:
1427 package_list.append(pkg)
1428 d.setVar('PACKAGES', ' '.join(package_list))
1429
1430 unshipped = []
1431 for root, dirs, files in cpath.walk(dvar):
1432 dir = root[len(dvar):]
1433 if not dir:
1434 dir = os.sep
1435 for f in (files + dirs):
1436 path = os.path.join(dir, f)
1437 if ('.' + path) not in seen:
1438 unshipped.append(path)
1439
1440 if unshipped != []:
1441 msg = pn + ": Files/directories were installed but not shipped in any package:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001442 if "installed-vs-shipped" in (d.getVar('INSANE_SKIP_' + pn) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001443 bb.note("Package %s skipping QA tests: installed-vs-shipped" % pn)
1444 else:
1445 for f in unshipped:
1446 msg = msg + "\n " + f
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001447 msg = msg + "\nPlease set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install.\n"
1448 msg = msg + "%s: %d installed and not shipped files." % (pn, len(unshipped))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001449 package_qa_handle_error("installed-vs-shipped", msg, d)
1450}
1451populate_packages[dirs] = "${D}"
1452
1453python package_fixsymlinks () {
1454 import errno
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001455 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001456 packages = d.getVar("PACKAGES", False).split()
1457
1458 dangling_links = {}
1459 pkg_files = {}
1460 for pkg in packages:
1461 dangling_links[pkg] = []
1462 pkg_files[pkg] = []
1463 inst_root = os.path.join(pkgdest, pkg)
1464 for path in pkgfiles[pkg]:
1465 rpath = path[len(inst_root):]
1466 pkg_files[pkg].append(rpath)
1467 rtarget = cpath.realpath(path, inst_root, True, assume_dir = True)
1468 if not cpath.lexists(rtarget):
1469 dangling_links[pkg].append(os.path.normpath(rtarget[len(inst_root):]))
1470
1471 newrdepends = {}
1472 for pkg in dangling_links:
1473 for l in dangling_links[pkg]:
1474 found = False
1475 bb.debug(1, "%s contains dangling link %s" % (pkg, l))
1476 for p in packages:
1477 if l in pkg_files[p]:
1478 found = True
1479 bb.debug(1, "target found in %s" % p)
1480 if p == pkg:
1481 break
1482 if pkg not in newrdepends:
1483 newrdepends[pkg] = []
1484 newrdepends[pkg].append(p)
1485 break
1486 if found == False:
1487 bb.note("%s contains dangling symlink to %s" % (pkg, l))
1488
1489 for pkg in newrdepends:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001490 rdepends = bb.utils.explode_dep_versions2(d.getVar('RDEPENDS_' + pkg) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001491 for p in newrdepends[pkg]:
1492 if p not in rdepends:
1493 rdepends[p] = []
1494 d.setVar('RDEPENDS_' + pkg, bb.utils.join_deps(rdepends, commasep=False))
1495}
1496
1497
1498python package_package_name_hook() {
1499 """
1500 A package_name_hook function can be used to rewrite the package names by
1501 changing PKG. For an example, see debian.bbclass.
1502 """
1503 pass
1504}
1505
1506EXPORT_FUNCTIONS package_name_hook
1507
1508
1509PKGDESTWORK = "${WORKDIR}/pkgdata"
1510
Andrew Geissler1e34c2d2020-05-29 16:02:59 -05001511PKGDATA_VARS = "PN PE PV PR PKGE PKGV PKGR LICENSE DESCRIPTION SUMMARY RDEPENDS RPROVIDES RRECOMMENDS RSUGGESTS RREPLACES RCONFLICTS SECTION PKG ALLOW_EMPTY FILES CONFFILES FILES_INFO PACKAGE_ADD_METADATA pkg_postinst pkg_postrm pkg_preinst pkg_prerm"
Brad Bishop15ae2502019-06-18 21:44:24 -04001512
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001513python emit_pkgdata() {
1514 from glob import glob
1515 import json
1516
Brad Bishop316dfdd2018-06-25 12:45:53 -04001517 def process_postinst_on_target(pkg, mlprefix):
Brad Bishop96ff1982019-08-19 13:50:42 -04001518 pkgval = d.getVar('PKG_%s' % pkg)
1519 if pkgval is None:
1520 pkgval = pkg
1521
Brad Bishop316dfdd2018-06-25 12:45:53 -04001522 defer_fragment = """
1523if [ -n "$D" ]; then
1524 $INTERCEPT_DIR/postinst_intercept delay_to_first_boot %s mlprefix=%s
1525 exit 0
1526fi
Brad Bishop96ff1982019-08-19 13:50:42 -04001527""" % (pkgval, mlprefix)
Brad Bishop316dfdd2018-06-25 12:45:53 -04001528
1529 postinst = d.getVar('pkg_postinst_%s' % pkg)
1530 postinst_ontarget = d.getVar('pkg_postinst_ontarget_%s' % pkg)
1531
1532 if postinst_ontarget:
1533 bb.debug(1, 'adding deferred pkg_postinst_ontarget() to pkg_postinst() for %s' % pkg)
1534 if not postinst:
1535 postinst = '#!/bin/sh\n'
1536 postinst += defer_fragment
1537 postinst += postinst_ontarget
1538 d.setVar('pkg_postinst_%s' % pkg, postinst)
1539
1540 def add_set_e_to_scriptlets(pkg):
1541 for scriptlet_name in ('pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm'):
1542 scriptlet = d.getVar('%s_%s' % (scriptlet_name, pkg))
1543 if scriptlet:
1544 scriptlet_split = scriptlet.split('\n')
1545 if scriptlet_split[0].startswith("#!"):
1546 scriptlet = scriptlet_split[0] + "\nset -e\n" + "\n".join(scriptlet_split[1:])
1547 else:
1548 scriptlet = "set -e\n" + "\n".join(scriptlet_split[0:])
1549 d.setVar('%s_%s' % (scriptlet_name, pkg), scriptlet)
1550
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001551 def write_if_exists(f, pkg, var):
1552 def encode(str):
1553 import codecs
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001554 c = codecs.getencoder("unicode_escape")
1555 return c(str)[0].decode("latin1")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001556
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001557 val = d.getVar('%s_%s' % (var, pkg))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001558 if val:
1559 f.write('%s_%s: %s\n' % (var, pkg, encode(val)))
1560 return val
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001561 val = d.getVar('%s' % (var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001562 if val:
1563 f.write('%s: %s\n' % (var, encode(val)))
1564 return val
1565
1566 def write_extra_pkgs(variants, pn, packages, pkgdatadir):
1567 for variant in variants:
1568 with open("%s/%s-%s" % (pkgdatadir, variant, pn), 'w') as fd:
1569 fd.write("PACKAGES: %s\n" % ' '.join(
1570 map(lambda pkg: '%s-%s' % (variant, pkg), packages.split())))
1571
1572 def write_extra_runtime_pkgs(variants, packages, pkgdatadir):
1573 for variant in variants:
1574 for pkg in packages.split():
1575 ml_pkg = "%s-%s" % (variant, pkg)
1576 subdata_file = "%s/runtime/%s" % (pkgdatadir, ml_pkg)
1577 with open(subdata_file, 'w') as fd:
1578 fd.write("PKG_%s: %s" % (ml_pkg, pkg))
1579
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001580 packages = d.getVar('PACKAGES')
1581 pkgdest = d.getVar('PKGDEST')
1582 pkgdatadir = d.getVar('PKGDESTWORK')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001583
Brad Bishop64c979e2019-11-04 13:55:29 -05001584 data_file = pkgdatadir + d.expand("/${PN}")
1585 with open(data_file, 'w') as fd:
1586 fd.write("PACKAGES: %s\n" % packages)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001587
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001588 pn = d.getVar('PN')
1589 global_variants = (d.getVar('MULTILIB_GLOBAL_VARIANTS') or "").split()
1590 variants = (d.getVar('MULTILIB_VARIANTS') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001591
1592 if bb.data.inherits_class('kernel', d) or bb.data.inherits_class('module-base', d):
1593 write_extra_pkgs(variants, pn, packages, pkgdatadir)
1594
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001595 if bb.data.inherits_class('allarch', d) and not variants \
1596 and not bb.data.inherits_class('packagegroup', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001597 write_extra_pkgs(global_variants, pn, packages, pkgdatadir)
1598
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001599 workdir = d.getVar('WORKDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001600
1601 for pkg in packages.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001602 pkgval = d.getVar('PKG_%s' % pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001603 if pkgval is None:
1604 pkgval = pkg
1605 d.setVar('PKG_%s' % pkg, pkg)
1606
1607 pkgdestpkg = os.path.join(pkgdest, pkg)
1608 files = {}
1609 total_size = 0
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001610 seen = set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001611 for f in pkgfiles[pkg]:
1612 relpth = os.path.relpath(f, pkgdestpkg)
1613 fstat = os.lstat(f)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001614 files[os.sep + relpth] = fstat.st_size
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001615 if fstat.st_ino not in seen:
1616 seen.add(fstat.st_ino)
1617 total_size += fstat.st_size
Brad Bishop19323692019-04-05 15:28:33 -04001618 d.setVar('FILES_INFO', json.dumps(files, sort_keys=True))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001619
Brad Bishop316dfdd2018-06-25 12:45:53 -04001620 process_postinst_on_target(pkg, d.getVar("MLPREFIX"))
1621 add_set_e_to_scriptlets(pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001622
Brad Bishop15ae2502019-06-18 21:44:24 -04001623 subdata_file = pkgdatadir + "/runtime/%s" % pkg
1624 with open(subdata_file, 'w') as sf:
1625 for var in (d.getVar('PKGDATA_VARS') or "").split():
1626 val = write_if_exists(sf, pkg, var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001627
Brad Bishop15ae2502019-06-18 21:44:24 -04001628 write_if_exists(sf, pkg, 'FILERPROVIDESFLIST')
1629 for dfile in (d.getVar('FILERPROVIDESFLIST_' + pkg) or "").split():
1630 write_if_exists(sf, pkg, 'FILERPROVIDES_' + dfile)
1631
1632 write_if_exists(sf, pkg, 'FILERDEPENDSFLIST')
1633 for dfile in (d.getVar('FILERDEPENDSFLIST_' + pkg) or "").split():
1634 write_if_exists(sf, pkg, 'FILERDEPENDS_' + dfile)
1635
1636 sf.write('%s_%s: %d\n' % ('PKGSIZE', pkg, total_size))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001637
1638 # Symlinks needed for rprovides lookup
Brad Bishop15ae2502019-06-18 21:44:24 -04001639 rprov = d.getVar('RPROVIDES_%s' % pkg) or d.getVar('RPROVIDES')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001640 if rprov:
1641 for p in rprov.strip().split():
1642 subdata_sym = pkgdatadir + "/runtime-rprovides/%s/%s" % (p, pkg)
1643 bb.utils.mkdirhier(os.path.dirname(subdata_sym))
1644 oe.path.symlink("../../runtime/%s" % pkg, subdata_sym, True)
1645
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001646 allow_empty = d.getVar('ALLOW_EMPTY_%s' % pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001647 if not allow_empty:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001648 allow_empty = d.getVar('ALLOW_EMPTY')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001649 root = "%s/%s" % (pkgdest, pkg)
1650 os.chdir(root)
1651 g = glob('*')
1652 if g or allow_empty == "1":
1653 # Symlinks needed for reverse lookups (from the final package name)
1654 subdata_sym = pkgdatadir + "/runtime-reverse/%s" % pkgval
1655 oe.path.symlink("../runtime/%s" % pkg, subdata_sym, True)
1656
1657 packagedfile = pkgdatadir + '/runtime/%s.packaged' % pkg
1658 open(packagedfile, 'w').close()
1659
1660 if bb.data.inherits_class('kernel', d) or bb.data.inherits_class('module-base', d):
1661 write_extra_runtime_pkgs(variants, packages, pkgdatadir)
1662
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001663 if bb.data.inherits_class('allarch', d) and not variants \
1664 and not bb.data.inherits_class('packagegroup', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001665 write_extra_runtime_pkgs(global_variants, packages, pkgdatadir)
1666
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001667}
1668emit_pkgdata[dirs] = "${PKGDESTWORK}/runtime ${PKGDESTWORK}/runtime-reverse ${PKGDESTWORK}/runtime-rprovides"
1669
1670ldconfig_postinst_fragment() {
1671if [ x"$D" = "x" ]; then
1672 if [ -x /sbin/ldconfig ]; then /sbin/ldconfig ; fi
1673fi
1674}
1675
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001676RPMDEPS = "${STAGING_LIBDIR_NATIVE}/rpm/rpmdeps --alldeps"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001677
1678# Collect perfile run-time dependency metadata
1679# Output:
1680# FILERPROVIDESFLIST_pkg - list of all files w/ deps
1681# FILERPROVIDES_filepath_pkg - per file dep
1682#
1683# FILERDEPENDSFLIST_pkg - list of all files w/ deps
1684# FILERDEPENDS_filepath_pkg - per file dep
1685
1686python package_do_filedeps() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001687 if d.getVar('SKIP_FILEDEPS') == '1':
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001688 return
1689
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001690 pkgdest = d.getVar('PKGDEST')
1691 packages = d.getVar('PACKAGES')
1692 rpmdeps = d.getVar('RPMDEPS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001693
1694 def chunks(files, n):
1695 return [files[i:i+n] for i in range(0, len(files), n)]
1696
1697 pkglist = []
1698 for pkg in packages.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001699 if d.getVar('SKIP_FILEDEPS_' + pkg) == '1':
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001700 continue
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001701 if pkg.endswith('-dbg') or pkg.endswith('-doc') or pkg.find('-locale-') != -1 or pkg.find('-localedata-') != -1 or pkg.find('-gconv-') != -1 or pkg.find('-charmap-') != -1 or pkg.startswith('kernel-module-') or pkg.endswith('-src'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001702 continue
1703 for files in chunks(pkgfiles[pkg], 100):
1704 pkglist.append((pkg, files, rpmdeps, pkgdest))
1705
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001706 processed = oe.utils.multiprocess_launch(oe.package.filedeprunner, pkglist, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001707
1708 provides_files = {}
1709 requires_files = {}
1710
1711 for result in processed:
1712 (pkg, provides, requires) = result
1713
1714 if pkg not in provides_files:
1715 provides_files[pkg] = []
1716 if pkg not in requires_files:
1717 requires_files[pkg] = []
1718
Brad Bishop19323692019-04-05 15:28:33 -04001719 for file in sorted(provides):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001720 provides_files[pkg].append(file)
1721 key = "FILERPROVIDES_" + file + "_" + pkg
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001722 d.appendVar(key, " " + " ".join(provides[file]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001723
Brad Bishop19323692019-04-05 15:28:33 -04001724 for file in sorted(requires):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001725 requires_files[pkg].append(file)
1726 key = "FILERDEPENDS_" + file + "_" + pkg
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001727 d.appendVar(key, " " + " ".join(requires[file]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001728
1729 for pkg in requires_files:
1730 d.setVar("FILERDEPENDSFLIST_" + pkg, " ".join(requires_files[pkg]))
1731 for pkg in provides_files:
1732 d.setVar("FILERPROVIDESFLIST_" + pkg, " ".join(provides_files[pkg]))
1733}
1734
Brad Bishop96ff1982019-08-19 13:50:42 -04001735SHLIBSDIRS = "${WORKDIR_PKGDATA}/${MLPREFIX}shlibs2"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001736SHLIBSWORKDIR = "${PKGDESTWORK}/${MLPREFIX}shlibs2"
1737
1738python package_do_shlibs() {
Brad Bishop00e122a2019-10-05 11:10:57 -04001739 import itertools
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001740 import re, pipes
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001741 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001742
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001743 exclude_shlibs = d.getVar('EXCLUDE_FROM_SHLIBS', False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001744 if exclude_shlibs:
1745 bb.note("not generating shlibs")
1746 return
1747
Brad Bishop19323692019-04-05 15:28:33 -04001748 lib_re = re.compile(r"^.*\.so")
1749 libdir_re = re.compile(r".*/%s$" % d.getVar('baselib'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001750
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001751 packages = d.getVar('PACKAGES')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001752
1753 shlib_pkgs = []
1754 exclusion_list = d.getVar("EXCLUDE_PACKAGES_FROM_SHLIBS")
1755 if exclusion_list:
1756 for pkg in packages.split():
1757 if pkg not in exclusion_list.split():
1758 shlib_pkgs.append(pkg)
1759 else:
1760 bb.note("not generating shlibs for %s" % pkg)
1761 else:
1762 shlib_pkgs = packages.split()
1763
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001764 hostos = d.getVar('HOST_OS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001765
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001766 workdir = d.getVar('WORKDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001767
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001768 ver = d.getVar('PKGV')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001769 if not ver:
1770 msg = "PKGV not defined"
1771 package_qa_handle_error("pkgv-undefined", msg, d)
1772 return
1773
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001774 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001775
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001776 shlibswork_dir = d.getVar('SHLIBSWORKDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001777
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001778 def linux_so(file, pkg, pkgver, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001779 needs_ldconfig = False
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001780 needed = set()
1781 sonames = set()
1782 renames = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001783 ldir = os.path.dirname(file).replace(pkgdest + "/" + pkg, '')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001784 cmd = d.getVar('OBJDUMP') + " -p " + pipes.quote(file) + " 2>/dev/null"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001785 fd = os.popen(cmd)
1786 lines = fd.readlines()
1787 fd.close()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001788 rpath = tuple()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001789 for l in lines:
Brad Bishop19323692019-04-05 15:28:33 -04001790 m = re.match(r"\s+RPATH\s+([^\s]*)", l)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001791 if m:
1792 rpaths = m.group(1).replace("$ORIGIN", ldir).split(":")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001793 rpath = tuple(map(os.path.normpath, rpaths))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001794 for l in lines:
Brad Bishop19323692019-04-05 15:28:33 -04001795 m = re.match(r"\s+NEEDED\s+([^\s]*)", l)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001796 if m:
1797 dep = m.group(1)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001798 if dep not in needed:
1799 needed.add((dep, file, rpath))
Brad Bishop19323692019-04-05 15:28:33 -04001800 m = re.match(r"\s+SONAME\s+([^\s]*)", l)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001801 if m:
1802 this_soname = m.group(1)
1803 prov = (this_soname, ldir, pkgver)
1804 if not prov in sonames:
1805 # if library is private (only used by package) then do not build shlib for it
Brad Bishop79641f22019-09-10 07:20:22 -04001806 import fnmatch
1807 if not private_libs or len([i for i in private_libs if fnmatch.fnmatch(this_soname, i)]) == 0:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001808 sonames.add(prov)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001809 if libdir_re.match(os.path.dirname(file)):
1810 needs_ldconfig = True
1811 if snap_symlinks and (os.path.basename(file) != this_soname):
1812 renames.append((file, os.path.join(os.path.dirname(file), this_soname)))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001813 return (needs_ldconfig, needed, sonames, renames)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001814
1815 def darwin_so(file, needed, sonames, renames, pkgver):
1816 if not os.path.exists(file):
1817 return
1818 ldir = os.path.dirname(file).replace(pkgdest + "/" + pkg, '')
1819
1820 def get_combinations(base):
1821 #
1822 # Given a base library name, find all combinations of this split by "." and "-"
1823 #
1824 combos = []
1825 options = base.split(".")
1826 for i in range(1, len(options) + 1):
1827 combos.append(".".join(options[0:i]))
1828 options = base.split("-")
1829 for i in range(1, len(options) + 1):
1830 combos.append("-".join(options[0:i]))
1831 return combos
1832
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001833 if (file.endswith('.dylib') or file.endswith('.so')) and not pkg.endswith('-dev') and not pkg.endswith('-dbg') and not pkg.endswith('-src'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001834 # Drop suffix
1835 name = os.path.basename(file).rsplit(".",1)[0]
1836 # Find all combinations
1837 combos = get_combinations(name)
1838 for combo in combos:
1839 if not combo in sonames:
1840 prov = (combo, ldir, pkgver)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001841 sonames.add(prov)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001842 if file.endswith('.dylib') or file.endswith('.so'):
1843 rpath = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001844 p = subprocess.Popen([d.expand("${HOST_PREFIX}otool"), '-l', file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001845 out, err = p.communicate()
1846 # If returned successfully, process stdout for results
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001847 if p.returncode == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001848 for l in out.split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001849 l = l.strip()
1850 if l.startswith('path '):
1851 rpath.append(l.split()[1])
1852
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001853 p = subprocess.Popen([d.expand("${HOST_PREFIX}otool"), '-L', file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001854 out, err = p.communicate()
1855 # If returned successfully, process stdout for results
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001856 if p.returncode == 0:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001857 for l in out.split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001858 l = l.strip()
1859 if not l or l.endswith(":"):
1860 continue
1861 if "is not an object file" in l:
1862 continue
1863 name = os.path.basename(l.split()[0]).rsplit(".", 1)[0]
1864 if name and name not in needed[pkg]:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001865 needed[pkg].add((name, file, tuple()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001866
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001867 def mingw_dll(file, needed, sonames, renames, pkgver):
1868 if not os.path.exists(file):
1869 return
1870
1871 if file.endswith(".dll"):
1872 # assume all dlls are shared objects provided by the package
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001873 sonames.add((os.path.basename(file), os.path.dirname(file).replace(pkgdest + "/" + pkg, ''), pkgver))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001874
1875 if (file.endswith(".dll") or file.endswith(".exe")):
1876 # use objdump to search for "DLL Name: .*\.dll"
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001877 p = subprocess.Popen([d.expand("${HOST_PREFIX}objdump"), "-p", file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001878 out, err = p.communicate()
1879 # process the output, grabbing all .dll names
1880 if p.returncode == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001881 for m in re.finditer(r"DLL Name: (.*?\.dll)$", out.decode(), re.MULTILINE | re.IGNORECASE):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001882 dllname = m.group(1)
1883 if dllname:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001884 needed[pkg].add((dllname, file, tuple()))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001885
1886 if d.getVar('PACKAGE_SNAP_LIB_SYMLINKS') == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001887 snap_symlinks = True
1888 else:
1889 snap_symlinks = False
1890
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001891 needed = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001892
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001893 shlib_provider = oe.package.read_shlib_providers(d)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001894
1895 for pkg in shlib_pkgs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001896 private_libs = d.getVar('PRIVATE_LIBS_' + pkg) or d.getVar('PRIVATE_LIBS') or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001897 private_libs = private_libs.split()
1898 needs_ldconfig = False
1899 bb.debug(2, "calculating shlib provides for %s" % pkg)
1900
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001901 pkgver = d.getVar('PKGV_' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001902 if not pkgver:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001903 pkgver = d.getVar('PV_' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001904 if not pkgver:
1905 pkgver = ver
1906
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001907 needed[pkg] = set()
1908 sonames = set()
1909 renames = []
1910 linuxlist = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001911 for file in pkgfiles[pkg]:
1912 soname = None
1913 if cpath.islink(file):
1914 continue
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001915 if hostos == "darwin" or hostos == "darwin8":
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001916 darwin_so(file, needed, sonames, renames, pkgver)
Andrew Geisslerb7d28612020-07-24 16:15:54 -05001917 elif hostos.startswith("mingw"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001918 mingw_dll(file, needed, sonames, renames, pkgver)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001919 elif os.access(file, os.X_OK) or lib_re.match(file):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001920 linuxlist.append(file)
1921
1922 if linuxlist:
1923 results = oe.utils.multiprocess_launch(linux_so, linuxlist, d, extraargs=(pkg, pkgver, d))
1924 for r in results:
1925 ldconfig = r[0]
1926 needed[pkg] |= r[1]
1927 sonames |= r[2]
1928 renames.extend(r[3])
1929 needs_ldconfig = needs_ldconfig or ldconfig
1930
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001931 for (old, new) in renames:
1932 bb.note("Renaming %s to %s" % (old, new))
1933 os.rename(old, new)
1934 pkgfiles[pkg].remove(old)
Brad Bishop64c979e2019-11-04 13:55:29 -05001935
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001936 shlibs_file = os.path.join(shlibswork_dir, pkg + ".list")
1937 if len(sonames):
Brad Bishop64c979e2019-11-04 13:55:29 -05001938 with open(shlibs_file, 'w') as fd:
Andrew Geissler635e0e42020-08-21 15:58:33 -05001939 for s in sorted(sonames):
Brad Bishop64c979e2019-11-04 13:55:29 -05001940 if s[0] in shlib_provider and s[1] in shlib_provider[s[0]]:
1941 (old_pkg, old_pkgver) = shlib_provider[s[0]][s[1]]
1942 if old_pkg != pkg:
1943 bb.warn('%s-%s was registered as shlib provider for %s, changing it to %s-%s because it was built later' % (old_pkg, old_pkgver, s[0], pkg, pkgver))
1944 bb.debug(1, 'registering %s-%s as shlib provider for %s' % (pkg, pkgver, s[0]))
1945 fd.write(s[0] + ':' + s[1] + ':' + s[2] + '\n')
1946 if s[0] not in shlib_provider:
1947 shlib_provider[s[0]] = {}
1948 shlib_provider[s[0]][s[1]] = (pkg, pkgver)
Brad Bishop1d80a2e2019-11-15 16:35:03 -05001949 if needs_ldconfig:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001950 bb.debug(1, 'adding ldconfig call to postinst for %s' % pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001951 postinst = d.getVar('pkg_postinst_%s' % pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001952 if not postinst:
1953 postinst = '#!/bin/sh\n'
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001954 postinst += d.getVar('ldconfig_postinst_fragment')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001955 d.setVar('pkg_postinst_%s' % pkg, postinst)
1956 bb.debug(1, 'LIBNAMES: pkg %s sonames %s' % (pkg, sonames))
1957
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001958 assumed_libs = d.getVar('ASSUME_SHLIBS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001959 if assumed_libs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001960 libdir = d.getVar("libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001961 for e in assumed_libs.split():
1962 l, dep_pkg = e.split(":")
1963 lib_ver = None
1964 dep_pkg = dep_pkg.rsplit("_", 1)
1965 if len(dep_pkg) == 2:
1966 lib_ver = dep_pkg[1]
1967 dep_pkg = dep_pkg[0]
1968 if l not in shlib_provider:
1969 shlib_provider[l] = {}
1970 shlib_provider[l][libdir] = (dep_pkg, lib_ver)
1971
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001972 libsearchpath = [d.getVar('libdir'), d.getVar('base_libdir')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001973
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001974 for pkg in shlib_pkgs:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001975 bb.debug(2, "calculating shlib requirements for %s" % pkg)
1976
Brad Bishop316dfdd2018-06-25 12:45:53 -04001977 private_libs = d.getVar('PRIVATE_LIBS_' + pkg) or d.getVar('PRIVATE_LIBS') or ""
1978 private_libs = private_libs.split()
1979
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001980 deps = list()
1981 for n in needed[pkg]:
1982 # if n is in private libraries, don't try to search provider for it
1983 # this could cause problem in case some abc.bb provides private
1984 # /opt/abc/lib/libfoo.so.1 and contains /usr/bin/abc depending on system library libfoo.so.1
1985 # but skipping it is still better alternative than providing own
1986 # version and then adding runtime dependency for the same system library
Brad Bishop79641f22019-09-10 07:20:22 -04001987 import fnmatch
1988 if private_libs and len([i for i in private_libs if fnmatch.fnmatch(n[0], i)]) > 0:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001989 bb.debug(2, '%s: Dependency %s covered by PRIVATE_LIBS' % (pkg, n[0]))
1990 continue
1991 if n[0] in shlib_provider.keys():
Brad Bishop00e122a2019-10-05 11:10:57 -04001992 shlib_provider_map = shlib_provider[n[0]]
1993 matches = set()
1994 for p in itertools.chain(list(n[2]), sorted(shlib_provider_map.keys()), libsearchpath):
1995 if p in shlib_provider_map:
1996 matches.add(p)
1997 if len(matches) > 1:
1998 matchpkgs = ', '.join([shlib_provider_map[match][0] for match in matches])
1999 bb.error("%s: Multiple shlib providers for %s: %s (used by files: %s)" % (pkg, n[0], matchpkgs, n[1]))
2000 elif len(matches) == 1:
2001 (dep_pkg, ver_needed) = shlib_provider_map[matches.pop()]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002002
2003 bb.debug(2, '%s: Dependency %s requires package %s (used by files: %s)' % (pkg, n[0], dep_pkg, n[1]))
2004
2005 if dep_pkg == pkg:
2006 continue
2007
2008 if ver_needed:
2009 dep = "%s (>= %s)" % (dep_pkg, ver_needed)
2010 else:
2011 dep = dep_pkg
2012 if not dep in deps:
2013 deps.append(dep)
2014 continue
2015 bb.note("Couldn't find shared library provider for %s, used by files: %s" % (n[0], n[1]))
2016
2017 deps_file = os.path.join(pkgdest, pkg + ".shlibdeps")
2018 if os.path.exists(deps_file):
2019 os.remove(deps_file)
Brad Bishop64c979e2019-11-04 13:55:29 -05002020 if deps:
2021 with open(deps_file, 'w') as fd:
2022 for dep in sorted(deps):
2023 fd.write(dep + '\n')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002024}
2025
2026python package_do_pkgconfig () {
2027 import re
2028
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002029 packages = d.getVar('PACKAGES')
2030 workdir = d.getVar('WORKDIR')
2031 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002032
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002033 shlibs_dirs = d.getVar('SHLIBSDIRS').split()
2034 shlibswork_dir = d.getVar('SHLIBSWORKDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002035
Brad Bishop19323692019-04-05 15:28:33 -04002036 pc_re = re.compile(r'(.*)\.pc$')
2037 var_re = re.compile(r'(.*)=(.*)')
2038 field_re = re.compile(r'(.*): (.*)')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002039
2040 pkgconfig_provided = {}
2041 pkgconfig_needed = {}
2042 for pkg in packages.split():
2043 pkgconfig_provided[pkg] = []
2044 pkgconfig_needed[pkg] = []
2045 for file in pkgfiles[pkg]:
2046 m = pc_re.match(file)
2047 if m:
2048 pd = bb.data.init()
2049 name = m.group(1)
2050 pkgconfig_provided[pkg].append(name)
2051 if not os.access(file, os.R_OK):
2052 continue
Brad Bishop64c979e2019-11-04 13:55:29 -05002053 with open(file, 'r') as f:
2054 lines = f.readlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002055 for l in lines:
2056 m = var_re.match(l)
2057 if m:
2058 name = m.group(1)
2059 val = m.group(2)
2060 pd.setVar(name, pd.expand(val))
2061 continue
2062 m = field_re.match(l)
2063 if m:
2064 hdr = m.group(1)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002065 exp = pd.expand(m.group(2))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002066 if hdr == 'Requires':
2067 pkgconfig_needed[pkg] += exp.replace(',', ' ').split()
2068
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002069 for pkg in packages.split():
2070 pkgs_file = os.path.join(shlibswork_dir, pkg + ".pclist")
2071 if pkgconfig_provided[pkg] != []:
Brad Bishop64c979e2019-11-04 13:55:29 -05002072 with open(pkgs_file, 'w') as f:
2073 for p in pkgconfig_provided[pkg]:
2074 f.write('%s\n' % p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002075
2076 # Go from least to most specific since the last one found wins
2077 for dir in reversed(shlibs_dirs):
2078 if not os.path.exists(dir):
2079 continue
Brad Bishop08902b02019-08-20 09:16:51 -04002080 for file in sorted(os.listdir(dir)):
Brad Bishop19323692019-04-05 15:28:33 -04002081 m = re.match(r'^(.*)\.pclist$', file)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002082 if m:
2083 pkg = m.group(1)
Brad Bishop64c979e2019-11-04 13:55:29 -05002084 with open(os.path.join(dir, file)) as fd:
2085 lines = fd.readlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002086 pkgconfig_provided[pkg] = []
2087 for l in lines:
2088 pkgconfig_provided[pkg].append(l.rstrip())
2089
2090 for pkg in packages.split():
2091 deps = []
2092 for n in pkgconfig_needed[pkg]:
2093 found = False
2094 for k in pkgconfig_provided.keys():
2095 if n in pkgconfig_provided[k]:
2096 if k != pkg and not (k in deps):
2097 deps.append(k)
2098 found = True
2099 if found == False:
2100 bb.note("couldn't find pkgconfig module '%s' in any package" % n)
2101 deps_file = os.path.join(pkgdest, pkg + ".pcdeps")
2102 if len(deps):
Brad Bishop64c979e2019-11-04 13:55:29 -05002103 with open(deps_file, 'w') as fd:
2104 for dep in deps:
2105 fd.write(dep + '\n')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002106}
2107
2108def read_libdep_files(d):
2109 pkglibdeps = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002110 packages = d.getVar('PACKAGES').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002111 for pkg in packages:
2112 pkglibdeps[pkg] = {}
2113 for extension in ".shlibdeps", ".pcdeps", ".clilibdeps":
2114 depsfile = d.expand("${PKGDEST}/" + pkg + extension)
2115 if os.access(depsfile, os.R_OK):
Brad Bishop64c979e2019-11-04 13:55:29 -05002116 with open(depsfile) as fd:
2117 lines = fd.readlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002118 for l in lines:
2119 l.rstrip()
2120 deps = bb.utils.explode_dep_versions2(l)
2121 for dep in deps:
2122 if not dep in pkglibdeps[pkg]:
2123 pkglibdeps[pkg][dep] = deps[dep]
2124 return pkglibdeps
2125
2126python read_shlibdeps () {
2127 pkglibdeps = read_libdep_files(d)
2128
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002129 packages = d.getVar('PACKAGES').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002130 for pkg in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002131 rdepends = bb.utils.explode_dep_versions2(d.getVar('RDEPENDS_' + pkg) or "")
Brad Bishop19323692019-04-05 15:28:33 -04002132 for dep in sorted(pkglibdeps[pkg]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002133 # Add the dep if it's not already there, or if no comparison is set
2134 if dep not in rdepends:
2135 rdepends[dep] = []
2136 for v in pkglibdeps[pkg][dep]:
2137 if v not in rdepends[dep]:
2138 rdepends[dep].append(v)
2139 d.setVar('RDEPENDS_' + pkg, bb.utils.join_deps(rdepends, commasep=False))
2140}
2141
2142python package_depchains() {
2143 """
2144 For a given set of prefix and postfix modifiers, make those packages
2145 RRECOMMENDS on the corresponding packages for its RDEPENDS.
2146
2147 Example: If package A depends upon package B, and A's .bb emits an
2148 A-dev package, this would make A-dev Recommends: B-dev.
2149
2150 If only one of a given suffix is specified, it will take the RRECOMMENDS
2151 based on the RDEPENDS of *all* other packages. If more than one of a given
2152 suffix is specified, its will only use the RDEPENDS of the single parent
2153 package.
2154 """
2155
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002156 packages = d.getVar('PACKAGES')
2157 postfixes = (d.getVar('DEPCHAIN_POST') or '').split()
2158 prefixes = (d.getVar('DEPCHAIN_PRE') or '').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002159
2160 def pkg_adddeprrecs(pkg, base, suffix, getname, depends, d):
2161
2162 #bb.note('depends for %s is %s' % (base, depends))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002163 rreclist = bb.utils.explode_dep_versions2(d.getVar('RRECOMMENDS_' + pkg) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002164
Brad Bishop19323692019-04-05 15:28:33 -04002165 for depend in sorted(depends):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002166 if depend.find('-native') != -1 or depend.find('-cross') != -1 or depend.startswith('virtual/'):
2167 #bb.note("Skipping %s" % depend)
2168 continue
2169 if depend.endswith('-dev'):
2170 depend = depend[:-4]
2171 if depend.endswith('-dbg'):
2172 depend = depend[:-4]
2173 pkgname = getname(depend, suffix)
2174 #bb.note("Adding %s for %s" % (pkgname, depend))
2175 if pkgname not in rreclist and pkgname != pkg:
2176 rreclist[pkgname] = []
2177
2178 #bb.note('setting: RRECOMMENDS_%s=%s' % (pkg, ' '.join(rreclist)))
2179 d.setVar('RRECOMMENDS_%s' % pkg, bb.utils.join_deps(rreclist, commasep=False))
2180
2181 def pkg_addrrecs(pkg, base, suffix, getname, rdepends, d):
2182
2183 #bb.note('rdepends for %s is %s' % (base, rdepends))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002184 rreclist = bb.utils.explode_dep_versions2(d.getVar('RRECOMMENDS_' + pkg) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002185
Brad Bishop19323692019-04-05 15:28:33 -04002186 for depend in sorted(rdepends):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002187 if depend.find('virtual-locale-') != -1:
2188 #bb.note("Skipping %s" % depend)
2189 continue
2190 if depend.endswith('-dev'):
2191 depend = depend[:-4]
2192 if depend.endswith('-dbg'):
2193 depend = depend[:-4]
2194 pkgname = getname(depend, suffix)
2195 #bb.note("Adding %s for %s" % (pkgname, depend))
2196 if pkgname not in rreclist and pkgname != pkg:
2197 rreclist[pkgname] = []
2198
2199 #bb.note('setting: RRECOMMENDS_%s=%s' % (pkg, ' '.join(rreclist)))
2200 d.setVar('RRECOMMENDS_%s' % pkg, bb.utils.join_deps(rreclist, commasep=False))
2201
2202 def add_dep(list, dep):
2203 if dep not in list:
2204 list.append(dep)
2205
2206 depends = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002207 for dep in bb.utils.explode_deps(d.getVar('DEPENDS') or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002208 add_dep(depends, dep)
2209
2210 rdepends = []
2211 for pkg in packages.split():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002212 for dep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + pkg) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002213 add_dep(rdepends, dep)
2214
2215 #bb.note('rdepends is %s' % rdepends)
2216
2217 def post_getname(name, suffix):
2218 return '%s%s' % (name, suffix)
2219 def pre_getname(name, suffix):
2220 return '%s%s' % (suffix, name)
2221
2222 pkgs = {}
2223 for pkg in packages.split():
2224 for postfix in postfixes:
2225 if pkg.endswith(postfix):
2226 if not postfix in pkgs:
2227 pkgs[postfix] = {}
2228 pkgs[postfix][pkg] = (pkg[:-len(postfix)], post_getname)
2229
2230 for prefix in prefixes:
2231 if pkg.startswith(prefix):
2232 if not prefix in pkgs:
2233 pkgs[prefix] = {}
2234 pkgs[prefix][pkg] = (pkg[:-len(prefix)], pre_getname)
2235
2236 if "-dbg" in pkgs:
2237 pkglibdeps = read_libdep_files(d)
2238 pkglibdeplist = []
2239 for pkg in pkglibdeps:
2240 for k in pkglibdeps[pkg]:
2241 add_dep(pkglibdeplist, k)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002242 dbgdefaultdeps = ((d.getVar('DEPCHAIN_DBGDEFAULTDEPS') == '1') or (bb.data.inherits_class('packagegroup', d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002243
2244 for suffix in pkgs:
2245 for pkg in pkgs[suffix]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002246 if d.getVarFlag('RRECOMMENDS_' + pkg, 'nodeprrecs'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002247 continue
2248 (base, func) = pkgs[suffix][pkg]
2249 if suffix == "-dev":
2250 pkg_adddeprrecs(pkg, base, suffix, func, depends, d)
2251 elif suffix == "-dbg":
2252 if not dbgdefaultdeps:
2253 pkg_addrrecs(pkg, base, suffix, func, pkglibdeplist, d)
2254 continue
2255 if len(pkgs[suffix]) == 1:
2256 pkg_addrrecs(pkg, base, suffix, func, rdepends, d)
2257 else:
2258 rdeps = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002259 for dep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + base) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002260 add_dep(rdeps, dep)
2261 pkg_addrrecs(pkg, base, suffix, func, rdeps, d)
2262}
2263
2264# Since bitbake can't determine which variables are accessed during package
2265# iteration, we need to list them here:
Andrew Geissler1e34c2d2020-05-29 16:02:59 -05002266PACKAGEVARS = "FILES RDEPENDS RRECOMMENDS SUMMARY DESCRIPTION RSUGGESTS RPROVIDES RCONFLICTS PKG ALLOW_EMPTY pkg_postinst pkg_postrm pkg_postinst_ontarget INITSCRIPT_NAME INITSCRIPT_PARAMS DEBIAN_NOAUTONAME ALTERNATIVE PKGE PKGV PKGR USERADD_PARAM GROUPADD_PARAM CONFFILES SYSTEMD_SERVICE LICENSE SECTION pkg_preinst pkg_prerm RREPLACES GROUPMEMS_PARAM SYSTEMD_AUTO_ENABLE SKIP_FILEDEPS PRIVATE_LIBS PACKAGE_ADD_METADATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002267
Andrew Geissler82c905d2020-04-13 13:39:40 -05002268def gen_packagevar(d, pkgvars="PACKAGEVARS"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002269 ret = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002270 pkgs = (d.getVar("PACKAGES") or "").split()
Andrew Geissler82c905d2020-04-13 13:39:40 -05002271 vars = (d.getVar(pkgvars) or "").split()
2272 for v in vars:
2273 ret.append(v)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002274 for p in pkgs:
2275 for v in vars:
2276 ret.append(v + "_" + p)
2277
2278 # Ensure that changes to INCOMPATIBLE_LICENSE re-run do_package for
2279 # affected recipes.
2280 ret.append('LICENSE_EXCLUSION-%s' % p)
2281 return " ".join(ret)
2282
2283PACKAGE_PREPROCESS_FUNCS ?= ""
2284# Functions for setting up PKGD
2285PACKAGEBUILDPKGD ?= " \
Brad Bishop96ff1982019-08-19 13:50:42 -04002286 package_prepare_pkgdata \
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002287 perform_packagecopy \
2288 ${PACKAGE_PREPROCESS_FUNCS} \
2289 split_and_strip_files \
2290 fixup_perms \
2291 "
2292# Functions which split PKGD up into separate packages
2293PACKAGESPLITFUNCS ?= " \
2294 package_do_split_locales \
2295 populate_packages"
2296# Functions which process metadata based on split packages
2297PACKAGEFUNCS += " \
2298 package_fixsymlinks \
2299 package_name_hook \
2300 package_do_filedeps \
2301 package_do_shlibs \
2302 package_do_pkgconfig \
2303 read_shlibdeps \
2304 package_depchains \
2305 emit_pkgdata"
2306
2307python do_package () {
2308 # Change the following version to cause sstate to invalidate the package
2309 # cache. This is useful if an item this class depends on changes in a
2310 # way that the output of this class changes. rpmdeps is a good example
2311 # as any change to rpmdeps requires this to be rerun.
Brad Bishopd7bf8c12018-02-25 22:55:05 -05002312 # PACKAGE_BBCLASS_VERSION = "2"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002313
2314 # Init cachedpath
2315 global cpath
2316 cpath = oe.cachedpath.CachedPath()
2317
2318 ###########################################################################
2319 # Sanity test the setup
2320 ###########################################################################
2321
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002322 packages = (d.getVar('PACKAGES') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002323 if len(packages) < 1:
2324 bb.debug(1, "No packages to build, skipping do_package")
2325 return
2326
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002327 workdir = d.getVar('WORKDIR')
2328 outdir = d.getVar('DEPLOY_DIR')
2329 dest = d.getVar('D')
2330 dvar = d.getVar('PKGD')
2331 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002332
2333 if not workdir or not outdir or not dest or not dvar or not pn:
2334 msg = "WORKDIR, DEPLOY_DIR, D, PN and PKGD all must be defined, unable to package"
2335 package_qa_handle_error("var-undefined", msg, d)
2336 return
2337
2338 bb.build.exec_func("package_get_auto_pr", d)
2339
2340 ###########################################################################
2341 # Optimisations
2342 ###########################################################################
2343
2344 # Continually expanding complex expressions is inefficient, particularly
2345 # when we write to the datastore and invalidate the expansion cache. This
2346 # code pre-expands some frequently used variables
2347
2348 def expandVar(x, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002349 d.setVar(x, d.getVar(x))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002350
2351 for x in 'PN', 'PV', 'BPN', 'TARGET_SYS', 'EXTENDPRAUTO':
2352 expandVar(x, d)
2353
2354 ###########################################################################
2355 # Setup PKGD (from D)
2356 ###########################################################################
2357
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002358 for f in (d.getVar('PACKAGEBUILDPKGD') or '').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002359 bb.build.exec_func(f, d)
2360
2361 ###########################################################################
2362 # Split up PKGD into PKGDEST
2363 ###########################################################################
2364
2365 cpath = oe.cachedpath.CachedPath()
2366
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002367 for f in (d.getVar('PACKAGESPLITFUNCS') or '').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002368 bb.build.exec_func(f, d)
2369
2370 ###########################################################################
2371 # Process PKGDEST
2372 ###########################################################################
2373
2374 # Build global list of files in each split package
2375 global pkgfiles
2376 pkgfiles = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002377 packages = d.getVar('PACKAGES').split()
2378 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002379 for pkg in packages:
2380 pkgfiles[pkg] = []
2381 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
2382 for file in files:
2383 pkgfiles[pkg].append(walkroot + os.sep + file)
2384
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002385 for f in (d.getVar('PACKAGEFUNCS') or '').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002386 bb.build.exec_func(f, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002387
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002388 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05002389 if not qa_sane:
2390 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002391}
2392
2393do_package[dirs] = "${SHLIBSWORKDIR} ${PKGDESTWORK} ${D}"
2394do_package[vardeps] += "${PACKAGEBUILDPKGD} ${PACKAGESPLITFUNCS} ${PACKAGEFUNCS} ${@gen_packagevar(d)}"
2395addtask package after do_install
2396
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002397SSTATETASKS += "do_package"
2398do_package[cleandirs] = "${PKGDEST} ${PKGDESTWORK}"
2399do_package[sstate-plaindirs] = "${PKGD} ${PKGDEST} ${PKGDESTWORK}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002400do_package_setscene[dirs] = "${STAGING_DIR}"
2401
2402python do_package_setscene () {
2403 sstate_setscene(d)
2404}
2405addtask do_package_setscene
2406
Brad Bishopc68388fc2019-08-26 01:33:31 -04002407# Copy from PKGDESTWORK to tempdirectory as tempdirectory can be cleaned at both
2408# do_package_setscene and do_packagedata_setscene leading to races
2409python do_packagedata () {
2410 src = d.expand("${PKGDESTWORK}")
2411 dest = d.expand("${WORKDIR}/pkgdata-pdata-input")
2412 oe.path.copyhardlinktree(src, dest)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002413}
2414
2415addtask packagedata before do_build after do_package
2416
2417SSTATETASKS += "do_packagedata"
Brad Bishopc68388fc2019-08-26 01:33:31 -04002418do_packagedata[sstate-inputdirs] = "${WORKDIR}/pkgdata-pdata-input"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002419do_packagedata[sstate-outputdirs] = "${PKGDATA_DIR}"
Brad Bishop316dfdd2018-06-25 12:45:53 -04002420do_packagedata[stamp-extra-info] = "${MACHINE_ARCH}"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002421
2422python do_packagedata_setscene () {
2423 sstate_setscene(d)
2424}
2425addtask do_packagedata_setscene
2426
2427#
2428# Helper functions for the package writing classes
2429#
2430
2431def mapping_rename_hook(d):
2432 """
2433 Rewrite variables to account for package renaming in things
2434 like debian.bbclass or manual PKG variable name changes
2435 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -05002436 pkg = d.getVar("PKG")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002437 runtime_mapping_rename("RDEPENDS", pkg, d)
2438 runtime_mapping_rename("RRECOMMENDS", pkg, d)
2439 runtime_mapping_rename("RSUGGESTS", pkg, d)