summaryrefslogtreecommitdiffstats
path: root/bitbake/bin/bitbake-layers
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/bin/bitbake-layers')
-rwxr-xr-xbitbake/bin/bitbake-layers720
1 files changed, 720 insertions, 0 deletions
diff --git a/bitbake/bin/bitbake-layers b/bitbake/bin/bitbake-layers
new file mode 100755
index 0000000000..047583c497
--- /dev/null
+++ b/bitbake/bin/bitbake-layers
@@ -0,0 +1,720 @@
1#!/usr/bin/env python
2
3# This script has subcommands which operate against your bitbake layers, either
4# displaying useful information, or acting against them.
5# See the help output for details on available commands.
6
7# Copyright (C) 2011 Mentor Graphics Corporation
8# Copyright (C) 2012 Intel Corporation
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import cmd
24import logging
25import os
26import sys
27import fnmatch
28from collections import defaultdict
29import re
30
31bindir = os.path.dirname(__file__)
32topdir = os.path.dirname(bindir)
33sys.path[0:0] = [os.path.join(topdir, 'lib')]
34
35import bb.cache
36import bb.cooker
37import bb.providers
38import bb.utils
39import bb.tinfoil
40
41
42logger = logging.getLogger('BitBake')
43
44
45def main(args):
46 cmds = Commands()
47 if args:
48 # Allow user to specify e.g. show-layers instead of show_layers
49 args = [args[0].replace('-', '_')] + args[1:]
50 cmds.onecmd(' '.join(args))
51 else:
52 cmds.do_help('')
53 return cmds.returncode
54
55
56class Commands(cmd.Cmd):
57 def __init__(self):
58 cmd.Cmd.__init__(self)
59 self.bbhandler = bb.tinfoil.Tinfoil()
60 self.returncode = 0
61 self.bblayers = (self.bbhandler.config_data.getVar('BBLAYERS', True) or "").split()
62
63 def default(self, line):
64 """Handle unrecognised commands"""
65 sys.stderr.write("Unrecognised command or option\n")
66 self.do_help('')
67
68 def do_help(self, topic):
69 """display general help or help on a specified command"""
70 if topic:
71 sys.stdout.write('%s: ' % topic)
72 cmd.Cmd.do_help(self, topic.replace('-', '_'))
73 else:
74 sys.stdout.write("usage: bitbake-layers <command> [arguments]\n\n")
75 sys.stdout.write("Available commands:\n")
76 procnames = list(set(self.get_names()))
77 for procname in procnames:
78 if procname[:3] == 'do_':
79 sys.stdout.write(" %s\n" % procname[3:].replace('_', '-'))
80 doc = getattr(self, procname).__doc__
81 if doc:
82 sys.stdout.write(" %s\n" % doc.splitlines()[0])
83
84 def do_show_layers(self, args):
85 """show current configured layers"""
86 self.bbhandler.prepare(config_only = True)
87 logger.plain("%s %s %s" % ("layer".ljust(20), "path".ljust(40), "priority"))
88 logger.plain('=' * 74)
89 for layerdir in self.bblayers:
90 layername = self.get_layer_name(layerdir)
91 layerpri = 0
92 for layer, _, regex, pri in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
93 if regex.match(os.path.join(layerdir, 'test')):
94 layerpri = pri
95 break
96
97 logger.plain("%s %s %d" % (layername.ljust(20), layerdir.ljust(40), layerpri))
98
99
100 def version_str(self, pe, pv, pr = None):
101 verstr = "%s" % pv
102 if pr:
103 verstr = "%s-%s" % (verstr, pr)
104 if pe:
105 verstr = "%s:%s" % (pe, verstr)
106 return verstr
107
108
109 def do_show_overlayed(self, args):
110 """list overlayed recipes (where the same recipe exists in another layer)
111
112usage: show-overlayed [-f] [-s]
113
114Lists the names of overlayed recipes and the available versions in each
115layer, with the preferred version first. Note that skipped recipes that
116are overlayed will also be listed, with a " (skipped)" suffix.
117
118Options:
119 -f instead of the default formatting, list filenames of higher priority
120 recipes with the ones they overlay indented underneath
121 -s only list overlayed recipes where the version is the same
122"""
123 self.bbhandler.prepare()
124
125 show_filenames = False
126 show_same_ver_only = False
127 for arg in args.split():
128 if arg == '-f':
129 show_filenames = True
130 elif arg == '-s':
131 show_same_ver_only = True
132 else:
133 sys.stderr.write("show-overlayed: invalid option %s\n" % arg)
134 self.do_help('')
135 return
136
137 items_listed = self.list_recipes('Overlayed recipes', None, True, show_same_ver_only, show_filenames, True)
138
139 # Check for overlayed .bbclass files
140 classes = defaultdict(list)
141 for layerdir in self.bblayers:
142 classdir = os.path.join(layerdir, 'classes')
143 if os.path.exists(classdir):
144 for classfile in os.listdir(classdir):
145 if os.path.splitext(classfile)[1] == '.bbclass':
146 classes[classfile].append(classdir)
147
148 # Locating classes and other files is a bit more complicated than recipes -
149 # layer priority is not a factor; instead BitBake uses the first matching
150 # file in BBPATH, which is manipulated directly by each layer's
151 # conf/layer.conf in turn, thus the order of layers in bblayers.conf is a
152 # factor - however, each layer.conf is free to either prepend or append to
153 # BBPATH (or indeed do crazy stuff with it). Thus the order in BBPATH might
154 # not be exactly the order present in bblayers.conf either.
155 bbpath = str(self.bbhandler.config_data.getVar('BBPATH', True))
156 overlayed_class_found = False
157 for (classfile, classdirs) in classes.items():
158 if len(classdirs) > 1:
159 if not overlayed_class_found:
160 logger.plain('=== Overlayed classes ===')
161 overlayed_class_found = True
162
163 mainfile = bb.utils.which(bbpath, os.path.join('classes', classfile))
164 if show_filenames:
165 logger.plain('%s' % mainfile)
166 else:
167 # We effectively have to guess the layer here
168 logger.plain('%s:' % classfile)
169 mainlayername = '?'
170 for layerdir in self.bblayers:
171 classdir = os.path.join(layerdir, 'classes')
172 if mainfile.startswith(classdir):
173 mainlayername = self.get_layer_name(layerdir)
174 logger.plain(' %s' % mainlayername)
175 for classdir in classdirs:
176 fullpath = os.path.join(classdir, classfile)
177 if fullpath != mainfile:
178 if show_filenames:
179 print(' %s' % fullpath)
180 else:
181 print(' %s' % self.get_layer_name(os.path.dirname(classdir)))
182
183 if overlayed_class_found:
184 items_listed = True;
185
186 if not items_listed:
187 logger.plain('No overlayed files found.')
188
189
190 def do_show_recipes(self, args):
191 """list available recipes, showing the layer they are provided by
192
193usage: show-recipes [-f] [-m] [pnspec]
194
195Lists the names of overlayed recipes and the available versions in each
196layer, with the preferred version first. Optionally you may specify
197pnspec to match a specified recipe name (supports wildcards). Note that
198skipped recipes will also be listed, with a " (skipped)" suffix.
199
200Options:
201 -f instead of the default formatting, list filenames of higher priority
202 recipes with other available recipes indented underneath
203 -m only list where multiple recipes (in the same layer or different
204 layers) exist for the same recipe name
205"""
206 self.bbhandler.prepare()
207
208 show_filenames = False
209 show_multi_provider_only = False
210 pnspec = None
211 title = 'Available recipes:'
212 for arg in args.split():
213 if arg == '-f':
214 show_filenames = True
215 elif arg == '-m':
216 show_multi_provider_only = True
217 elif not arg.startswith('-'):
218 pnspec = arg
219 title = 'Available recipes matching %s:' % pnspec
220 else:
221 sys.stderr.write("show-recipes: invalid option %s\n" % arg)
222 self.do_help('')
223 return
224 self.list_recipes(title, pnspec, False, False, show_filenames, show_multi_provider_only)
225
226
227 def list_recipes(self, title, pnspec, show_overlayed_only, show_same_ver_only, show_filenames, show_multi_provider_only):
228 pkg_pn = self.bbhandler.cooker.recipecache.pkg_pn
229 (latest_versions, preferred_versions) = bb.providers.findProviders(self.bbhandler.config_data, self.bbhandler.cooker.recipecache, pkg_pn)
230 allproviders = bb.providers.allProviders(self.bbhandler.cooker.recipecache)
231
232 # Ensure we list skipped recipes
233 # We are largely guessing about PN, PV and the preferred version here,
234 # but we have no choice since skipped recipes are not fully parsed
235 skiplist = self.bbhandler.cooker.skiplist.keys()
236 skiplist.sort( key=lambda fileitem: self.bbhandler.cooker.collection.calc_bbfile_priority(fileitem) )
237 skiplist.reverse()
238 for fn in skiplist:
239 recipe_parts = os.path.splitext(os.path.basename(fn))[0].split('_')
240 p = recipe_parts[0]
241 if len(recipe_parts) > 1:
242 ver = (None, recipe_parts[1], None)
243 else:
244 ver = (None, 'unknown', None)
245 allproviders[p].append((ver, fn))
246 if not p in pkg_pn:
247 pkg_pn[p] = 'dummy'
248 preferred_versions[p] = (ver, fn)
249
250 def print_item(f, pn, ver, layer, ispref):
251 if f in skiplist:
252 skipped = ' (skipped)'
253 else:
254 skipped = ''
255 if show_filenames:
256 if ispref:
257 logger.plain("%s%s", f, skipped)
258 else:
259 logger.plain(" %s%s", f, skipped)
260 else:
261 if ispref:
262 logger.plain("%s:", pn)
263 logger.plain(" %s %s%s", layer.ljust(20), ver, skipped)
264
265 preffiles = []
266 items_listed = False
267 for p in sorted(pkg_pn):
268 if pnspec:
269 if not fnmatch.fnmatch(p, pnspec):
270 continue
271
272 if len(allproviders[p]) > 1 or not show_multi_provider_only:
273 pref = preferred_versions[p]
274 preffile = bb.cache.Cache.virtualfn2realfn(pref[1])[0]
275 if preffile not in preffiles:
276 preflayer = self.get_file_layer(preffile)
277 multilayer = False
278 same_ver = True
279 provs = []
280 for prov in allproviders[p]:
281 provfile = bb.cache.Cache.virtualfn2realfn(prov[1])[0]
282 provlayer = self.get_file_layer(provfile)
283 provs.append((provfile, provlayer, prov[0]))
284 if provlayer != preflayer:
285 multilayer = True
286 if prov[0] != pref[0]:
287 same_ver = False
288
289 if (multilayer or not show_overlayed_only) and (same_ver or not show_same_ver_only):
290 if not items_listed:
291 logger.plain('=== %s ===' % title)
292 items_listed = True
293 print_item(preffile, p, self.version_str(pref[0][0], pref[0][1]), preflayer, True)
294 for (provfile, provlayer, provver) in provs:
295 if provfile != preffile:
296 print_item(provfile, p, self.version_str(provver[0], provver[1]), provlayer, False)
297 # Ensure we don't show two entries for BBCLASSEXTENDed recipes
298 preffiles.append(preffile)
299
300 return items_listed
301
302
303 def do_flatten(self, args):
304 """flattens layer configuration into a separate output directory.
305
306usage: flatten [layer1 layer2 [layer3]...] <outputdir>
307
308Takes the specified layers (or all layers in the current layer
309configuration if none are specified) and builds a "flattened" directory
310containing the contents of all layers, with any overlayed recipes removed
311and bbappends appended to the corresponding recipes. Note that some manual
312cleanup may still be necessary afterwards, in particular:
313
314* where non-recipe files (such as patches) are overwritten (the flatten
315 command will show a warning for these)
316* where anything beyond the normal layer setup has been added to
317 layer.conf (only the lowest priority number layer's layer.conf is used)
318* overridden/appended items from bbappends will need to be tidied up
319* when the flattened layers do not have the same directory structure (the
320 flatten command should show a warning when this will cause a problem)
321
322Warning: if you flatten several layers where another layer is intended to
323be used "inbetween" them (in layer priority order) such that recipes /
324bbappends in the layers interact, and then attempt to use the new output
325layer together with that other layer, you may no longer get the same
326build results (as the layer priority order has effectively changed).
327"""
328 arglist = args.split()
329 if len(arglist) < 1:
330 logger.error('Please specify an output directory')
331 self.do_help('flatten')
332 return
333
334 if len(arglist) == 2:
335 logger.error('If you specify layers to flatten you must specify at least two')
336 self.do_help('flatten')
337 return
338
339 outputdir = arglist[-1]
340 if os.path.exists(outputdir) and os.listdir(outputdir):
341 logger.error('Directory %s exists and is non-empty, please clear it out first' % outputdir)
342 return
343
344 self.bbhandler.prepare()
345 layers = self.bblayers
346 if len(arglist) > 2:
347 layernames = arglist[:-1]
348 found_layernames = []
349 found_layerdirs = []
350 for layerdir in layers:
351 layername = self.get_layer_name(layerdir)
352 if layername in layernames:
353 found_layerdirs.append(layerdir)
354 found_layernames.append(layername)
355
356 for layername in layernames:
357 if not layername in found_layernames:
358 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])))
359 return
360 layers = found_layerdirs
361 else:
362 layernames = []
363
364 # Ensure a specified path matches our list of layers
365 def layer_path_match(path):
366 for layerdir in layers:
367 if path.startswith(os.path.join(layerdir, '')):
368 return layerdir
369 return None
370
371 appended_recipes = []
372 for layer in layers:
373 overlayed = []
374 for f in self.bbhandler.cooker.collection.overlayed.iterkeys():
375 for of in self.bbhandler.cooker.collection.overlayed[f]:
376 if of.startswith(layer):
377 overlayed.append(of)
378
379 logger.plain('Copying files from %s...' % layer )
380 for root, dirs, files in os.walk(layer):
381 for f1 in files:
382 f1full = os.sep.join([root, f1])
383 if f1full in overlayed:
384 logger.plain(' Skipping overlayed file %s' % f1full )
385 else:
386 ext = os.path.splitext(f1)[1]
387 if ext != '.bbappend':
388 fdest = f1full[len(layer):]
389 fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
390 bb.utils.mkdirhier(os.path.dirname(fdest))
391 if os.path.exists(fdest):
392 if f1 == 'layer.conf' and root.endswith('/conf'):
393 logger.plain(' Skipping layer config file %s' % f1full )
394 continue
395 else:
396 logger.warn('Overwriting file %s', fdest)
397 bb.utils.copyfile(f1full, fdest)
398 if ext == '.bb':
399 if f1 in self.bbhandler.cooker.collection.appendlist:
400 appends = self.bbhandler.cooker.collection.appendlist[f1]
401 if appends:
402 logger.plain(' Applying appends to %s' % fdest )
403 for appendname in appends:
404 if layer_path_match(appendname):
405 self.apply_append(appendname, fdest)
406 appended_recipes.append(f1)
407
408 # Take care of when some layers are excluded and yet we have included bbappends for those recipes
409 for recipename in self.bbhandler.cooker.collection.appendlist.iterkeys():
410 if recipename not in appended_recipes:
411 appends = self.bbhandler.cooker.collection.appendlist[recipename]
412 first_append = None
413 for appendname in appends:
414 layer = layer_path_match(appendname)
415 if layer:
416 if first_append:
417 self.apply_append(appendname, first_append)
418 else:
419 fdest = appendname[len(layer):]
420 fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
421 bb.utils.mkdirhier(os.path.dirname(fdest))
422 bb.utils.copyfile(appendname, fdest)
423 first_append = fdest
424
425 # Get the regex for the first layer in our list (which is where the conf/layer.conf file will
426 # have come from)
427 first_regex = None
428 layerdir = layers[0]
429 for layername, pattern, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
430 if regex.match(os.path.join(layerdir, 'test')):
431 first_regex = regex
432 break
433
434 if first_regex:
435 # Find the BBFILES entries that match (which will have come from this conf/layer.conf file)
436 bbfiles = str(self.bbhandler.config_data.getVar('BBFILES', True)).split()
437 bbfiles_layer = []
438 for item in bbfiles:
439 if first_regex.match(item):
440 newpath = os.path.join(outputdir, item[len(layerdir)+1:])
441 bbfiles_layer.append(newpath)
442
443 if bbfiles_layer:
444 # Check that all important layer files match BBFILES
445 for root, dirs, files in os.walk(outputdir):
446 for f1 in files:
447 ext = os.path.splitext(f1)[1]
448 if ext in ['.bb', '.bbappend']:
449 f1full = os.sep.join([root, f1])
450 entry_found = False
451 for item in bbfiles_layer:
452 if fnmatch.fnmatch(f1full, item):
453 entry_found = True
454 break
455 if not entry_found:
456 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)
457
458 def get_file_layer(self, filename):
459 for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
460 if regex.match(filename):
461 for layerdir in self.bblayers:
462 if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
463 return self.get_layer_name(layerdir)
464 return "?"
465
466 def get_file_layerdir(self, filename):
467 for layer, _, regex, _ in self.bbhandler.cooker.recipecache.bbfile_config_priorities:
468 if regex.match(filename):
469 for layerdir in self.bblayers:
470 if regex.match(os.path.join(layerdir, 'test')) and re.match(layerdir, filename):
471 return layerdir
472 return "?"
473
474 def remove_layer_prefix(self, f):
475 """Remove the layer_dir prefix, e.g., f = /path/to/layer_dir/foo/blah, the
476 return value will be: layer_dir/foo/blah"""
477 f_layerdir = self.get_file_layerdir(f)
478 prefix = os.path.join(os.path.dirname(f_layerdir), '')
479 return f[len(prefix):] if f.startswith(prefix) else f
480
481 def get_layer_name(self, layerdir):
482 return os.path.basename(layerdir.rstrip(os.sep))
483
484 def apply_append(self, appendname, recipename):
485 appendfile = open(appendname, 'r')
486 recipefile = open(recipename, 'a')
487 recipefile.write('\n')
488 recipefile.write('##### bbappended from %s #####\n' % self.get_file_layer(appendname))
489 recipefile.writelines(appendfile.readlines())
490 recipefile.close()
491 appendfile.close()
492
493 def do_show_appends(self, args):
494 """list bbappend files and recipe files they apply to
495
496usage: show-appends
497
498Recipes are listed with the bbappends that apply to them as subitems.
499"""
500 self.bbhandler.prepare()
501 if not self.bbhandler.cooker.collection.appendlist:
502 logger.plain('No append files found')
503 return
504
505 logger.plain('=== Appended recipes ===')
506
507 pnlist = list(self.bbhandler.cooker_data.pkg_pn.keys())
508 pnlist.sort()
509 for pn in pnlist:
510 self.show_appends_for_pn(pn)
511
512 self.show_appends_for_skipped()
513
514 def show_appends_for_pn(self, pn):
515 filenames = self.bbhandler.cooker_data.pkg_pn[pn]
516
517 best = bb.providers.findBestProvider(pn,
518 self.bbhandler.config_data,
519 self.bbhandler.cooker_data,
520 self.bbhandler.cooker_data.pkg_pn)
521 best_filename = os.path.basename(best[3])
522
523 self.show_appends_output(filenames, best_filename)
524
525 def show_appends_for_skipped(self):
526 filenames = [os.path.basename(f)
527 for f in self.bbhandler.cooker.skiplist.iterkeys()]
528 self.show_appends_output(filenames, None, " (skipped)")
529
530 def show_appends_output(self, filenames, best_filename, name_suffix = ''):
531 appended, missing = self.get_appends_for_files(filenames)
532 if appended:
533 for basename, appends in appended:
534 logger.plain('%s%s:', basename, name_suffix)
535 for append in appends:
536 logger.plain(' %s', append)
537
538 if best_filename:
539 if best_filename in missing:
540 logger.warn('%s: missing append for preferred version',
541 best_filename)
542 self.returncode |= 1
543
544
545 def get_appends_for_files(self, filenames):
546 appended, notappended = [], []
547 for filename in filenames:
548 _, cls = bb.cache.Cache.virtualfn2realfn(filename)
549 if cls:
550 continue
551
552 basename = os.path.basename(filename)
553 appends = self.bbhandler.cooker.collection.appendlist.get(basename)
554 if appends:
555 appended.append((basename, list(appends)))
556 else:
557 notappended.append(basename)
558 return appended, notappended
559
560 def do_show_cross_depends(self, args):
561 """figure out the dependency between recipes that crosses a layer boundary.
562
563usage: show-cross-depends [-f]
564
565Figure out the dependency between recipes that crosses a layer boundary.
566
567Options:
568 -f show full file path
569
570NOTE:
571The .bbappend file can impact the dependency.
572"""
573 self.bbhandler.prepare()
574
575 show_filenames = False
576 for arg in args.split():
577 if arg == '-f':
578 show_filenames = True
579 else:
580 sys.stderr.write("show-cross-depends: invalid option %s\n" % arg)
581 self.do_help('')
582 return
583
584 pkg_fn = self.bbhandler.cooker_data.pkg_fn
585 bbpath = str(self.bbhandler.config_data.getVar('BBPATH', True))
586 self.require_re = re.compile(r"require\s+(.+)")
587 self.include_re = re.compile(r"include\s+(.+)")
588 self.inherit_re = re.compile(r"inherit\s+(.+)")
589
590 # The bb's DEPENDS and RDEPENDS
591 for f in pkg_fn:
592 f = bb.cache.Cache.virtualfn2realfn(f)[0]
593 # Get the layername that the file is in
594 layername = self.get_file_layer(f)
595
596 # The DEPENDS
597 deps = self.bbhandler.cooker_data.deps[f]
598 for pn in deps:
599 if pn in self.bbhandler.cooker_data.pkg_pn:
600 best = bb.providers.findBestProvider(pn,
601 self.bbhandler.config_data,
602 self.bbhandler.cooker_data,
603 self.bbhandler.cooker_data.pkg_pn)
604 self.check_cross_depends("DEPENDS", layername, f, best[3], show_filenames)
605
606 # The RDPENDS
607 all_rdeps = self.bbhandler.cooker_data.rundeps[f].values()
608 # Remove the duplicated or null one.
609 sorted_rdeps = {}
610 # The all_rdeps is the list in list, so we need two for loops
611 for k1 in all_rdeps:
612 for k2 in k1:
613 sorted_rdeps[k2] = 1
614 all_rdeps = sorted_rdeps.keys()
615 for rdep in all_rdeps:
616 all_p = bb.providers.getRuntimeProviders(self.bbhandler.cooker_data, rdep)
617 if all_p:
618 best = bb.providers.filterProvidersRunTime(all_p, rdep,
619 self.bbhandler.config_data,
620 self.bbhandler.cooker_data)[0][0]
621 self.check_cross_depends("RDEPENDS", layername, f, best, show_filenames)
622
623 # The inherit class
624 cls_re = re.compile('classes/')
625 if f in self.bbhandler.cooker_data.inherits:
626 inherits = self.bbhandler.cooker_data.inherits[f]
627 for cls in inherits:
628 # The inherits' format is [classes/cls, /path/to/classes/cls]
629 # ignore the classes/cls.
630 if not cls_re.match(cls):
631 inherit_layername = self.get_file_layer(cls)
632 if inherit_layername != layername:
633 if not show_filenames:
634 f_short = self.remove_layer_prefix(f)
635 cls = self.remove_layer_prefix(cls)
636 else:
637 f_short = f
638 logger.plain("%s inherits %s" % (f_short, cls))
639
640 # The 'require/include xxx' in the bb file
641 pv_re = re.compile(r"\${PV}")
642 fnfile = open(f, 'r')
643 line = fnfile.readline()
644 while line:
645 m, keyword = self.match_require_include(line)
646 # Found the 'require/include xxxx'
647 if m:
648 needed_file = m.group(1)
649 # Replace the ${PV} with the real PV
650 if pv_re.search(needed_file) and f in self.bbhandler.cooker_data.pkg_pepvpr:
651 pv = self.bbhandler.cooker_data.pkg_pepvpr[f][1]
652 needed_file = re.sub(r"\${PV}", pv, needed_file)
653 self.print_cross_files(bbpath, keyword, layername, f, needed_file, show_filenames)
654 line = fnfile.readline()
655 fnfile.close()
656
657 # The "require/include xxx" in conf/machine/*.conf, .inc and .bbclass
658 conf_re = re.compile(".*/conf/machine/[^\/]*\.conf$")
659 inc_re = re.compile(".*\.inc$")
660 # The "inherit xxx" in .bbclass
661 bbclass_re = re.compile(".*\.bbclass$")
662 for layerdir in self.bblayers:
663 layername = self.get_layer_name(layerdir)
664 for dirpath, dirnames, filenames in os.walk(layerdir):
665 for name in filenames:
666 f = os.path.join(dirpath, name)
667 s = conf_re.match(f) or inc_re.match(f) or bbclass_re.match(f)
668 if s:
669 ffile = open(f, 'r')
670 line = ffile.readline()
671 while line:
672 m, keyword = self.match_require_include(line)
673 # Only bbclass has the "inherit xxx" here.
674 bbclass=""
675 if not m and f.endswith(".bbclass"):
676 m, keyword = self.match_inherit(line)
677 bbclass=".bbclass"
678 # Find a 'require/include xxxx'
679 if m:
680 self.print_cross_files(bbpath, keyword, layername, f, m.group(1) + bbclass, show_filenames)
681 line = ffile.readline()
682 ffile.close()
683
684 def print_cross_files(self, bbpath, keyword, layername, f, needed_filename, show_filenames):
685 """Print the depends that crosses a layer boundary"""
686 needed_file = bb.utils.which(bbpath, needed_filename)
687 if needed_file:
688 # Which layer is this file from
689 needed_layername = self.get_file_layer(needed_file)
690 if needed_layername != layername:
691 if not show_filenames:
692 f = self.remove_layer_prefix(f)
693 needed_file = self.remove_layer_prefix(needed_file)
694 logger.plain("%s %s %s" %(f, keyword, needed_file))
695 def match_inherit(self, line):
696 """Match the inherit xxx line"""
697 return (self.inherit_re.match(line), "inherits")
698
699 def match_require_include(self, line):
700 """Match the require/include xxx line"""
701 m = self.require_re.match(line)
702 keyword = "requires"
703 if not m:
704 m = self.include_re.match(line)
705 keyword = "includes"
706 return (m, keyword)
707
708 def check_cross_depends(self, keyword, layername, f, needed_file, show_filenames):
709 """Print the DEPENDS/RDEPENDS file that crosses a layer boundary"""
710 best_realfn = bb.cache.Cache.virtualfn2realfn(needed_file)[0]
711 needed_layername = self.get_file_layer(best_realfn)
712 if needed_layername != layername:
713 if not show_filenames:
714 f = self.remove_layer_prefix(f)
715 best_realfn = self.remove_layer_prefix(best_realfn)
716
717 logger.plain("%s %s %s" % (f, keyword, best_realfn))
718
719if __name__ == '__main__':
720 sys.exit(main(sys.argv[1:]) or 0)