Yocto is a very popular tool for developing custom embedded distributions, primarily used by corporations and favored by managers. The tools themselves are inherently complex. Additionally, it is made more complex by the fact that development is not centralized. The way Yocto is designed encourages vendors with little or limited experience to develop their own custom solutions independently of the community. This often means basic functionality is duplicated and hardware vendors dictate the full software stack including userspace. In practice this creates a rat’s nest or spaghetti implementation that can be incredibly hard to understand and debug.

Yocto is a build system tool for people who love complex build systems, rather than engineers who want to implement firmware, operating systems or applications. Without a wealth of knowledge and experience it will dramatically slow down development.

Additionally, OpenEmbedded either doesn’t support basic functionality or it isn’t clear to users or vendors, which end up creating their open implementations. For example, repo and kas wrap Yocto since it doesn’t support setting up the build environment. Mender configures the system partitions with variables rather than WKS.

Yocto is also less isolated than other tools like Buildroot, which causes a stricter dependency on particular versions of particular distributions. This has improved greatly with newer releaes.

Yocto will ignore anything it doesn’t understand so small typos or empty variables can be especially nefarious. To check that everything is run as expected you can pass -e to bitbake to print a fully expanded output.

Yocto includes it’s own build scripting language, bitbake, which can also include shell and Python. And within bitbake there are different file types (e.g. .bb, .bbappend, .inc, .cfg) that can have subtle differences, especially in .inc. For example, Python can’t be in a .inc file. This can make simple tasks like adding a debug print statement much more challenging than with other tools or languages.

It is easy to get into a development loop with relatively long iterations. Whether that is rebuild, updating the target or searching for files/strings in the build directory.

Builds, particularly from hardware vendors can easily be hundreds of gigabytes.

In Yocto you don’t use releases of your dependencies, but effectively take latest on a release branch that tracks the version of the Yocto project itself. So a layer from a third-party might have a branch named “kirkstone”, which refers to a particular Yocto release. This of course doesn’t follow standard development practices for versioning software (e.g. semantic versioning) and testing releases. I do not believe any other software project follows this scheme.

Resources

Building everything from source, particularly for these large demo distributions from hardware vendors requires high performance hardware and even with that hardware it still requires a significant amount of time. This generally means that people need to have high performance workstations or access to remote compute that can be expensive and more difficult to operate than a local machine.

bbappend

Source code can be manipulated by adding changes in completely different repositories. This requires tools to print the aggregated code (i.e. bitbake -e), which are much more cumbersome than the normal way of storing source code as flat files in directories.

The do_ prefix

Functions prefixed with do_* are sometimes referenced with the prefix and sometimes without. For example, bitbake -c does not include the prefix. Or as follows:

do_deploy() {
  ...
}
addtask deploy after do_install

Tips

Note that commands like do_clean are passed without the do_ prefix to -c.

tmp/deploy/images/
tmp/work/
bitbake -c cleanall -c cleansstate core-image-minimal
bitbake -e core-image-minimal | less
bitbake -c rootfs core-image-minimal -D | less
bitbake -D core-image-minimal | less
# Sometimes Yocto does not believe something changed so you need to force it,
# but this will "taint" the command
bitbake -c deploy -f foobar

Whether on a shared build machine or personal machine consider limiting the number of cores available to the build. Note that I never found that this actually worked.

BB_NUMBER_THREADS = "4"
PARALLEL_MAKE = "4"
PARALLEL_MAKE = "-j 4"

inherit vs. require

INHERIT += adds one or more classes (i.e. *.bbclass) to be inherited globally. If it is added to a recipe it will be silently ignored.

See https://docs.yoctoproject.org/ref-manual/variables.html#term-INHERIT

systemctl

Poky includes a script named systemctl that is a Python script for modifying systemd service files. Besides the confusing name it also implements custom logic that does not necessarilly adhere to the systemd implementation. For example, it does not support parsing Environment="ONE=one" 'TWO=two two', wich is an example fromman systemd.service`.

Patches

Normally patches are applied in order of the prefix in the filename (e.g. 0001-). However in Bitbake patches are added to the SRC_URI variable along with other source files. The prefix, although kept and completely abritrary, is not used. Instead the order is dependent on the order that the patches are added to SRC_URI and then the complex precedence/priority of layers.

Linux

It is not possible to modify the kernel source normally. Even generating a directory containing the kernel source with Yocto patches applied is painful. I found the easiest was to run the following:

bitbake -f -c patch linux

The recommended tool, devtool, has a modify sub-command to setup an environment to modify the kernel, but cleaning it up requires manually modifying config files and deleting directories.