Kconfig for new kernel module
Kernel Development
William Patterson  

Use Kconfig for New Kernel Module

You want a clear path to add a configuration option that shows up in menuconfig and builds cleanly without wasted rebuilds.

I’ll walk you through a compact, practical approach that ties a tiny example driver into the kernel configuration, so the symbol appears where it should and obeys dependencies.

We’ll cover the essential config and menu keywords and show how to compile Image.gz and modules, install them, and verify behavior with modinfo, insmod, and dmesg.

Along the way, I point out common pitfalls—hidden options, recursive dependency traps, and misuse of select—so you avoid surprises when shipping code.

Table of Contents

Key Takeaways

  • Define a clear config symbol and prompt so it appears in menuconfig.
  • Wire the option into Kbuild and verify build targets like Image.gz and modules.
  • Use modinfo, lsmod, and dmesg to confirm runtime behavior.
  • Avoid hidden dependency traps and careless use of select.
  • Keep prompts and help text concise to aid maintainability and review.

What this How-To covers and why Kconfig matters for kernel modules

I’ll lay out what this guide covers and why an organized configuration layer controls what gets built and what can be loaded later. You’ll get a compact, practical path from writing a tiny driver to exposing a clear option in the menu and managing dependencies.

We walk end-to-end: authoring a small source file, defining a config symbol, wiring build rules, compiling, installing, and loading the result on a running system.

Why this matters: the config system decides if a feature is built-in (y), built as a module (m), or disabled (n). That choice gives you flexibility—no need to rebuild the entire image when you want dynamic loading via modprobe or insmod and safe unloads with rmmod.

Build modeMeaningUser impact
yBuilt-inNo runtime load/unload
mAs modulesLoadable, smaller image
nDisabledHidden in menus

Clear dependencies keep the UI tidy by hiding options that won’t work on a given platform. I’ll also show how to write concise prompt and help text so users find the right option in menuconfig and avoid surprising reverse dependencies.

Prerequisites, tooling, and source layout for a clean start

A tidy tree and predictable build targets make iterating on a small driver fast and safe. Start by placing your primary source under drivers/misc/ and add entries alphabetically to drivers/misc/Kconfig and drivers/misc/Makefile.

You’ll need a working kernel source, common build essentials, and permission to install modules—use sudo when calling modules_install. Keep one user account with sudo access for installs and testing in your VM or target system.

Use standard make targets: make -C “$IIO_TREE” menuconfig, make -C “$IIO_TREE” -j$(nproc) Image.gz modules, and make -C “$IIO_TREE” modules_install. When changing just your directory, run make -C “$IIO_TREE” M= to rebuild only that area.

  • Use obj-$(CONFIG_FOO) += foo.o in the Makefile.
  • Keep Kconfig and Makefile entries alphabetical to aid reviewers.
  • After install, run depmod and validate with modinfo, lsmod, and dmesg.

One last tip: ensure the running kernel version matches the installed .ko path to avoid undefined behavior. Small edits, M= builds, copy .ko, depmod, and test—repeat quickly.

Fast path: create, configure, build, and load a simple example module

Let’s get a working example running quickly: create a tiny C file, expose a tristate config symbol, and load the built object to verify the full path.

Author a tiny file and minimal init/exit code

Create simple_mod.c with these includes: <linux/module.h> and <linux/init.h&gt.

Define module_init and module_exit and use pr_info in both functions so dmesg shows init and exit messages.

Enable the symbol and save .config

Add this entry under drivers/misc/Kconfig: config SIMPLE_MOD, tristate, default n, and a brief help paragraph. In drivers/misc/Makefile add:

  • obj-$(CONFIG_SIMPLE_MOD) += simple_mod.o

Run menuconfig, search SIMPLE_MOD, set it to m, and save the .config used by the build.

Build, install, and verify the path

Build with: make -C “$IIO_TREE” -j$(nproc) Image.gz modules. Then run modules_install and depmod so modprobe can find your .ko.

Check metadata and load status with modinfo and lsmod. Use dmesg to see the pr_info lines from init and exit.

Unload and reload to validate lifecycle

Remove using rmmod or modprobe -r, then reload with modprobe (preferred) or insmod if you need a direct path. Iterate by rebuilding with M= to speed edits.

Kconfig building blocks: keywords, entries, and menu structure

