Introduction to the Yocto Project
In the previous section, the benefits of having an open source environment were presented. Taking a look at how embedded development was done before the advent of the Yocto Project offers a complete picture of the benefits of this project. It also gives an answer as to why it was adopted so quickly and in such huge numbers.
Using the Yocto Project, the whole process gets a bit more automatic, mostly because the workflow permitted this. Doing things manually requires a number of steps to be taken by developers:
- Select and download the necessary packages and components.
- Configure the downloaded packages.
- Compile the configured packages.
- Install the generated binary, libraries, and so on, on
rootfs
available on development machine. - Generate the final deployable format.
All these steps tend to become more complex with the increase in the number of software packages that need to be introduced in the final deployable state. Taking this into consideration, it can clearly be stated that manual work is suitable only for a small number of components; automation tools are usually preferred for large and complex systems.
In the last ten years, a number of automation tools could be used to generate an embedded Linux distribution. All of them were based on the same strategy as the one described previously, but they also needed some extra information to solve dependency related problems. These tools are all built around an engine for the execution of tasks and contain metadata that describes actions, dependencies, exceptions, and rules.
The most notable solutions are Buildroot, Linux Target Image Builder (LTIB), Scratchbox, OpenEmbedded, Yocto, and Angstrom. However, Scratchbox doesn't seem to be active anymore, with the last commit being done in April 2012. LTIB was the preferred build tool for Freescale and it has lately moved more toward Yocto; in a short span of time, LTIB may become deprecated also.
Buildroot
Buildroot as a tool tries to simplify the ways in which a Linux system is generated using a cross-compiler. Buildroot is able to generate a bootloader, kernel image, root filesystem, and even a cross-compiler. It can generate each one of these components, although in an independent way, and because of this, its main usage has been restricted to a cross-compiled toolchain that generates a corresponding and custom root filesystem. It is mainly used in embedded devices and very rarely for x86 architectures; its main focus being architectures, such as ARM, PowerPC, or MIPS. As with every tool presented in this book, it is designed to run on Linux, and certain packages are expected to be present on the host system for their proper usage. There are a couple of mandatory packages and some optional ones as well.
There is a list of mandatory packages that contain the certain packages, and are described inside the Buildroot manual available at http://buildroot.org/downloads/manual/manual.html. These packages are as follows:
which
sed
make
(version 3.81 or any later ones)binutils
build-essential
(required for Debian-based systems only)gcc
(version 2.95 or any later ones)g++
(version 2.95 or any later ones)bash
patch
gzip
bzip2
perl
(version 5.8.7 or any later ones)tar
cpio
python
(version 2.6 or 2.7 ones)unzip
rsync
wget
Beside these mandatory packages, there are also a number of optional packages. They are very useful for the following:
- Source fetching tools: In an official tree, most of the package retrieval is done using
wget
fromhttp
,https
, or evenftp
links, but there are also a couple of links that need a version control system or another type of tool. To make sure that the user does not have a limitation to fetch a package, these tools can be used:bazaar
cvs
git
mercurial
rsync
scp
subversion
- Interface configuration dependencies: They are represented by the packages that are needed to ensure that the tasks, such as kernel, BusyBox, and U-Boot configuration, are executed without problems:
ncurses5
is used for the menuconfig interfaceqt4
is used for thexconfig
interfaceglib2
,gtk2
, andglade2
are used for thegconfig
interface
- Java related package interaction: This is used to make sure that when a user wants to interact with the Java Classpath component, that it will be done without any hiccups:
javac
: this refers to the Java compilerjar
: This refers to the Java archive tool
- Graph generation tools: The following are the graph generation tools:
graphviz
to usegraph-depends
and<pkg>-graph-depends
python-matplotlib
to usegraph-build
- Documentation generation tools: The following are the tools necessary for the documentation generation process:
asciidoc
, version 8.6.3 or higherw3m
python
with theargparse
module (which is automatically available in 2.7+ and 3.2+ versions)dblatex
(necessary for pdf manual generation only)
Buildroot releases are made available to the open source community at http://buildroot.org/downloads/ every three months, specifically in February, May, August, and November, and the release name has the buildroot-yyyy-mm
format. For people interested in giving Buildroot a try, the manual described in the previous section should be the starting point for installing and configuration. Developers interested in taking a look at the Buildroot source code can refer to http://git.buildroot.net/buildroot/.
Note
Before cloning the Buildroot source code, I suggest taking a quick look at http://buildroot.org/download. It could help out anyone who works with a proxy server.
Next, there will be presented a new set of tools that brought their contribution to this field and place on a lower support level the Buildroot project. I believe that a quick review of the strengths and weaknesses of these tools would be required. We will start with Scratchbox and, taking into consideration that it is already deprecated, there is not much to say about it; it's being mentioned purely for historical reasons. Next on the line is LTIB, which constituted the standard for Freescale hardware until the adoption of Yocto. It is well supported by Freescale in terms of Board Support Packages (BSPs) and contains a large database of components. On the other hand, it is quite old and it was switched with Yocto. It does not contain the support of new distributions, it is not used by many hardware providers, and, in a short period of time, it could very well become as deprecated as Scratchbox. Buildroot is the last of them and is easy to use, having a Makefile
base format and an active community behind it. However, it is limited to smaller and simpler images or devices, and it is not aware of partial builds or packages.
OpenEmbedded
The next tools to be introduced are very closely related and, in fact, have the same inspiration and common ancestor, the OpenEmbedded project. All three projects are linked by the common engine called Bitbake and are inspired by the Gentoo Portage build tool. OpenEmbedded was first developed in 2001 when the Sharp Corporation launched the ARM-based PDA, and SL-5000 Zaurus, which run Lineo, an embedded Linux distribution. After the introduction of Sharp Zaurus, it did not take long for Chris Larson to initiate the OpenZaurus Project, which was meant to be a replacement for SharpROM, based on Buildroot. After this, people started to contribute many more software packages, and even the support of new devices, and, eventually, the system started to show its limitations. In 2003, discussions were initiated around a new build system that could offer a generic build environment and incorporate the usage models requested by the open source community; this was the system to be used for embedded Linux distributions. These discussions started showing results in 2003, and what has emerged today is the Openembedded project. It had packages ported from OpenZaurus by people, such as Chris Larson, Michael Lauer, and Holger Schurig, according to the capabilities of the new build system.
The Yocto Project is the next evolutionary stage of the same project and has the Poky build system as its core piece, which was created by Richard Purdie. The project started as a stabilized branch of the OpenEmbedded project and only included a subset of the numerous recipes available on OpenEmbedded; it also had a limited set of devices and support of architectures. Over time, it became much more than this: it changed into a software development platform that incorporated a fakeroot replacement, an Eclipse plug-in, and QEMU-based images. Both the Yocto Project and OpenEmbedded now coordinate around a core set of metadata called OpenEmbedded-Core (OE-Core).
The Yocto Project is sponsored by the Linux Foundation, and offers a starting point for developers of Linux embedded systems who are interested in developing a customized distribution for embedded products in a hardware-agnostic environment. The Poky build system represents one of its core components and is also quite complex. At the center of all this lies Bitbake, the engine that powers everything, the tool that processes metadata, downloads corresponding source codes, resolves dependencies, and stores all the necessary libraries and executables inside the build directory accordingly. Poky combines the best from OpenEmbedded with the idea of layering additional software components that could be added or removed from a build environment configuration, depending on the needs of the developer.
Poky is build system that is developed with the idea of keeping simplicity in mind. By default, the configuration for a test build requires very little interaction from the user. Based on the clone made in one of the previous exercises, we can do a new exercise to emphasize this idea:
cd poky source oe-init-build-env ../build-test bitbake core-image-minimal
As shown in this example, it is easy to obtain a Linux image that can be later used for testing inside a QEMU environment. There are a number of images footprints available that will vary from a shell-accessible minimal image to an LSB compliant image with GNOME Mobile user interface support. Of course, that these base images can be imported in new ones for added functionalities. The layered structure that Poky has is a great advantage because it adds the possibility to extend functionalities and to contain the impact of errors. Layers could be used for all sort of functionalities, from adding support for a new hardware platform to extending the support for tools, and from a new software stack to extended image features. The sky is the limit here because almost any recipe can be combined with another.
All this is possible because of the Bitbake engine, which, after the environment setup and the tests for minimal systems requirements are met, based on the configuration files and input received, identifies the interdependencies between tasks, the execution order of tasks, generates a fully functional cross-compilation environment, and starts building the necessary native and target-specific packages tasks exactly as they were defined by the developer. Here is an example with a list of the available tasks for a package:
Note
More information about Bitbake and its baking process can be found in Embedded Linux Development with Yocto Project, by Otavio Salvador and Daiane Angolini.
The metadata modularization is based on two ideas—the first one refers to the possibility of prioritizing the structure of layers, and the second refers to the possibility of not having the need for duplicate work when a recipe needs changes. The layers are overlapping. The most general layer is meta, and all the other layers are usually stacked over it, such as meta-yocto
with Yocto-specific recipes, machine specific board support packages, and other optional layers, depending on the requirements and needs of developers. The customization of recipes should be done using bbappend
situated in an upper layer. This method is preferred to ensure that the duplication of recipes does not happen, and it also helps to support newer and older versions of them.
An example of the organization of layers is found in the previous example that specified the list of the available tasks for a package. If a user is interested in identifying the layers used by the test
build setup in the previous exercise that specified the list of the available tasks for a package, the bblayers.conf
file is a good source of inspiration. If cat
is done on this file, the following output will be visible:
# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf # changes incompatibly LCONF_VERSION = "6" BBPATH = "${TOPDIR}" BBFILES ?= "" BBLAYERS ?= " \ /home/alex/workspace/book/poky/meta \ /home/alex/workspace/book/poky/meta-yocto \ /home/alex/workspace/book/poky/meta-yocto-bsp \ " BBLAYERS_NON_REMOVABLE ?= " \ /home/alex/workspace/book/poky/meta \ /home/alex/workspace/book/poky/meta-yocto \ "
The complete command for doing this is:
cat build-test/conf/bblayers.conf
Here is a visual mode for the layered structure of a more generic build directory:
Yocto as a project offers another important feature: the possibility of having an image regenerated in the same way, no matter what factors change on your host machine. This is a very important feature, taking into consideration not only that, in the development process, changes to a number of tools, such as autotools
, cross-compiler
, Makefile
, perl
, bison
, pkgconfig
, and so on, could occur, but also the fact that parameters could change in the interaction process with regards to a repository. Simply cloning one of the repository branches and applying corresponding patches may not solve all the problems. The solution that the Yocto Project has to these problems is quite simple. By defining parameters prior to any of the steps of the installation as variables and configuration parameters inside recipes, and by making sure that the configuration process is also automated, will minimize the risks of manual interaction are minimized. This process makes sure that image generation is always done as it was the first time.
Since the development tools on the host machine are prone to change, Yocto usually compiles the necessary tools for the development process of packages and images, and only after their build process is finished, the Bitbake build engine starts building the requested packages. This isolation from the developer's machine helps the development process by guaranteeing the fact that updates from the host machine do not influence or affect the processes of generating the embedded Linux distribution.
Another critical point that was elegantly solved by the Yocto Project is represented by the way that the toolchain handles the inclusion of headers and libraries; because this could bring later on not only compilation but also execution errors that are very hard to predict. Yocto resolves these problems by moving all the headers and libraries inside the corresponding sysroots
directory, and by using the sysroot
option, the build process makes sure that no contamination is done with the native components. An example will emphasize this information better:
ls -l build-test/tmp/sysroots/ total 12K drwxr-xr-x 8 alex alex 4,0K sep 28 04:17 qemux86/ drwxr-xr-x 5 alex alex 4,0K sep 28 00:48 qemux86-tcbootstrap/ drwxr-xr-x 9 alex alex 4,0K sep 28 04:21 x86_64-linux/ ls -l build-test/tmp/sysroots/qemux86/ total 24K drwxr-xr-x 2 alex alex 4,0K sep 28 01:52 etc/ drwxr-xr-x 5 alex alex 4,0K sep 28 04:15 lib/ drwxr-xr-x 6 alex alex 4,0K sep 28 03:51 pkgdata/ drwxr-xr-x 2 alex alex 4,0K sep 28 04:17 sysroot-providers/ drwxr-xr-x 7 alex alex 4,0K sep 28 04:16 usr/ drwxr-xr-x 3 alex alex 4,0K sep 28 01:52 var/
The Yocto project contributes to making reliable embedded Linux development and because of its dimensions, it is used for lots of things, ranging from board support packages by hardware companies to new software solutions by software development companies. Yocto is not a perfect tool and it has certain drawbacks:
- Requirements for disk space and machine usage are quite high
- Documentation for advanced usage is lacking
- Tools, such as Autobuilder and Eclipse plug-ins, now have functionality problems
There are also other things that bother developers, such as ptest
integration and SDK sysroot's lack of extensibility, but a part of them are solved by the big community behind the project, and until the project shows its limitations, a new one will still need to wait to take its place. Until this happens, Yocto is the framework to use to develop custom embedded Linux distribution or products based in Linux.