TipsAndTricks/Tinfoil: Difference between revisions
PaulEggleton (talk | contribs) No edit summary |
PaulEggleton (talk | contribs) No edit summary |
||
Line 6: | Line 6: | ||
= Writing simple utility scripts using Tinfoil = | = 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 scripts to interact with the metadata and call into BitBake/OpenEmbedded code. Some of the scripts that come with BitBake / OpenEmbedded make heavy use of it - <code>bitbake-layers</code>, <code>devtool</code>, <code>recipetool</code> and <code>oe-pkgdata-util</code> are examples. | 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 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 - <code>bitbake-layers</code>, <code>devtool</code>, <code>recipetool</code> and <code>oe-pkgdata-util</code> are examples. | ||
== Getting a variable value == | == Getting a variable value == | ||
Line 33: | Line 33: | ||
</pre> | </pre> | ||
If you are querying multiple variable values this is much more efficient than calling out to "bitbake -e" and parsing its output. | 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 == | == Parsing recipes == | ||
Line 57: | Line 57: | ||
tinfoil.prepare(config_only=False) | tinfoil.prepare(config_only=False) | ||
# Parse the gzip recipe | |||
rd = tinfoil.parse_recipe('gzip') | rd = tinfoil.parse_recipe('gzip') | ||
print('gzip SRC_URI = "%s"' % rd.getVar('SRC_URI')) | 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') | rd = tinfoil.parse_recipe('virtual/kernel') | ||
print('Kernel recipe is %s' % rd.getVar('PN')) | 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)) | |||
</pre> | </pre> | ||
Notice that in this second example we pass <code>config_only=False</code> - this | Notice that in this second example we pass <code>config_only=False</code> - 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 <code>config_only=False</code> 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 <code>parse_recipe()</code> function will accept recipe names, or providers such as <code>virtual/kernel</code> in the second call above. It returns a datastore (usually seen as <code>d</code> within recipes and other python code within OE). | The <code>parse_recipe()</code> function will accept recipe names, or providers such as <code>virtual/kernel</code> in the second call above. It returns a datastore (usually seen as <code>d</code> within recipes and other python code within OE) which you can then use to get variable values, check inheritance etc. | ||
== Enumerating available recipes == | |||
<pre> | |||
#!/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) | |||
</pre> | |||
A few notes about <code>pkg_pn</code>: | |||
* 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 <code>BBCLASSEXTEND</code> in there as well. | |||
* There's a corresponding <code>pkg_fn</code> dict that maps files to <code>PN</code> values, but bear in mind this also contains <code>virtual:...</code> entries, again created through <code>BBCLASSEXTEND</code>. | |||
* This doesn't yet work with multiconfig - just the main configuration | |||
== 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. |
Revision as of 02:46, 1 June 2017
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 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
#!/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
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.