Understanding the minimal set of directives makes the config tree predictable and easy to scan. I map each keyword to a clear role so UI rendering matches intent.

  • config — defines a symbol and its type.
  • menuconfig — creates a visible parent that groups related entries.
  • choice/endchoice — enforces one selection among many.
  • menu/endmenu, comment — structure and guidance, shown only when dependencies apply.
  • if/endif — applies a dependency to all nested items to avoid repetition.
  • source — pulls in other files unconditionally to keep files tidy.
KeywordRoleRendering note
configDefines a symbolShows as selectable entry
menuconfigGroup visible optionsSubentries must depend on the menu symbol
choiceMutual exclusionFront ends show radio-style options
if/endifScoped dependencyApplies to all nested entries

Help text matters — use it to explain y/m/n choices and warn about side effects. Keep names and prompts consistent so menu entries stay discoverable as the tree grows.

Defining a config symbol with prompt, help text, and default value

Design the symbol so it is descriptive and predictable in the config UI. Start with a clear name and a user-friendly prompt that matches nearby entries. A concise prompt helps users find the option quickly.

Choose the right type: use tristate when you want y/m/n values. Tristate is ideal when building as a module speeds iteration and keeps the image small. Use bool when the option must be built-in (y/n) or when modular loading is not applicable.

Set a safe default. Prefer default n unless the value is widely useful and harmless. You can also use conditional defaults like default m if … to favor modular builds on common setups.

Use depends on to hide an option until prerequisites are met—this improves discoverability and avoids errors. Avoid select unless you must force a symbol to y; it bypasses normal checks and can cause surprising results.

Practical checklist

  • Write a short prompt and clear help text that explains y vs m vs n.
  • Prefer tristate when modular support is useful; use bool for core bits.
  • Pick a safe default value and document rationale in help.
  • Use depends on to enforce prerequisites; use select sparingly.
AttributeWhen to useEffect
tristateDriver that can be modulary/m/n values
boolAlways-on core featuresy/n values
defaultSets initial choiceControls saved .config value

Wire-up in Kbuild: Makefile entries and object output control

Linking a config symbol to build rules is what turns a menu entry into real output you can test. I keep the Makefile lines tiny and explicit so a change in the config reliably changes which files compile.

Use the obj-$(CONFIG_FOO) += foo.o pattern to connect a config name to the object file. Place that line in the directory Makefile and keep entries alphabetical—this helps reviewers and avoids merge churn.

When iterating, compile only your subtree with: make -C “$IIO_TREE” M=drivers/misc/. Run modules_prepare if you add exported headers or change interfaces so autogenerated files are current.

  • CONFIG_FOO toggles foo.o; the installed .ko lands under the matching path.
  • Switching m ↔ y changes linkage and final output — verify by toggling the option and rebuilding.
  • For multi-file units list each .o or use foo-y / foo-m as the codebase grows.
ActionEffectTip
obj-$(CONFIG_…)Controls object inclusionKeep alphabetical
M=Partial build of a subtreeSaves time when editing
modules_prepareUpdates headers/autogenRun after interface changes

Kconfig for new kernel module

I place the tristate symbol beside the C file so the option, object, and menu stay together. This keeps review simple and makes the path from prompt to .ko obvious.

Add an entry in drivers/misc/Kconfig with a clear prompt, short help text, and tristate. Then add this line to the directory Makefile:

  • obj-$(CONFIG_SIMPLE_MOD) += simple_mod.o

Open menuconfig and search (/) for the symbol. Set it to m, save .config, and rebuild modules. Use a partial build (M=…) during development to speed iterate cycles.

Verify end-to-end: run modules_install, depmod, then check metadata with modinfo and load with modprobe. If other features are required, add depends on so the option only appears when prerequisites exist.

ActionTarget fileTip
Add config entrydrivers/misc/KconfigKeep prompt concise
Makefile linkagedrivers/misc/MakefileUse obj-$(CONFIG_…) += file.o
Verify.config & .koSearch, set to m, save, rebuild
TestInstalled .komodinfo + modprobe to validate

Controlling visibility and behavior with depends on and select

Good dependency design keeps the config UI tidy and prevents link-time surprises. I use depends on to hide symbols unless the platform or build coverage makes them sensible.

Prefer expressions like depends on ARCH_FOO_VENDOR || COMPILE_TEST so CI compiles the code even when hardware is absent. For optional pieces, use the BAR || !BAR pattern. That prevents your option being forced built-in while BAR is only modular.

