Welcome to part 9 in this series that we are doing on Yocto! In the previous parts, we started from scratch, learnt to build basic images for QEMU and Raspberry Pi machines, learnt how to created a new layer and write bitbake recipes for it. You can check out all of these posts using the links below!
In this part, talk about bring our work done in parts 5 to 8 and customise a pre-existing image by adding our recipes to the image build. There are multiple ways to do this – we shall explore the most common methods.
Strategy for a custom image
The strategy for developing a custom image is pretty simple actually. You should take something that already exists and then add your secret sauce to it. There are a number of basic image recipes already within poky, open-embedded and the meta-layers provided to you by your machine providers. Make use of them! In a nutshell, the strategy can be visualised like this.
This is much more time-saving, safe and future-proof than building an image from scratch because there are just so many things that can go wrong. For example, you may miss some essential packages that can break your build or even worse – the image builds but the system runs into a wall upon boot!
Bottomline – whenever feasible, don’t create a new image…. customise an existing one!
There are multiple methods to add your recipes to an existing image or build configuration. Let us take a look at the most common approaches starting with the easiest.
[Easiest] Method 1 – Customise the build configuration (edit
This is probably the easiest way to customise an image.
The build configuration can be edited by modifying the
local.conf located in the build directory’s
conf/ directory. But please note – this method only allows you to add packages and is not as flexible as creating your own customised image. The variable changes done in
local.conf are applied to all builds equally and hence affect all images. If this is not acceptable to you i.e. you want the additional packages to be a part of only a particular image, then you will need to explicitly specify the image into which you want to add the packages.
To add a custom package to your image using the
local.conf file, you can use the IMAGE_INSTALL variable with the
_append operator. For example, to add the recipe we created in our last post to the build, we can add the following to the
IMAGE_INSTALL_append = " hwgit"
Use of the syntax is important – specifically, the space between the quote and the package name, which is
hwgit in this example. This space is required since the
_append operator does not add the space.
Furthermore, you must use
_append instead of the
+= operator (recommended on some resources available online) if you want to avoid ordering issues. As shown in its simplest use,
IMAGE_INSTALL_append affects all images. However, it is possible to extend the syntax so that the variable applies to a specific image only. For example, if you want to add a package to only a particular image (say
core-image-minimal), the using
IMAGE_INSTALL_append as below.
IMAGE_INSTALL_append_pn-core-image-minimal = " hwgit"
The above change to
local.conf will add
hwgit to the
core-image-minimal image only. By the way, you can add packages using a similar approach through the CORE_IMAGE_EXTRA_INSTALL variable. If you use this variable, only core-image-* images are affected.
[Easier] Method 2 – Writing an image recipe based on an existing recipe
This is another very convenient and rather clean method of building a custom image.
The method is pretty simple – we create a new image recipe (.bb file), specify the image that we want to base our custom image on and then specify the new packages that we want to add to it.
Let us take our
meta-ke layer that we have used in our previous posts – here, here, here and here. We create a new folder inside
images and create a new recipe named
ke-core-image-minimal.bb that looks like this.
# We base this recipe on core-image-minimal core image require recipes-core/images/core-image-minimal.bb # Adding a description is optional but often helps the user understand the purpose of the image DESCRIPTION = "This is a customized version of the core-image-minimal image available in poky - this contains dev packages and installs the custom hello-world recipes present in meta-ke." # We specify here the additional recipes to be added to the build IMAGE_INSTALL += "hwlocal hwgit"
NOTE: We have used
IMAGE_INSTALL variable directly here as we don’t have any ordering risk here. Also, we have not provided the white-space here unlike the
IMAGE_INSTALL_append usage above as the
+= operation takes care of adding that for us.
That’s it – you can now build your custom
[Easy] Method 3 – Customising the image recipe by adding to it
There may be cases when you want to modify an existing core image but cannot create a custom recipe .bb file due to reusability or legacy reasons. In such cases, instead of creating a brand new
.bb file, you can create a
.bbappend file with the same name as the core recipe that you wish to add to or modify. Bitbake has a facility to provide bbappend files that are a good way to append metadata to an existing configuration.
Let us say, we cannot create
ke-core-image-minimal.bb as we did above in method 2. But, we still need to add
hwlocal to our
core-image-minimal builds. We will create a
core-image-minimal.bbappend in our
meta-ke/images folder that looks something like below.
IMAGE_INSTALL += "hwlocal hwgit"
NOTE: This is a very simple example – but
.bbappend files can become very complex when building complex images. The trick to keep things simple is to choose a suitable base image that is as close to your final custom image as possible.
Now, you can bake your custom image without changing the name of the base recipe but still having your custom packages inside the image.
In this post, we looked at three different ways to quickly add custom packages to your image build. There are some more approaches as well but these are pretty common, easy to implement and are in line with our core strategy to use the layered nature of Yocto to our advantage!
Which method did you like from methods 1, 2 and 3 above and why? Or do you use a different method altogether? Do let us know in the comment box!
See you in the next post!