TipsAndTricks/Tinfoil
NOTE: This is currently a draft, needs additional content & editing - PaulEggleton (talk) 18:22, 30 May 2017 (PDT) |
Writing simple utility scripts using Tinfoil
The tinfoil API, which was introduced to BitBake a number of years ago and underwent a major rework in the 2.3 (pyro) release, provides a way for you to write python scripts to interact with the metadata and call into BitBake/OpenEmbedded code. It's intended to be an easier-to-use wrapper around BitBake's internal code, hence the name. Some of the scripts that come with BitBake / OpenEmbedded make heavy use of it - bitbake-layers
, devtool
, recipetool
and oe-pkgdata-util
are examples.
Getting a variable value
Let's take a look at a simple example which reads a configuration-level variable value - TMPDIR
to be specific. This script needs to be placed in the scripts
subdirectory to work as-is, although you can modify the import code to make it work from anywhere:
#!/usr/bin/env python3 import os import sys # Set up sys.path to let us import tinfoil scripts_path = os.path.dirname(os.path.realpath(__file__)) lib_path = scripts_path + '/lib' sys.path.insert(0, lib_path) import scriptpath scriptpath.add_bitbake_lib_path() import bb.tinfoil with bb.tinfoil.Tinfoil() as tinfoil: tinfoil.prepare(config_only=True) tmpdir = tinfoil.config_data.getVar('TMPDIR') print('TMPDIR is "%s"' % tmpdir)
If you are querying multiple variable values this is much more efficient than calling out to "bitbake -e" and parsing its output, which was the old way of getting this kind of information.
Parsing recipes
Here's another example where we parse a couple of recipes:
#!/usr/bin/env python3 import os import sys # Set up sys.path to let us import tinfoil scripts_path = os.path.dirname(os.path.realpath(__file__)) lib_path = scripts_path + '/lib' sys.path.insert(0, lib_path) import scriptpath scriptpath.add_bitbake_lib_path() import bb.tinfoil with bb.tinfoil.Tinfoil() as tinfoil: tinfoil.prepare(config_only=False) # Parse the gzip recipe rd = tinfoil.parse_recipe('gzip') print('gzip SRC_URI = "%s"' % rd.getVar('SRC_URI')) # Parse the kernel recipe (whichever is selected in your configuration) rd = tinfoil.parse_recipe('virtual/kernel') print('Kernel recipe is %s' % rd.getVar('PN')) # Check if the kernel recipe inherits the kernel class - we'd expect True print('Kernel recipe inherits kernel class: %s' % bb.data.inherits_class('kernel', rd)) # Check if the kernel recipe inherits the cmake class - we'd expect False print('Kernel recipe inherits cmake class: %s' % bb.utils.inherits_class('cmake', rd))
Notice that in this second example we pass config_only=False
- this tells tinfoil to load the data for all recipes enabled in your configuration, just as bitbake does every time you run a normal build. You don't have to specify config_only=False
to parse a recipe file if you know the path to it, but it is required if you want to specify it simply by name and get the preferred version / provider.
The parse_recipe()
function will accept recipe names, or providers such as virtual/kernel
in the second call above. It returns a datastore (usually seen as d
within recipes and other python code within OE) which you can then use to get variable values, check inheritance etc.
Enumerating available recipes
Iterating over available recipes in the system is relatively straightforward:
#!/usr/bin/env python3 import os import sys # Set up sys.path to let us import tinfoil scripts_path = os.path.dirname(os.path.realpath(__file__)) lib_path = scripts_path + '/lib' sys.path.insert(0, lib_path) import scriptpath scriptpath.add_bitbake_lib_path() import bb.tinfoil with bb.tinfoil.Tinfoil() as tinfoil: tinfoil.prepare(config_only=False) for pn in tinfoil.cooker.recipecaches[""].pkg_pn: print(pn)
A few notes about pkg_pn
:
- It's actually a dictionary and so the keys aren't sorted alphabetically
- It contains every target, not just every recipe file - i.e. there will be variants created through
BBCLASSEXTEND
in there as well. - There's a corresponding
pkg_fn
dict that maps files toPN
values, but bear in mind this also containsvirtual:...
entries, again created throughBBCLASSEXTEND
. - This doesn't yet work with multiconfig - just the main configuration
There are some improvements to be made in this area which should hopefully land in 2.4.
Other useful functions
The bitbake/lib/bb/utils.py, meta/lib/oe/utils.py, and meta/lib/oe/recipeutils.py files all contain useful functions that will help you perform various tasks that might be interesting from a script that uses tinfoil.