summaryrefslogtreecommitdiff
path: root/meta/classes/package.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes/package.bbclass')
-rw-r--r--meta/classes/package.bbclass3044
1 files changed, 2099 insertions, 945 deletions
diff --git a/meta/classes/package.bbclass b/meta/classes/package.bbclass
index 3ca8532376..cc466bd1b2 100644
--- a/meta/classes/package.bbclass
+++ b/meta/classes/package.bbclass
@@ -1,1030 +1,2184 @@
#
-# General packaging help functions
+# Packaging process
#
+# Executive summary: This class iterates over the functions listed in PACKAGEFUNCS
+# Taking D and splitting it up into the packages listed in PACKAGES, placing the
+# resulting output in PKGDEST.
+#
+# There are the following default steps but PACKAGEFUNCS can be extended:
+#
+# a) package_get_auto_pr - get PRAUTO from remote PR service
+#
+# b) perform_packagecopy - Copy D into PKGD
+#
+# c) package_do_split_locales - Split out the locale files, updates FILES and PACKAGES
+#
+# d) split_and_strip_files - split the files into runtime and debug and strip them.
+# Debug files include debug info split, and associated sources that end up in -dbg packages
+#
+# e) fixup_perms - Fix up permissions in the package before we split it.
+#
+# f) populate_packages - Split the files in PKGD into separate packages in PKGDEST/<pkgname>
+# Also triggers the binary stripping code to put files in -dbg packages.
+#
+# g) package_do_filedeps - Collect perfile run-time dependency metadata
+# The data is stores in FILER{PROVIDES,DEPENDS}_file_pkg variables with
+# a list of affected files in FILER{PROVIDES,DEPENDS}FLIST_pkg
+#
+# h) package_do_shlibs - Look at the shared libraries generated and autotmatically add any
+# depenedencies found. Also stores the package name so anyone else using this library
+# knows which package to depend on.
+#
+# i) package_do_pkgconfig - Keep track of which packages need and provide which .pc files
+#
+# j) read_shlibdeps - Reads the stored shlibs information into the metadata
+#
+# k) package_depchains - Adds automatic dependencies to -dbg and -dev packages
+#
+# l) emit_pkgdata - saves the packaging data into PKGDATA_DIR for use in later
+# packaging steps
-PKGDEST = "${WORKDIR}/install"
+inherit packagedata
+inherit chrpath
-def legitimize_package_name(s):
- """
- Make sure package names are legitimate strings
- """
- import re
-
- def fixutf(m):
- cp = m.group(1)
- if cp:
- return ('\u%s' % cp).decode('unicode_escape').encode('utf-8')
-
- # Handle unicode codepoints encoded as <U0123>, as in glibc locale files.
- s = re.sub('<U([0-9A-Fa-f]{1,4})>', fixutf, s)
-
- # Remaining package name validity fixes
- return s.lower().replace('_', '-').replace('@', '+').replace(',', '+').replace('/', '-')
-
-def 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):
- """
- Used in .bb files to split up dynamically generated subpackages of a
- given package, usually plugins or modules.
- """
- import os, os.path, bb
-
- dvar = bb.data.getVar('D', d, 1)
- if not dvar:
- bb.error("D not defined")
- return
-
- packages = bb.data.getVar('PACKAGES', d, 1).split()
-
- if postinst:
- postinst = '#!/bin/sh\n' + postinst + '\n'
- if postrm:
- postrm = '#!/bin/sh\n' + postrm + '\n'
- if not recursive:
- objs = os.listdir(dvar + root)
- else:
- objs = []
- for walkroot, dirs, files in os.walk(dvar + root):
- for file in files:
- relpath = os.path.join(walkroot, file).replace(dvar + root + '/', '', 1)
- if relpath:
- objs.append(relpath)
-
- if extra_depends == None:
- # This is *really* broken
- mainpkg = packages[0]
- # At least try and patch it up I guess...
- if mainpkg.find('-dbg'):
- mainpkg = mainpkg.replace('-dbg', '')
- if mainpkg.find('-dev'):
- mainpkg = mainpkg.replace('-dev', '')
- extra_depends = mainpkg
-
- for o in objs:
- import re, stat
- if match_path:
- m = re.match(file_regex, o)
- else:
- m = re.match(file_regex, os.path.basename(o))
-
- if not m:
- continue
- f = os.path.join(dvar + root, o)
- mode = os.lstat(f).st_mode
- if not (stat.S_ISREG(mode) or (allow_dirs and stat.S_ISDIR(mode))):
- continue
- on = legitimize_package_name(m.group(1))
- pkg = output_pattern % on
- if not pkg in packages:
- if prepend:
- packages = [pkg] + packages
- else:
- packages.append(pkg)
- the_files = [os.path.join(root, o)]
- if aux_files_pattern:
- if type(aux_files_pattern) is list:
- for fp in aux_files_pattern:
- the_files.append(fp % on)
- else:
- the_files.append(aux_files_pattern % on)
- if aux_files_pattern_verbatim:
- if type(aux_files_pattern_verbatim) is list:
- for fp in aux_files_pattern_verbatim:
- the_files.append(fp % m.group(1))
- else:
- the_files.append(aux_files_pattern_verbatim % m.group(1))
- bb.data.setVar('FILES_' + pkg, " ".join(the_files), d)
- if extra_depends != '':
- the_depends = bb.data.getVar('RDEPENDS_' + pkg, d, 1)
- if the_depends:
- the_depends = '%s %s' % (the_depends, extra_depends)
- else:
- the_depends = extra_depends
- bb.data.setVar('RDEPENDS_' + pkg, the_depends, d)
- bb.data.setVar('DESCRIPTION_' + pkg, description % on, d)
- if postinst:
- bb.data.setVar('pkg_postinst_' + pkg, postinst, d)
- if postrm:
- bb.data.setVar('pkg_postrm_' + pkg, postrm, d)
- else:
- oldfiles = bb.data.getVar('FILES_' + pkg, d, 1)
- if not oldfiles:
- bb.fatal("Package '%s' exists but has no files" % pkg)
- bb.data.setVar('FILES_' + pkg, oldfiles + " " + os.path.join(root, o), d)
- if callable(hook):
- hook(f, pkg, file_regex, output_pattern, m.group(1))
-
- bb.data.setVar('PACKAGES', ' '.join(packages), d)
+# Need the package_qa_handle_error() in insane.bbclass
+inherit insane
-PACKAGE_DEPENDS += "file-native"
+PKGD = "${WORKDIR}/package"
+PKGDEST = "${WORKDIR}/packages-split"
-python () {
- import bb
- if bb.data.getVar('PACKAGES', d, True) != '':
- deps = bb.data.getVarFlag('do_package', 'depends', d) or ""
- for dep in (bb.data.getVar('PACKAGE_DEPENDS', d, True) or "").split():
- deps += " %s:do_populate_staging" % dep
- bb.data.setVarFlag('do_package', 'depends', deps, d)
-
- deps = (bb.data.getVarFlag('do_package', 'deptask', d) or "").split()
- # shlibs requires any DEPENDS to have already packaged for the *.list files
- deps.append("do_package")
- bb.data.setVarFlag('do_package', 'deptask', " ".join(deps), d)
-}
+LOCALE_SECTION ?= ''
-def runstrip(file, d):
- # Function to strip a single file, called from populate_packages below
- # A working 'file' (one which works on the target architecture)
- # is necessary for this stuff to work, hence the addition to do_package[depends]
+ALL_MULTILIB_PACKAGE_ARCHS = "${@all_multilib_tune_values(d, 'PACKAGE_ARCHS')}"
- import bb, os, commands, stat
+# rpm is used for the per-file dependency identification
+PACKAGE_DEPENDS += "rpm-native"
- pathprefix = "export PATH=%s; " % bb.data.getVar('PATH', d, 1)
- ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, file))
+# If your postinstall can execute at rootfs creation time rather than on
+# target but depends on a native/cross tool in order to execute, you need to
+# list that tool in PACKAGE_WRITE_DEPENDS. Target package dependencies belong
+# in the package dependencies as normal, this is just for native/cross support
+# tools at rootfs build time.
+PACKAGE_WRITE_DEPS ??= ""
- if ret:
- bb.error("runstrip: 'file %s' failed (forced strip)" % file)
+def legitimize_package_name(s):
+ """
+ Make sure package names are legitimate strings
+ """
+ import re
+
+ def fixutf(m):
+ cp = m.group(1)
+ if cp:
+ return ('\\u%s' % cp).encode('latin-1').decode('unicode_escape')
+
+ # Handle unicode codepoints encoded as <U0123>, as in glibc locale files.
+ s = re.sub('<U([0-9A-Fa-f]{1,4})>', fixutf, s)
+
+ # Remaining package name validity fixes
+ return s.lower().replace('_', '-').replace('@', '+').replace(',', '+').replace('/', '-')
+
+def 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):
+ """
+ Used in .bb files to split up dynamically generated subpackages of a
+ given package, usually plugins or modules.
+
+ Arguments:
+ root -- the path in which to search
+ file_regex -- regular expression to match searched files. Use
+ parentheses () to mark the part of this expression
+ that should be used to derive the module name (to be
+ substituted where %s is used in other function
+ arguments as noted below)
+ output_pattern -- pattern to use for the package names. Must include %s.
+ description -- description to set for each package. Must include %s.
+ postinst -- postinstall script to use for all packages (as a
+ string)
+ recursive -- True to perform a recursive search - default False
+ hook -- a hook function to be called for every match. The
+ function will be called with the following arguments
+ (in the order listed):
+ f: full path to the file/directory match
+ pkg: the package name
+ file_regex: as above
+ output_pattern: as above
+ modulename: the module name derived using file_regex
+ extra_depends -- extra runtime dependencies (RDEPENDS) to be set for
+ all packages. The default value of None causes a
+ dependency on the main package (${PN}) - if you do
+ not want this, pass '' for this parameter.
+ aux_files_pattern -- extra item(s) to be added to FILES for each
+ package. Can be a single string item or a list of
+ strings for multiple items. Must include %s.
+ postrm -- postrm script to use for all packages (as a string)
+ allow_dirs -- True allow directories to be matched - default False
+ prepend -- if True, prepend created packages to PACKAGES instead
+ of the default False which appends them
+ match_path -- match file_regex on the whole relative path to the
+ root rather than just the file name
+ aux_files_pattern_verbatim -- extra item(s) to be added to FILES for
+ each package, using the actual derived module name
+ rather than converting it to something legal for a
+ package name. Can be a single string item or a list
+ of strings for multiple items. Must include %s.
+ allow_links -- True to allow symlinks to be matched - default False
+ summary -- Summary to set for each package. Must include %s;
+ defaults to description if not set.
+
+ """
+
+ dvar = d.getVar('PKGD')
+ root = d.expand(root)
+ output_pattern = d.expand(output_pattern)
+ extra_depends = d.expand(extra_depends)
+
+ # If the root directory doesn't exist, don't error out later but silently do
+ # no splitting.
+ if not os.path.exists(dvar + root):
+ return []
+
+ ml = d.getVar("MLPREFIX")
+ if ml:
+ if not output_pattern.startswith(ml):
+ output_pattern = ml + output_pattern
+
+ newdeps = []
+ for dep in (extra_depends or "").split():
+ if dep.startswith(ml):
+ newdeps.append(dep)
+ else:
+ newdeps.append(ml + dep)
+ if newdeps:
+ extra_depends = " ".join(newdeps)
+
+
+ packages = d.getVar('PACKAGES').split()
+ split_packages = set()
+
+ if postinst:
+ postinst = '#!/bin/sh\n' + postinst + '\n'
+ if postrm:
+ postrm = '#!/bin/sh\n' + postrm + '\n'
+ if not recursive:
+ objs = os.listdir(dvar + root)
+ else:
+ objs = []
+ for walkroot, dirs, files in os.walk(dvar + root):
+ for file in files:
+ relpath = os.path.join(walkroot, file).replace(dvar + root + '/', '', 1)
+ if relpath:
+ objs.append(relpath)
+
+ if extra_depends == None:
+ extra_depends = d.getVar("PN")
+
+ if not summary:
+ summary = description
+
+ for o in sorted(objs):
+ import re, stat
+ if match_path:
+ m = re.match(file_regex, o)
+ else:
+ m = re.match(file_regex, os.path.basename(o))
+
+ if not m:
+ continue
+ f = os.path.join(dvar + root, o)
+ mode = os.lstat(f).st_mode
+ if not (stat.S_ISREG(mode) or (allow_links and stat.S_ISLNK(mode)) or (allow_dirs and stat.S_ISDIR(mode))):
+ continue
+ on = legitimize_package_name(m.group(1))
+ pkg = output_pattern % on
+ split_packages.add(pkg)
+ if not pkg in packages:
+ if prepend:
+ packages = [pkg] + packages
+ else:
+ packages.append(pkg)
+ oldfiles = d.getVar('FILES_' + pkg)
+ newfile = os.path.join(root, o)
+ # These names will be passed through glob() so if the filename actually
+ # contains * or ? (rare, but possible) we need to handle that specially
+ newfile = newfile.replace('*', '[*]')
+ newfile = newfile.replace('?', '[?]')
+ if not oldfiles:
+ the_files = [newfile]
+ if aux_files_pattern:
+ if type(aux_files_pattern) is list:
+ for fp in aux_files_pattern:
+ the_files.append(fp % on)
+ else:
+ the_files.append(aux_files_pattern % on)
+ if aux_files_pattern_verbatim:
+ if type(aux_files_pattern_verbatim) is list:
+ for fp in aux_files_pattern_verbatim:
+ the_files.append(fp % m.group(1))
+ else:
+ the_files.append(aux_files_pattern_verbatim % m.group(1))
+ d.setVar('FILES_' + pkg, " ".join(the_files))
+ else:
+ d.setVar('FILES_' + pkg, oldfiles + " " + newfile)
+ if extra_depends != '':
+ d.appendVar('RDEPENDS_' + pkg, ' ' + extra_depends)
+ if not d.getVar('DESCRIPTION_' + pkg):
+ d.setVar('DESCRIPTION_' + pkg, description % on)
+ if not d.getVar('SUMMARY_' + pkg):
+ d.setVar('SUMMARY_' + pkg, summary % on)
+ if postinst:
+ d.setVar('pkg_postinst_' + pkg, postinst)
+ if postrm:
+ d.setVar('pkg_postrm_' + pkg, postrm)
+ if callable(hook):
+ hook(f, pkg, file_regex, output_pattern, m.group(1))
+
+ d.setVar('PACKAGES', ' '.join(packages))
+ return list(split_packages)
- if "not stripped" not in result:
- bb.debug(1, "runstrip: skip %s" % file)
- return 0
+PACKAGE_DEPENDS += "file-native"
- # If the file is in a .debug directory it was already stripped,
- # don't do it again...
- if os.path.dirname(file).endswith(".debug"):
- bb.note("Already ran strip")
- return 0
+python () {
+ if d.getVar('PACKAGES') != '':
+ deps = ""
+ for dep in (d.getVar('PACKAGE_DEPENDS') or "").split():
+ deps += " %s:do_populate_sysroot" % dep
+ d.appendVarFlag('do_package', 'depends', deps)
+
+ # shlibs requires any DEPENDS to have already packaged for the *.list files
+ d.appendVarFlag('do_package', 'deptask', " do_packagedata")
+}
- strip = bb.data.getVar("STRIP", d, 1)
- objcopy = bb.data.getVar("OBJCOPY", d, 1)
+# Get a list of files from file vars by searching files under current working directory
+# The list contains symlinks, directories and normal files.
+def files_from_filevars(filevars):
+ import os,glob
+ cpath = oe.cachedpath.CachedPath()
+ files = []
+ for f in filevars:
+ if os.path.isabs(f):
+ f = '.' + f
+ if not f.startswith("./"):
+ f = './' + f
+ globbed = glob.glob(f)
+ if globbed:
+ if [ f ] != globbed:
+ files += globbed
+ continue
+ files.append(f)
+
+ symlink_paths = []
+ for ind, f in enumerate(files):
+ # Handle directory symlinks. Truncate path to the lowest level symlink
+ parent = ''
+ for dirname in f.split('/')[:-1]:
+ parent = os.path.join(parent, dirname)
+ if dirname == '.':
+ continue
+ if cpath.islink(parent):
+ bb.warn("FILES contains file '%s' which resides under a "
+ "directory symlink. Please fix the recipe and use the "
+ "real path for the file." % f[1:])
+ symlink_paths.append(f)
+ files[ind] = parent
+ f = parent
+ break
+
+ if not cpath.islink(f):
+ if cpath.isdir(f):
+ newfiles = [ os.path.join(f,x) for x in os.listdir(f) ]
+ if newfiles:
+ files += newfiles
+
+ return files, symlink_paths
+
+# Called in package_<rpm,ipk,deb>.bbclass to get the correct list of configuration files
+def get_conffiles(pkg, d):
+ pkgdest = d.getVar('PKGDEST')
+ root = os.path.join(pkgdest, pkg)
+ cwd = os.getcwd()
+ os.chdir(root)
+
+ conffiles = d.getVar('CONFFILES_%s' % pkg);
+ if conffiles == None:
+ conffiles = d.getVar('CONFFILES')
+ if conffiles == None:
+ conffiles = ""
+ conffiles = conffiles.split()
+ conf_orig_list = files_from_filevars(conffiles)[0]
+
+ # Remove links and directories from conf_orig_list to get conf_list which only contains normal files
+ conf_list = []
+ for f in conf_orig_list:
+ if os.path.isdir(f):
+ continue
+ if os.path.islink(f):
+ continue
+ if not os.path.exists(f):
+ continue
+ conf_list.append(f)
+
+ # Remove the leading './'
+ for i in range(0, len(conf_list)):
+ conf_list[i] = conf_list[i][1:]
+
+ os.chdir(cwd)
+ return conf_list
+
+def checkbuildpath(file, d):
+ tmpdir = d.getVar('TMPDIR')
+ with open(file) as f:
+ file_content = f.read()
+ if tmpdir in file_content:
+ return True
+
+ return False
+
+def splitdebuginfo(file, debugfile, debugsrcdir, sourcefile, d):
+ # Function to split a single file into two components, one is the stripped
+ # target system binary, the other contains any debugging information. The
+ # two files are linked to reference each other.
+ #
+ # sourcefile is also generated containing a list of debugsources
+
+ import stat
+
+ dvar = d.getVar('PKGD')
+ objcopy = d.getVar("OBJCOPY")
+ debugedit = d.expand("${STAGING_LIBDIR_NATIVE}/rpm/debugedit")
+
+ # We ignore kernel modules, we don't generate debug info files.
+ if file.find("/lib/modules/") != -1 and file.endswith(".ko"):
+ return 1
newmode = None
- if not os.access(file, os.W_OK):
+ if not os.access(file, os.W_OK) or os.access(file, os.R_OK):
origmode = os.stat(file)[stat.ST_MODE]
- newmode = origmode | stat.S_IWRITE
+ newmode = origmode | stat.S_IWRITE | stat.S_IREAD
os.chmod(file, newmode)
- extraflags = ""
- if ".so" in file and "shared" in result:
- extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded"
- elif "shared" in result or "executable" in result:
- extraflags = "--remove-section=.comment --remove-section=.note"
+ # We need to extract the debug src information here...
+ if debugsrcdir:
+ cmd = "'%s' -i -l '%s' '%s'" % (debugedit, sourcefile, file)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("debugedit failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else ""))
- bb.mkdirhier(os.path.join(os.path.dirname(file), ".debug"))
- debugfile=os.path.join(os.path.dirname(file), ".debug", os.path.basename(file))
+ bb.utils.mkdirhier(os.path.dirname(debugfile))
- stripcmd = "'%s' %s '%s'" % (strip, extraflags, file)
- bb.debug(1, "runstrip: %s" % stripcmd)
+ cmd = "'%s' --only-keep-debug '%s' '%s'" % (objcopy, file, debugfile)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("objcopy failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else ""))
- os.system("%s'%s' --only-keep-debug '%s' '%s'" % (pathprefix, objcopy, file, debugfile))
- ret = os.system("%s%s" % (pathprefix, stripcmd))
- os.system("%s'%s' --add-gnu-debuglink='%s' '%s'" % (pathprefix, objcopy, debugfile, file))
+ # Set the debuglink to have the view of the file path on the target
+ cmd = "'%s' --add-gnu-debuglink='%s' '%s'" % (objcopy, debugfile, file)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("objcopy failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else ""))
if newmode:
os.chmod(file, origmode)
- if ret:
- bb.error("runstrip: '%s' strip command failed" % stripcmd)
-
- return 1
+ return 0
+
+def copydebugsources(debugsrcdir, d):
+ # The debug src information written out to sourcefile is further procecessed
+ # and copied to the destination here.
+
+ import stat
+
+ sourcefile = d.expand("${WORKDIR}/debugsources.list")
+ if debugsrcdir and os.path.isfile(sourcefile):
+ dvar = d.getVar('PKGD')
+ strip = d.getVar("STRIP")
+ objcopy = d.getVar("OBJCOPY")
+ debugedit = d.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit")
+ workdir = d.getVar("WORKDIR")
+ workparentdir = os.path.dirname(os.path.dirname(workdir))
+ workbasedir = os.path.basename(os.path.dirname(workdir)) + "/" + os.path.basename(workdir)
+
+ # If build path exists in sourcefile, it means toolchain did not use
+ # -fdebug-prefix-map to compile
+ if checkbuildpath(sourcefile, d):
+ localsrc_prefix = workparentdir + "/"
+ else:
+ localsrc_prefix = "/usr/src/debug/"
+
+ nosuchdir = []
+ basepath = dvar
+ for p in debugsrcdir.split("/"):
+ basepath = basepath + "/" + p
+ if not cpath.exists(basepath):
+ nosuchdir.append(basepath)
+ bb.utils.mkdirhier(basepath)
+ cpath.updatecache(basepath)
+
+ # Ignore files from the recipe sysroots (target and native)
+ processdebugsrc = "LC_ALL=C ; sort -z -u '%s' | egrep -v -z '((<internal>|<built-in>)$|/.*recipe-sysroot.*/)' | "
+ # We need to ignore files that are not actually ours
+ # we do this by only paying attention to items from this package
+ processdebugsrc += "fgrep -zw '%s' | "
+ # Remove prefix in the source paths
+ processdebugsrc += "sed 's#%s##g' | "
+ processdebugsrc += "(cd '%s' ; cpio -pd0mlL --no-preserve-owner '%s%s' 2>/dev/null)"
+
+ cmd = processdebugsrc % (sourcefile, workbasedir, localsrc_prefix, workparentdir, dvar, debugsrcdir)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ # Can "fail" if internal headers/transient sources are attempted
+ #if retval:
+ # bb.fatal("debug source copy failed with exit code %s (cmd was %s)" % (retval, cmd))
+
+ # cpio seems to have a bug with -lL together and symbolic links are just copied, not dereferenced.
+ # Work around this by manually finding and copying any symbolic links that made it through.
+ cmd = "find %s%s -type l -print0 -delete | sed s#%s%s/##g | (cd '%s' ; cpio -pd0mL --no-preserve-owner '%s%s' 2>/dev/null)" % (dvar, debugsrcdir, dvar, debugsrcdir, workparentdir, dvar, debugsrcdir)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("debugsrc symlink fixup failed with exit code %s (cmd was %s)" % (retval, cmd))
+
+ # The copy by cpio may have resulted in some empty directories! Remove these
+ cmd = "find %s%s -empty -type d -delete" % (dvar, debugsrcdir)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("empty directory removal failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else ""))
+
+ # Also remove debugsrcdir if its empty
+ for p in nosuchdir[::-1]:
+ if os.path.exists(p) and not os.listdir(p):
+ os.rmdir(p)
#
# Package data handling routines
#
-def get_package_mapping (pkg, d):
- import bb, os
+def get_package_mapping (pkg, basepkg, d):
+ import oe.packagedata
- data = read_subpkgdata(pkg, d)
- key = "PKG_%s" % pkg
+ data = oe.packagedata.read_subpkgdata(pkg, d)
+ key = "PKG_%s" % pkg
- if key in data:
- return data[key]
+ if key in data:
+ # Have to avoid undoing the write_extra_pkgs(global_variants...)
+ if bb.data.inherits_class('allarch', d) and data[key] == basepkg:
+ return pkg
+ return data[key]
- return pkg
+ return pkg
-def runtime_mapping_rename (varname, d):
- import bb, os
+def get_package_additional_metadata (pkg_type, d):
+ base_key = "PACKAGE_ADD_METADATA"
+ for key in ("%s_%s" % (base_key, pkg_type.upper()), base_key):
+ if d.getVar(key, False) is None:
+ continue
+ d.setVarFlag(key, "type", "list")
+ if d.getVarFlag(key, "separator") is None:
+ d.setVarFlag(key, "separator", "\\n")
+ metadata_fields = [field.strip() for field in oe.data.typed_value(key, d)]
+ return "\n".join(metadata_fields).strip()
- #bb.note("%s before: %s" % (varname, bb.data.getVar(varname, d, 1)))
+def runtime_mapping_rename (varname, pkg, d):
+ #bb.note("%s before: %s" % (varname, d.getVar(varname)))
- new_depends = []
- for depend in explode_deps(bb.data.getVar(varname, d, 1) or ""):
- # Have to be careful with any version component of the depend
- split_depend = depend.split(' (')
- new_depend = get_package_mapping(split_depend[0].strip(), d)
- if len(split_depend) > 1:
- new_depends.append("%s (%s" % (new_depend, split_depend[1]))
- else:
- new_depends.append(new_depend)
+ new_depends = {}
+ deps = bb.utils.explode_dep_versions2(d.getVar(varname) or "")
+ for depend in deps:
+ new_depend = get_package_mapping(depend, pkg, d)
+ new_depends[new_depend] = deps[depend]
- bb.data.setVar(varname, " ".join(new_depends) or None, d)
+ d.setVar(varname, bb.utils.join_deps(new_depends, commasep=False))
- #bb.note("%s after: %s" % (varname, bb.data.getVar(varname, d, 1)))
+ #bb.note("%s after: %s" % (varname, d.getVar(varname)))
#
# Package functions suitable for inclusion in PACKAGEFUNCS
#
+python package_get_auto_pr() {
+ import oe.prservice
+ import re
+
+ # Support per recipe PRSERV_HOST
+ pn = d.getVar('PN')
+ host = d.getVar("PRSERV_HOST_" + pn)
+ if not (host is None):
+ d.setVar("PRSERV_HOST", host)
+
+ pkgv = d.getVar("PKGV")
+
+ # PR Server not active, handle AUTOINC
+ if not d.getVar('PRSERV_HOST'):
+ if 'AUTOINC' in pkgv:
+ d.setVar("PKGV", pkgv.replace("AUTOINC", "0"))
+ return
+
+ auto_pr = None
+ pv = d.getVar("PV")
+ version = d.getVar("PRAUTOINX")
+ pkgarch = d.getVar("PACKAGE_ARCH")
+ checksum = d.getVar("BB_TASKHASH")
+
+ if d.getVar('PRSERV_LOCKDOWN'):
+ auto_pr = d.getVar('PRAUTO_' + version + '_' + pkgarch) or d.getVar('PRAUTO_' + version) or None
+ if auto_pr is None:
+ bb.fatal("Can NOT get PRAUTO from lockdown exported file")
+ d.setVar('PRAUTO',str(auto_pr))
+ return
+
+ try:
+ conn = d.getVar("__PRSERV_CONN")
+ if conn is None:
+ conn = oe.prservice.prserv_make_conn(d)
+ if conn is not None:
+ if "AUTOINC" in pkgv:
+ srcpv = bb.fetch2.get_srcrev(d)
+ base_ver = "AUTOINC-%s" % version[:version.find(srcpv)]
+ value = conn.getPR(base_ver, pkgarch, srcpv)
+ d.setVar("PKGV", pkgv.replace("AUTOINC", str(value)))
+
+ auto_pr = conn.getPR(version, pkgarch, checksum)
+ except Exception as e:
+ bb.fatal("Can NOT get PRAUTO, exception %s" % str(e))
+ if auto_pr is None:
+ bb.fatal("Can NOT get PRAUTO from remote PR service")
+ d.setVar('PRAUTO',str(auto_pr))
+}
+
+LOCALEBASEPN ??= "${PN}"
+
python package_do_split_locales() {
- import os
-
- if (bb.data.getVar('PACKAGE_NO_LOCALE', d, 1) == '1'):
- bb.debug(1, "package requested not splitting locales")
- return
-
- packages = (bb.data.getVar('PACKAGES', d, 1) or "").split()
-
- datadir = bb.data.getVar('datadir', d, 1)
- if not datadir:
- bb.note("datadir not defined")
- return
-
- dvar = bb.data.getVar('D', d, 1)
- if not dvar:
- bb.error("D not defined")
- return
-
- pn = bb.data.getVar('PN', d, 1)
- if not pn:
- bb.error("PN not defined")
- return
-
- if pn + '-locale' in packages:
- packages.remove(pn + '-locale')
-
- localedir = os.path.join(dvar + datadir, 'locale')
-
- if not os.path.isdir(localedir):
- bb.debug(1, "No locale files in this package")
- return
-
- locales = os.listdir(localedir)
-
- # This is *really* broken
- mainpkg = packages[0]
- # At least try and patch it up I guess...
- if mainpkg.find('-dbg'):
- mainpkg = mainpkg.replace('-dbg', '')
- if mainpkg.find('-dev'):
- mainpkg = mainpkg.replace('-dev', '')
-
- for l in locales:
- ln = legitimize_package_name(l)
- pkg = pn + '-locale-' + ln
- packages.append(pkg)
- bb.data.setVar('FILES_' + pkg, os.path.join(datadir, 'locale', l), d)
- bb.data.setVar('RDEPENDS_' + pkg, '%s virtual-locale-%s' % (mainpkg, ln), d)
- bb.data.setVar('RPROVIDES_' + pkg, '%s-locale %s-translation' % (pn, ln), d)
- bb.data.setVar('DESCRIPTION_' + pkg, '%s translation for %s' % (l, pn), d)
-
- bb.data.setVar('PACKAGES', ' '.join(packages), d)
-
- # Disabled by RP 18/06/07
- # Wildcards aren't supported in debian
- # They break with ipkg since glibc-locale* will mean that
- # glibc-localedata-translit* won't install as a dependency
- # for some other package which breaks meta-toolchain
- # Probably breaks since virtual-locale- isn't provided anywhere
- #rdep = (bb.data.getVar('RDEPENDS_%s' % mainpkg, d, 1) or bb.data.getVar('RDEPENDS', d, 1) or "").split()
- #rdep.append('%s-locale*' % pn)
- #bb.data.setVar('RDEPENDS_%s' % mainpkg, ' '.join(rdep), d)
+ if (d.getVar('PACKAGE_NO_LOCALE') == '1'):
+ bb.debug(1, "package requested not splitting locales")
+ return
+
+ packages = (d.getVar('PACKAGES') or "").split()
+
+ datadir = d.getVar('datadir')
+ if not datadir:
+ bb.note("datadir not defined")
+ return
+
+ dvar = d.getVar('PKGD')
+ pn = d.getVar('LOCALEBASEPN')
+
+ if pn + '-locale' in packages:
+ packages.remove(pn + '-locale')
+
+ localedir = os.path.join(dvar + datadir, 'locale')
+
+ if not cpath.isdir(localedir):
+ bb.debug(1, "No locale files in this package")
+ return
+
+ locales = os.listdir(localedir)
+
+ summary = d.getVar('SUMMARY') or pn
+ description = d.getVar('DESCRIPTION') or ""
+ locale_section = d.getVar('LOCALE_SECTION')
+ mlprefix = d.getVar('MLPREFIX') or ""
+ for l in sorted(locales):
+ ln = legitimize_package_name(l)
+ pkg = pn + '-locale-' + ln
+ packages.append(pkg)
+ d.setVar('FILES_' + pkg, os.path.join(datadir, 'locale', l))
+ d.setVar('RRECOMMENDS_' + pkg, '%svirtual-locale-%s' % (mlprefix, ln))
+ d.setVar('RPROVIDES_' + pkg, '%s-locale %s%s-translation' % (pn, mlprefix, ln))
+ d.setVar('SUMMARY_' + pkg, '%s - %s translations' % (summary, l))
+ d.setVar('DESCRIPTION_' + pkg, '%s This package contains language translation files for the %s locale.' % (description, l))
+ if locale_section:
+ d.setVar('SECTION_' + pkg, locale_section)
+
+ d.setVar('PACKAGES', ' '.join(packages))
+
+ # Disabled by RP 18/06/07
+ # Wildcards aren't supported in debian
+ # They break with ipkg since glibc-locale* will mean that
+ # glibc-localedata-translit* won't install as a dependency
+ # for some other package which breaks meta-toolchain
+ # Probably breaks since virtual-locale- isn't provided anywhere
+ #rdep = (d.getVar('RDEPENDS_%s' % pn) or "").split()
+ #rdep.append('%s-locale*' % pn)
+ #d.setVar('RDEPENDS_%s' % pn, ' '.join(rdep))
+}
+
+python perform_packagecopy () {
+ dest = d.getVar('D')
+ dvar = d.getVar('PKGD')
+
+ # Start by package population by taking a copy of the installed
+ # files to operate on
+ # Preserve sparse files and hard links
+ cmd = 'tar -cf - -C %s -p . | tar -xf - -C %s' % (dest, dvar)
+ (retval, output) = oe.utils.getstatusoutput(cmd)
+ if retval:
+ bb.fatal("file copy failed with exit code %s (cmd was %s)%s" % (retval, cmd, ":\n%s" % output if output else ""))
+
+ # replace RPATHs for the nativesdk binaries, to make them relocatable
+ if bb.data.inherits_class('nativesdk', d) or bb.data.inherits_class('cross-canadian', d):
+ rpath_replace (dvar, d)
+}
+perform_packagecopy[cleandirs] = "${PKGD}"
+perform_packagecopy[dirs] = "${PKGD}"
+
+# We generate a master list of directories to process, we start by
+# seeding this list with reasonable defaults, then load from
+# the fs-perms.txt files
+python fixup_perms () {
+ import pwd, grp
+
+ # init using a string with the same format as a line as documented in
+ # the fs-perms.txt file
+ # <path> <mode> <uid> <gid> <walk> <fmode> <fuid> <fgid>
+ # <path> link <link target>
+ #
+ # __str__ can be used to print out an entry in the input format
+ #
+ # if fs_perms_entry.path is None:
+ # an error occured
+ # if fs_perms_entry.link, you can retrieve:
+ # fs_perms_entry.path = path
+ # fs_perms_entry.link = target of link
+ # if not fs_perms_entry.link, you can retrieve:
+ # fs_perms_entry.path = path
+ # fs_perms_entry.mode = expected dir mode or None
+ # fs_perms_entry.uid = expected uid or -1
+ # fs_perms_entry.gid = expected gid or -1
+ # fs_perms_entry.walk = 'true' or something else
+ # fs_perms_entry.fmode = expected file mode or None
+ # fs_perms_entry.fuid = expected file uid or -1
+ # fs_perms_entry_fgid = expected file gid or -1
+ class fs_perms_entry():
+ def __init__(self, line):
+ lsplit = line.split()
+ if len(lsplit) == 3 and lsplit[1].lower() == "link":
+ self._setlink(lsplit[0], lsplit[2])
+ elif len(lsplit) == 8:
+ self._setdir(lsplit[0], lsplit[1], lsplit[2], lsplit[3], lsplit[4], lsplit[5], lsplit[6], lsplit[7])
+ else:
+ msg = "Fixup Perms: invalid config line %s" % line
+ package_qa_handle_error("perm-config", msg, d)
+ self.path = None
+ self.link = None
+
+ def _setdir(self, path, mode, uid, gid, walk, fmode, fuid, fgid):
+ self.path = os.path.normpath(path)
+ self.link = None
+ self.mode = self._procmode(mode)
+ self.uid = self._procuid(uid)
+ self.gid = self._procgid(gid)
+ self.walk = walk.lower()
+ self.fmode = self._procmode(fmode)
+ self.fuid = self._procuid(fuid)
+ self.fgid = self._procgid(fgid)
+
+ def _setlink(self, path, link):
+ self.path = os.path.normpath(path)
+ self.link = link
+
+ def _procmode(self, mode):
+ if not mode or (mode and mode == "-"):
+ return None
+ else:
+ return int(mode,8)
+
+ # Note uid/gid -1 has special significance in os.lchown
+ def _procuid(self, uid):
+ if uid is None or uid == "-":
+ return -1
+ elif uid.isdigit():
+ return int(uid)
+ else:
+ return pwd.getpwnam(uid).pw_uid
+
+ def _procgid(self, gid):
+ if gid is None or gid == "-":
+ return -1
+ elif gid.isdigit():
+ return int(gid)
+ else:
+ return grp.getgrnam(gid).gr_gid
+
+ # Use for debugging the entries
+ def __str__(self):
+ if self.link:
+ return "%s link %s" % (self.path, self.link)
+ else:
+ mode = "-"
+ if self.mode:
+ mode = "0%o" % self.mode
+ fmode = "-"
+ if self.fmode:
+ fmode = "0%o" % self.fmode
+ uid = self._mapugid(self.uid)
+ gid = self._mapugid(self.gid)
+ fuid = self._mapugid(self.fuid)
+ fgid = self._mapugid(self.fgid)
+ return "%s %s %s %s %s %s %s %s" % (self.path, mode, uid, gid, self.walk, fmode, fuid, fgid)
+
+ def _mapugid(self, id):
+ if id is None or id == -1:
+ return "-"
+ else:
+ return "%d" % id
+
+ # Fix the permission, owner and group of path
+ def fix_perms(path, mode, uid, gid, dir):
+ if mode and not os.path.islink(path):
+ #bb.note