L24: How to Add a Custom Kconfig Option to the Linux Kernel

 

How to Add a Custom Kconfig Option to the Linux Kernel
Chapter 2 — Linux Kernel Configuration (Part 4 of 5) — Updated for Linux 6.x
📚 100% Free Course
⚙ Linux Kernel 6.x
🔥 Hands-On Lab
🎓 Interview Q&A

🏷 What You Will Learn in This Tutorial

Custom CONFIG_ Symbol
Kconfig bool / tristate
init/Kconfig editing
make menuconfig
autoconf.h generation
IS_ENABLED() macro
obj-$(CONFIG_FOO) Makefile
depends on / select
Linux 6.x kbuild

Why This Topic Matters

Every feature inside the Linux kernel — from USB drivers to network protocols to file systems — is guarded by a CONFIG_ symbol. When you write kernel code for a product, one of the first things you do is create your own symbol so users can turn your feature on or off without touching any C code.

This tutorial teaches you exactly that. You will add a custom Boolean configuration option to the kernel from scratch, see it appear in make menuconfig, watch it flow into autoconf.h, and then use it correctly inside kernel C code. Everything here is tested against Linux 6.x and reflects the current kernel coding style guide.

If you are preparing for a Linux kernel developer interview, or if you are doing a project that involves custom kernel features, this tutorial is essential reading.

📷 Suggested Image for This Section

Insert a screenshot of make menuconfig with the General Setup submenu open and a custom option highlighted. Alt text: “make menuconfig showing a custom CONFIG_ option in General Setup menu — Linux kernel tutorial”. File name: menuconfig-custom-kconfig-linux-kernel.png.

1. The Big Picture — What Happens When You Add a Config Option

Before touching any file, understand the full journey a Kconfig symbol takes from definition to C code. This is the pipeline every kernel developer must know:

Kconfig Symbol Pipeline — From Definition to C Macro
① Kconfig File
init/Kconfig
② menuconfig
User enables option
③ .config
CONFIG_FOO=y written
④ make build
kbuild reads .config
⑤ include/generated/autoconf.h
#define CONFIG_FOO 1 is generated here
⑥ Kernel C Source
IS_ENABLED(CONFIG_FOO) used in code

Each arrow in the diagram above represents a different tool or build step. Understanding this pipeline means you will never be confused about why a change in Kconfig does not immediately show up in your C code — there are specific steps in between.

2. Choosing the Right Kconfig File to Edit

The kernel source tree has a Kconfig file in nearly every directory. The rule is simple: edit the Kconfig file in the same directory as your source file. The top-level configuration menu is built by recursively including all these files.

Which Kconfig File Controls Which Menu?
Your Code Location Kconfig File to Edit Menu It Appears In
init/ init/Kconfig General Setup
drivers/char/ drivers/char/Kconfig Device Drivers → Character devices
net/myproto/ net/myproto/Kconfig Networking Support
arch/x86/ arch/x86/Kconfig Processor type and features
security/ security/Kconfig Security options
fs/myfs/ fs/Kconfig File systems

For this tutorial we will work inside init/Kconfig because we are adding a general-purpose demo option to the General Setup menu — the same menu that holds global kernel build knobs like the local version string and build ID salt.

3. Step-by-Step: Adding a Custom Boolean CONFIG_ Symbol

We will create a config option called CONFIG_EP_MYFEATURE. The EP_ prefix is our own namespace. In a real product you should always use a prefix that identifies your team or company — this prevents name collisions with upstream kernel options, which could cause extremely confusing build failures.

① Back Up the File Before Editing

Kconfig files are indentation-sensitive. A single wrong tab can break the entire configuration menu. Always back up first:

cp init/Kconfig init/Kconfig.bak

If anything goes wrong, you can restore with cp init/Kconfig.bak init/Kconfig.

② Open the Kconfig File and Find a Good Insertion Point

Open init/Kconfig in any text editor. Scroll through the file to find the area after LOCALVERSION_AUTO and before BUILD_SALT. This is a clean, logical place for a new general setup entry.

vim init/Kconfig

Use /LOCALVERSION_AUTO inside vim to jump directly to that line. Then move a few lines down and prepare to insert.

③ Write Your Kconfig Entry

Insert this block at the chosen location. Use a real Tab character for indentation — not spaces. We will break down each keyword in Section 5.

config EP_MYFEATURE
	bool "Enable My Custom Feature (EmbeddedPathashala demo)"
	default n
	help
	  This is a demonstration Kconfig option for the
	  EmbeddedPathashala Linux kernel programming course.

	  When enabled, the kernel includes ep_myfeature.c
	  at build time.

	  If unsure, say N.

