diff options
Diffstat (limited to 'meta/classes/package.bbclass')
| -rw-r--r-- | meta/classes/package.bbclass | 1437 |
1 files changed, 837 insertions, 600 deletions
diff --git a/meta/classes/package.bbclass b/meta/classes/package.bbclass index 4be2fc2dc5..d731757f14 100644 --- a/meta/classes/package.bbclass +++ b/meta/classes/package.bbclass @@ -42,6 +42,9 @@ inherit packagedata inherit prserv inherit chrpath +# Need the package_qa_handle_error() in insane.bbclass +inherit insane + PKGD = "${WORKDIR}/package" PKGDEST = "${WORKDIR}/packages-split" @@ -69,12 +72,62 @@ def legitimize_package_name(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): +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', True) + + # 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", True) if ml: if not output_pattern.startswith(ml): @@ -89,9 +142,9 @@ def do_split_packages(d, root, file_regex, output_pattern, description, postinst if newdeps: extra_depends = " ".join(newdeps) - dvar = d.getVar('PKGD', True) packages = d.getVar('PACKAGES', True).split() + split_packages = [] if postinst: postinst = '#!/bin/sh\n' + postinst + '\n' @@ -110,6 +163,9 @@ def do_split_packages(d, root, file_regex, output_pattern, description, postinst if extra_depends == None: extra_depends = d.getVar("PN", True) + if not summary: + summary = description + for o in sorted(objs): import re, stat if match_path: @@ -125,14 +181,20 @@ def do_split_packages(d, root, file_regex, output_pattern, description, postinst continue on = legitimize_package_name(m.group(1)) pkg = output_pattern % on + split_packages.append(pkg) if not pkg in packages: if prepend: packages = [pkg] + packages else: packages.append(pkg) oldfiles = d.getVar('FILES_' + pkg, True) + 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 = [os.path.join(root, o)] + the_files = [newfile] if aux_files_pattern: if type(aux_files_pattern) is list: for fp in aux_files_pattern: @@ -146,19 +208,23 @@ def do_split_packages(d, root, file_regex, output_pattern, description, postinst else: the_files.append(aux_files_pattern_verbatim % m.group(1)) d.setVar('FILES_' + pkg, " ".join(the_files)) - if extra_depends != '': - d.appendVar('RDEPENDS_' + pkg, ' ' + extra_depends) - d.setVar('DESCRIPTION_' + pkg, description % on) - if postinst: - d.setVar('pkg_postinst_' + pkg, postinst) - if postrm: - d.setVar('pkg_postrm_' + pkg, postrm) else: - d.setVar('FILES_' + pkg, oldfiles + " " + os.path.join(root, o)) + d.setVar('FILES_' + pkg, oldfiles + " " + newfile) + if extra_depends != '': + d.appendVar('RDEPENDS_' + pkg, ' ' + extra_depends) + if not d.getVar('DESCRIPTION_' + pkg, True): + d.setVar('DESCRIPTION_' + pkg, description % on) + if not d.getVar('SUMMARY_' + pkg, True): + 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 split_packages PACKAGE_DEPENDS += "file-native" @@ -170,29 +236,83 @@ python () { d.appendVarFlag('do_package', 'depends', deps) # shlibs requires any DEPENDS to have already packaged for the *.list files - d.appendVarFlag('do_package', 'deptask', " do_package") - - elif not bb.data.inherits_class('image', d): - d.setVar("PACKAGERDEPTASK", "") + d.appendVarFlag('do_package', 'deptask', " do_packagedata") } -def splitfile(file, debugfile, debugsrcdir, d): - # Function to split a single file, called from split_and_strip_files below - # A working 'file' (one which works on the target architecture) - # is split and the split off portions go to debugfile. +# 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) + + for f in files: + 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 + +# Called in package_<rpm,ipk,deb>.bbclass to get the correct list of configuration files +def get_conffiles(pkg, d): + pkgdest = d.getVar('PKGDEST', True) + root = os.path.join(pkgdest, pkg) + cwd = os.getcwd() + os.chdir(root) + + conffiles = d.getVar('CONFFILES_%s' % pkg, True); + if conffiles == None: + conffiles = d.getVar('CONFFILES', True) + if conffiles == None: + conffiles = "" + conffiles = conffiles.split() + conf_orig_list = files_from_filevars(conffiles) + + # 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 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. # - # The debug information is then processed for src references. These - # references are copied to debugsrcdir, if defined. + # sourcefile is also generated containing a list of debugsources - import commands, stat, subprocess + import stat dvar = d.getVar('PKGD', True) - pathprefix = "export PATH=%s; " % d.getVar('PATH', True) objcopy = d.getVar("OBJCOPY", True) debugedit = d.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit") workdir = d.getVar("WORKDIR", True) - workparentdir = d.getVar("DEBUGSRC_OVERRIDE_PATH", True) or os.path.dirname(workdir) - sourcefile = d.expand("${WORKDIR}/debugsources.list") + workparentdir = d.getVar("DEBUGSRC_OVERRIDE_PATH", True) or os.path.dirname(os.path.dirname(workdir)) # We ignore kernel modules, we don't generate debug info files. if file.find("/lib/modules/") != -1 and file.endswith(".ko"): @@ -206,145 +326,126 @@ def splitfile(file, debugfile, debugsrcdir, d): # We need to extract the debug src information here... if debugsrcdir: - subprocess.call("%s'%s' -b '%s' -d '%s' -i -l '%s' '%s'" % (pathprefix, debugedit, workparentdir, debugsrcdir, sourcefile, file), shell=True) + cmd = "'%s' -b '%s' -d '%s' -i -l '%s' '%s'" % (debugedit, workparentdir, debugsrcdir, 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.dirname(debugfile)) + bb.utils.mkdirhier(os.path.dirname(debugfile)) - subprocess.call("%s'%s' --only-keep-debug '%s' '%s'" % (pathprefix, objcopy, file, debugfile), shell=True) + 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 "")) # Set the debuglink to have the view of the file path on the target - subprocess.call("%s'%s' --add-gnu-debuglink='%s' '%s'" % (pathprefix, objcopy, debugfile, file), shell=True) + 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) return 0 -def splitfile2(debugsrcdir, d): - # Function to split a single file, called from split_and_strip_files below - # - # The debug src information processed in the splitfile2 is further procecessed +def copydebugsources(debugsrcdir, d): + # The debug src information written out to sourcefile is further procecessed # and copied to the destination here. - import commands, stat, subprocess + import stat sourcefile = d.expand("${WORKDIR}/debugsources.list") if debugsrcdir and os.path.isfile(sourcefile): - dvar = d.getVar('PKGD', True) - pathprefix = "export PATH=%s; " % d.getVar('PATH', True) - strip = d.getVar("STRIP", True) - objcopy = d.getVar("OBJCOPY", True) - debugedit = d.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit") - workdir = d.getVar("WORKDIR", True) - workparentdir = os.path.dirname(workdir) - workbasedir = os.path.basename(workdir) - - nosuchdir = [] - basepath = dvar - for p in debugsrcdir.split("/"): - basepath = basepath + "/" + p - if not os.path.exists(basepath): - nosuchdir.append(basepath) - bb.mkdirhier(basepath) - - processdebugsrc = "LC_ALL=C ; sort -z -u '%s' | egrep -v -z '(<internal>|<built-in>)$' | " - # We need to ignore files that are not actually ours - # we do this by only paying attention to items from this package - processdebugsrc += "fgrep -z '%s' | " - processdebugsrc += "(cd '%s' ; cpio -pd0mL --no-preserve-owner '%s%s' 2>/dev/null)" - - subprocess.call(processdebugsrc % (sourcefile, workbasedir, workparentdir, dvar, debugsrcdir), shell=True) - - # The copy by cpio may have resulted in some empty directories! Remove these - for root, dirs, files in os.walk("%s%s" % (dvar, debugsrcdir)): - for d in dirs: - dir = os.path.join(root, d) - #bb.note("rmdir -p %s" % dir) - subprocess.call("rmdir -p %s 2>/dev/null" % dir, shell=True) - - # Also remove debugsrcdir if its empty - for p in nosuchdir[::-1]: - if os.path.exists(p) and not os.listdir(p): - os.rmdir(p) - -def runstrip(file, elftype, d): - # Function to strip a single file, called from split_and_strip_files below - # A working 'file' (one which works on the target architecture) - # - # The elftype is a bit pattern (explained in split_and_strip_files) to tell - # us what type of file we're processing... - # 4 - executable - # 8 - shared library - - import commands, stat, subprocess - - pathprefix = "export PATH=%s; " % d.getVar('PATH', True) - strip = d.getVar("STRIP", True) - - # Handle kernel modules specifically - .debug directories here are pointless - if file.find("/lib/modules/") != -1 and file.endswith(".ko"): - return subprocess.call("%s'%s' --strip-debug --remove-section=.comment --remove-section=.note --preserve-dates '%s'" % (pathprefix, strip, file), shell=True) - - newmode = None - 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 | stat.S_IREAD - os.chmod(file, newmode) - - extraflags = "" - - # split_and_strip_files is calling this with elf_type None, causing: - # TypeError: unsupported operand type(s) for &: 'NoneType' and 'int' - if elftype: - # .so and shared library - if ".so" in file and elftype & 8: - extraflags = "--remove-section=.comment --remove-section=.note --strip-unneeded" - # shared or executable: - elif elftype & 8 or elftype & 4: - extraflags = "--remove-section=.comment --remove-section=.note" - - stripcmd = "'%s' %s '%s'" % (strip, extraflags, file) - bb.debug(1, "runstrip: %s" % stripcmd) - - ret = subprocess.call("%s%s" % (pathprefix, stripcmd), shell=True) - - if newmode: - os.chmod(file, origmode) - - if ret: - bb.error("runstrip: '%s' strip command failed" % stripcmd) - - return 0 + dvar = d.getVar('PKGD', True) + strip = d.getVar("STRIP", True) + objcopy = d.getVar("OBJCOPY", True) + debugedit = d.expand("${STAGING_LIBDIR_NATIVE}/rpm/bin/debugedit") + workdir = d.getVar("WORKDIR", True) + workparentdir = os.path.dirname(os.path.dirname(workdir)) + workbasedir = os.path.basename(os.path.dirname(workdir)) + "/" + os.path.basename(workdir) + + 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) + + processdebugsrc = "LC_ALL=C ; sort -z -u '%s' | egrep -v -z '(<internal>|<built-in>)$' | " + # 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' | " + processdebugsrc += "(cd '%s' ; cpio -pd0mlL --no-preserve-owner '%s%s' 2>/dev/null)" + + cmd = processdebugsrc % (sourcefile, workbasedir, 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): +def get_package_mapping (pkg, basepkg, d): import oe.packagedata data = oe.packagedata.read_subpkgdata(pkg, d) key = "PKG_%s" % pkg 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 -def runtime_mapping_rename (varname, d): +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) 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() + +def runtime_mapping_rename (varname, pkg, d): #bb.note("%s before: %s" % (varname, d.getVar(varname, True))) - new_depends = [] - deps = bb.utils.explode_dep_versions(d.getVar(varname, True) or "") + if bb.data.inherits_class('packagegroup', d): + return + + new_depends = {} + deps = bb.utils.explode_dep_versions2(d.getVar(varname, True) or "") for depend in deps: - # Have to be careful with any version component of the depend - new_depend = get_package_mapping(depend, d) - if deps[depend]: - new_depends.append("%s (%s)" % (new_depend, deps[depend])) - else: - new_depends.append(new_depend) + new_depend = get_package_mapping(depend, pkg, d) + new_depends[new_depend] = deps[depend] - d.setVar(varname, " ".join(new_depends) or None) + d.setVar(varname, bb.utils.join_deps(new_depends, commasep=False)) #bb.note("%s after: %s" % (varname, d.getVar(varname, True))) @@ -353,27 +454,53 @@ def runtime_mapping_rename (varname, d): # python package_get_auto_pr() { - # per recipe PRSERV_HOST PRSERV_PORT + import oe.prservice + import re + + # Support per recipe PRSERV_HOST pn = d.getVar('PN', True) host = d.getVar("PRSERV_HOST_" + pn, True) - port = d.getVar("PRSERV_PORT_" + pn, True) if not (host is None): d.setVar("PRSERV_HOST", host) - if not (port is None): - d.setVar("PRSERV_PORT", port) - if d.getVar('USE_PR_SERV', True) != "0": - try: - auto_pr=prserv_get_pr_auto(d) - except Exception as e: - bb.fatal("Can NOT get PRAUTO, exception %s" % str(e)) - return + + pkgv = d.getVar("PKGV", True) + + # PR Server not active, handle AUTOINC + if not d.getVar('PRSERV_HOST', True): + if 'AUTOINC' in pkgv: + d.setVar("PKGV", pkgv.replace("AUTOINC", "0")) + return + + auto_pr = None + pv = d.getVar("PV", True) + version = d.getVar("PRAUTOINX", True) + pkgarch = d.getVar("PACKAGE_ARCH", True) + checksum = d.getVar("BB_TASKHASH", True) + + if d.getVar('PRSERV_LOCKDOWN', True): + auto_pr = d.getVar('PRAUTO_' + version + '_' + pkgarch, True) or d.getVar('PRAUTO_' + version, True) or None if auto_pr is None: - if d.getVar('PRSERV_LOCKDOWN', True): - bb.fatal("Can NOT get PRAUTO from lockdown exported file") - else: - bb.fatal("Can NOT get PRAUTO from remote PR service") - return + bb.fatal("Can NOT get PRAUTO from lockdown exported file") d.setVar('PRAUTO',str(auto_pr)) + return + + try: + conn = d.getVar("__PRSERV_CONN", True) + 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}" @@ -398,7 +525,7 @@ python package_do_split_locales() { localedir = os.path.join(dvar + datadir, 'locale') - if not os.path.isdir(localedir): + if not cpath.isdir(localedir): bb.debug(1, "No locale files in this package") return @@ -413,7 +540,7 @@ python package_do_split_locales() { pkg = pn + '-locale-' + ln packages.append(pkg) d.setVar('FILES_' + pkg, os.path.join(datadir, 'locale', l)) - d.setVar('RDEPENDS_' + pkg, '%s %svirtual-locale-%s' % (pn, mlprefix, ln)) + 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)) @@ -428,28 +555,29 @@ python package_do_split_locales() { # 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, True) or d.getVar('RDEPENDS', True) or "").split() + #rdep = (d.getVar('RDEPENDS_%s' % pn, True) or "").split() #rdep.append('%s-locale*' % pn) #d.setVar('RDEPENDS_%s' % pn, ' '.join(rdep)) } python perform_packagecopy () { - import subprocess dest = d.getVar('D', True) dvar = d.getVar('PKGD', True) - bb.mkdirhier(dvar) - # Start by package population by taking a copy of the installed # files to operate on - subprocess.call('rm -rf %s/*' % (dvar), shell=True) # Preserve sparse files and hard links - subprocess.call('tar -cf - -C %s -ps . | tar -xf - -C %s' % (dest, dvar), shell=True) + 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): + 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 @@ -486,7 +614,8 @@ python fixup_perms () { elif len(lsplit) == 8: self._setdir(lsplit[0], lsplit[1], lsplit[2], lsplit[3], lsplit[4], lsplit[5], lsplit[6], lsplit[7]) else: - bb.error("Fixup Perms: invalid config line %s" % line) + msg = "Fixup Perms: invalid config line %s" % line + package_qa_handle_error("perm-config", msg, d) self.path = None self.link = None @@ -567,11 +696,12 @@ python fixup_perms () { # paths are resolved via BBPATH def get_fs_perms_list(d): str = "" + bbpath = d.getVar('BBPATH', True) fs_perms_tables = d.getVar('FILESYSTEM_PERMS_TABLES', True) if not fs_perms_tables: fs_perms_tables = 'files/fs-perms.txt' for conf_file in fs_perms_tables.split(): - str += " %s" % bb.which(d.getVar('BBPATH', True), conf_file) + str += " %s" % bb.utils.which(bbpath, conf_file) return str @@ -620,7 +750,8 @@ python fixup_perms () { if len(lsplit) == 0: continue if len(lsplit) != 8 and not (len(lsplit) == 3 and lsplit[1].lower() == "link"): - bb.error("Fixup perms: %s invalid line: %s" % (conf, line)) + msg = "Fixup perms: %s invalid line: %s" % (conf, line) + package_qa_handle_error("perm-line", msg, d) continue entry = fs_perms_entry(d.expand(line)) if entry and entry.path: @@ -638,7 +769,7 @@ python fixup_perms () { continue origin = dvar + dir - if not (os.path.exists(origin) and os.path.isdir(origin) and not os.path.islink(origin)): + if not (cpath.exists(origin) and cpath.isdir(origin) and not cpath.islink(origin)): continue link = fs_perms_table[dir].link @@ -649,11 +780,12 @@ python fixup_perms () { target = os.path.join(os.path.dirname(origin), link) ptarget = os.path.join(os.path.dirname(dir), link) if os.path.exists(target): - bb.error("Fixup Perms: Unable to correct directory link, target already exists: %s -> %s" % (dir, ptarget)) + msg = "Fixup Perms: Unable to correct directory link, target already exists: %s -> %s" % (dir, ptarget) + package_qa_handle_error("perm-link", msg, d) continue # Create path to move directory to, move it, and then setup the symlink - bb.mkdirhier(os.path.dirname(target)) + bb.utils.mkdirhier(os.path.dirname(target)) #bb.note("Fixup Perms: Rename %s -> %s" % (dir, ptarget)) os.rename(origin, target) #bb.note("Fixup Perms: Link %s -> %s" % (dir, link)) @@ -664,7 +796,7 @@ python fixup_perms () { continue origin = dvar + dir - if not (os.path.exists(origin) and os.path.isdir(origin)): + if not (cpath.exists(origin) and cpath.isdir(origin)): continue fix_perms(origin, fs_perms_table[dir].mode, fs_perms_table[dir].uid, fs_perms_table[dir].gid, dir) @@ -680,7 +812,7 @@ python fixup_perms () { } python split_and_strip_files () { - import commands, stat, errno, subprocess + import stat, errno dvar = d.getVar('PKGD', True) pn = d.getVar('PN', True) @@ -692,6 +824,12 @@ python split_and_strip_files () { debugdir = "" debuglibdir = "/usr/lib/debug" debugsrcdir = "/usr/src/debug" + elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE', True) == 'debug-without-src': + # Original OE-core, a.k.a. ".debug", style debug info, but without sources in /usr/src/debug + debugappend = "" + debugdir = "/.debug" + debuglibdir = "" + debugsrcdir = "" else: # Original OE-core, a.k.a. ".debug", style debug info debugappend = "" @@ -699,6 +837,9 @@ python split_and_strip_files () { debuglibdir = "" debugsrcdir = "/usr/src/debug" + sourcefile = d.expand("${WORKDIR}/debugsources.list") + bb.utils.remove(sourcefile) + os.chdir(dvar) # Return type (bits): @@ -707,13 +848,14 @@ python split_and_strip_files () { # 2 - stripped # 4 - executable # 8 - shared library + # 16 - kernel module def isELF(path): type = 0 - pathprefix = "export PATH=%s; " % d.getVar('PATH', True) - ret, result = commands.getstatusoutput("%sfile '%s'" % (pathprefix, path)) + ret, result = oe.utils.getstatusoutput("file \"%s\"" % path.replace("\"", "\\\"")) if ret: - bb.error("split_and_strip_files: 'file %s' failed" % path) + msg = "split_and_strip_files: 'file %s' failed" % path + package_qa_handle_error("split-strip", msg, d) return type # Not stripped @@ -731,130 +873,138 @@ python split_and_strip_files () { # # First lets figure out all of the files we may have to process ... do this only once! # - file_list = {} - file_links = {} - if (d.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', True) != '1') and \ - (d.getVar('INHIBIT_PACKAGE_STRIP', True) != '1'): - for root, dirs, files in os.walk(dvar): + elffiles = {} + symlinks = {} + kernmods = [] + inodes = {} + libdir = os.path.abspath(dvar + os.sep + d.getVar("libdir", True)) + baselibdir = os.path.abspath(dvar + os.sep + d.getVar("base_libdir", True)) + if (d.getVar('INHIBIT_PACKAGE_STRIP', True) != '1'): + for root, dirs, files in cpath.walk(dvar): for f in files: file = os.path.join(root, f) - # Only process files (and symlinks)... Skip files that are obviously debug files - if not (debugappend != "" and file.endswith(debugappend)) and \ - not (debugdir != "" and debugdir in os.path.dirname(file[len(dvar):])) and \ - os.path.isfile(file): - try: - s = os.stat(file) - except OSError, (err, strerror): - if err != errno.ENOENT: - raise - # Skip broken symlinks + if file.endswith(".ko") and file.find("/lib/modules/") != -1: + kernmods.append(file) + continue + + # Skip debug files + if debugappend and file.endswith(debugappend): + continue + if debugdir and debugdir in os.path.dirname(file[len(dvar):]): + continue + + try: + ltarget = cpath.realpath(file, dvar, False) + s = cpath.lstat(ltarget) + except OSError as e: + (err, strerror) = e.args + if err != errno.ENOENT: + raise + # Skip broken symlinks + continue + if not s: + continue + # Check its an excutable + if (s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) or (s[stat.ST_MODE] & stat.S_IXOTH) \ + or ((file.startswith(libdir) or file.startswith(baselibdir)) and ".so" in f): + # If it's a symlink, and points to an ELF file, we capture the readlink target + if cpath.islink(file): + target = os.readlink(file) + if isELF(ltarget): + #bb.note("Sym: %s (%d)" % (ltarget, isELF(ltarget))) + symlinks[file] = target continue - # Is the item excutable? Then we need to process it. - if (s[stat.ST_MODE] & stat.S_IXUSR) or \ - (s[stat.ST_MODE] & stat.S_IXGRP) or \ - (s[stat.ST_MODE] & stat.S_IXOTH): - # If it's a symlink, and points to an ELF file, we capture the readlink target - if os.path.islink(file): - target = os.readlink(file) - if not os.path.isabs(target): - ltarget = os.path.join(os.path.dirname(file), target) - else: - ltarget = target - if isELF(ltarget): - #bb.note("Sym: %s (%d)" % (ltarget, isELF(ltarget))) - file_list[file] = "sym: " + target + # It's a file (or hardlink), not a link + # ...but is it ELF, and is it already stripped? + elf_file = isELF(file) + if elf_file & 1: + if elf_file & 2: + if 'already-stripped' in (d.getVar('INSANE_SKIP_' + pn, True) or "").split(): + bb.note("Skipping file %s from %s for already-stripped QA test" % (file[len(dvar):], pn)) + else: + msg = "File '%s' from %s was already stripped, this will prevent future debugging!" % (file[len(dvar):], pn) + package_qa_handle_error("already-stripped", msg, d) continue - # It's a file (or hardlink), not a link - # ...but is it ELF, and is it already stripped? - elf_file = isELF(file) - if elf_file & 1: - # Check if it's a hard link to something else - if s.st_nlink > 1: - file_reference = "%d_%d" % (s.st_dev, s.st_ino) - # Hard link to something else - file_list[file] = "hard: " + file_reference - continue - - file_list[file] = "ELF: %d" % elf_file + # At this point we have an unstripped elf file. We need to: + # a) Make sure any file we strip is not hardlinked to anything else outside this tree + # b) Only strip any hardlinked file once (no races) + # c) Track any hardlinks between files so that we can reconstruct matching debug file hardlinks + + # Use a reference of device ID and inode number to indentify files + file_reference = "%d_%d" % (s.st_dev, s.st_ino) + if file_reference in inodes: + os.unlink(file) + os.link(inodes[file_reference][0], file) + inodes[file_reference].append(file) + else: + inodes[file_reference] = [file] + # break hardlink + bb.utils.copyfile(file, file) + elffiles[file] = elf_file + # Modified the file so clear the cache + cpath.updatecache(file) # # First lets process debug splitting # if (d.getVar('INHIBIT_PACKAGE_DEBUG_SPLIT', True) != '1'): - for file in file_list: + for file in elffiles: src = file[len(dvar):] dest = debuglibdir + os.path.dirname(src) + debugdir + "/" + os.path.basename(src) + debugappend fpath = dvar + dest - # Preserve symlinks in debug area... - if file_list[file].startswith("sym: "): - ltarget = file_list[file][5:] - lpath = os.path.dirname(ltarget) - lbase = os.path.basename(ltarget) - ftarget = "" - if lpath and lpath != ".": - ftarget += lpath + debugdir + "/" - ftarget += lbase + debugappend - if lpath.startswith(".."): - ftarget = os.path.join("..", ftarget) - bb.mkdirhier(os.path.dirname(fpath)) - #bb.note("Symlink %s -> %s" % (fpath, ftarget)) - os.symlink(ftarget, fpath) - continue - # Preserve hard links in debug area... - file_reference = "" - if file_list[file].startswith("hard: "): - file_reference = file_list[file][6:] - if file_reference not in file_links: - # If this is a new file, add it as a reference, and - # update it's type, so we can fall through and split - file_list[file] = "ELF: %d" % (isELF(file)) - else: - target = file_links[file_reference][len(dvar):] - ftarget = dvar + debuglibdir + os.path.dirname(target) + debugdir + "/" + os.path.basename(target) + debugappend - bb.mkdirhier(os.path.dirname(fpath)) - #bb.note("Link %s -> %s" % (fpath, ftarget)) - os.link(ftarget, fpath) - |
