Week 2 — The Kernel Build System: Kconfig and menuconfig¶
Goal¶
Understand how the kernel's configuration system works, how to navigate menuconfig, and how to create a minimal config suitable for QEMU. By the end of this week, you'll be able to find any option, understand its dependencies, and make informed choices about what goes into your kernel.
Why This Matters¶
The kernel has over 15,000 configurable options. The configuration you choose determines what hardware is supported, what features are available, how big the kernel is, and how fast it builds. For kernel development, you want a minimal config that boots in QEMU quickly — not the kitchen-sink config your distro ships.
Kconfig: The Configuration Language¶
Every directory in the kernel has a Kconfig file that defines the options for that
subsystem. These files use a simple declarative language.
Look at a real example:
You'll see entries like:
menuconfig NET
bool "Networking support"
---help---
Unless you really know what you are doing, you should say Y here.
config INET
bool "TCP/IP networking"
depends on NET
Key concepts:
bool— option is either Y (yes) or N (no)tristate— option can be Y (built-in), M (module), or N (disabled)depends on— this option only appears if its dependency is enabledselect— enabling this option forces another option on (use with care)default— the default value if the user doesn't choosemenuconfig— creates a submenu that can be entirely disabled
The tristate distinction matters:
=y— compiled directly into vmlinux. Always present. Can't be unloaded.=m— compiled as a.komodule. Loaded on demand. Can be unloaded.=n— not compiled at all.
For development, modules (=m) are convenient because you can rebuild and reload a
single module without rebooting.
menuconfig: The TUI Configuration Tool¶
This opens an ncurses-based UI. Navigation:
- Arrow keys — move between options
- Enter — enter a submenu
- Space — cycle through Y/M/N
- ? — show help for the highlighted option (including dependencies)
- / — search for an option by name
- Esc Esc — go back / exit
The search (/) is your most important tool. Type /TCP and you'll see every option
mentioning TCP, along with its location in the menu hierarchy, its current value, and its
dependencies.
Other Configuration Targets¶
make defconfig # Default config for your architecture (minimal, boots on QEMU)
make allnoconfig # Everything disabled — absolute minimum
make allyesconfig # Everything enabled — huge, slow, used for build testing
make allmodconfig # Everything as module where possible
make localmodconfig # Disables modules not currently loaded on your system
make tinyconfig # Smallest possible kernel
make xconfig # Qt-based GUI (needs qt5 dev packages)
make nconfig # Alternative ncurses UI
Creating a Minimal QEMU Config¶
The distro config you copied in Week 1 builds thousands of drivers you don't need. Let's make a lean config for development:
This gives you a config that boots on x86_64 QEMU with virtio drivers. It's a great starting point. Now enable what we need for networking development:
Navigate and enable these (use / to search):
- Networking support → should already be
=y - Networking options → enable what you want to test (TCP, UDP, IPv6, etc.)
- Device Drivers → Network device support → Virtual drivers → virtio network →
=yor=m - Device Drivers → Virtio drivers → ensure virtio core is enabled
- Kernel hacking → Kernel debugging →
=y - Kernel hacking → Compile-time checks → Debug info (DWARF) → enable for GDB
- General setup → Configure standard kernel features → keep defaults
Save and exit.
Understanding .config¶
After saving, examine .config:
# See what's set
grep -c '=y' .config # Built-in options
grep -c '=m' .config # Module options
grep '=n' .config # Won't appear! Disabled options are commented out
# Disabled options look like this:
grep 'CONFIG_BLUETOOTH' .config
# # CONFIG_BLUETOOTH is not set
Important: Never edit .config by hand. If you need to change options
programmatically, use:
scripts/config --enable CONFIG_SOMETHING
scripts/config --disable CONFIG_SOMETHING
scripts/config --module CONFIG_SOMETHING
Then run make olddefconfig to resolve dependencies.
How Configuration Flows Into the Build¶
When you run make, the build system:
- Reads
.config - Generates
include/generated/autoconf.h— C#definestatements - Generates
include/config/auto.conf— Makefile variables
In C code, you'll see:
In Makefiles, you'll see:
If CONFIG_IPV6=y, this becomes obj-y += ipv6.o (built-in).
If CONFIG_IPV6=m, this becomes obj-m += ipv6.o (module).
If not set, the file is never compiled.
Build Targets You Should Know¶
make -j$(nproc) # Build everything (vmlinux + bzImage + modules)
make -j$(nproc) bzImage # Build only the kernel image
make -j$(nproc) modules # Build only modules
make net/ipv4/tcp.o # Build a single object file (great for quick compile checks)
make net/ipv4/ # Build everything in a directory
make M=net/ipv4 # Build out-of-tree style for a directory
make C=1 # Run sparse (static analyzer) during build
make W=1 # Extra compiler warnings
The single-file build (make net/ipv4/tcp.o) is invaluable during development. You
can check if your changes compile without building the entire kernel.
Exercises¶
- Run
make defconfig, thenmake menuconfig. Use/to findCONFIG_BPF. Read its help text and note its dependencies. - Compare the line counts:
wc -l .configafterdefconfigvs the distro config from Week 1. The difference is why defconfig builds are faster. - Look at
net/ipv4/Makefile. Find the line fortcp.o. What config option controls whether it's built? (Trick question — TCP is always built if INET is enabled.) - Run
scripts/config --enable CONFIG_NET_SCH_FQthenmake olddefconfig. Check if any new options appeared in.configdue to dependencies.
What's Next¶
Next week we look at what happens between pressing the power button and reaching a shell — the Linux boot process. Understanding this is essential because when your kernel doesn't boot, you need to know where it failed.