Chapter 2 — Kernel Configuration
Lecture 18 of Series
Linux Kernel Configuration:
make menuconfig Explained
Understand how the Linux kernel configuration system works — what Kconfig and Kbuild do,
what every menuconfig symbol means, and how the .config file drives your kernel build.
Updated for Linux 6.x.
🎯 What You Will Learn
- Why the Linux kernel needs a configuration step before building
- What Kbuild and Kconfig are and how they work together
- How to run
make menuconfigand fix the most common errors - What every symbol in the menuconfig UI means —
[*],<M>,{.}and more - The exact difference between built-in, module, and disabled
- How the
.configfile is generated and how the kernel uses it - All other config targets:
make defconfig,make oldconfig, and more
📌 Keywords for This Lecture
Kconfig
Kbuild
.config file
linux kernel build system
CONFIG_XXX=y
kernel module .ko
tristate boolean
make defconfig
make oldconfig
free linux kernel course
1. Why Does the Linux Kernel Need Configuration?
The Linux kernel runs on everything from a tiny Raspberry Pi to a 128-core cloud server to
an automotive infotainment system. The same source code tree covers all of them — but no single
build can blindly include every driver, every filesystem, every networking protocol for every
possible platform. That would produce a kernel image too large to boot on small devices and
full of drivers for hardware that does not exist on a given system.
This is the reason for the configuration step. Before you compile, you tell the
build system exactly which features, drivers, and subsystems you want. The output of this step
is a plain text file called .config. Every compile-time decision the kernel makes
flows from that single file.
How Kernel Configuration Fits Into the Build Flow
│ LINUX KERNEL BUILD PIPELINE │
└─────────────────────────────────────────────────────────────────────┘┌──────────────┐ ┌────────────────┐ ┌──────────────┐
│ Kernel │ │ make │ │ .config │
│ Source Code │───▶│ menuconfig │───▶│ (choices │
│ (C files, │ │ (you choose │ │ saved as │
│ Kconfig, │ │ options) │ │ text file) │
│ Makefiles) │ └────────────────┘ └──────┬───────┘
└──────────────┘ │
▼
┌──────────────────┐
│ make │
│ (Kbuild reads │
│ .config and │
│ compiles only │
│ what you want) │
└────────┬─────────┘
│
▼
┌─────────────────────────┐
│ bzImage / vmlinux │
│ (your bootable kernel) │
└─────────────────────────┘
2. Meet Kconfig and Kbuild — The Two Pillars
These two names look similar but do completely different jobs. Confusing them is one of
the most common mistakes beginners make.
📝 Kconfig — The Configuration System
Kconfig reads special files named Kconfig that exist in almost every
directory of the kernel source tree. Each file describes available options — their
names, types (boolean or tristate), default values, dependencies, and the help text
you see when you press H in menuconfig.
The menuconfig, nconfig, and xconfig programs
all read these Kconfig files to build the menus you interact with.
🔧 Kbuild — The Build System
Once your choices are saved in .config, Kbuild takes over. It reads
.config and the Makefile in every source directory to
decide what to compile and what to skip. Kbuild is what turns your configuration
choices into actual object files and links them into the final kernel binary.
Kbuild is also reused by many other open source projects outside the Linux kernel
because it is so well designed.
Simple analogy: Kconfig is the restaurant menu — it lists everything
available. Kbuild is the kitchen — it cooks exactly what you ordered. You cannot skip
either step.
3. Running make menuconfig — and Fixing Common Errors
Go into your kernel source directory and run:
make menuconfig
This compiles a small ncurses-based host program called mconf, then launches
it. You get a full-screen text UI in your terminal. Arrow keys to navigate, Space to
toggle, Enter to go into a sub-menu, Escape to go back.
⚠️ Common Error on Fresh Ubuntu / Debian
If you run make menuconfig on a fresh system, the build will fail with:
/bin/sh: 1: bison: not found
scripts/Makefile.lib: recipe for target '...' failed
make[1]: *** Error 127
Root cause: Building mconf requires bison
(a parser generator) and flex (a lexer), which are not installed by default.
The ncurses UI also needs libncurses-dev.
Fix — Ubuntu / Debian:
sudo apt install build-essential bison flex libncurses-dev libssl-dev libelf-dev
Fix — Fedora / RHEL / Rocky:
sudo dnf install gcc make bison flex ncurses-devel openssl-devel elfutils-libelf-devel
4. menuconfig Symbols — What Every Character Means
When menuconfig opens, every line starts with a small symbol. These are not decoration —
each symbol tells you the type of an option and its current state.
Learning them is the most important skill for navigating the kernel config UI.
There are two fundamental option types:
- Boolean — only two states: ON or OFF
- Tristate — three states: built-in (y), module (m), or off (n)
menuconfig Symbol Quick Reference
─────────────────────────────────────────────────────────────────────────[*] Boolean ON → feature compiled into CONFIG_XXX=y
the kernel image (built-in)[ ] Boolean OFF → not compiled at all # CONFIG_XXX is not set
<*> Tristate ON → compiled into kernel image CONFIG_XXX=y
<M> Tristate MODULE → compiled as a .ko file CONFIG_XXX=m
loaded with modprobe on demand
< > Tristate OFF → not compiled at all # CONFIG_XXX is not set
{.} Any Dependency forces this ON. y or m
Another selected option needs
this one — you cannot disable it.
-*- Any Dependency forces BUILT-IN. y (locked)
Must be in the kernel image,
cannot be a module.
(…) String Text input prompt. Press Enter CONFIG_XXX=”your-text”
to type a value (e.g. version
string, custom name).
—> n/a Sub-menu follows. (navigation only)
Press Enter to go deeper.
─────────────────────────────────────────────────────────────────────────
TOGGLE: Press SPACE to cycle through available states for an option.
HELP: Press H or select < Help > to see full description + CONFIG name.
5. Built-in vs Module vs Disabled — The Core Choice
This decision comes up for nearly every driver and subsystem you configure.
Getting it right is the difference between a lean, fast kernel and a bloated
one — or worse, a kernel that panics because a critical driver was not present
at the right time.
Built-in vs Module vs Disabled — Side by Side
│ BUILT-IN (y) │ MODULE (m) │ DISABLED (n) │
│ Symbol: [*] or <*> │ Symbol: <M> │ Symbol: [ ] or < > │
├─────────────────────────┼──────────────────────────────┼─────────────────────────┤
│ Code is PART of the │ Code compiled to a separate │ Code is NOT compiled. │
│ kernel image (vmlinux) │ .ko file on disk │ No binary produced. │
│ │ │ │
│ Available from first │ Loaded on demand via │ Feature does not exist │
│ instruction of boot │ modprobe or auto by udev │ at all in this build │
│ │ │ │
│ Cannot be unloaded │ Can be loaded AND unloaded │ Saves build time and │
│ │ without rebooting │ kernel image size │
│ │ │ │
│ .config: │ .config: │ .config: │
│ CONFIG_FOO=y │ CONFIG_FOO=m │ # CONFIG_FOO is not set │
├─────────────────────────┼──────────────────────────────┼─────────────────────────┤
│ USE WHEN: │ USE WHEN: │ USE WHEN: │
│ • Root filesystem driver│ • Optional hardware drivers │ • Hardware never used │
│ • Early boot hardware │ • Rarely used features │ • Minimising attack │
│ • Core networking stack │ • Features you test/toggle │ surface │
│ • Security subsystems │ • VirtualBox, Wi-Fi, sound │ • Minimal embedded build│
└─────────────────────────┴──────────────────────────────┴─────────────────────────┘KEY RULE: If a driver is needed BEFORE the root filesystem mounts → must be BUILT-IN.
Everything else can safely be a MODULE.
6. The .config File — Where All Your Choices Live
Every selection you make in make menuconfig is written to a plain text file
called .config in your kernel source root. This file is the only input
Kbuild needs. You can open it with any editor — it is human-readable.
#
# .config — Linux Kernel Configuration
# Generated by make menuconfig
#
#
# General setup
#
CONFIG_LOCALVERSION="-mydevice"
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_PROFILING is not set
# CONFIG_HAMRADIO is not set
CONFIG_VBOXGUEST=m
CONFIG_UIO=m
# CONFIG_SECURITY is not set ← WARNING: never do this on real systems
CONFIG_DEBUG_STACK_USAGE=y
The three patterns you must memorise:
CONFIG_XXX=y→ built into kernel imageCONFIG_XXX=m→ compiled as a loadable module# CONFIG_XXX is not set→ disabled, not compiled
📌 Reading Your Running Kernel’s Config — Linux 6.x
You do not always have to build from scratch to see a kernel’s config. On modern systems:
# Method 1 — most distros store it here (Ubuntu, Fedora, Arch):
cat /boot/config-$(uname -r)
# Method 2 — if CONFIG_IKCONFIG_PROC=y was set at build time:
zcat /proc/config.gz | less
# Method 3 — Linux 6.x stores config here too:
cat /lib/modules/$(uname -r)/config
# Method 4 — extract from kernel image directly:
./scripts/extract-ikconfig /boot/vmlinuz-$(uname -r) > recovered.config
cat /boot/config-$(uname -r) | grep CONFIG_USB
7. How menuconfig Works Internally — Step by Step
When you type make menuconfig, several things happen before you even see
the first screen. Understanding this removes the mystery from error messages.
What Happens When You Run make menuconfig
──────────────────────────────────────────────────────────────────────────
make compiles scripts/kconfig/mconf.c into a host binary called mconf.
This requires: bison (parser), flex (lexer), libncurses (terminal UI).
If any of these are missing → you see the “not found” error here.Step 2 — Parse all Kconfig files
──────────────────────────────────────────────────────────────────────────
mconf starts at the root Kconfig file.
That file uses “source” statements to pull in every sub-directory’s
Kconfig. This builds up a complete tree of 10,000+ possible options.Kconfig (root)
├── source init/Kconfig
├── source drivers/Kconfig
│ ├── source drivers/net/Kconfig
│ ├── source drivers/usb/Kconfig
│ └── …
├── source fs/Kconfig
└── … (1700+ files in Linux 6.x)
Step 3 — Load existing .config (if found)
──────────────────────────────────────────────────────────────────────────
If .config already exists in your source dir, your previous choices
are pre-loaded into the menu. If not, architecture defaults are used.
Step 4 — You interact with the menu
──────────────────────────────────────────────────────────────────────────
You navigate, toggle, and change options.
Dependencies are enforced in real time:
→ Enable feature A that needs feature B → B is auto-selected.
→ Try to disable B while A still needs it → not allowed.
Step 5 — Save to .config on exit
──────────────────────────────────────────────────────────────────────────
On exit → “Save configuration?” → Yes → .config written to disk.
The kernel build (make) then reads this file. Done.
8. All Configuration Targets — Linux 6.x Reference
make menuconfig is just one of many config targets. Here are all the
important ones — every kernel developer should know these:
Kernel Configuration Targets Reference (Linux 6.x)
──────────────────────────────────────────────────────────────────────────make menuconfig ncurses TUI Full-screen text menu.
✓ Works in any SSH terminal.
✓ Best for daily use.make nconfig ncurses TUI Alternative text menu with F-key
shortcuts (F1=help, F6=save etc).
Slightly faster to navigate.
make xconfig Qt GUI Mouse-driven graphical interface.
Needs Qt5 dev libraries.
Good for exploring option trees.
make gconfig GTK GUI GTK-based GUI. Needs gtk2-devel.
Less commonly used today.
make defconfig None (auto) Generates a default .config for
your current architecture.
✓ Best starting point for a build.
make oldconfig Prompt only Loads existing .config and prompts
ONLY for options new in this kernel
version. Everything else unchanged.
✓ Use when upgrading kernel version.
make olddefconfig None (auto) Like oldconfig but silently sets
all new options to their defaults.
✓ Use in scripts / CI builds.
make allmodconfig None (auto) Sets ALL tristate options to module.
Good for testing module builds.
make allyesconfig None (auto) Sets ALL options to yes (built-in).
Warning: produces huge kernel image.
make allnoconfig None (auto) Sets ALL options to no/off.
Minimal possible kernel — mostly
used for testing and CI.
make localmodconfig None (auto) Reads currently LOADED modules on
your running system and sets only
those to =m. Everything else off.
✓ Great for lean custom builds.
──────────────────────────────────────────────────────────────────────────
Where to learn more: Documentation/kbuild/kconfig.rst (in kernel source)
✅ Key Takeaways — Lecture 18
- The kernel must be configured before building —
.configdrives everything - Kconfig describes options | Kbuild compiles based on them
- Install
bison flex libncurses-devbefore runningmake menuconfig [*]/<*>= built-in (y) |<M>= module (m) | empty = off (n)- Built-in = always present from boot; Module = loaded on demand with
modprobe - All choices are plain text in
.config— readable and portable - Use
make olddefconfigwhen upgrading kernel version to keep existing choices
🌟 Frequently Asked Questions
What is make menuconfig in Linux kernel?
make menuconfig is the most widely used interface for configuring the
Linux kernel before compiling it. It launches a full-screen, text-based menu in your
terminal (powered by the ncurses library) that lets you browse thousands of kernel
options, enable or disable features, and choose whether drivers are built into the
kernel image or compiled as loadable modules. Your selections are saved to a file
called .config, which the Kbuild system reads when you run make
to actually compile the kernel.
What is the difference between Kconfig and Kbuild?
Kconfig is the configuration system — it defines every available
kernel option using special text files named Kconfig scattered across
the source tree. Programs like menuconfig read these files to build
the interactive menus. Kbuild is the build system — it reads the
resulting .config file and uses Makefile rules in every
source directory to compile and link only the selected components into the final
kernel binary. Put simply: Kconfig is about choosing what to build; Kbuild is about
actually building it.
What is the .config file in Linux kernel compilation?
The .config file is a plain text file placed at the root of your kernel
source directory. It contains one line per configuration option in one of three forms:
CONFIG_XXX=y (built-in), CONFIG_XXX=m (loadable module), or
# CONFIG_XXX is not set (disabled). Kbuild reads this file to determine
which C source files to compile, which to skip, and how to link the final kernel. It
is the single source of truth for your entire kernel build.
What does tristate mean in Linux kernel configuration?
A tristate option can take three values: y (built into the kernel image),
m (compiled as a loadable kernel module), or n (not compiled
at all). Tristate options appear with angle brackets in menuconfig — <*>
for built-in, <M> for module, < > for off. Boolean
options only have two states (on or off) and appear with square brackets. Most device
drivers are tristate because you often want the flexibility to load the driver only when
the hardware is present.
Why does make menuconfig fail with “bison not found”?
Before menuconfig can display its UI, the kernel build system compiles a small host
program called mconf from C source. Building mconf requires
bison (a parser generator) and flex (a lexer) to be installed
on your host machine. If either is missing, the build fails with the “not found” error.
Fix it on Ubuntu/Debian with:
sudo apt install bison flex libncurses-dev.
On Fedora/RHEL: sudo dnf install bison flex ncurses-devel.
What is the difference between make oldconfig and make olddefconfig?
Both targets are used when you want to carry an existing .config to a new
kernel version. make oldconfig reads your existing choices and
interactively prompts you for any options that are new in the updated kernel —
you must answer each one manually. make olddefconfig does the same but
silently sets all new options to their default values without prompting.
Use oldconfig when you want control over new options; use
olddefconfig in scripts and CI pipelines where interactive input is not
possible.
How do I view my running kernel’s configuration in Linux?
There are several ways. Most Linux distributions store the kernel config at
/boot/config-$(uname -r) — run cat /boot/config-$(uname -r)
to read it. If the kernel was built with CONFIG_IKCONFIG_PROC=y, the
config is also exposed at /proc/config.gz — read it with
zcat /proc/config.gz. On Linux 6.x, many distributions also place it at
/lib/modules/$(uname -r)/config. If you have the kernel image file, you
can use the scripts/extract-ikconfig script to extract the embedded config
(only if CONFIG_IKCONFIG=y was set at build time).
📷 Suggested Images for This Post
- Hero image: Terminal screenshot of
make menuconfig
running on Ubuntu 24.04 with the Linux 6.8 kernel source — General Setup menu
open. Alt text: “make menuconfig Linux kernel configuration menu on Ubuntu” - Section 5: Two-panel image — left panel shows the kernel image
size with everything built-in, right panel shows the same kernel with most
drivers as modules. Highlights the size difference visually.
Alt text: “Linux kernel built-in vs module size comparison” - Section 6: Text editor screenshot of an actual
.config
file with CONFIG_XXX=y, =m, and is-not-set lines highlighted in different colours.
Alt text: “Linux kernel .config file showing CONFIG_XXX=y and CONFIG_XXX=m” - Section 8: Comparison grid of menuconfig vs nconfig vs xconfig
screenshots side by side. Alt text: “Linux kernel menuconfig nconfig xconfig comparison”
Lecture 18
EmbeddedPathashala — Free Embedded Systems & Linux Kernel Education — embeddedpathashala.com
