The previous lecture in this free linux device drivers course used an overlay to drop an already-compiled binary onto the target. That works for a handful of files, but it breaks down the moment your own code needs to be built as part of the Buildroot pipeline itself – picked up in menuconfig, compiled with the correct toolchain automatically, and reproducible from a clean checkout. That is exactly what a Buildroot package gives you, and this lecture builds one from scratch, then closes with how to audit the licenses of everything Buildroot pulled in.
What You Will Learn
- The two files every Buildroot package needs, and what each one is responsible for
- How to write a Config.in entry that shows up correctly in menuconfig
- How to write a generic-package makefile that builds and installs a local program
- How to run Buildroot’s built-in license audit before shipping a product
Prerequisites
- A working Buildroot tree already producing a bootable image, from earlier lectures in this free embedded systems course
- Basic Makefile syntax and a general sense of Kconfig menus from kernel configuration work
Why a Package Instead of an Overlay
An overlay copies files that already exist. A package tells Buildroot how to obtain source code, configure it, compile it with the correct cross toolchain, and install the results – the same four steps Buildroot performs for every one of the thousand-plus packages it ships out of the box, from BusyBox to OpenSSL. Once your own program is a package, it gains everything that comes with that: it appears as a selectable option in menuconfig, it gets rebuilt automatically when its dependencies change, and it participates in Buildroot’s dependency graph and license reporting.
Every package lives in its own subdirectory under package/ and needs exactly two files: a Config.in that describes the Kconfig option, and a <name>.mk makefile that tells Buildroot how to build it.
Step 1: The Kconfig Entry
Create package/ep_statusd/Config.in. The variable name must follow the pattern BR2_PACKAGE_<UPPERCASE_NAME>, matching the package directory name:
# package/ep_statusd/Config.in
config BR2_PACKAGE_EP_STATUSD
bool "ep_statusd"
help
A small original status-reporting daemon written for this
lecture. Periodically reports memory and uptime figures to
the kernel log for demonstration purposes.
Then make menuconfig aware this Config.in exists by sourcing it from a top-level menu, typically inside package/Config.in:
menu "EmbeddedPathashala packages"
source "package/ep_statusd/Config.in"
endmenu
Step 2: The Source
Keep the demonstration source small and original. Here is ep_statusd.c, a daemon distinct from anything in the source material, that logs a status line to the kernel ring buffer every ten seconds:
/* ep_statusd.c - periodic status logger, original demo for this lecture */
#include <stdio.h>
#include <unistd.h>
#include <sys/sysinfo.h>
int main(void)
{
struct sysinfo info;
while (1) {
if (sysinfo(&info) == 0) {
printf("ep_statusd: uptime=%lds freeram=%luKB\n",
info.uptime, info.freeram / 1024);
fflush(stdout);
}
sleep(10);
}
return 0;
}
$ mkdir -p package/ep_statusd
$ cp ep_statusd.c package/ep_statusd/
Step 3: The Package Makefile
The makefile declares metadata as uppercase variables prefixed with the package name, provides _BUILD_CMDS and _INSTALL_TARGET_CMDS rules, and finishes with a call into Buildroot’s generic-package infrastructure, which wires those rules into the overall dependency graph:
# package/ep_statusd/ep_statusd.mk
EP_STATUSD_VERSION = 1.0
EP_STATUSD_SITE = $(BR2_EXTERNAL_EP_PATH)/package/ep_statusd
EP_STATUSD_SITE_METHOD = local
EP_STATUSD_LICENSE = MIT
EP_STATUSD_LICENSE_FILES = LICENSE
define EP_STATUSD_BUILD_CMDS
$(TARGET_CC) $(TARGET_CFLAGS) -o $(@D)/ep_statusd $(@D)/ep_statusd.c
endef
define EP_STATUSD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/ep_statusd $(TARGET_DIR)/usr/bin/ep_statusd
endef
$(eval $(generic-package))
Two things are worth calling out. TARGET_CC and TARGET_CFLAGS are variables Buildroot already resolved to the correct cross compiler and flags for the selected architecture – a package never hardcodes a toolchain prefix, which is exactly why it stays portable across boards. And EP_STATUSD_LICENSE is not optional decoration; it is the metadata the next section’s audit tool reads directly, so fill it in honestly for anything you ship.
Building and Verifying
Enable the package in menuconfig under the new “EmbeddedPathashala packages” menu, then build normally:
$ make menuconfig # select ep_statusd under EmbeddedPathashala packages
$ make
$ ls output/target/usr/bin/ep_statusd
output/target/usr/bin/ep_statusd
Compare this with the previous lecture’s overlay: this time, changing ep_statusd.c and running make again is enough – Buildroot tracks the dependency and rebuilds automatically, without you manually recopying a binary.
Step 4: License Compliance
Every package Buildroot builds, including the hundreds already in the tree, carries a license field similar to the one you just wrote for ep_statusd. Before a product ships, run Buildroot’s built-in legal audit to collect every license and every source archive into one reviewable bundle:
$ make legal-info
manifest.csv is the file a legal or compliance reviewer actually reads: one row per package listing its declared license and where its source came from. Packages that Buildroot cannot fully verify – typically ones missing a clear license file – are flagged so a human can look at them individually rather than being silently skipped.
Common Mistakes and Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| Package does not appear in menuconfig | Config.in was never sourced from a parent menu | Add a source line to package/Config.in or your own external tree’s Config.in |
Build fails with an undefined TARGET_CC | Makefile written before $(eval $(generic-package)), or missing that final line entirely | Always end the makefile with the generic-package eval so infrastructure variables are defined |
| Binary uses the host compiler instead of the cross compiler | Build command called gcc directly instead of $(TARGET_CC) | Always reference $(TARGET_CC) / $(TARGET_CFLAGS), never a bare compiler name |
make legal-info flags a package as unknown license | Package’s _LICENSE or _LICENSE_FILES variable missing or wrong | Set both variables accurately for every custom package you add |
Best Practices
- Prefer
generic-packagefor simple local sources; Buildroot also shipscmake-package,autotools-package, andpython-packageinfrastructures for those build systems specifically - Always set an accurate
_LICENSEfield, even for internal-only packages, solegal-infostays trustworthy for the whole tree - Keep custom packages in a
BR2_EXTERNALtree rather than patching them directly into Buildroot’s own source tree, so upgrading Buildroot does not overwrite your work - Run
make legal-infoas a routine step before any release build, not only when a customer explicitly asks for it
Summary and Key Takeaways
- A Buildroot package needs exactly two files: a Config.in for the Kconfig entry and a makefile for the build and install rules
- Always build with
$(TARGET_CC)/$(TARGET_CFLAGS)so the package stays portable across architectures make legal-infocompiles a manifest and license bundle for every package in the build, driven by the_LICENSEmetadata you provide
Conclusion
Turning your own code into a real Buildroot package is a small amount of boilerplate for a large amount of long-term benefit: automatic dependency tracking, automatic rebuilds, and participation in the same license audit that governs every other package in the tree. That audit step is not optional polish – it is the difference between a hobby build and something you can legally ship – which is why it closes out this module of the free linux device drivers course. With the kernel configured, an overlay in place, a custom package building, and licenses accounted for, your Buildroot-based board support package is now a complete, reproducible artifact.
Frequently Asked Questions
What is the minimum set of files a Buildroot package needs?
A Config.in describing the Kconfig option, and a name.mk makefile with build and install rules ending in a call to the appropriate package infrastructure, such as generic-package.
Why use $(TARGET_CC) instead of calling gcc directly?
$(TARGET_CC) always resolves to the correct cross compiler for the currently selected architecture, keeping the package portable across boards without editing the makefile.
What does make legal-info actually produce?
A manifest.csv listing every package’s license and source origin, copies of license texts, and source archives for packages that require redistribution.
Where should custom packages live so they survive a Buildroot upgrade?
In a separate BR2_EXTERNAL tree rather than directly inside Buildroot’s own package directory, so pulling a new Buildroot release does not overwrite your work.
Is generic-package the only package infrastructure available?
No, Buildroot also provides cmake-package, autotools-package, python-package and others tailored to specific build systems.
What happens if a package’s license field is left blank?
make legal-info flags it so a reviewer notices, rather than silently treating it as compliant.
Continue the Free Linux Device Drivers Course
You have now completed the Buildroot module: kernel configuration, overlays, custom packages, and license compliance.
Explore More Free Courses Browse the Full Course
2 Comments