How to use bbappend files in a Yocto Project

One of the key things I often stress when working with the Yocto Project is:

Never edit the recipe files of a layer you have downloaded from the Internet

(unless you are planning on pushing those changes back upstream)

If you need to add, modify or override the behaviour of a recipe you should be doing it with a .bbappend file within a layer that you maintain.

Naming Convention

The whole point of a bbappend file is to change an existing recipe – so the name of your append file must match the name of the recipe you are changing.

Recipe Names

The name of a recipe file (file ending in .bb) is:

<PACKAGE-NAME>_<PACKAGE-VERSION>.bb

PACKAGE-NAME

This is the name of the package. This can be anything, with words separated by a dash ( - ). Do not use an underscore ( _ ) as that is the separator between the Name and Version.

Within the recipe, this can be referenced by the variable PN.

PACKAGE-VERSION (Optional).

This is whatever is after the underscore and is the version of the package. This means that it is possible to have multiple versions of a package in your layer. Unless you explicitly specify a version, BitBake will use the highest version number.

Append File Naming

The convention for naming your bbappend file is

<Recipe-to-be-changed>.bbappend

So, if you had a recipe linux-yocto_6.6.bb that you wanted to modify, you would need an append file named linux-yocto_6.6.bbappend.

Wildcards

BitBake recognises the character % in the filename as a wildcard and will match anything.

For example, if we had multiple recipes for a package, such as:

linux-yocto_5.4.bb
linux-yocto_6.1.bb
linux-yocto_6.6.bb

Depending on what we wanted to modify, we would have options:

  • linux-yocto_6.6.bbappend would be applied after BitBake had parsed linux-yocto_6.6.bb and only that recipe.
  • linux-yocto_6.%.bbappend would match both linux-yocto_6.6.bb and linux-yocto_6.1.bb.
  • linux-yocto_%.bbappend would match all versions of linux-yocto

Multiple Append Files With The Same Name

If for some reason you have multiple append files with the same name (bizarre, but it is not unheard of), then you need to be aware of the layer priorities. The build system works from the top-down through the layers listed in BBLAYERS (namely defined in your conf/bblayers.conf file.

To see what layers you have defined and their priority, use the command bitbake-layers show-layers

bitbake-layers show-layers
NOTE: Starting bitbake server...
layer              path                                               priority
==============================================================================
core               /work/build/../layers/third-party/poky/meta              5
yocto              /work/build/../layers/third-party/poky/meta-poky         5
yoctobsp           /work/build/../layers/third-party/poky/meta-yocto-bsp    5
meta-my_bsp        /work/build/../layers/project/meta-my_bsp                20
meta-my_distro     /work/build/../layers/project/meta-my_distro             20

If you want to see all the append files in your project, use the command bitbake-layers show-appends

The Contents of a bbappend File

Now that you have an append file to change a recipe, the main things you can do are add, remove or override.

Overriding

To override a variable (as in completely change its value), just redefine it.

Say, the base recipe defines a variable FOO

FOO = "Value1"

If you wanted to change that to be My-Value

FOO = "My-Value"

The value of FOO is now "My-Value"

Adding Values

There are two ways to add to a recipe. The first and simplest is if the thing you are adding does not already exist in the base recipe. In which case, just add it to the append file. This would typically be if you wanted to add your own tasks to a recipe – which is outside the scope of this article.

Typically however, you want to add to something that has already been defined. This could be adding a value to a variable or adding/overwriting a file (see How to Override Standard Files in a Yocto Project).

There are two options to add something to a variable in an append file.

Add to the Start

If you want your new value to appear before the existing value, use the modifier :prepend

Say, the base recipe defines a variable FOO

FOO = "Value1 Value2"

If you wanted to add a Value0 to the start of the list

FOO:prepend = "Value0"

The value of FOO is now "Value0 Value1 Value2"

One of the most common use of this is to add a directory to BitBake’s search path

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

This will now look for files in the SRC_URI in the local ./files directory before anywhere else (which is how you can override files in your project – just make sure the filename exists in the files directory and it will get picked up and used before the original file of that name).

Add to the End

If you want your new value to appear after the existing value, use the modifier :append

Say, the base recipe defines a variable FOO

FOO = "Value1 Value2"

If you wanted to add a Value3 to the end of the list

FOO:apppend = "Value3"

The value of FOO is now "Value1 Value2 Value3"

NOTE: The :append and :prepend can also be applied to tasks as well as variables.

For example, if you wanted to add some commands to you install task you could use

do_install:append() {
  # Shell commands to run here
}

A typical example of this is if you wanted to add a file to your image as part of an existing recipe

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI:append= "file://new-file"

do_install:append() {
  install -d /usr/share
  install -m 0755 ${WORKDIR}/new-file ${D}/usr/share/new-file
}

FILES:${PN} += "\
  /usr/share/new-file \
"

Removing Values

To remove a value from a variable, use the modifier :remove

Say, the base recipe defines a variable FOO

FOO = "Value1 Value2 Value3"

If you wanted to remove Value2 from the list

FOO:remove = "Value2"

The value of FOO is now "Value1 Value3"

An example of this is where I have a production image with a Read-Only root filesystem and I want a development version that is Read-Write

IMAGE_FEATURES:remove = "read-only-rootfs"