Avoid select except for leaf symbols that truly must be y. Select forces a symbol to y and bypasses other dependency checks — that creates surprising dependency chains and hidden build failures.

  • Define helper symbols when many drivers share a pattern.
  • Reflect runtime constraints in depends expressions and document stubs when !BAR applies.
  • Verify by toggling y/m/n on both sides to catch link issues early.
PatternWhen to useEffect
ARCH_FOO_VENDOR || COMPILE_TESTCI + platform coverageBuilds in CI, hides on wrong arch
BAR || !BAROptional dependencyKeeps y/m combinations valid
select LEAFLeaf, no depsForces y, bypasses checks — use rarely
helper symbolShared complex rulesSimplifies maintenance and review

Using menuconfig, nconfig, and xconfig effectively

A few small habits—searching prompts, jumping from results, and diffing configs—cut guesswork when adjusting options.

Use menuconfig when you want a straightforward TUI. Try nconfig or xconfig when you need richer search and navigation.

Search and jump tricks

In nconfig press “/” to search menu prompts and F8 to search by symbol. Results show linked numbers—press the number to jump straight to that entry.

Track what changed

Run make listnewconfig to list added options since your last .config. Use make oldconfig to step through prompts interactively.

After that, run scripts/diffconfig .config.old .config to review differences before committing.

  • Keep your .config under version control so changes are auditable by other users.
  • If your .config is a symlink, set KCONFIG_OVERWRITECONFIG to preserve it when saving.
  • Search both by symbol name and by prompt text when a name is not obvious.
  • Always save before exiting—choices don’t apply until the file is written.
ToolBest useTip
menuconfigQuick TUI editsSimple navigation
nconfigPrompt and symbol searchUse “/” and F8 to jump
xconfigGUI editsGood for visual review of entries

Environment variables that streamline kernel configuration

A handful of environment variables make automated config workflows reliable and auditable. I use them to pin which config file to read, seed randconfig runs, and control how autogenerated files are written.

KCONFIG_CONFIG and miniconfig workflows

Set KCONFIG_CONFIG to point at an alternate config file when you maintain multiple target profiles. This lets a user or CI pick a specific config file without interactive edits.

KCONFIG_ALLCONFIG can point to a tiny miniconfig that seeds an all*config flow. A small file with a few pinned options will expand into a full .config deterministically.

Seeding randconfig and tuning probabilities

Use KCONFIG_SEED to make randconfig runs reproducible in CI. Record the seed alongside logs so failures are debuggable later.

KCONFIG_PROBABILITY biases how often values land on y/m/n — a handy way to stress uncommon option combinations during testing.

Syncconfig and autogenerated file control

Set KCONFIG_NOSILENTUPDATE to force explicit confirmation when saved values change. That avoids surprise updates in shared trees.

Redirect outputs with KCONFIG_AUTOCONFIG and KCONFIG_AUTOHEADER when your build expects different paths for auto.conf and autoconf.h.

  • Keep miniconfigs small and documented—note which values must stay fixed and which can float.
  • Store seeds and probability strings with CI logs to reproduce test runs later.
  • Combine these variables with listnewconfig and diffconfig to track what changed and why.
VariablePrimary useTip
KCONFIG_CONFIGAlternate config fileName configs per target
KCONFIG_ALLCONFIGMiniconfig seedPin a few critical options
KCONFIG_SEED / PROBABILITYDeterministic randconfigLog seed and ratio
KCONFIG_AUTOCONFIG / AUTOHEADEROutput pathsMatch CI layout

Module lifecycle: building, installing, and dependency resolution

Let’s pin down the lifecycle: how a build turns source into installed artifacts and how to verify they load cleanly. I focus on the practical commands and quick checks I use during development.

Build and stage

Run make -C “$IIO_TREE” -j$(nproc) Image.gz modules to keep ABI alignment between image and modules. Then install with make -C “$IIO_TREE” modules_install so tools like modprobe can find the installed files.

Prepare and refresh metadata

If you change exported headers or build only a subtree, run make -C “$IIO_TREE” modules_prepare first. After copying a .ko during quick iterations, run depmod –quick to refresh dependency metadata.

  • Use modinfo to inspect metadata and detect required firmware or symbols.
  • Prefer modprobe over insmod — modprobe resolves dependencies via modules.dep.
  • Check dmesg after load/unload to see pr_info lines and diagnose probe errors.
  • Verify uname -r matches installed modules and use INSTALL_MOD_PATH when staging into a VM or chroot.
