diff options
Diffstat (limited to 'meta/classes/package.bbclass')
| -rw-r--r-- | meta/classes/package.bbclass | 3044 |
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 |
