Introduction
This tutorial will show some practises that have been found useful when setting up a build environment and maintaining itl
Version notes
This tutorial targets the following Yocto Project versions:
Yocto Project | Tutorial applies | Maintenance |
---|---|---|
nanbield (4.3) | development | |
mickledore (4.2) | current stable | |
langdale (4.1) | stable | |
kirkstone (4.0) | LTS | |
honister (3.4) | EOL | |
hardknott (3.3) | 1 | EOL |
gatesgarth (3.2) | 2 | EOL |
dunfell (3.1) | 3 | LTS |
zeus (3.0) | 4 | EOL |
warrior (2.7) | 4 | EOL |
thud (2.6) | 4 | EOL |
sumo (2.5) | 4 | EOL |
rocko (2.4) | 4 | EOL |
1. Support for the :
-override syntax was added to hardknott
in the 3.3.3 patch release.
2. Support for the :
-override syntax was added to gatesgarth
master only, no patch release.
3. Support for the :
-override syntax was added to dunfell
in the 3.1.11 patch release.
4. See the EOL versions appendix.
Preliminary notes
This post aims to collect best practices around setting up, architecting and maintaining a Yocto Project based build. They are by no means mandatory to follow or hard rules, but strategies that have proven successful in a number of real life projects.
Note: code/directory listings do not necessarily appear in alphabetical order or as listed by the shell, but arranged for best understanding.
Base: Work directory
Typically, a work directory for a build consists of multiple layers and at least one build directory. As a general rule, active nesting should be avoided.
A very simple example looks like that:
my-directory
./poky
./poky/meta
./poky/meta-poky
./poky/meta-yocto-bsp
./poky/…
./build
Effectively, it is the result of executing the bare minimum setup:
mkdir my-directory
cd my-directory
git clone git://git.yoctoproject.org/poky.git
source poky/oe-init-build-env
A more real life example therefore might look like this:
my-directory
./poky
./poky/meta
./poky/meta-poky
./poky/meta-yocto-bsp
./poky/…
./meta-openembedded/meta-oe
./meta-openembedded/meta-python
./meta-openembedded/…
./meta-raspberrypi
./meta-mender/meta-mender-core
./meta-mender/meta-mender-demo
./meta-mender/meta-mender-raspberrypi
./meta-mender/…
./build
Adding layers to the build should be done using the bitbake-layers
tool:
bitbake-layers add-layer ${path to layer}
In the above example, while being in the build
directory, meta-oe
would be added like this:
bitbake-layer add-layer ../meta-openembedded/meta-oe
all following code snippets will expect a similar hierarchy, and unless noted otherwise, assume that build
is the current working directory
Using bitbake-layers
for such operations is recommended for some reasons:
- the path is checked
- dependencies as defined in the
LAYERDEPENDS
variable of a layer are verified
Avoid stacking up things in local.conf
When starting a project build it is very tempting to get going quickly, and making small incremental changes through the local.conf
file.
Create a layer early (…and create a layer often)
You can create and add your myproject
layer like this:
bitbake-layers create-layer ../meta-myproject
bitbake-layers add-layer ../meta-myproject
The layer should also be put under revision control early on, preferably by using git.
Build a custom image
As tempting as it is to throw IMAGE_INSTALL
and CORE_IMAGE_EXTRA_INSTALL
operations into local.conf
, it makes revision control unnecessarily hard. Especially when trying to trim down a bloated demo image from a vendor, creating a custom image is definitely the better choice. You can start
out like this:
mkdir -p ../meta-myproject/recipes-myproject/images
cp ../poky/meta/recipes-core/images/core-image-base.bb ../meta-myproject/recipes-myproject/images/myproject-image.bb
Now you have a custom image that you can build with bitbake myproject-image
, and start adding your application and packages.
Create a custom distribution
Images are “just” recipes, which means that they have the sometimes surprising property of not being able to affect global properties. The probably
most prominent example is the init manager choice:
INIT_MANAGER += "systemd"
will have the desired effect in local.conf
, but not in myproject-image.bb
.
Remember: as it is possible to build recipes directly without targetting an image, any information that is inside an image would not be available
when building the recipe directly, resulting in different build output depending on how the recipe build was initiated. To avoid this inconsistency, recipes can never affect other recipes - their infomation is local - only configuration information is global.
The correct place to put settings that have operating system wide effects is the distro
configuration. For getting started, the easiest way is basing off poky
.
mkdir -p ../meta-myproject/conf/distro
cat << EOF >> ../meta-myproject/conf/distro/mydistro.conf
require conf/distro/poky.conf
DISTROOVERRIDES = "poky"
EOF
To enable it, you can either prefix the call to bitbake
:
DISTRO=mydistro bitbake myproject-image
or change the DISTRO
setting in your local.conf
, replacing poky
:
DISTRO ?= "mydistro"
This gives you a custom distribution that behaves just like poky. You can start adding your modifications and settings in ../meta-myproject/conf/distro/mydistro.conf
. As your project evolves, you will probably gradually change things more and more, so its a good idea to check back into the file after some time and see if the original require
is still needed. Also, if you make nontrivial changes it is advisable to change the reported DISTRO_NAME
.
Append, don’t modify
Layers that you do not own and maintain should be treated as immutable. Do not modify anything in there.
Why is that? When it comes to version control of your build (see below), you should rely on defined states of the layers upstream. Those defined states, usually in form of git hashes, enable reproducibility of your build. Any modification in an upstream layer therefore means that you either lose reproducility, or have to maintain your own fork. Neither is desirable.
The correct approach to change the behaviour of a layer outside of your control is to use an append. Those are denoted by the .bbappend
file suffix.
This mechanism is commonly used in vanilla poky
and meta-openembedded
already. To see all the .bbappend
s that are currently active in your build, use the bitbake-layers
tool:
bitbake-layers show-appends
The name of your bbappend
has to match the original recipe, including the version. If you want it to be more flexible, then you can use %
as a wildcard in the version part.
Thus you can change most parts of recipe behaviour, such as variable assignments, adding patches, or injecting additional operations adjacent to tasks, using the same syntax and mechanisms as in the recipe.