⚠ Tab Indentation Warning

Kconfig files require real tab characters for indentation. Spaces will cause a parse error that is hard to debug. After saving, verify with:

cat -A init/Kconfig | grep -A5 "EP_MYFEATURE"

You should see ^I (the tab symbol) at the start of each indented line. If you see spaces instead, fix the indentation before proceeding.

④ Launch menuconfig and Enable Your Option

Save and exit the editor, then run the configuration interface:

make menuconfig

Navigate to General Setup. Scroll down until you see Enable My Custom Feature. Press Space to toggle it on — you will see [*] appear. Press Esc Esc to exit the submenu and choose Yes when asked to save.

💡 Pro Tip — Use the Search

Press / inside menuconfig to open the search box. Type EP_MYFEATURE and press Enter. menuconfig will jump directly to your option no matter where it is in the tree. This is the fastest way to find any option in the kernel’s thousands of configuration entries.

⑤ Check the .config File

After saving from menuconfig, verify the option was recorded:

grep "EP_MYFEATURE" .config

When enabled you should see:

CONFIG_EP_MYFEATURE=y

When disabled you will see:

# CONFIG_EP_MYFEATURE is not set

The .config file is the source of truth for your build. The actual C header has not been generated yet — that happens in the next step.

⑥ Build the Kernel and Check autoconf.h

Run the kernel build. Use -j$(nproc) to utilise all CPU cores — this is the modern recommended approach for Linux 6.x builds, much faster than the old -j4 hardcoded in older examples:

make -j$(nproc)

Once the build completes, check the auto-generated header:

grep "EP_MYFEATURE" include/generated/autoconf.h

Expected output:

#define CONFIG_EP_MYFEATURE 1

This #define is what your kernel C code will see. The kbuild system generates this file automatically from .config during every build.

4. Wiring Your Config Symbol into the Makefile

Having the symbol defined is only half the job. You also need to tell the build system which source file to compile when the option is enabled. This is done with a single line in the Makefile that lives alongside your source code.

Suppose your feature code lives in init/ep_myfeature.c. Add this line to init/Makefile:

obj-$(CONFIG_EP_MYFEATURE)  +=  ep_myfeature.o

Anatomy of the kbuild Conditional Compile Line

obj-

Tells kbuild this is a build target. obj-y links into the kernel image. obj-m builds as a module.

+

$(CONFIG_EP_MYFEATURE)

Expands to y, m, or empty string at build time, depending on the user’s choice.

=

ep_myfeature.o

kbuild compiles ep_myfeature.c when the variable is non-empty; completely ignores it otherwise.

What obj-$(CONFIG_EP_MYFEATURE) Expands To
.config value Makefile expands to Build result
CONFIG_EP_MYFEATURE=y obj-y += ep_myfeature.o Compiled and linked directly into the kernel image (vmlinux)
CONFIG_EP_MYFEATURE=m obj-m += ep_myfeature.o Built as a loadable module: ep_myfeature.ko
Option disabled (absent) obj- += ep_myfeature.o → ignored Source file not compiled at all

5. Using Your Config Symbol in Kernel C Code

Once autoconf.h is generated, your CONFIG_ symbol is available as a C preprocessor macro. There are two ways to use it, but the kernel community has a strong, documented preference for one over the other.

#ifdef vs IS_ENABLED() — Side by Side Comparison

✘ #ifdef — Avoid in Kernel Code

#ifdef CONFIG_EP_MYFEATURE
    ep_do_my_thing();
#endif

Problems:

Disabled code is never type-checked
Compiler never sees it when off
Bugs hide silently for years
API changes go undetected

✔ IS_ENABLED() — Preferred in Linux 6.x

if (IS_ENABLED(CONFIG_EP_MYFEATURE)) {
    ep_do_my_thing();
}

Benefits:

Compiler always parses both branches
Full type-checking even when disabled
Zero runtime overhead (constant-folded)
Handles tristate y/m/n correctly

IS_ENABLED() is defined in include/linux/kconfig.h. It evaluates to 1 or 0 at compile time. Because the compiler knows it is a compile-time constant, it eliminates the dead branch during optimisation, giving you exactly the same binary output as #ifdef — but with the safety of always compiling both paths.