ActionCommandWhy
Build & installmake … Image.gz modules; modules_installKeep image and modules in sync
Preparemodules_prepareUpdate autogenerated headers
Depsdepmod –quickFast dependency refresh during iteration

Document this lifecycle in your repo so teammates reproduce tests without friction. Copying just the updated .ko, rerunning depmod, then modprobe saves time during tight loops.

Expressing inter-module APIs, namespaces, and dependencies

When subsystems need a clear API, using named export namespaces keeps ownership explicit and avoids accidental linkages. I recommend exposing only the functions you intend to support and guarding experimental hooks behind a config toggle.

Use the EXPORT_SYMBOL_NS_GPL macro to publish a symbol with a name string. Consumers must declare the function prototype and use MODULE_IMPORT_NS(“NAMESPACE”) so the loader and linker enforce the relationship.

Example pattern in code: the provider exports simple_mod_func with

EXPORT_SYMBOL_NS_GPL(simple_mod_func, “IIO_WORKSHOP_SIMPLE_MOD”);

Consumers declare extern, import the namespace, and call the API. Let modprobe handle load order by verifying dependencies in the provider’s metadata.

  • Keep exported APIs minimal and documented—treat them like contracts.
  • Prefer GPL-only exports when appropriate to signal intent.
  • Group exports near implementations and comment the public surface.
ActionWhat to addWhy
ExportEXPORT_SYMBOL_NS_GPL(symbol, “NAMESPACE”)Named ownership and clear linkage
ImportMODULE_IMPORT_NS(“NAMESPACE”); extern declLoader enforces provider presence
Guardconfig toggle around APISafe iteration and staged support

Common pitfalls and how to avoid recursive dependency issues

Circular dependencies are a frequent roadside hazard; spotting them early saves long debugging sessions.

When the config system reports a recursive dependency detected, it means symbols reference each other in a loop. I advise removing any superfluous select lines and replacing them with depends on when semantics require respecting target constraints.

Keep dependency chains short. Long chains make dependencies hard to reason about and hide why an option became visible or forced to y. Introduce a helper symbol when multiple entries must share a common requirement.

  • Avoid reverse dependencies that force y — they create hidden build and visibility surprises.
  • Remove redundant selects — parents often already depend on the same core symbol.
  • Document tricky expressions with comments so future maintainers understand the shape.
  • Reproduce issues with minimal test files and run allnoconfig to validate fixes quickly.
ProblemSymptomFix
Circular dependencyRecursive dependency detectedSwap select to depends on
Redundant selectUnexpected y forcedRemove select or rely on parent dependency
Long chainHard to debug visibilityIntroduce helper symbol and shorten chain

Finally, check that help text and prompt text match the real dependency logic and that any variable or entry mentioned in the menu remains accurate. Clarity beats cleverness — simplify when unsure.

Testing strategies: COMPILE_TEST, architecture constraints, and CI

I combine platform guards with a compile-time test flag to widen coverage without cluttering the configuration UI. Use the literal depends on ARCH_FOO_VENDOR || COMPILE_TEST so CI builds drivers even when hardware is absent.

This pattern keeps architecture-specific options hidden on user systems while giving CI and maintainers broader build support. When code compiles without real hardware, the probe path must exit cleanly and avoid crashes at runtime.

configuration testing

Practical checks I run

  • Add COMPILE_TEST to dependency lines to expand CI coverage without exposing irrelevant options.
  • Build across toolchains and arches to catch endianness, pointer-size, and header issues early.
  • Use a fixed seed in randconfig to replay odd failures and track which symbols gate hardware paths.
  • Keep test docs and miniconfigs near the code so contributors can validate changes locally.
ActionWhyTip
Include COMPILE_TESTCI builds absent hardwareKeeps system menus clean
Cross-toolchainCatch ABI issuesRun on example boards or QEMU
Record configsReproduce failuresUse diffconfig with CI logs

Next steps to ship reliable Kconfig entries and modules today

Ship readiness is about small habits that prevent big surprises. Keep Kconfig and Makefile entries alphabetized so reviewers see the intended order. Use menuconfig to confirm the prompt and that the symbol shows in the right section for users.

Start with modular builds to iterate fast. Verify each option and related options with listnewconfig and scripts/diffconfig. Keep one example file and a clear symbol name so tests map back to source quickly.

Automate: add COMPILE_TEST in CI, run M= builds and modules_prepare during edits, and re-run depmod plus modprobe checks. Document dependencies, exported APIs, and the review checklist so the next contributor ships even smoother.

