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.
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.
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.
do_
prefixFunctions 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
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
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 from
man
systemd.service`.
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.
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.