The Three IS_ Macros — When to Use Each
Macro True when Use case
IS_ENABLED(CONFIG_FOO) CONFIG_FOO is y or m Most common. Use when you do not care whether it is built-in or a module.
IS_BUILTIN(CONFIG_FOO) CONFIG_FOO is exactly y When your code needs early-boot access or must be in the kernel image itself.
IS_MODULE(CONFIG_FOO) CONFIG_FOO is exactly m When behaviour differs between built-in and module mode (e.g., init ordering).

6. Kconfig Language Reference

Kconfig has a small but expressive language. You do not need to memorise all of it — but knowing the most common constructs means you can read any driver’s Kconfig entry and understand what it is doing.

Kconfig Entry Types (Data Types)
Keyword States .config value Use when
bool on / off =y or absent Feature that cannot be a module (early boot code, core subsystems)
tristate built-in / module / off =y, =m, or absent Drivers, filesystems, protocols — anything that can be a loadable module
int numeric value =4 (example) Tunable numbers like queue depths, buffer sizes, retry counts
hex hex value =0x1000 (example) Addresses, masks, hardware register values
string text ="v1.2" (example) Version suffixes, device name strings

Common Kconfig Attributes and What They Do
Attribute Purpose Example
default n / default y Default value when the user has not explicitly chosen. Almost always n for new options. default n
depends on X Your option is hidden and cannot be enabled until X is already enabled. Forward dependency. depends on NET && INET
select X When your option is enabled, X is force-enabled too. Reverse dependency. Use only for invisible helper libraries. select CRYPTO_AES
imply X Suggests enabling X when your option is on, but the user can still turn X off. Weaker than select. imply SOME_HELPER
range min max Restricts valid values for int or hex types. range 1 64
help Multi-line help text shown when the user presses <Help> in menuconfig. Very important — write this well. See full example below

depends on vs select — The Key Difference

depends on X

Direction: Forward (X must already be on for you to appear)

Control: User controls X independently

If X is off: Your option is hidden from the menu entirely

Use for: Optional prerequisites — networking stack, crypto API, architecture-specific hardware

vs

select X

Direction: Reverse (you force X on when you enable yourself)

Control: User cannot turn X off while you are on

If you are on: X is force-enabled regardless of user preference

Use for: Invisible helper libraries your code absolutely requires (e.g., CRYPTO_SHA256 for a driver that hashes packets)

7. A Complete Realistic Kconfig Entry with Dependencies

Here is what a production-quality Kconfig entry looks like for a tristate network monitoring driver. Study this carefully — this is the pattern you will use when writing real kernel code:

menu "EmbeddedPathashala Kernel Features"

config EP_NET_MONITOR
	tristate "EP Network Packet Monitor"
	depends on NET && INET
	select CRYPTO_SHA256
	default m
	help
	  Enables the EmbeddedPathashala network packet monitor.
	  This driver inspects incoming packets and logs statistics
	  to the kernel ring buffer via printk.

	  Requires the networking stack (NET and INET).
	  Automatically enables SHA-256 support for packet hashing.

	  To compile as a loadable module choose M here.
	  The module will be called ep_net_monitor.ko

	  If unsure, say N.

endmenu

💡 Why Write Good Help Text?

The help section is read by engineers who are trying to decide whether to enable your feature on their system. Explain what the feature does, what it depends on, what the performance or security implications are, and what the safe default is. Poor help text leads to configuration mistakes that are hard to debug.

8. Complete Workflow Cheat Sheet

Here is the entire sequence consolidated for quick reference whenever you add a new config option to a real project:

# 1. Back up the Kconfig file
cp init/Kconfig init/Kconfig.bak

# 2. Add your config block (using tabs for indentation)
vim init/Kconfig

# 3. Launch menuconfig and enable your option
make menuconfig

# 4. Confirm .config was updated
grep "EP_MYFEATURE" .config
#  → CONFIG_EP_MYFEATURE=y

# 5. Build the kernel (use all CPU cores)
make -j$(nproc)

# 6. Confirm autoconf.h was generated
grep "EP_MYFEATURE" include/generated/autoconf.h
#  → #define CONFIG_EP_MYFEATURE 1

Corresponding Makefile line (in the directory with your .c file):

obj-$(CONFIG_EP_MYFEATURE)  +=  ep_myfeature.o

Usage in kernel C code (the preferred way):

#include <linux/kconfig.h>
#include <linux/printk.h>

static int __init ep_feature_init(void)
{
        if (IS_ENABLED(CONFIG_EP_MYFEATURE)) {
                pr_info("EP: My feature is active\n");
                ep_do_my_thing();
        }
        return 0;
}
module_init(ep_feature_init);

9. Linux 6.x vs Older Kernels — What Changed

