This is the lecture where everything in this free linux device drivers course and
build-system track finally clicks: you take a program you wrote yourself, wrap it in a BitBake recipe,
build it, and watch it land inside a bootable image. We’ll build a tiny original utility —
ep-greet — inside the meta-ep-board layer from the earlier lecture, cover
licensing correctly, and finish by adding the package to an image without rebuilding from scratch.
SRC_URI
do_compile do_install
LIC_FILES_CHKSUM
IMAGE_INSTALL_append
free linux device drivers course
What You Will Learn
- Recipe naming convention and where local source lives
- The metadata every recipe needs: DESCRIPTION, LICENSE, LIC_FILES_CHKSUM
- Writing minimal do_compile and do_install tasks
- Building a single recipe and finding its output package
- Adding your new package to a target image with IMAGE_INSTALL:append
- Handling non-open-source licenses safely
Prerequisites
You’ll need the meta-ep-board layer registered and verified (previous lecture) and a
basic grasp of BitBake’s metadata types and task model (the lecture before that). A little C is
helpful but not required — the example program is five lines.
Step 1 — Lay Out the Recipe Directory
Recipe files follow the convention <package-name>_<version>.bb. Local
source that isn’t fetched from a git remote or tarball lives in a files subdirectory next
to the recipe, and BitBake finds it automatically through its default search path:
└── recipes-ep/
└── ep-greet/
├── files/
│ └── ep-greet.c
└── ep-greet_1.0.bb
Our example program is deliberately trivial — the point of this lecture is the recipe, not the C:
/* files/ep-greet.c */
#include <stdio.h>
int main(void)
{
printf("ep-greet: hello from a custom BitBake recipen");
return 0;
}
Step 2 — Write the Recipe Metadata
Every recipe needs a description, a license, and proof that the license text matches what the
recipe claims — that’s what LIC_FILES_CHKSUM is for. BitBake will refuse to build if the
checksum doesn’t match, catching license text that changed silently upstream:
# ep-greet_1.0.bb
DESCRIPTION = "A minimal original demo package for the EmbeddedPathashala BitBake lecture"
PRIORITY = "optional"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://ep-greet.c"
S = "${WORKDIR}"
do_compile() {
${CC} ${CFLAGS} ${LDFLAGS} -o ep-greet ep-greet.c
}
do_install() {
install -d ${D}${bindir}
install -m 0755 ep-greet ${D}${bindir}
}
SRC_URI tells BitBake where the source lives — file://ep-greet.c makes it
search the recipe’s files directory automatically. S is the directory BitBake
treats as the unpacked source root; for a lone local file it’s just ${WORKDIR}, the
recipe’s private working area. ${D} expands to the staging root for the target image, and
${bindir} to the standard binary directory, /usr/bin, so
install is really writing to ${D}/usr/bin/ep-greet.
Step 3 — Build Just This Recipe
$ bitbake ep-greet
A successful run creates a per-recipe working directory and, more importantly, a real package
artifact you can inspect independently of any image:
$ ls tmp/deploy/rpm/cortexa8hf_vfp_neon/ | grep ep-greet
ep-greet-1.0-r0.cortexa8hf_vfp_neon.rpm
At this point ep-greet is built and packaged, but it isn’t part of any image yet — that
distinction (built vs. installed-in-image) trips up a lot of newcomers.
Step 4 — Add It to an Image Without a Full Recipe Change
The list of packages an image pulls in is controlled by the IMAGE_INSTALL variable.
Rather than editing the image recipe itself, append to it from conf/local.conf — this is
the standard way to pull a package into development builds:
# build/conf/local.conf
IMAGE_INSTALL:append = " ep-greet"
Note the leading space inside the quotes — without it, BitBake would concatenate directly onto the
previous entry with no separator. Rebuild the image and the package is now included:
$ bitbake core-image-minimal
$ tar tf tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.tar.bz2 | grep ep-greet
./usr/bin/ep-greet
Handling Non-Open-Source Licenses
By default, BitBake refuses to build anything not explicitly cleared, and commercial or otherwise
restricted licenses need an explicit opt-in in two places — first the recipe declares the flag:
LICENSE_FLAGS = "commercial"
then local.conf explicitly allows it for that specific build:
LICENSE_FLAGS_ACCEPTED = "commercial"
This two-step design exists on purpose — a recipe alone can never silently pull in a restricted
license; the person configuring the build has to consciously accept it.
Real-World Use Case
This exact pattern — a tiny local recipe plus an IMAGE_INSTALL:append — is how most teams add
in-house diagnostic tools, factory test binaries, or provisioning scripts to a product image during
bring-up, before those tools graduate into a properly versioned package with real upstream source
fetched over git or https instead of a local file.
Common Mistakes
Missing the leading space in IMAGE_INSTALL:append
Without it, the appended package name runs together with the last existing entry and BitBake fails
to find either package.
Wrong LIC_FILES_CHKSUM
A mismatched md5 aborts the build immediately with an explicit error — copy the checksum BitBake
reports on first failure rather than guessing.
Forgetting do_install entirely
A recipe that only defines do_compile will build the binary but install nothing — it will never
appear in any image, silently.
Best Practices
- Keep local demo/test recipes clearly separated in their own recipes-* directory
- Always set LICENSE and LIC_FILES_CHKSUM, even for trivial internal tools
- Use IMAGE_INSTALL:append in local.conf for development, and a proper image recipe for production
- Never accept LICENSE_FLAGS globally — scope it to the specific build that needs it
Summary and Key Takeaways
- Recipes follow <name>_<version>.bb naming with local source under files/
- LICENSE and LIC_FILES_CHKSUM are mandatory, not optional, metadata
- do_compile and do_install are the two tasks a minimal recipe must define
- Building a recipe and installing it in an image are two separate steps
- IMAGE_INSTALL:append in local.conf is the fast path for development builds
Conclusion
You’ve now taken a layer, understood BitBake’s metadata model, and written a working recipe end to
end — the complete loop that every real BSP and product image is built from. That closes out the build
systems arc of this free embedded systems course; from here the series moves into
customizing images more deeply, including package selection strategies beyond a single
IMAGE_INSTALL:append line.
Frequently Asked Questions
Do I always need a files/ subdirectory for local source?
Only when SRC_URI uses file://. Recipes pulling from git or https don’t need one — BitBake fetches
the source into WORKDIR directly.
What if my recipe needs configure/autotools instead of a manual do_compile?
Add inherit autotools to the recipe and remove your manual do_compile — the class provides
do_configure, do_compile, and do_install automatically for autotools-based projects.
Why is my package built but missing from the image?
Almost always because it was never added to IMAGE_INSTALL. Building a recipe with bitbake <name>
never automatically pulls it into an image.
Can I use IMAGE_INSTALL:append for a production build?
It works, but production images typically define their own image recipe listing exact package sets
rather than relying on local.conf overrides that aren’t version controlled with the image.
What does the leading space in IMAGE_INSTALL:append actually do?
BitBake’s append syntax concatenates strings with no automatic separator, so the space prevents your
new package name from merging into the previous one.
Is LICENSE_FLAGS only for truly commercial software?
It covers any license the Yocto Project’s default policy considers restricted enough to require
explicit acceptance, not exclusively paid/commercial licenses.
Keep Building With EmbeddedPathashala
This lecture is part of a completely free embedded Linux course covering toolchains, bootloaders,
kernel porting, root filesystems, and build systems from first principles.

2 Comments