Lesson
Images and Packages
How Yocto images are built from packages and how to control what goes into them
One of the most important things to understand in the Yocto Project is the relationship between images and packages.
People often start by thinking of an image as a single build target, but in Yocto an image is really the result of selecting:
- a set of packages
- a package manager or package format
- image features
- output formats such as
wic,ext4, ortar.gz
Once you understand that relationship, it becomes much easier to build clean, maintainable system images.
The Basic Idea
At a high level:
That means your image usually should not contain lots of custom logic itself. Instead, the image should select the packages that make up the system.
Recipes, Packages, and Images
It helps to separate these terms clearly.
- Recipe
-
Metadata that tells BitBake how to fetch, configure, compile, install, and package some software.
- Package
-
An installable output produced from a recipe.
- Image
-
A root filesystem and related output files built by installing selected packages into a final system image.
For example, a recipe called myapp.bb might produce a debug build and documentation:
myappmyapp-dbgmyapp-doc
An image installs the package myapp or myapp-dbg, not the recipe name as an
abstract concept. Normally, the binary package will be the same as the recipe name.
What an Image Recipe Looks Like
A simple image recipe might look like this:
SUMMARY = "My example image"
LICENSE = "MIT"
inherit core-image
IMAGE_INSTALL:append = " myapp i2c-tools"
This inherits the standard core-image behaviour, which defines it as an image recipe
and then adds packages to the image.
IMAGE_INSTALL
The most common way to define the image contents is with IMAGE_INSTALL in an image recipe.
This is a list (space separated) of packages that will be installed in the final image.
IMAGE_INSTALL:append = " htop strace"
This adds htop and strace packages to the image.
You can also use EXTRA_IMAGE_INSTALL outside an image recipe, for example to quickly test
add a package in your local.conf.
Finding packages to install
There are many, many packages that are provided by the community. Before writing your own recipe, it is sensible to check if one already exists.
- Go to https://layers.openembedded.org/layerindex/branch/master/recipes/
- Select your Yocto Project release branch
- Search for your your package
You will get a list of matching recipes and the layer that defines them - you will need to add that layer to your project if you have not already done so.
Find the Layer
Click on the link of the layer name
This takes you to a page about the layer and most importantly, the location of the repository so that you can clone it.
Clone the layer.
git clone -b <branch> <repo> layers/third-party/<layer name>
Add the layer to your project
bitbake-layers add-layer layers/third-party/<layer name>
Add the package to your image
Now you can add the package to your IMAGE_INSTALL variable.
Core Image Features
You can also influence image contents through IMAGE_FEATURES (if set in an image recipe) or
EXTRA_IMAGE_FEATURES (if set outside an image recipe, such as in local.conf).
For example:
IMAGE_FEATURES += " ssh-server-openssh"
EXTRA_IMAGE_FEATURES += " debug-tweaks"
These are not arbitrary package names. They are feature flags that expand to specific behaviour or package selections. They may pull in specific packages but also can trigger flags within some recipes.
Some common examples are:
debug-tweakspackage-managementread-only-rootfsssh-server-dropbearssh-server-openssh
See https://docs.yoctoproject.org/current/ref-manual/features.html#image-features for more details.
The Difference Between IMAGE_FEATURES and IMAGE_INSTALL
Use IMAGE_FEATURES when you want to enable a supported image-level behaviour.
Use IMAGE_INSTALL when you want to install specific packages.
For example:
- use
IMAGE_FEATURES += "ssh-server-openssh"to request SSH support as an image feature - use
IMAGE_INSTALL:append = " openssh-sftp-server"if you specifically need one package
Base Images
You do not have to start every image from scratch.
Yocto already provides some base images, such as:
core-image-basecore-image-minimal
You can either build those directly or create your own image recipe that inherits
from core-image.
Example: A Development Image and a Production Image
It is common to maintain more than one image for a product.
For example:
Production image
SUMMARY = "Production image"
LICENSE = "MIT"
inherit core-image
IMAGE_INSTALL:append = " myapp"
IMAGE_FEATURES += " read-only-rootfs"
Development image
SUMMARY = "Development image"
LICENSE = "MIT"
inherit core-image
IMAGE_INSTALL:append = " myapp gdbserver strace"
IMAGE_FEATURES += " ssh-server-openssh"
EXTRA_IMAGE_FEATURES += " debug-tweaks"
This is a good pattern because:
- the production image stays small and focused
- the development image carries the debugging tools
- each image clearly expresses its purpose
Package Formats
Images can also be tied to a package format depending on how your system is meant to be updated or managed.
Common formats include:
- package_rpm
-
RedHat Packages - defined by RedHat, Fedora, CentOS, etc
- package_deb
-
Debian Packages - defined by Debian, Ubuntu, etc
- package_ipk
-
Opkg Packages - A light-weight package manager, optimised for embedded systems
These are selected through:
PACKAGE_CLASSES ?= "package_ipk"
This affects how packages are emitted during the build and whether package management can be used on the target.
Enable Package Management on the Target
If you want to install or update packages on the running target, you will need to enable package management support in the image.
IMAGE_FEATURES += " package-management"
Without that, packages may still be built during the Yocto build, but the target image may not include the tooling or metadata needed to manage them at runtime.
Image Output Formats
The image is not just a root filesystem directory. Yocto can create several final artifacts depending on what you need.
For example:
IMAGE_FSTYPES += " wic.gz ext4"
would produce a full disk image (the ‘wic’ image), which contains the partitions, bootloader, etc and would also create an ext4 formatted image of the root filesystem.
Common output formats include:
tar.gzext4wiccpio.gz
The right choice depends on how the image will be deployed:
- SD card image
- eMMC image
- initramfs
- update bundle
Where the Files Go
After the build, the image artifacts are typically written under:
tmp/deploy/images/<machine>/
You will usually find:
- kernel images
- device trees
- bootloader artifacts
- root filesystem images
- package feed artifacts
Common Mistakes
Installing Too Much in the Image Recipe
If your image recipe contains a huge list of packages, it becomes hard to maintain.
That is often a sign that you should:
- split development and production images
- move reusable policy into the distro layer
We will look at creating package groups later.
Confusing Recipes with Packages
Do not forget that recipes may generate several packages.
If something does not appear in the image as expected, check what packages the recipe actually produced.
Using local.conf for Long-Term Image Design
It is fine to experiment in local.conf, for example:
IMAGE_INSTALL:append = " vim"
But long-term project image definitions should live in your own image recipes or project metadata, not only in local developer configuration.
Useful Debugging Commands
To list the packages built by a recipe:
bitbake -e myapp | less
bitbake -e shows all of the variables used by a build.
Look for variables such as:
PACKAGESFILES:${PN}RDEPENDS:${PN}
To inspect the final image contents after a build, you can also look under the
root filesystem area in tmp/work/... or inspect the built image directly.
A Maintainable Pattern
A good general structure is:
- recipes describe how to build software
- package groups define reusable software sets
- distro configuration defines platform-wide policy
- image recipes describe the final system role
That separation makes it easier to understand why a package is present and where a change should really be made.
Summary
Images are built by installing packages into a final root filesystem.
The main ideas from this lesson are:
- recipes produce packages, and images install packages
- use
IMAGE_INSTALLto add specific packages - use
IMAGE_FEATURESfor supported image-level behaviour - use package groups to keep image recipes manageable
- keep development and production image roles separate where possible
- use
PACKAGE_CLASSESandIMAGE_FSTYPESto control output behaviour
Check your understanding
Quick quiz: images and packages
A quick review of how image composition works in Yocto.