Linux 6.x vs Older Kernels — Kconfig and Build System Changes
Topic Older Kernels (4.x / 5.x) Linux 6.x
Kconfig syntax Core syntax identical Same. imply keyword (added 4.x) is now widely used in driver Kconfigs.
Build parallelism Examples used make -j4 Use make -j$(nproc). Detects CPU count automatically. Much faster on modern hardware.
IS_ENABLED() Available since 3.x, optional Strongly preferred. Kernel style guide explicitly discourages #ifdef in favour of IS_ENABLED().
Compiler support GCC primary, Clang experimental Clang/LLVM is a first-class supported compiler. IS_ENABLED() and all Kconfig macros work identically with both.
autoconf.h path include/generated/autoconf.h Unchanged. This path has been stable since kernel 3.x.
menuconfig interface ncurses text UI Same. make xconfig (Qt5) and make nconfig are also available and work well in 6.x.
Kconfig warning level Many warnings ignored 6.x kbuild treats Kconfig warnings more strictly. Duplicate entries and missing dependencies cause build warnings you should fix.

📷 Suggested Image for Section 9

A side-by-side terminal screenshot showing make -j4 on an older system vs make -j$(nproc) on a 16-core machine to illustrate the performance difference. Alt text: “Linux kernel build with make -j$(nproc) for parallel compilation — Linux 6.x tutorial”. File name: linux-kernel-make-jnproc-parallel-build.png.

❓ Frequently Asked Questions (FAQ)

What is the difference between a Kconfig file and a .config file?

A Kconfig file is a declaration file written by the kernel developer. It defines what options exist, their types, default values, dependencies, and help text. There are hundreds of Kconfig files across the kernel source tree, one per subsystem. The .config file is the user’s configuration record — it stores the choices the user made when running make menuconfig. The .config file is in the kernel root directory and is read by the build system. Kconfig files are read-only from the user’s perspective; .config is what changes when you configure the kernel.

Why is my new Kconfig option not showing up in menuconfig?

The most common reasons are: (1) You have a depends on X clause and X is not enabled — navigate to X and enable it first. (2) Your entry is inside a menu ... endmenu block that is collapsed — expand it. (3) There is a syntax error in your Kconfig entry (wrong indentation, missing tab) — run make menuconfig from the terminal and look for error messages printed before the UI launches. (4) You edited the wrong Kconfig file — double-check which menu your file belongs to and which Kconfig file controls that menu.

Can I add a Kconfig option without rebuilding the entire kernel?

Yes, partially. You can add the entry to the Kconfig file, run make menuconfig to update .config, and then run make -j$(nproc). The build system is incremental — it only recompiles files that changed. If your new option only adds one new source file, only that file and any modules that depend on it will be rebuilt. The full kernel image will be re-linked, but the compilation step is minimal.

What is the difference between select and depends on in Kconfig?

depends on X is a forward dependency: your option only appears in the menu when X is already enabled. select X is a reverse dependency: when the user enables your option, X is automatically enabled too. The kernel style guide recommends using select only for invisible low-level helper libraries (like crypto implementations) that users would not want to manage manually. For anything users might want independent control over, use depends on instead.

Is it safe to use select in Kconfig?

Use select with caution. When you select X, you force X to be enabled regardless of whether X’s own depends on clauses are satisfied. This can create dependency loops and inconsistent configurations. The rule of thumb: only use select for options that have no dependencies themselves (leaf nodes in the dependency graph). For anything complex, prefer depends on and let the user resolve dependencies explicitly.

🎓 Interview Questions and Answers

