How does Customizing Yocto Images work in Linux-Embedded Linux Training In Hyderabad

Customizing Yocto Images
Image features, custom recipes, and reproducible builds — part of EmbeddedPathashala’s free Linux device drivers course track

If you have ever hand-edited local.conf to add a package to your Yocto image, you already know the problem with that approach: nobody else on your team gets those changes, and a fresh build machine starts from scratch. This lecture, part of EmbeddedPathashala’s free linux device drivers course track, shows you the proper way to customize a Yocto image — through image features and dedicated image recipes — so your build is reproducible on every machine, every time. This is exactly the kind of practical build-system skill this free embedded systems course is built around.

Yocto image recipes
IMAGE_INSTALL
EXTRA_IMAGE_FEATURES
bitbake
free linux device drivers course
free embedded linux course

What You Will Learn

  • Adding and removing packages from an image
  • EXTRA_IMAGE_FEATURES and IMAGE_FEATURES explained
  • Writing a standalone image recipe with require
  • Building total control images from scratch
  • Common recipe mistakes and how to debug them

Prerequisites

This lecture assumes you already have a working Yocto build environment (Poky checked out, a BSP layer for your board, and at least one successful bitbake core-image-minimal build behind you). If you are new to Yocto layers and the BitBake workflow, go back to the earlier lectures in this free linux development course before continuing here.

Why local.conf Is the Wrong Place for Image Changes

local.conf lives inside your build directory, which is machine-specific and almost always excluded from version control. Any package or feature you add there disappears the moment a teammate clones your metadata layers into a fresh build/ directory. Worse, two developers editing their own local.conf files independently can end up shipping images that silently differ from each other, which is a nightmare to debug six months later when a field device behaves differently from the one on your desk.

The fix is to move anything that defines what the final image contains — packages, image features, filesystem types, root filesystem size — into a proper image recipe that lives in a layer and gets committed alongside your other metadata. That recipe becomes the single source of truth for what “your product’s Linux image” actually is.

Adding and Removing Packages Cleanly

The most direct way to change an image’s package set is the IMAGE_INSTALL variable. Using the modern BitBake override syntax (replacing the older _append/_remove suffix style you may see in older references), you append packages like this:

IMAGE_INSTALL:append = " ep-diag-tool strace"

And remove a package that a lower layer or base image already pulled in with:

IMAGE_INSTALL:remove = "some-unwanted-app"

Note the leading space before the package name in the append line — BitBake concatenates strings literally, so a missing space silently merges two package names into one and your build fails with a confusing “nothing provides” error.

EXTRA_IMAGE_FEATURES: Sweeping Image-Wide Changes

Sometimes you want more than “add this package.” EXTRA_IMAGE_FEATURES (set in local.conf for local experimentation, or IMAGE_FEATURES inside a recipe for something permanent) toggles entire behavior sets defined by core-image.bbclass. The table below covers the ones you will reach for most often:

Feature Effect
dbg-pkgs Installs the debug-symbol package for every package in the image
debug-tweaks Allows passwordless root login and other developer conveniences — never ship this to production
package-management Keeps the on-target package manager and its database, so packages can be updated post-deployment
read-only-rootfs Mounts the root filesystem read-only, a common requirement for field-deployed embedded devices
x11-base Installs a minimal X server environment
Where Each Customization Layer Lives
local.conf (machine-local, throwaway)
-> EXTRA_IMAGE_FEATURES, quick IMAGE_INSTALL:append for testing
your-image.bb (in a layer, version-controlled)
-> IMAGE_INSTALL, IMAGE_FEATURES, LICENSE, IMAGE_ROOTFS_SIZE
-> this is what actually ships

Writing Your First Custom Image Recipe

The simplest permanent recipe just extends an existing one using require. Suppose you want core-image-minimal plus your own diagnostics tool and strace. Create ep-diag-image.bb inside meta-yourlayer/recipes-local/images/:

DESCRIPTION = "core-image-minimal plus EP diagnostic tooling"
require recipes-core/images/core-image-minimal.bb

IMAGE_INSTALL:append = " ep-diag-tool strace"

Build it exactly like any other image target:

$ bitbake ep-diag-image

Expected tail of a successful build:

NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 3142 tasks of which 2891 didn't need to be rerun and all succeeded.

Summary: There were 0 WARNING messages shown.

Total Control: Building an Image From Scratch

For a product image, you often don’t want to inherit anything you didn’t explicitly ask for. Start from an empty IMAGE_INSTALL and build up:

SUMMARY = "Minimal EP product image with diagnostics"
IMAGE_INSTALL = "packagegroup-core-boot ep-diag-tool strace"
IMAGE_LINGUAS = " "
LICENSE = "MIT"
IMAGE_ROOTFS_SIZE ?= "8192"

inherit core-image

A quick field guide to the four variables that trip people up most:

Variable Purpose
IMAGE_LINGUAS Which glibc locales to install; leave empty if you don’t need locale-aware library functions, saving real rootfs space
LICENSE The license of the image recipe itself (not the packages inside it — see the license-audit lecture in this series)
IMAGE_ROOTFS_SIZE Target disk image size in KiB — use ?= so a machine config can still override it
inherit core-image Pulls in the actual image-building logic; almost everything above is just configuration for this class

Real-World Use Case

A typical pattern in a production embedded Linux project: a shared company-base-image.bb holds packages and features common to every product line, and each board-specific team layer adds a thin recipe that does require company-base-image.bb plus two or three board-specific packages. This keeps the “what’s actually on the device” question answerable by reading one small file instead of grepping through a shared local.conf nobody remembers editing.

Common Mistakes and Troubleshooting

  • Missing leading space in append lines — always write IMAGE_INSTALL:append = " pkg", never "pkg".
  • Shipping debug-tweaks to production — this feature exists for development images only; a production image with passwordless root is a serious security hole.
  • Forgetting inherit core-image in a from-scratch recipe — without it, none of the image-generation tasks exist and BitBake will complain the target has no do_image task.
  • Confusing recipe LICENSE with package licensing — the recipe’s LICENSE variable only describes the recipe file itself.

Best Practices

  • Keep experimentation in local.conf, but promote anything permanent into a versioned image recipe before it reaches a shared branch.
  • Prefer require over duplicating an existing base image recipe — you inherit upstream fixes automatically.
  • Set IMAGE_ROOTFS_SIZE with ?= so machine-specific configs can still adjust it for boards with tighter storage.

Summary and Key Takeaways

Image features give you sweeping, class-level control over what an image contains; IMAGE_INSTALL gives you fine-grained package control; and a dedicated, version-controlled image recipe is what turns both into something reproducible across your whole team. Master these three levers and you have full command over what actually ships on your device.

Conclusion

Custom image recipes are the backbone of any serious Yocto-based product, and they are a core skill in this free linux device drivers course. Once you’re comfortable writing them, the next natural step is building a standalone SDK so other developers on your team don’t need a full Yocto build environment just to compile against your image — covered in the next lecture of this free linux kernel development course series.

FAQ

What’s the difference between IMAGE_FEATURES and EXTRA_IMAGE_FEATURES?

IMAGE_FEATURES is set inside an image recipe and is permanent; EXTRA_IMAGE_FEATURES is meant for local.conf and is meant to be temporary, machine-local experimentation.

Can I use both IMAGE_INSTALL and IMAGE_INSTALL:append in the same recipe?

Yes, but be deliberate: setting IMAGE_INSTALL directly replaces the whole variable, while :append adds to whatever value it already has (typically inherited from a base recipe).

Does read-only-rootfs work with every image type?

It works with most, but any package that expects to write to the rootfs at runtime (like a database that writes to /var) needs to be reconfigured to write to a writable overlay or tmpfs instead.

Why did my IMAGE_INSTALL:append do nothing?

Almost always a missing leading space, or the append line being parsed before the base recipe assigns the variable — check that your recipe file processes after the one setting the base value.

Is packagegroup-core-boot required for a from-scratch image?

No, but it saves you from manually listing every package a bootable Linux system needs (init system, base utilities, kernel modules handling). Most from-scratch recipes still start from it.

Keep Learning Yocto and Embedded Linux — Free

More build-system lectures like this one are part of EmbeddedPathashala’s free linux device drivers course and free embedded linux course.



2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *