L14: Configuring the Linux Kernel

← Previous Lecture
Lecture 14 — Configuring the Linux Kernel
Next Lecture →

Free Linux Kernel Development Course — Chapter 2

Configuring the Linux Kernel

Master kbuild, .config, localmodconfig and menuconfig — Updated for Kernel 6.x

⏳ ~25 min read
🎯 Beginner to Intermediate
🐧 Kernel 6.x
📚 Lecture 14

Welcome to Lecture 14 of the free Linux kernel development course on EmbeddedPathashala. This lecture covers one of the most important steps in kernel development — configuring the Linux kernel. Before you can compile a single line of kernel code, you must tell the build system exactly what to include. This is done through the kbuild configuration system. Whether you are pursuing a free embedded Linux course, a free Linux device drivers course, or a broader free embedded systems course, understanding kernel configuration is a foundational skill you cannot skip.

The kernel is not a monolithic fixed binary. It supports hundreds of CPU architectures, thousands of devices, and thousands of optional features. Configuration lets you build exactly what you need — nothing more, nothing less.

Keywords Covered in This Lecture

kbuild system
.config file
make menuconfig
localmodconfig
Kconfig
make defconfig
make olddefconfig
CONFIG_=y/m/n
embedded Linux
BSP config
make mrproper
kernel modules

🎓 What You Will Learn

  • Why the Linux kernel must be configured before building
  • What the .config file is and how it controls everything
  • The three states of any kernel config option: Y, M, and N
  • How to generate a lean starting config using make localmodconfig
  • How to browse and fine-tune the config using make menuconfig
  • All available kernel configuration tools compared side by side
  • Cross-machine config techniques for embedded Linux development
  • Common mistakes beginners make during kernel configuration
  • Best practices for managing kernel configs in real projects

✅ Prerequisites

  • Basic Linux command line knowledge (ls, cd, make)
  • Completed Lectures 1–13 of this free Linux kernel development course, or equivalent familiarity with the kernel source tree
  • A Linux machine (Ubuntu 22.04+ or Fedora 38+ recommended) with build tools installed
  • Kernel source downloaded and extracted (see previous lecture)

1. Why Does the Linux Kernel Need to Be Configured?

The Linux kernel source tree contains over 30 million lines of code. It supports everything from tiny embedded microcontrollers to massive server machines with hundreds of CPU cores. Every driver, every protocol, every optional feature is present in the source. But you do not want all of it compiled into every kernel image — that would be enormous and impractical.

Configuration is how you tell the kbuild system what to include. If you are taking this free Linux kernel development course to build drivers for a specific piece of hardware, you need to know which config options enable your target subsystem. If you are on a free embedded Linux course, you need a lean kernel with only what your board needs. Configuration is the first step toward both goals.

Think of it like ordering a custom-built PC — you pick exactly which components go in, and everything else stays out. The output of this selection process is a file called .config.

How Kernel Configuration Fits Into the Full Build Process
📁
Kernel Source
30M+ lines
Kconfig files
C source
⚙️
Config Step
make menuconfig
generates
.config
🔨
Build Step
make -j$(nproc)
compiles only
what you chose
🐧
Final Output
vmlinuz
bzImage
+ modules.ko

2. The .config File — How the Kernel Knows What to Build

The .config file is a plain text file that lives in the root of the kernel source tree. It contains hundreds or thousands of lines, one for each configuration option. Every option is prefixed with CONFIG_ and assigned a value. Here is what a real snippet looks like:

#
# General setup
#
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=130200
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_AUDIT is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_USB_SERIAL=m

There are exactly three possible states for any kernel config option:

The Three States of a Kernel Config Option
🟢
CONFIG_XYZ=y
Built-in (Y)
Compiled directly into the kernel image. Always present from the very first moment of boot. Cannot be removed without rebooting. Use this for boot-critical drivers.
Example: CONFIG_SYSVIPC=y
🟡
CONFIG_XYZ=m
Module (M)
Compiled as a separate .ko file. Can be loaded and unloaded at runtime using modprobe. Stored in /lib/modules/$(uname -r)/. Ideal for optional hardware support.
Example: CONFIG_USB_SERIAL=m
🔴
# CONFIG_XYZ is not set
Disabled (N)
Not compiled at all. Zero code, zero overhead. The feature is completely absent from the resulting kernel. Use this for hardware or features you simply do not need.
Example: # CONFIG_AUDIT is not set

💡 Embedded Developer Note

On embedded systems, it is common to build critical drivers as built-in (=y) rather than modules (=m). The reason: modules require a filesystem to be mounted before they can be loaded, but some drivers — like the storage driver for the root filesystem — must be available before any filesystem is mounted. If you are studying a free embedded systems course, this Y vs M distinction will come up repeatedly in your device driver work.

3. Start Clean — Preparing the Kernel Source Tree

Before generating a config, especially if you are working in a source tree that was previously built, you should start from a clean state. The kernel provides commands for this:

# Removes ALL generated files including .config
# Use when starting completely from scratch
make mrproper

# Even more thorough — also removes editor backup files
make distclean

# Lighter clean — keeps .config but removes compiled objects
make clean

⚠️ Warning: mrproper Deletes Your .config

Both make mrproper and make distclean will delete your existing .config file permanently. Always back it up first:

cp .config ~/backup-kernel.config

4. Generating Your First Config with make localmodconfig

If you are building the kernel for your own development machine, the fastest and most practical way to generate a starting .config is make localmodconfig. This target looks at what kernel modules are currently loaded on your running system and generates a config that includes only those — nothing unnecessary.

Your running system already knows exactly what hardware it needs. localmodconfig captures that knowledge as a config file.

Step 1 — Capture the Currently Loaded Modules

# lsmod lists all currently loaded kernel modules
# Save this list to a file
lsmod > /tmp/lsmod.now

# Verify it captured something
wc -l /tmp/lsmod.now

Step 2 — Generate the Config from Your Module List

# Point kbuild at your module list and generate .config
make LSMOD=/tmp/lsmod.now localmodconfig

When you run this, kbuild reads the running kernel’s existing config (found at /boot/config-$(uname -r)) and trims it down to match your loaded modules. For any new options that did not exist in the old config, it prompts you with a (NEW) marker. Simply press Enter to accept the default.

Here is a representative sample of the output you will see. The full output is much longer — this shows the important patterns:

$ make LSMOD=/tmp/lsmod.now localmodconfig

*
* General setup
*
Compile also drivers which will not load (COMPILE_TEST) [N/y/?] n
Local version (LOCALVERSION) []
Kernel compression mode
  1. Gzip (KERNEL_GZIP)
  2. Bzip2 (KERNEL_BZIP2)
  3. XZ  (KERNEL_XZ)
  4. LZ4 (KERNEL_LZ4)
choice[1-4?]: 1
...
Enable userfaultfd() system call (USERFAULTFD) [Y/n/?] y
Enable rseq() system call (RSEQ) [Y/n/?] (NEW)   <-- press Enter
...
#
# configuration written to .config
#

$ ls -lh .config
-rw-r--r-- 1 user user 140K Jun 20 10:31 .config

📋 Tip: What Does (NEW) Mean?

When you see a prompt ending with (NEW), it means this config option did not exist in the running kernel’s config. For most new options, pressing Enter accepts the default value, which is safe for a first build.

Cross-Machine localmodconfig for Embedded Targets

A powerful feature for embedded Linux developers: you can generate a localmodconfig for a different target board. Run lsmod on the target, transfer the file to your build host, and generate a matching config there.

# On the target board:
lsmod > /tmp/target-modules.txt
scp /tmp/target-modules.txt buildhost:/tmp/

# On the build host (cross-compile scenario):
make LSMOD=/tmp/target-modules.txt localmodconfig

# Preserve specific subsystems even if not in the lsmod list:
make LSMOD=/tmp/target-modules.txt \
     LMC_KEEP="drivers/usb:drivers/gpu:fs" \
     localmodconfig

5. All Kernel Configuration Tools Compared

The kernel provides five different ways to view and edit the .config file. They all produce the same .config output — they just offer different user interfaces. As a student of this free Linux kernel development course, you should know all of them.

Kernel Configuration Tools Comparison
Command Interface Requires Best For
make config Plain text Q&A Nothing Scripting / automation
make menuconfig Text color menus (ncurses) libncurses-dev SSH & headless servers — most popular
make nconfig Enhanced text + F-keys libncurses-dev Cleaner terminal with shortcuts
make xconfig Graphical GUI (Qt) qtbase5-dev Desktop users, easy visual search
make gconfig Graphical GUI (GTK) libgtk-3-dev GNOME desktop users

6. Fine-Tuning Kernel Config with make menuconfig

Once you have a starting .config from localmodconfig or another source, use make menuconfig to browse and modify it visually. This is the core workflow skill for anyone doing Linux kernel development or writing Linux device drivers.

Install the Required Dependency

# Debian / Ubuntu / Linux Mint:
sudo apt-get install libncurses-dev

# Fedora / RHEL / Rocky Linux:
sudo dnf install ncurses-devel

# Arch Linux:
sudo pacman -S ncurses

Launch menuconfig

# From the root of the kernel source tree:
make menuconfig

# For a specific architecture (cross-compile / embedded):
make ARCH=arm64 menuconfig
make ARCH=arm menuconfig

The first time you run this, kbuild compiles a helper C program called mconf inside the kernel tree. This only happens once:

UPD  scripts/kconfig/.mconf-cfg
HOSTCC scripts/kconfig/mconf.o
HOSTCC scripts/kconfig/lxdialog/checklist.o
HOSTCC scripts/kconfig/lxdialog/menubox.o
HOSTCC scripts/kconfig/lxdialog/inputbox.o
HOSTLD  scripts/kconfig/mconf
scripts/kconfig/mconf  Kconfig

After that, the colorful menu screen appears immediately. Here is a representation of what the top-level menu looks like:

menuconfig Top-Level Menu (Conceptual View)
Arrow keys navigate. <Enter> selects submenus. <Y> includes, <N> excludes, <M> modularizes. Press </> to search.
▷ General setup —>
[*] 64-bit kernel
Processor type and features —>
Power management and ACPI options —>
Bus options (PCI etc.) —>
[*] Enable loadable module support —>
[*] Enable the block layer —>
IO Schedulers —>
[*] Networking support —>
Device Drivers —>
File systems —>
Security options —>
Kernel hacking —>
<Select>
<Exit>
<Help>
<Save>
<Load>

Keyboard Navigation Reference

menuconfig Keyboard Shortcuts
Key Action
↑ ↓ Arrow Move up / down through the menu list
Enter Enter a submenu (items shown with --->)
Y Set selected option to built-in (=y)
M Set selected option to module (=m)
N Disable the selected option
Space Toggle between Y / M / N
? Show help text for the highlighted option
/ Open search dialog — find any config symbol by name
Esc Esc Go back to previous menu or exit menuconfig

How to Search for a Config Option in menuconfig

This is one of the most useful skills in the entire free Linux kernel development course. When you know the name of a config symbol but not which submenu it lives under, use the built-in search:

# While inside menuconfig, press the / key
# Type your search term — example: USB_SERIAL
# menuconfig shows the option, its current value,
# its exact menu location, and all its dependencies

Search results show you the exact path through the menu tree where the option lives, so you can navigate directly to it. This saves enormous time when dealing with the thousands of options a real kernel has.

7. Other Important Config Targets Every Developer Should Know

Beyond localmodconfig and menuconfig, the kbuild system provides many more configuration targets essential for real-world free Linux device drivers development and embedded work.

# Start from the architecture's default configuration
make defconfig

# Like localmodconfig but sets all modules to built-in (=y)
# Ideal for embedded systems where you want everything baked in
make localyesconfig

# Update an existing .config for a new kernel version interactively
# Asks you about each NEW option added since your old config was made
make oldconfig

# Same as oldconfig but automatically accepts the default
# Best for automated CI builds or quick upgrades
make olddefconfig

# Produce the absolute smallest possible kernel (research/testing only)
make tinyconfig

# Add settings optimized for running Linux inside a KVM virtual machine
make kvm_guest.config

Config Workflow — Desktop Build vs Embedded Cross-Compile
💻 Desktop / Dev Machine
lsmod > /tmp/lsmod.now
make LSMOD=/tmp/lsmod.now
localmodconfig
make menuconfig
make -j$(nproc)
🔌 Embedded / Cross-Compile
Get BSP config from vendor
OR make ARCH=arm64 defconfig
make ARCH=arm64 \
menuconfig
Enable board drivers
Disable unused options
Cross-compile & Flash

8. Common Mistakes Beginners Make in Kernel Configuration

❌ Mistake 1: Running make before creating .config

If you run make without a .config file present, the build fails immediately with: *** Configuration file ".config" not found! Always generate or copy a config first.

❌ Mistake 2: Setting a boot-critical driver to =m

If you set the driver for your root filesystem or storage controller to module (=m), the kernel cannot mount root during boot. The system hangs with a kernel panic. Storage drivers and the root filesystem driver must always be =y.

❌ Mistake 3: Using make allyesconfig carelessly

make allyesconfig enables everything as built-in. The resulting kernel is hundreds of megabytes and will not boot on most real hardware due to conflicts. Use it only for compile-testing, never for a real machine.

❌ Mistake 4: Not backing up a working .config

Many students run make mrproper while troubleshooting and lose their carefully crafted configuration. Always back it up: cp .config ~/configs/working-$(uname -r)-$(date +%Y%m%d).config

❌ Mistake 5: Skipping make olddefconfig when upgrading kernel version

When you upgrade from kernel 6.6 to 6.12 with the same .config, new options from the newer kernel may be missing. Always run make olddefconfig first when reusing a config across different kernel versions.

9. Best Practices for Kernel Configuration

✅ Always start from a known-good base config

In production and embedded projects, your hardware vendor or BSP team provides a tested .config. In a learning build, start from localmodconfig or defconfig. Never start from scratch by manually editing .config — the dependency chains are too complex.

✅ Version-control your kernel configs

Treat your .config like source code. Keep it in a git repository. Name it clearly, for example rpi4-6.12-production.config. When a config produces a working kernel, tag that commit in git.

✅ Use make olddefconfig for kernel upgrades

Do not take a .config from kernel 6.6 and compile kernel 6.12 with it directly. Always run make olddefconfig first to populate all new symbols with safe defaults.

✅ Document your deliberate config changes

When you enable or disable a specific option for a reason (for example, enabling CONFIG_KGDB for kernel debugging), note it in your project README. Future-you will be grateful when debugging six months later.

10. Under the Hood — How Kconfig Works Internally

Every directory in the kernel source tree contains a Kconfig file. These files define the configuration options for that subsystem, their names, types, descriptions, dependencies, and defaults. When you run make menuconfig, kbuild reads all these files recursively and assembles the menu tree you see on screen.

When you save and exit, your choices go into .config. Before compilation starts, the build system generates two intermediate files that the C compiler and Makefiles actually use:

include/generated/autoconf.h
# C header auto-included in every kernel C file.
# CONFIG_SYSVIPC=y in .config becomes:
#   #define CONFIG_SYSVIPC 1

include/config/auto.conf
# Makefile fragment used by the build system.
# CONFIG_USB_SERIAL=m expands to: obj-m += usb-serial.o

This is how kernel developers write conditionally compiled code:

#ifdef CONFIG_SYSVIPC
    ipc_init();   /* only compiled when CONFIG_SYSVIPC=y */
#endif

/* IS_ENABLED() works for both =y and =m */
if (IS_ENABLED(CONFIG_USB_SERIAL)) {
    /* runs when USB serial is configured */
}

How Kconfig Feeds Into the Compiled Kernel
📄
Kconfig files
(one per subsystem directory)
⚙️
make menuconfig
reads Kconfig, shows menu, saves choices
📝
.config
CONFIG_XYZ=y
CONFIG_ABC=m
include/generated/autoconf.h
#define CONFIG_SYSVIPC 1
#define CONFIG_USB_SERIAL_MODULE 1
Used by: all kernel C source files
include/config/auto.conf
CONFIG_SYSVIPC=y
obj-$(CONFIG_USB_SERIAL) += …
Used by: kernel Makefiles

11. Quick Command Reference Card

# CLEAN THE SOURCE TREE
make mrproper          # Full clean, removes .config too
make distclean         # mrproper + removes editor backup files
make clean             # Remove objects only, keep .config

# GENERATE A STARTING .config
lsmod > /tmp/lsmod.now
make LSMOD=/tmp/lsmod.now localmodconfig   # Based on running system
make defconfig                              # Architecture defaults
make tinyconfig                             # Absolute minimum kernel

# BROWSE AND EDIT THE .config
make menuconfig        # Text menus (ncurses) — recommended
make nconfig           # Enhanced text menus with F-key shortcuts
make xconfig           # Qt-based graphical UI
make gconfig           # GTK-based graphical UI

# UPDATE .config FOR A NEWER KERNEL VERSION
make oldconfig         # Interactive — asks about new options
make olddefconfig      # Auto-accept defaults for new options

# SPECIAL TARGETS
make localyesconfig    # Like localmodconfig but =y instead of =m
make kvm_guest.config  # Optimized for KVM guest kernel
make xen.config        # Optimized for Xen dom0 guest

12. Summary and Key Takeaways

Kernel configuration is not just a setup step — it is a core skill for anyone in Linux kernel development, embedded Linux, or device driver writing. In this lecture from our free Linux kernel development course, you learned:

  • The .config file controls every aspect of what gets compiled. It is the most important file in your build.
  • Every option is either built-in (=y), a loadable module (=m), or disabled. Choosing correctly — especially for boot-critical drivers — determines whether your system boots at all.
  • make localmodconfig is the fastest way to get a lean, working starting config for your development machine.
  • make menuconfig is the standard tool for browsing and editing config. It works over SSH and has a powerful search function.
  • For embedded Linux work, the BSP vendor’s config is your starting point. Use make ARCH=arm64 menuconfig to tailor it for your board.
  • Always run make olddefconfig before building a newer kernel version with an existing config.
  • Back up any config that produces a working kernel. Treat it like source code.

🔗 Authoritative References and Further Reading

  • Official Linux Kernel Kconfig Documentation: docs.kernel.org/kbuild/kconfig.html
  • Linux Kernel 6.x README: www.kernel.org/doc/html/latest/admin-guide/README.html
  • Kernel Build System (kbuild) Documentation: docs.kernel.org/kbuild/index.html
  • Linux Kernel Makefiles Reference: docs.kernel.org/kbuild/makefiles.html
  • Kconfig Language Specification: docs.kernel.org/kbuild/kconfig-language.html

Frequently Asked Questions — Linux Kernel Configuration

Q1. What is the .config file and why is it needed in Linux kernel development?

The .config file is the kernel’s master configuration file. It is a plain text file containing hundreds of CONFIG_ options, each set to y (built-in), m (module), or left unset (disabled). Without it, the kernel cannot be compiled. Every free Linux kernel development course teaches this as the very first step before building.

Q2. What does make localmodconfig do and when should I use it?

make localmodconfig generates a .config based on the kernel modules currently loaded on your running system. It produces a lean config that includes only what your hardware actually needs. Use it when setting up a development kernel build on your own machine for a much faster build and smaller kernel image.

Q3. What is the difference between CONFIG_=y (built-in) and CONFIG_=m (module)?

A built-in option (=y) is compiled directly into the kernel image and is always available from boot. A module (=m) is compiled as a separate .ko file and can be loaded or unloaded at runtime. For boot-critical drivers like storage controllers, you must use =y. For optional hardware, =m gives flexibility without bloating the kernel image.

Q4. What is make menuconfig and why is it the most popular kernel configuration tool?

make menuconfig is a terminal-based color menu system for browsing and editing the kernel configuration. It is the most popular tool because it works in any terminal including SSH sessions to remote servers, and requires no graphical desktop. It also features a search function — press / — to find any config option by name instantly.

Q5. What is make mrproper and when should I use it?

make mrproper removes all generated files from the kernel source tree including the .config file and all compiled objects. Use it when starting a completely fresh build from scratch. Always back up your .config before running it since the deletion is permanent.

Q6. How do I update my .config when upgrading to a newer kernel version?

Run make olddefconfig from the root of the new kernel source tree with your existing .config in place. This automatically accepts default values for all new config options introduced in the newer kernel. If you want to manually review each new option, use make oldconfig instead.

Q7. Where do Kconfig files live and what do they do?

Kconfig files are present in almost every directory of the kernel source tree. Each one defines the configuration options for that subsystem, including their names, types, descriptions, default values, and dependencies on other options. When you run make menuconfig, kbuild reads all these files recursively to build the menu tree.

Q8. In embedded Linux development, where does the initial kernel config come from?

In embedded projects, the initial .config typically comes from the hardware vendor or BSP team. It is a tested, known-good configuration for the specific platform. If no vendor config is available, start with make ARCH=arm64 defconfig to get architecture defaults, then use make ARCH=arm64 menuconfig to enable board-specific drivers.

Q9. What is the difference between make nconfig and make menuconfig?

Both use an ncurses-based terminal interface. nconfig displays function key shortcuts at the bottom of the screen making navigation more discoverable, and has a slightly cleaner layout. For most purposes they are equivalent and both require libncurses-dev to be installed.

Q10. Is this free Linux kernel development course suitable for complete beginners?

Yes. EmbeddedPathashala’s free Linux kernel development course starts from fundamentals — setting up the build environment, downloading kernel source, understanding the source tree structure — and progressively builds up to writing actual kernel modules and device drivers. Basic Linux command line familiarity is expected, but no prior kernel experience is required.

← Previous Lecture
Lecture 14 — Configuring the Linux Kernel
Next Lecture →

EmbeddedPathashala — Free Embedded Systems Education
Free Linux Kernel Development Course — Lecture 14 — Updated for Kernel 6.x

Leave a Reply

Your email address will not be published. Required fields are marked *