Q1. What is a CONFIG_ symbol in the Linux kernel? Where is it defined and where is its value stored?
A CONFIG_ symbol is a kernel configuration variable produced by the Kconfig system. It is declared inside a Kconfig file using the config keyword — this is where the developer specifies the type, default, dependencies, and help text. The user’s chosen value is recorded in the .config file at the kernel root directory. When the kernel is built, the build system reads .config and generates include/generated/autoconf.h, which converts each symbol into a C preprocessor #define macro that kernel source code can use.
Q2. What is the difference between bool and tristate in Kconfig? When would you choose one over the other?
A bool option has exactly two states: enabled (y, compiled into the kernel) or disabled (absent from .config). A tristate option has three states: built-in (y), compiled as a loadable module (m), or disabled. Choose bool for code that must be part of the kernel image at boot time — such as early init code, core memory management, or architecture-specific boot routines that cannot be deferred to a module. Choose tristate for device drivers, filesystems, network protocols, and any feature that makes sense to load on-demand after boot, such as a USB driver or a filesystem like NTFS.
Q3. Why does the Linux kernel community prefer IS_ENABLED() over #ifdef for guarding CONFIG_ symbols in C code?
With #ifdef CONFIG_FOO, the compiler completely skips the enclosed block when the option is disabled. This means type errors, wrong function signatures, missing struct members, and obsolete API calls inside the block are never detected by the compiler — they accumulate silently until someone enables the option and discovers a broken build. IS_ENABLED(CONFIG_FOO) evaluates to a compile-time integer constant (0 or 1), which means the compiler always parses and type-checks both the true and false branches. Because it is a compile-time constant, the compiler’s optimiser eliminates the dead branch, so the generated machine code is identical to #ifdef. You get full type safety with zero runtime cost.
Q4. Explain the line obj-$(CONFIG_EP_MYFEATURE) += ep_myfeature.o in a kernel Makefile.
This is kbuild’s standard pattern for conditional compilation. The variable $(CONFIG_EP_MYFEATURE) is expanded by make at build time using the contents of the .config file. When CONFIG_EP_MYFEATURE=y, the variable expands to y and the full line becomes obj-y += ep_myfeature.o, which instructs kbuild to compile ep_myfeature.c and link it into the kernel image. When the value is m, the line becomes obj-m += ep_myfeature.o and kbuild builds a loadable module ep_myfeature.ko. When the option is disabled, the variable expands to an empty string and kbuild produces the invalid-but-ignored obj- which it simply skips. The source file is not compiled at all.
Q5. What is the difference between depends on and select in Kconfig? When should you use each?
depends on X is a forward dependency. Your option is hidden in the menu and cannot be enabled until X is already enabled by the user. This gives the user full control over X. select X is a reverse or forced dependency. When your option is enabled, X is automatically enabled regardless of any other setting. The key danger with select is that it bypasses X’s own depends on constraints, potentially creating an inconsistent or broken configuration. The kernel community’s guidance is to use select only for invisible leaf-node helper libraries — for example, a driver that needs a specific crypto algorithm can select CRYPTO_SHA256. For anything a user would care about independently, always prefer depends on.
Q6. After enabling a CONFIG_ option in menuconfig and saving, why does grep show nothing in include/generated/autoconf.h?
include/generated/autoconf.h is not written by menuconfig. It is a file generated by the kbuild build system during the compilation phase. menuconfig only writes to .config. The actual header is generated the first time you run make after changing the configuration. Until then, the symbol exists in .config as a text line but has not yet been translated into a C preprocessor macro. This is a common source of confusion: always run a build after changing configuration before checking autoconf.h.
Q7. What are IS_BUILTIN() and IS_MODULE() and how do they differ from IS_ENABLED()?
IS_ENABLED(CONFIG_FOO) returns true (1) when CONFIG_FOO is either y or m — that is, when the feature is present in any form. IS_BUILTIN(CONFIG_FOO) returns true only when CONFIG_FOO=y, meaning the code is directly compiled into the kernel image. IS_MODULE(CONFIG_FOO) returns true only when CONFIG_FOO=m, meaning it is a loadable module. These distinctions matter when a subsystem needs to register early-boot callbacks or use facilities that are only available to built-in code, or conversely when a module needs to handle its own init/cleanup lifecycle differently from built-in code.
Q8. How do you find a specific CONFIG_ option quickly in make menuconfig without scrolling through thousands of entries?
Press the forward-slash key / while inside menuconfig to open the built-in search dialog. Type the config symbol name without the CONFIG_ prefix — for example, type USB_STORAGE to find CONFIG_USB_STORAGE. Press Enter and menuconfig displays all matching entries, their current state (enabled or disabled), and their full menu path. You can select any result to jump directly to it. This works much faster than navigating the tree manually and is especially useful in large subsystems like networking or storage that have hundreds of related options.

Free Linux Kernel Programming Course — No Paywalls, No Ads

EmbeddedPathashala is a completely free resource for engineering students and working professionals who want to learn Linux kernel development, device drivers, and embedded systems from the ground up. Every tutorial is hands-on and updated for modern kernels.

📚 Full Course Index
📚 All Kernel Config Tutorials
📚 Linux Device Drivers Series

Tags:
Kconfig
Linux Kernel 6.x
CONFIG_ symbol
menuconfig
IS_ENABLED
kbuild
kernel configuration
free linux kernel development course
embedded systems tutorial
free device drivers course
EmbeddedPathashala

Leave a Reply

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