FAQ

What is the purpose of a Kconfig entry when adding support for a new kernel module?

A Kconfig entry defines a configuration symbol, its prompt, default value, dependencies, and help text so users and build systems can enable, disable, or build the feature as a loadable module. It ties the config symbol to build logic in Makefile (obj-$(CONFIG_FOO) patterns) so the object output, install, and module lifecycle behave predictably.

How do I structure source and build files for a clean start?

Keep a minimal tree: the module source (simple_mod.c), a Kconfig fragment, and a Makefile that uses the M= mechanism or obj-$(CONFIG_FOO) assignment. Use modules_prepare, modules_install, and depmod as needed. This layout makes menu-driven tools and CI workflows like randconfig and listnewconfig easier to run.

What steps create, enable, build, and validate a simple example module quickly?

Author simple_mod.c with init/exit, add a Kconfig symbol with prompt/help/default, update the Makefile, run menuconfig (or nconfig/xconfig) to enable the symbol as module (tristate = m), build (make modules or make M=. ), install modules_install, then verify with modinfo, lsmod, and dmesg. Use rmmod and modprobe to unload/reload and confirm lifecycle behavior.

Which Kconfig keywords and constructs should I learn first?

Start with config, menuconfig, choice/endchoice, menu/endmenu, if/endif, comment, and source. Understand prompt and help rendering in front ends, and how choice differs from tristate/boolean types. These building blocks control menu structure and symbol visibility.

When should I use tristate versus bool for a feature?

Use tristate when module support matters — it allows built-in (y), module (m), or disabled (n). Use bool for config options that cannot be modularized. Prefer module support when the driver can be loaded dynamically or affects boot-time size.

How do I wire the Kconfig symbol into the build system (Kbuild)?

In your Makefile use patterns like obj-$(CONFIG_FOO) += foo.o or foo-y/obj-m depending on layout. For out-of-tree or partial builds use M=path. This ensures the symbol controls which objects get compiled and where the module output goes.

How can I control visibility and conditional behavior with depends on and select?

Use depends on to hide a prompt until prerequisites are met. Use select sparingly — it forces another symbol on and can create hidden dependencies. For platform or architecture constraints, use if/endif and conditional patterns to keep menus clean and prevent recursive dependency issues.

How do menuconfig, nconfig, and xconfig differ and how should I use them?

menuconfig is terminal-based and widely available. nconfig provides a curses interface with better navigation. xconfig is graphical (Qt) and useful for visual layout. All support search by symbol/prompt and jumping from results; choose the front end that fits your workflow.

What environment variables help automate configuration workflows?

Use KCONFIG_CONFIG to point to a specific .config, KCONFIG_ALLCONFIG to supply minimal overrides, and miniconfig-style options for automation. KCONFIG_SEED and KCONFIG_PROBABILITY help randconfig runs. Use syncconfig knobs like KCONFIG_NOSILENTUPDATE, AUTOHEADER, and AUTOCONFIG to control header and auto-generated files.

What commands handle module installation and dependency resolution?

Build with make modules or Image.gz modules as appropriate, then run modules_install. Run depmod to refresh dependency maps. Use insmod for direct insertion, modprobe to load with dependencies, and check logs via dmesg for runtime messages.

How do I express inter-module APIs and namespaces safely?

Export symbols with EXPORT_SYMBOL_NS_GPL when you want namespaced, GPL-only exports. Use MODULE_IMPORT_NS when a module needs to import a namespace. This clarifies ABI boundaries and helps dependency tracking across modules.

What common pitfalls cause recursive dependencies and how do I avoid them?

Circular select usage, hidden selects, and badly scoped if/endif blocks often create recursion. Avoid select when possible, prefer depends on, and keep prompt/help text and menu structure explicit. Test with oldconfig and diffconfig to surface unexpected symbol changes.

How should I test configuration changes and module builds in CI?

Combine ARCH_xxx with COMPILE_TEST and run randconfig variations to exercise permutations. Use listnewconfig and diffconfig to track what changed. Include compile-only jobs, modules_install checks, and depmod validation to catch integration issues early.

What are practical next steps to ship reliable config entries and modules?

Write clear prompt and help text, set safe defaults, add dependency guards, and include Makefile wiring for obj-$(CONFIG_…) patterns. Run menu-driven front ends to validate UX, add CI compile tests, and document installation and runtime checks using modinfo, lsmod, and dmesg.