Every one of the thousands of options that decide what goes into your kernel build — from which filesystems are compiled in to which drivers are built as modules — is driven by a system called Kconfig, paired with a build system called Kbuild. This lecture in our free linux kernel development course demystifies both, and walks through writing your own Kconfig entry for an original demo driver so you can see the mechanism end to end.
Kbuild
menuconfig
kernel configuration
ARCH variable
free linux device drivers course
What You Will Learn
How the ARCH variable shapes the whole config menu
Reading and writing a Kconfig menu entry
The difference between y, m, and unset config values
Adding your own driver’s config option from scratch
Prerequisites
You should already know your way around the kernel source tree’s top-level layout (covered in the previous lecture of this free embedded linux course) and be comfortable running basic shell commands inside a checked-out kernel tree.
Why Configuration Exists
Linux runs on everything from a smart thermostat with kilobytes of flash to a rack server with terabytes of RAM. A single build can’t sensibly include every driver, filesystem, and subsystem for every possible target — that would be enormous, slow to build, and full of code that’s simply irrelevant on most boards. Kconfig is the mechanism that lets you select, out of many thousands of options, exactly the subset relevant to your hardware and use case.
Kconfig vs Kbuild: Two Different Jobs
| System | Job |
|---|---|
| Kconfig | Declares configuration options and their dependencies/relationships; produces the .config file describing what’s enabled |
| Kbuild | The actual build system (an extension of GNU Make) that reads .config and decides which files to compile, and whether each is built into the kernel image or as a loadable module |
Both are documented in Documentation/kbuild/ inside every kernel tree, and both are reused well beyond Linux itself — U-Boot, Barebox, BusyBox, and crosstool-NG all adopt the same Kconfig language for their own configuration menus, so learning it here pays off elsewhere too.
The Role of ARCH
Kconfig files are declared in a hierarchy, starting from a single top-level Kconfig file that sources an architecture-specific one based on the ARCH environment variable:
$ make ARCH=arm64 menuconfig
If you omit ARCH=, the build system defaults to your local host’s architecture — almost never what you want for embedded cross-compilation. Always set it explicitly. Note the one well-known oddity: both ARCH=i386 and ARCH=x86_64 resolve to the same source directory, arch/x86/Kconfig.
|
v
top-level Kconfig
|
| sources arch/$ARCH/Kconfig
v
arch/arm64/Kconfig
|
| pulls in driver/subsystem Kconfig files
v
drivers/*/Kconfig, fs/Kconfig, net/Kconfig, …
|
v
final menuconfig UI shown to you
Anatomy of a Kconfig Entry
Kconfig files are built from menu / endmenu blocks containing individual config entries. Here’s an original, simplified example modeled on real kernel style — a hypothetical option for an EmbeddedPathashala demo driver:
menu "EmbeddedPathashala demo drivers"
config EP_DEMO_GPIO_BLINKER
tristate "EP GPIO blinker demo driver"
depends on GPIOLIB
default n
help
Say Y or M here to build the EmbeddedPathashala GPIO blinker
demo driver, used in the free linux device drivers course to
illustrate basic Kconfig and Kbuild integration.
If unsure, say N.
endmenu
Breaking this down field by field:
| Field | Meaning |
|---|---|
config EP_DEMO_GPIO_BLINKER |
Declares a variable named CONFIG_EP_DEMO_GPIO_BLINKER |
tristate "..." |
The option can be y (built-in), m (module), or unset — the quoted string is the menu label shown to the user |
depends on GPIOLIB |
This option is only offered if the GPIO subsystem is also enabled |
default n |
Disabled unless the user explicitly enables it |
help |
Longer description shown when the user requests help text in the menu |
A simpler alternative is bool instead of tristate, which only allows y or unset — no module option. The kernel’s own drivers/char/Kconfig has a good real example of this, the DEVMEM option controlling /dev/mem support.
Wiring It Into Kbuild
Declaring the option in Kconfig alone doesn’t build anything — Kbuild’s Makefile in the same directory decides what to actually compile based on the resulting CONFIG_* value:
# drivers/gpio-demo/Makefile (example, not a real kernel path)
obj-$(CONFIG_EP_DEMO_GPIO_BLINKER) += ep_gpio_blinker.o
This one line is the entire integration: if the option resolves to y, the object file is linked into the kernel image; if m, it’s built as a standalone .ko module; if unset, Kbuild skips it entirely. No conditional compilation logic needed elsewhere — Kbuild handles it purely from the variable’s value.
Trying It: Running menuconfig
With any real driver’s Kconfig entry in place, launch the interactive configuration menu to see it appear:
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
Navigate to “EmbeddedPathashala demo drivers” in the menu tree, press Y or M to select it, then save and exit. Confirm it landed in the generated config:
$ grep EP_DEMO_GPIO_BLINKER .config
CONFIG_EP_DEMO_GPIO_BLINKER=m
Real-World Use Case: Trimming a Product Config
A very common embedded task is taking a vendor’s sprawling default config — often built for a development board with every peripheral wired up — and trimming it down for a specific product SKU. Understanding Kconfig dependencies matters here: disabling GPIOLIB, for instance, will silently disable every driver that depends on it, including ones you might still need. Always check dependency chains with menuconfig‘s search feature (press / and type the symbol name) before mass-disabling subsystems.
Common Mistakes and Troubleshooting
- Forgetting
ARCH=and cross-compiling against the wrong menu — always set it explicitly for embedded targets, even if it matches your host by coincidence today. - Writing a Kconfig entry but forgetting the matching
obj-$(CONFIG_...)line — the option appears in the menu and sets a variable, but nothing actually gets compiled. - Using tabs vs spaces inconsistently in Kconfig files — the Kconfig parser is sensitive to this; help text and property lines conventionally use a single tab of indentation.
- Not checking
depends onchains before disabling a subsystem — you can silently lose drivers you still need.
Best Practices
- Always set
ARCH=(andCROSS_COMPILE=where relevant) explicitly for embedded builds. - Use
tristaterather thanboolwhen there’s any chance your driver should be loadable as a module. - Write meaningful
helptext — it’s what future engineers (including future you) will read when deciding whether to enable an option. - Use menuconfig’s built-in symbol search before disabling shared subsystems in a product config.
Performance Considerations
Every built-in (y) option increases your kernel image size and boot-time initialization work, even for hardware that’s never present on a given board. For embedded targets with tight boot-time or flash-size budgets, prefer trimming unused options to n rather than leaving defaults from a generic development config.
Summary / Key Takeaways
- Kconfig declares configuration options and their dependencies; Kbuild is the Make-based system that actually compiles based on those choices.
- Always set
ARCH=explicitly — it selects which architecture-specific Kconfig menu you see. - A config option needs both a Kconfig declaration and a matching
obj-$(CONFIG_...)line in the Makefile to actually build anything. tristateoptions can be built-in (y), a module (m), or disabled entirely.
Conclusion
Kconfig and Kbuild together are what turn “the entire Linux kernel source tree” into “exactly the kernel your product needs” — no more, no less. With source, tree layout, and now configuration covered, you have the full foundation this free linux kernel development course needs before moving on to actually building and flashing a kernel image in the lectures ahead.
Frequently Asked Questions
What’s the difference between Kconfig and Kbuild?
Kconfig declares configuration options and produces the .config file; Kbuild is the actual Make-based build system that reads .config and decides what to compile.
What happens if I forget to set ARCH=?
The build defaults to your host machine’s architecture, which is almost never correct for embedded cross-compilation — always set it explicitly.
What’s the difference between bool and tristate in Kconfig?
bool only allows y (built-in) or unset. tristate additionally allows m (built as a loadable module), giving more flexibility for optional drivers.
My Kconfig option shows up in menuconfig but nothing builds — why?
You likely declared the config symbol but forgot the matching obj-$(CONFIG_YOUR_OPTION) line in the relevant Makefile — both are required.
Is Kconfig only used by the Linux kernel?
No — the same Kconfig language and tooling is reused by other projects including U-Boot, Barebox, BusyBox, and crosstool-NG.
Continue the Free Linux Kernel Development Course
Explore more free lectures on embedded Linux, kernel internals, and device drivers.
