Lesson
Working with Variables
How to set, override, and manipulate variables in the Yocto Project
Variables are one of the most important parts of working with the Yocto Project. They control almost everything:
- where files are installed
- which packages are built
- how recipes behave
- how images are configured
- how machine and distro specific behaviour is selected
If you are comfortable with variables, the rest of Yocto starts to make much more sense.
Why Variables Matter
BitBake metadata is mostly about describing build behaviour through variables.
A recipe does not have to hard-code paths such as /usr/bin or /etc. Instead,
they often makes use of variables such as ${bindir} and ${sysconfdir}.
Variable types
There are two types of variables:
- Global Variables
- Defined in configuration files (
.conf) - By convention in uppercase, e.g.
MACHINE
- Defined in configuration files (
- Local Variables
- Defined in recipes
- Values are strings
INITRAMFS_IMAGE_BUNDLE ?= "1"
A distro does not usually hard-code every package list in every image either. It defines defaults through variables that can then be extended or overridden.
This makes the system flexible, but it also means you need to understand:
- how to assign a value
- when a value is expanded
- how to add to or remove from an existing value
- how overrides affect the final result
Common Assignment Operators
The most common operators are:
Setting a Value
- =
-
Set a variable absolutely. BitBake will take the value assigned at that point in time. The only way to change it would be to use another absolute assignment in a later recipe.
VAR = "value" - ?=
-
Set a value but only if the variable has not previously been set somewhere else. This is useful for default values, where the user may want to override it in their own recipe.
Use
?=when you want to supply a default only if nobody has already provided a value.VAR ?= "value" - ??=
-
Set a weak default value that may still be replaced later. This also sets a default value, but waits until the end of the processing to commit it. This means that a later recipe can also override the value.
VAR ??= "value"
Multi-line Assignments
You can assign a variable value that goes over multiple lines by escaping the ‘new-line’. This is often used to make the assignment easier to read.
VAR = "This value \
needs multiple lines \
to make it more readable \
"
Changing a Value
- :append
-
Append text to the final value of a variable.
- :prepend
-
Prepend text to the final value of a variable.
- :remove
-
Remove matching text from the final value of a variable.
Appending and Prepending
If you want to add to an existing variable, the safest modern approach is usually
to use :append or :prepend.
IMAGE_INSTALL:append = " htop strace"
You can also prepend:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
This pattern is common in .bbappend files when extending the search path for
additional files.
Removing Values
Use :remove when you need to remove something from a value that has already been
built up elsewhere.
DISTRO_FEATURES:remove = "x11"
IMAGE_INSTALL:remove = "nano"
This is much cleaner than trying to reconstruct the whole variable by hand.
Immediate Expansion with :=
Normally, many variables are expanded later when BitBake actually needs them. Sometimes you want the right-hand side to be expanded immediately.
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
This is important because THISDIR depends on the file being parsed. If you wait
until later expansion, you may no longer get the value you expected.
Overrides
Overrides let you set different values depending on context such as:
- the package
- the machine
- the distro
- the recipe task
For example:
SRC_URI:append:qemux86 = " file://qemu-extra.cfg"
IMAGE_INSTALL:append:pn-core-image-minimal = " strace"
This means the change only applies when that specific override is active.
Overrides are one of the most powerful parts of the Yocto Project, but also one of the easiest places to create confusing behaviour if you forget the context in which the variable is being evaluated.
Basic Expansion
Variables are usually referenced using ${...} syntax.
MYDIR = "/opt/demo"
MYFILE = "${MYDIR}/config.txt"
In that example, MYFILE expands to /opt/demo/config.txt.
You will see this style everywhere in Yocto metadata.
Variable Expansion in Shell Tasks
Inside shell tasks, BitBake variables are expanded before the shell runs.
do_install() {
install -d ${D}${bindir}
install -m 0755 mytool ${D}${bindir}/mytool
}
In that example:
${D}is the destination staging area${bindir}is usually/usr/bin
So the file is installed into the package staging area under /usr/bin.
Inline Python Expansion
Sometimes the value you need depends on logic rather than a fixed string.
ROOTFS_DEVICE = "${@'/dev/mmcblk0' if d.getVar('IMAGE_BASENAME') \
== 'dev-image' else '/dev/mmcblk1'}"
This makes use of inline Python:
d.getVar()reads a BitBake variable- the expression returns the string that becomes the final value
Use this carefully. It is useful, but large amounts of inline Python can make metadata hard to read.
Order of Evaluation
Common Patterns
Add a Package to an Image
IMAGE_INSTALL:append = " i2c-tools"
Add a Distro Feature
DISTRO_FEATURES:append = " systemd"
Remove a Distro Feature
DISTRO_FEATURES:remove = "x11"
Set a Package-Specific Variable
RDEPENDS:${PN} += "bash"
${PN} means “the package name for this recipe”.
Add Files to a Package
FILES:${PN} += " /usr/local/bin/mytool"
This is a common pattern when a recipe installs something outside the usual default packaging locations.
Common Mistakes
Forgetting the Leading Space
This is one of the most common mistakes:
IMAGE_INSTALL:append = "htop"
That will usually produce a broken combined value.
The correct form is:
IMAGE_INSTALL:append = " htop"
Overwriting Instead of Extending
If you write:
DISTRO_FEATURES = "systemd"
you replace the whole variable.
That may be what you want, but often what you really meant was:
DISTRO_FEATURES:append = " systemd"
Using Immediate Expansion Without Needing It
:= is useful, but do not use it everywhere. If you do not need immediate
expansion, prefer the simpler form.
How to Inspect Variable Values
One of the most useful debugging commands is:
bitbake-getvar <variable-name>
For example:
bitbake-getvar DISTRO_FEATURES
NOTE: Starting bitbake server...
#
# $DISTRO_FEATURES [6 operations]
# set? /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/project/meta-ecw/meta-ecw-core/conf/distro/microforge.conf:20
# "${DISTRO_FEATURES_DEFAULT} ${MICROFORGE_DEFAULT_DISTRO_FEATURES}"
# :remove /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/project/meta-ecw/meta-ecw-core/conf/distro/microforge.conf:21
# "x11"
# set? /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/third-party/poky/meta/conf/distro/include/default-distrovars.inc:29
# "${DISTRO_FEATURES_DEFAULT}"
# :append /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/third-party/poky/meta/conf/distro/include/init-manager-systemd.inc:2
# " systemd usrmerge"
# set /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/third-party/poky/meta/conf/documentation.conf:145
# [doc] "The features enabled for the distribution."
# set? /home/ming/wip/devheads/repos/ECW_Yocto/build/../layers/third-party/poky/meta/conf/bitbake.conf:903
# ""
# pre-expansion value:
# "${DISTRO_FEATURES_DEFAULT} ${MICROFORGE_DEFAULT_DISTRO_FEATURES} systemd usrmerge"
DISTRO_FEATURES="acl alsa bluetooth debuginfod ext2 ipv4 ipv6 pcmcia usbgadget usbhost wifi xattr nfs zeroconf pci 3g nfc vfat seccomp usrmerge systemd systemd-resolved networkd systemd usrmerge"
This will show you not only the final value of variable, but also, importantly, which file(s) set the values.
If a variable is not behaving the way you expect, bitbake-getvar is usually the best
place to start.
Summary
Variables are the language of Yocto metadata.
The main ideas from this lesson are:
- use
=for normal assignment - use
?=and??=for defaults - use
:append,:prepend, and:removeto manipulate existing values - use
:=only when immediate expansion is required - remember that overrides change values depending on context
- use
bitbake-getvarto inspect the final value when debugging
Check your understanding
Quick quiz: Yocto variables
A few short checks before you move on.