123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720 |
- #!/usr/bin/env python
- # This script has subcommands which operate against your bitbake layers, either
- # displaying useful information, or acting against them.
- # See the help output for details on available commands.
- # Copyright (C) 2011 Mentor Graphics Corporation
- # Copyright (C) 2012 Intel Corporation
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License version 2 as
- # published by the Free Software Foundation.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- import cmd
- import logging
- import os
- import sys
- import fnmatch
- from collections import defaultdict
- import re
- bindir = os.path.dirname(__file__)
- topdir = os.path.dirname(bindir)
- sys.path[0:0] = [os.path.join(topdir, 'lib')]
- import bb.cache
- import bb.cooker
- import bb.providers
- import bb.utils
- import bb.tinfoil
- logger = logging.getLogger('BitBake')
- def main(args):
- cmds = Commands()
- if args:
- # Allow user to specify e.g. show-layers instead of show_layers
- args = [args[0].replace('-', '_')] + args[1:]
- cmds.onecmd(' '.join(args))
- else:
- cmds.do_help('')
- return cmds.returncode
- class Commands(cmd.Cmd):
- def __init__(self):
- cmd.Cmd.__init__(self)
- self.bbhandler = bb.tinfoil.Tinfoil()
- self.returncode = 0
- self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split()
- def default(self, line):
- """Handle unrecognised commands"""
- sys.stderr.write("Unrecognised command or option\n")
- self.do_help('')
- def do_help(self, topic):
- """display general help or help on a specified command"""
- if topic:
- sys.stdout.write('%s: ' % topic)
- cmd.Cmd.do_help(self, topic.replace('-', '_'))
- else:
- sys.stdout.write("usage: bitbake-layers <command> [arguments]\n\n")
- sys.stdout.write("Available commands:\n")
- procnames = list(set(self.get_names()))
- for procname in procnames:
- if procname[:3] == 'do_':
- sys.stdout.write(" %s\n" % procname[3:].replace('_', '-'))
- doc = getattr(self, procname).__doc__
- if doc:
- sys.stdout.write(" %s\n" % doc.splitlines()[0])
- def do_show_layers(self, args):
- """show current configured layers"""
- self.bbhandler.prepare(config_only = True)
- logger.plain("%s %s %s" % ("layer".ljust(20), "path".ljust(40), "priority"))
- logger.plain('=' * 74)
- for layerdir in self.bblayers:
- layername = self.get_layer_name(layerdir)
- layerpri = 0
- for layer, _, regex, pri in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
- if regex.match(os.path.join(layerdir, 'test')):
- layerpri = pri
- break
- logger.plain("%s %s %d" % (layername.ljust(20), layerdir.ljust(40), layerpri))
- def version_str(self, pe, pv, pr = None):
- verstr = "%s" % pv
- if pr:
- verstr = "%s-%s" % (verstr, pr)
- if pe:
- verstr = "%s:%s" % (pe, verstr)
- return verstr
- def do_show_overlayed(self, args):
- """list overlayed recipes (where the same recipe exists in another layer)
- usage: show-overlayed [-f] [-s]
- Lists the names of overlayed recipes and the available versions in each
- layer, with the preferred version first. Note that skipped recipes that
- are overlayed will also be listed, with a " (skipped)" suffix.
- Options:
- -f instead of the default formatting, list filenames of higher priority
- recipes with the ones they overlay indented underneath
- -s only list overlayed recipes where the version is the same
- """
- self.bbhandler.prepare()
- show_filenames = False
- show_same_ver_only = False
- for arg in args.split():
- if arg == '-f':
- show_filenames = True
- elif arg == '-s':
- show_same_ver_only = True
- else:
- sys.stderr.write("show-overlayed: invalid option %s\n" % arg)
- self.do_help('')
- return
- items_listed = self.list_recipes('Overlayed recipes', None, True, show_same_ver_only, show_filenames, True)
- # Check for overlayed .bbclass files
- classes = defaultdict(list)
- for layerdir in self.bblayers:
- classdir = os.path.join(layerdir, 'classes')
- if os.path.exists(classdir):
- for classfile in os.listdir(classdir):
- if os.path.splitext(classfile)[1] == '.bbclass':
- classes[classfile].append(classdir)
- # Locating classes and other files is a bit more complicated than recipes -
- # layer priority is not a factor; instead BitBake uses the first matching
- # file in BBPATH, which is manipulated directly by each layer's
- # conf/layer.conf in turn, thus the order of layers in bblayers.conf is a
- # factor - however, each layer.conf is free to either prepend or append to
- # BBPATH (or indeed do crazy stuff with it). Thus the order in BBPATH might
- # not be exactly the order present in bblayers.conf either.
- bbpath = str(self.bbhandler.config_data.getVar('BBPATH', True))
- overlayed_class_found = False
- for (classfile, classdirs) in classes.items():
- if len(classdirs) > 1:
- if not overlayed_class_found:
- logger.plain('=== Overlayed classes ===')
- overlayed_class_found = True
- mainfile = bb.utils.which(bbpath, os.path.join('classes', classfile))
- if show_filenames:
- logger.plain('%s' % mainfile)
- else:
- # We effectively have to guess the layer here
- logger.plain('%s:' % classfile)
- mainlayername = '?'
- for layerdir in self.bblayers:
- classdir = os.path.join(layerdir, 'classes')
- if mainfile.startswith(classdir):
- mainlayername = self.get_layer_name(layerdir)
- logger.plain(' %s' % mainlayername)
- for classdir in classdirs:
- fullpath = os.path.join(classdir, classfile)
- if fullpath != mainfile:
- if show_filenames:
- print(' %s' % fullpath)
- else:
- print(' %s' % self.get_layer_name(os.path.dirname(classdir)))
- if overlayed_class_found:
- items_listed = True;
- if not items_listed:
- logger.plain('No overlayed files found.')
- def do_show_recipes(self, args):
- """list available recipes, showing the layer they are provided by
- usage: show-recipes [-f] [-m] [pnspec]
- Lists the names of overlayed recipes and the available versions in each
- layer, with the preferred version first. Optionally you may specify
- pnspec to match a specified recipe name (supports wildcards). Note that
- skipped recipes will also be listed, with a " (skipped)" suffix.
- Options:
- -f instead of the default formatting, list filenames of higher priority
- recipes with other available recipes indented underneath
- -m only list where multiple recipes (in the same layer or different
- layers) exist for the same recipe name
- """
- self.bbhandler.prepare()
- show_filenames = False
- show_multi_provider_only = False
- pnspec = None
- title = 'Available recipes:'
- for arg in args.split():
- if arg == '-f':
- show_filenames = True
- elif arg == '-m':
- show_multi_provider_only = True
- elif not arg.startswith('-'):
- pnspec = arg
- title = 'Available recipes matching %s:' % pnspec
- else:
- sys.stderr.write("show-recipes: invalid option %s\n" % arg)
- self.do_help('')
- return
- self.list_recipes(title, pnspec, False, False, show_filenames, show_multi_provider_only)
- def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_multi_provider_only):
- pkg_pn = self.bbhandler.cooker.recipecache.pkg_pn
- (latest_versions, preferred_versions) = bb.providers.findProviders(self.bbhandler.cooker.configuration.data, self.bbhandler.cooker.recipecache, pkg_pn)
- allproviders = bb.providers.allProviders(self.bbhandler.cooker.recipecache)
- # Ensure we list skipped recipes
- # We are largely guessing about PN, PV and the preferred version here,
- # but we have no choice since skipped recipes are not fully parsed
- skiplist = self.bbhandler.cooker.skiplist.keys()
- skiplist.sort( key=lambda fileitem: self.bbhandler.cooker.calc_bbfile_priority(fileitem) )
- skiplist.reverse()
- for fn in skiplist:
- recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_')
- p = recipe_parts[0]
- if len(recipe_parts) > 1:
- ver = (None, recipe_parts[1], None)
- else:
- ver = (None, 'unknown', None)
- allproviders[p].append((ver, fn))
- if not p in pkg_pn:
- pkg_pn[p] = 'dummy'
- preferred_versions[p] = (ver, fn)
- def print_item(f, pn, ver, layer, ispref):
- if f in skiplist:
- skipped = ' (skipped)'
- else:
- skipped = ''
- if show_filenames:
- if ispref:
- logger.plain("%s%s", f, skipped)
- else:
- logger.plain(" %s%s", f, skipped)
- else:
- if ispref:
- logger.plain("%s:", pn)
- logger.plain(" %s %s%s", layer.ljust(20), ver, skipped)
- preffiles = []
- items_listed = False
- for p in sorted(pkg_pn):
- if pnspec:
- if not fnmatch.fnmatch(p, pnspec):
- continue
- if len(allproviders[p]) > 1 or not show_multi_provider_only:
- pref = preferred_versions[p]
- preffile = bb.cache.Cache.virtualfn2realfn(pref[1])[0]
- if preffile not in preffiles:
- preflayer = self.get_file_layer(preffile)
- multilayer = False
- same_ver = True
- provs = []
- for prov in allproviders[p]:
- provfile = bb.cache.Cache.virtualfn2realfn(prov[1])[0]
- provlayer = self.get_file_layer(provfile)
- provs.append((provfile, provlayer, prov[0]))
- if provlayer != preflayer:
- multilayer = True
- if prov[0] != pref[0]:
- same_ver = False
- if (multilayer or not show_overlayed_only) and (same_ver or not show_same_ver_only):
- if not items_listed:
- logger.plain('=== %s ===' % title)
- items_listed = True
- print_item(preffile, p, self.version_str(pref[0][0], pref[0][1]), preflayer, True)
- for (provfile, provlayer, provver) in provs:
- if provfile != preffile:
- print_item(provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
- # Ensure we don't show two entries for BBCLASSEXTENDed recipes
- preffiles.append(preffile)
- return items_listed
- def do_flatten(self, args):
- """flattens layer configuration into a separate output directory.
- usage: flatten [layer1 layer2 [layer3]...] <outputdir>
- Takes the specified layers (or all layers in the current layer
- configuration if none are specified) and builds a "flattened" directory
- containing the contents of all layers, with any overlayed recipes removed
- and bbappends appended to the corresponding recipes. Note that some manual
- cleanup may still be necessary afterwards, in particular:
- * where non-recipe files (such as patches) are overwritten (the flatten
- command will show a warning for these)
- * where anything beyond the normal layer setup has been added to
- layer.conf (only the lowest priority number layer's layer.conf is used)
- * overridden/appended items from bbappends will need to be tidied up
- * when the flattened layers do not have the same directory structure (the
- flatten command should show a warning when this will cause a problem)
- Warning: if you flatten several layers where another layer is intended to
- be used "inbetween" them (in layer priority order) such that recipes /
- bbappends in the layers interact, and then attempt to use the new output
- layer together with that other layer, you may no longer get the same
- build results (as the layer priority order has effectively changed).
- """
- arglist = args.split()
- if len(arglist) < 1:
- logger.error('Please specify an output directory')
- self.do_help('flatten')
- return
- if len(arglist) == 2:
- logger.error('If you specify layers to flatten you must specify at least two')
- self.do_help('flatten')
- return
- outputdir = arglist[-1]
- if os.path.exists(outputdir) and os.listdir(outputdir):
- logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
- return
- self.bbhandler.prepare()
- layers = self.bblayers
- if len(arglist) > 2:
- layernames = arglist[:-1]
- found_layernames = []
- found_layerdirs = []
- for layerdir in layers:
- layername = self.get_layer_name(layerdir)
- if layername in layernames:
- found_layerdirs.append(layerdir)
- found_layernames.append(layername)
- for layername in layernames:
- if not layername in found_layernames:
- logger.error('Unable to find layer %s in current configuration, please run "%s show-layers" to list configured layers' % (layername, os.path.basename(sys.argv[0])))
- return
- layers = found_layerdirs
- else:
- layernames = []
- # Ensure a specified path matches our list of layers
- def layer_path_match(path):
- for layerdir in layers:
- if path.startswith(os.path.join(layerdir, '')):
- return layerdir
- return None
- appended_recipes = []
- for layer in layers:
- overlayed = []
- for f in self.bbhandler.cooker.overlayed.iterkeys():
- for of in self.bbhandler.cooker.overlayed[f]:
- if of.startswith(layer):
- overlayed.append(of)
- logger.plain('Copying files from %s...' % layer )
- for root, dirs, files in os.walk(layer):
- for f1 in files:
- f1full = os.sep.join([root, f1])
- if f1full in overlayed:
- logger.plain(' Skipping overlayed file %s' % f1full )
- else:
- ext = os.path.splitext(f1)[1]
- if ext != '.bbappend':
- fdest = f1full[len(layer):]
- fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
- bb.utils.mkdirhier(os.path.dirname(fdest))
- if os.path.exists(fdest):
- if f1 == 'layer.conf' and root.endswith('/conf'):
- logger.plain(' Skipping layer config file %s' % f1full )
- continue
- else:
- logger.warn('Overwriting file %s', fdest)
- bb.utils.copyfile(f1full, fdest)
- if ext == '.bb':
- if f1 in self.bbhandler.cooker.appendlist:
- appends = self.bbhandler.cooker.appendlist[f1]
- if appends:
- logger.plain(' Applying appends to %s' % fdest )
- for appendname in appends:
- if layer_path_match(appendname):
- self.apply_append(appendname, fdest)
- appended_recipes.append(f1)
- # Take care of when some layers are excluded and yet we have included bbappends for those recipes
- for recipename in self.bbhandler.cooker.appendlist.iterkeys():
- if recipename not in appended_recipes:
- appends = self.bbhandler.cooker.appendlist[recipename]
- first_append = None
- for appendname in appends:
- layer = layer_path_match(appendname)
- if layer:
- if first_append:
- self.apply_append(appendname, first_append)
- else:
- fdest = appendname[len(layer):]
- fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
- bb.utils.mkdirhier(os.path.dirname(fdest))
- bb.utils.copyfile(appendname, fdest)
- first_append = fdest
- # Get the regex for the first layer in our list (which is where the conf/layer.conf file will
- # have come from)
- first_regex = None
- layerdir = layers[0]
- for layername, pattern, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
- if regex.match(os.path.join(layerdir, 'test')):
- first_regex = regex
- break
- if first_regex:
- # Find the BBFILES entries that match (which will have come from this conf/layer.conf file)
- bbfiles = str(self.bbhandler.config_data.getVar('BBFILES', True)).split()
- bbfiles_layer = []
- for item in bbfiles:
- if first_regex.match(item):
- newpath = os.path.join(outputdir, item[len(layerdir)+1:])
- bbfiles_layer.append(newpath)
- if bbfiles_layer:
- # Check that all important layer files match BBFILES
- for root, dirs, files in os.walk(outputdir):
- for f1 in files:
- ext = os.path.splitext(f1)[1]
- if ext in ['.bb', '.bbappend']:
- f1full = os.sep.join([root, f1])
- entry_found = False
- for item in bbfiles_layer:
- if fnmatch.fnmatch(f1full, item):
- entry_found = True
- break
- if not entry_found:
- logger.warning("File %s does not match the flattened layer's BBFILES setting, you may need to edit conf/layer.conf or move the file elsewhere" % f1full)
- def get_file_layer(self, filename):
- for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
- if regex.match(filename):
- for layerdir in self.bblayers:
- if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
- return self.get_layer_name(layerdir)
- return "?"
- def get_file_layerdir(self, filename):
- for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
- if regex.match(filename):
- for layerdir in self.bblayers:
- if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
- return layerdir
- return "?"
- def remove_layer_prefix(self, f):
- """Remove the layer_dir prefix, e.g., f = /path/to/layer_dir/foo/blah, the
- return value will be: layer_dir/foo/blah"""
- f_layerdir = self.get_file_layerdir(f)
- prefix = os.path.join(os.path.dirname(f_layerdir), '')
- return f[len(prefix):] if f.startswith(prefix) else f
- def get_layer_name(self, layerdir):
- return os.path.basename(layerdir.rstrip(os.sep))
- def apply_append(self, appendname, recipename):
- appendfile = open(appendname, 'r')
- recipefile = open(recipename, 'a')
- recipefile.write('\n')
- recipefile.write('##### bbappended from %s #####\n' % self.get_file_layer(appendname))
- recipefile.writelines(appendfile.readlines())
- recipefile.close()
- appendfile.close()
- def do_show_appends(self, args):
- """list bbappend files and recipe files they apply to
- usage: show-appends
- Recipes are listed with the bbappends that apply to them as subitems.
- """
- self.bbhandler.prepare()
- if not self.bbhandler.cooker.appendlist:
- logger.plain('No append files found')
- return
- logger.plain('=== Appended recipes ===')
- pnlist = list(self.bbhandler.cooker_data.pkg_pn.keys())
- pnlist.sort()
- for pn in pnlist:
- self.show_appends_for_pn(pn)
- self.show_appends_for_skipped()
- def show_appends_for_pn(self, pn):
- filenames = self.bbhandler.cooker_data.pkg_pn[pn]
- best = bb.providers.findBestProvider(pn,
- self.bbhandler.cooker.configuration.data,
- self.bbhandler.cooker_data,
- self.bbhandler.cooker_data.pkg_pn)
- best_filename = os.path.basename(best[3])
- self.show_appends_output(filenames, best_filename)
- def show_appends_for_skipped(self):
- filenames = [os.path.basename(f)
- for f in self.bbhandler.cooker.skiplist.iterkeys()]
- self.show_appends_output(filenames, None, " (skipped)")
- def show_appends_output(self, filenames, best_filename, name_suffix = ''):
- appended, missing = self.get_appends_for_files(filenames)
- if appended:
- for basename, appends in appended:
- logger.plain('%s%s:', basename, name_suffix)
- for append in appends:
- logger.plain(' %s', append)
- if best_filename:
- if best_filename in missing:
- logger.warn('%s: missing append for preferred version',
- best_filename)
- self.returncode |= 1
- def get_appends_for_files(self, filenames):
- appended, notappended = [], []
- for filename in filenames:
- _, cls = bb.cache.Cache.virtualfn2realfn(filename)
- if cls:
- continue
- basename = os.path.basename(filename)
- appends = self.bbhandler.cooker.appendlist.get(basename)
- if appends:
- appended.append((basename, list(appends)))
- else:
- notappended.append(basename)
- return appended, notappended
- def do_show_cross_depends(self, args):
- """figure out the dependency between recipes that crosses a layer boundary.
- usage: show-cross-depends [-f]
- Figure out the dependency between recipes that crosses a layer boundary.
- Options:
- -f show full file path
- NOTE:
- The .bbappend file can impact the dependency.
- """
- self.bbhandler.prepare()
- show_filenames = False
- for arg in args.split():
- if arg == '-f':
- show_filenames = True
- else:
- sys.stderr.write("show-cross-depends: invalid option %s\n" % arg)
- self.do_help('')
- return
- pkg_fn = self.bbhandler.cooker_data.pkg_fn
- bbpath = str(self.bbhandler.config_data.getVar('BBPATH', True))
- self.require_re = re.compile(r"require\s+(.+)")
- self.include_re = re.compile(r"include\s+(.+)")
- self.inherit_re = re.compile(r"inherit\s+(.+)")
- # The bb's DEPENDS and RDEPENDS
- for f in pkg_fn:
- f = bb.cache.Cache.virtualfn2realfn(f)[0]
- # Get the layername that the file is in
- layername = self.get_file_layer(f)
- # The DEPENDS
- deps = self.bbhandler.cooker_data.deps[f]
- for pn in deps:
- if pn in self.bbhandler.cooker_data.pkg_pn:
- best = bb.providers.findBestProvider(pn,
- self.bbhandler.cooker.configuration.data,
- self.bbhandler.cooker_data,
- self.bbhandler.cooker_data.pkg_pn)
- self.check_cross_depends("DEPENDS", layername, f, best[3], show_filenames)
- # The RDPENDS
- all_rdeps = self.bbhandler.cooker_data.rundeps[f].values()
- # Remove the duplicated or null one.
- sorted_rdeps = {}
- # The all_rdeps is the list in list, so we need two for loops
- for k1 in all_rdeps:
- for k2 in k1:
- sorted_rdeps[k2] = 1
- all_rdeps = sorted_rdeps.keys()
- for rdep in all_rdeps:
- all_p = bb.providers.getRuntimeProviders(self.bbhandler.cooker_data, rdep)
- if all_p:
- best = bb.providers.filterProvidersRunTime(all_p, rdep,
- self.bbhandler.cooker.configuration.data,
- self.bbhandler.cooker_data)[0][0]
- self.check_cross_depends("RDEPENDS", layername, f, best, show_filenames)
- # The inherit class
- cls_re = re.compile('classes/')
- if f in self.bbhandler.cooker_data.inherits:
- inherits = self.bbhandler.cooker_data.inherits[f]
- for cls in inherits:
- # The inherits' format is [classes/cls, /path/to/classes/cls]
- # ignore the classes/cls.
- if not cls_re.match(cls):
- inherit_layername = self.get_file_layer(cls)
- if inherit_layername != layername:
- if not show_filenames:
- f_short = self.remove_layer_prefix(f)
- cls = self.remove_layer_prefix(cls)
- else:
- f_short = f
- logger.plain("%s inherits %s" % (f_short, cls))
- # The 'require/include xxx' in the bb file
- pv_re = re.compile(r"\${PV}")
- fnfile = open(f, 'r')
- line = fnfile.readline()
- while line:
- m, keyword = self.match_require_include(line)
- # Found the 'require/include xxxx'
- if m:
- needed_file = m.group(1)
- # Replace the ${PV} with the real PV
- if pv_re.search(needed_file) and f in self.bbhandler.cooker_data.pkg_pepvpr:
- pv = self.bbhandler.cooker_data.pkg_pepvpr[f][1]
- needed_file = re.sub(r"\${PV}", pv, needed_file)
- self.print_cross_files(bbpath, keyword, layername, f, needed_file, show_filenames)
- line = fnfile.readline()
- fnfile.close()
- # The "require/include xxx" in conf/machine/*.conf, .inc and .bbclass
- conf_re = re.compile(".*/conf/machine/[^\/]*\.conf$")
- inc_re = re.compile(".*\.inc$")
- # The "inherit xxx" in .bbclass
- bbclass_re = re.compile(".*\.bbclass$")
- for layerdir in self.bblayers:
- layername = self.get_layer_name(layerdir)
- for dirpath, dirnames, filenames in os.walk(layerdir):
- for name in filenames:
- f = os.path.join(dirpath, name)
- s = conf_re.match(f) or inc_re.match(f) or bbclass_re.match(f)
- if s:
- ffile = open(f, 'r')
- line = ffile.readline()
- while line:
- m, keyword = self.match_require_include(line)
- # Only bbclass has the "inherit xxx" here.
- bbclass=""
- if not m and f.endswith(".bbclass"):
- m, keyword = self.match_inherit(line)
- bbclass=".bbclass"
- # Find a 'require/include xxxx'
- if m:
- self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, show_filenames)
- line = ffile.readline()
- ffile.close()
- def print_cross_files(self, bbpath, keyword, layername, f, needed_filename, show_filenames):
- """Print the depends that crosses a layer boundary"""
- needed_file = bb.utils.which(bbpath, needed_filename)
- if needed_file:
- # Which layer is this file from
- needed_layername = self.get_file_layer(needed_file)
- if needed_layername != layername:
- if not show_filenames:
- f = self.remove_layer_prefix(f)
- needed_file = self.remove_layer_prefix(needed_file)
- logger.plain("%s %s %s" %(f, keyword, needed_file))
- def match_inherit(self, line):
- """Match the inherit xxx line"""
- return (self.inherit_re.match(line), "inherits")
- def match_require_include(self, line):
- """Match the require/include xxx line"""
- m = self.require_re.match(line)
- keyword = "requires"
- if not m:
- m = self.include_re.match(line)
- keyword = "includes"
- return (m, keyword)
- def check_cross_depends(self, keyword, layername, f, needed_file, show_filenames):
- """Print the DEPENDS/RDEPENDS file that crosses a layer boundary"""
- best_realfn = bb.cache.Cache.virtualfn2realfn(needed_file)[0]
- needed_layername = self.get_file_layer(best_realfn)
- if needed_layername != layername:
- if not show_filenames:
- f = self.remove_layer_prefix(f)
- best_realfn = self.remove_layer_prefix(best_realfn)
- logger.plain("%s %s %s" % (f, keyword, best_realfn))
- if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]) or 0)
|