diff options
authorPaul Eggleton <>2012-01-08 12:06:49 +0000
committerRichard Purdie <>2012-01-10 17:40:42 +0000
commit4137b51f634bd0c7dec80701181dc3af79afbd71 (patch)
parent89f2d11561c225a875b5691aaadc936490fab5a6 (diff)
bitbake-layers: flatten: allow specifying layers to flatten
You can now optionally specify two or more layers to flatten into the output, rather than flattening all of the layers in the current configuration (but this is still the default behaviour if no layers are specified). Note that this means the output layer may still contain bbappends where the corresponding recipes are not present in the list of layers to flatten. There is also a caveat when a layer not being flattened would be "inbetween" the flattened layers (see the command help for details.) Implements feature request in [YOCTO #1564]. (Bitbake rev: 379b12107ec921b4458eda320078374a509164c1) Signed-off-by: Paul Eggleton <> Signed-off-by: Richard Purdie <>
1 files changed, 67 insertions, 8 deletions
diff --git a/bitbake/bin/bitbake-layers b/bitbake/bin/bitbake-layers
index b2781bbd56..572487d2db 100755
--- a/bitbake/bin/bitbake-layers
+++ b/bitbake/bin/bitbake-layers
@@ -139,9 +139,10 @@ Highest priority recipes are listed with the recipes they overlay as subitems.
def do_flatten(self, args):
"""flattens layer configuration into a separate output directory.
-usage: flatten <outputdir>
+usage: flatten [layer1 layer2 [layer3]...] <outputdir>
-Takes the current layer configuration and builds a "flattened" directory
+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:
@@ -149,21 +150,59 @@ 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 layer's layer.conf is used)
+ layer.conf (only the lowest priority number layer's layer.conf is used)
* overridden/appended items from bbappends will need to be tidied up
+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:
+ if len(arglist) < 1:
logger.error('Please specify an output directory')
- if os.path.exists(arglist[0]) and os.listdir(arglist[0]):
- logger.error('Directory %s exists and is non-empty, please clear it out first' % arglist[0])
+ 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)
layers = (self.config_data.getVar('BBLAYERS', True) or "").split()
+ if len(arglist) > 2:
+ layernames = arglist[:-1]
+ found_layernames = []
+ found_layerdirs = []
+ for layerdir in layers:
+ for layername, _, regex, _ in self.cooker.status.bbfile_config_priorities:
+ if layername in layernames:
+ if regex.match(os.path.join(layerdir, 'test')):
+ found_layerdirs.append(layerdir)
+ found_layernames.append(layername)
+ break
+ 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
+ # 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.cooker.overlayed.iterkeys():
@@ -181,7 +220,7 @@ cleanup may still be necessary afterwards, in particular:
ext = os.path.splitext(f1)[1]
if ext != '.bbappend':
fdest = f1full[len(layer):]
- fdest = os.path.normpath(os.sep.join([arglist[0],fdest]))
+ fdest = os.path.normpath(os.sep.join([outputdir,fdest]))
if os.path.exists(fdest):
if f1 == 'layer.conf' and root.endswith('/conf'):
@@ -196,7 +235,27 @@ cleanup may still be necessary afterwards, in particular:
if appends:
logger.plain(' Applying appends to %s' % fdest )
for appendname in appends:
- self.apply_append(appendname, fdest)
+ 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.cooker_data.appends.iterkeys():
+ if recipename not in appended_recipes:
+ appends = self.cooker_data.appends[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
def get_append_layer(self, appendname):
for layer, _, regex, _ in self.cooker.status.bbfile_config_priorities: