Every embedded Linux engineer eventually opens a Kconfig file and stares at a wall of bool, tristate, depends on, and select statements without really knowing what decides whether an option even shows up on screen. This lecture is part of our free linux kernel development course, and it exists to fix exactly that gap. By the end, you will know precisely how the kernel’s configuration system decides what to build, what to skip, and what one option silently forces on for you.
.config
bool / tristate
depends on
select
free embedded linux course
What You Will Learn
- How the kernel turns human-readable Kconfig entries into the machine-readable
.configfile - The five Kconfig data types and when to use each one
- The difference between a forward dependency (
depends on) and a reverse dependency (select) - How to write and test your own Kconfig entry for a demo driver
- Common mistakes that make a menu option “disappear” and how to debug them
Prerequisites
- A checked-out Linux kernel source tree (any recent stable release)
- Basic familiarity with running
make menuconfig - Comfort reading plain text configuration files
From Kconfig To .config
The kernel’s build system does not read your hardware and magically know what to compile. Instead, every subsystem ships a Kconfig file that describes, in a small declarative language, what configuration options exist, what they depend on, and what they enable. When you run make menuconfig, make xconfig, or make gconfig, the tool parses every Kconfig file reachable from the top-level one and renders it as a menu. Whatever you select is written out as a single flat file named .config, sitting at the root of the kernel source tree.
The dot in front of the filename hides it from a plain ls; you need ls -a to see it. Every line inside follows a simple pattern: a variable prefixed with CONFIG_, an equals sign, and a value. If you enable an option named EP_DEMO_DRIVER, the resulting line looks like this:
That single line is the bridge between the menu you clicked through and the actual C preprocessor macros the kernel source uses to decide what gets compiled.
The Five Kconfig Data Types
Not every configuration option is a simple on/off switch. Kconfig supports five distinct data types, and picking the right one matters — it changes both how the option is presented in the menu and how it is written into .config.
| Type | Possible Values | Typical Use |
|---|---|---|
bool |
y or unset |
Simple feature toggle, no module support |
tristate |
y, m, or unset |
Feature that can be built-in, built as a module, or left out entirely |
int |
Decimal integer | Buffer sizes, timeout values, counts |
hex |
Unsigned hexadecimal integer | Memory addresses, register offsets, bitmasks |
string |
Free-form text | Version tags, default file paths, board names |
The tristate type deserves special attention because it is the one most engineers get wrong at first. A bool option only ever ends up compiled directly into the kernel image or left out completely — there is no middle ground. A tristate option adds a third state, m, meaning the code is compiled as a loadable kernel module instead of being linked into the main image. Whether m is even offered as a choice depends on whether the kernel as a whole was configured with module support enabled in the first place.
Writing A Kconfig Entry
Here is an original example — not the kernel’s own tree, just a minimal entry you could drop into a demo subsystem’s Kconfig file to expose a fictional driver called ep_demo_driver:
config EP_DEMO_DRIVER
tristate "EmbeddedPathashala demo character driver"
default n
help
A minimal character driver used for teaching Kconfig
dependency handling. Say Y to build it into the kernel,
M to build it as a loadable module, or N to skip it.
Once this entry is reachable from a Kconfig file that the top-level build includes, running make menuconfig will show “EmbeddedPathashala demo character driver” as a selectable line, and pressing Y, M, or N will set its state accordingly.
Forward Dependencies With depends on
Real drivers rarely stand alone. A USB serial converter driver is meaningless without USB core support; an I2C sensor driver is meaningless without an I2C bus driver. Kconfig expresses this with depends on, which hides an option from the menu — and refuses to let it be selected — unless the thing it depends on is already enabled.
config EP_DEMO_I2C_SENSOR
tristate "EmbeddedPathashala demo I2C temperature sensor"
depends on I2C
help
Requires I2C bus support. Invisible in menuconfig until
CONFIG_I2C is enabled elsewhere in the configuration.
If CONFIG_I2C is not set, this menu entry simply will not appear at all — not greyed out, not hidden behind an error, just absent. This is the single most common reason engineers ask “where did my option go?” The answer is almost always an unmet depends on.
Reverse Dependencies With select
select works in the opposite direction. Instead of a driver waiting for a dependency to be turned on by the user, an option can force another option on automatically the moment it is itself enabled. Architecture Kconfig files (under arch/$ARCH) use this heavily to switch on dozens of architecture-specific capabilities as soon as the target architecture is chosen — the user never has to hunt those down individually.
config EP_DEMO_PLATFORM
bool "EmbeddedPathashala demo platform support"
select EP_DEMO_CLOCK_FRAMEWORK
select EP_DEMO_PINCTRL
help
Enabling this platform automatically pulls in the clock
framework and pin control support it depends on internally,
without asking the user to enable them by hand.
The practical difference: depends on is a gate that the user must satisfy before an option is even visible, while select is a lever that one option pulls on behalf of another. Mixing the two carelessly is a known source of circular-dependency build errors, which is why kernel maintainers are conservative about using select for anything with its own further dependencies.
Trying It Yourself
To see this in action without touching real kernel subsystems, create a scratch directory inside a kernel source tree, add a one-line Kconfig snippet like the EP_DEMO_DRIVER example above under a test menu, source it from an existing Kconfig, and run:
$ make ARCH=arm menuconfig
Search for it using the forward-slash search shortcut inside menuconfig — type /, then EP_DEMO_DRIVER (omit the CONFIG_ prefix, the search box does not expect it). Toggle it between N, M, and Y, save, and inspect the resulting line in .config:
$ grep EP_DEMO_DRIVER .config
CONFIG_EP_DEMO_DRIVER=m
Real-World Use Cases
- Board bring-up: a new SoC’s Kconfig entry
selects the clock, pinctrl, and interrupt controller drivers it always needs, so board engineers don’t forget one - Licensing isolation: a vendor’s proprietary GPU driver is kept as
tristateso it can be built as a module and distributed separately from the GPL-licensed kernel image - Feature gating for product tiers: an
intoption can cap a buffer size differently across product SKUs built from the same source tree
Common Mistakes And Troubleshooting
- “My option isn’t showing up” — check every
depends online above it in the Kconfig tree; one unmet dependency hides the entire entry - Using
selectfor something with its own unmet dependencies — this can silently force-enable an option whose owndepends onchain is not satisfied, producing a broken build; preferdepends onunless you specifically need forced enablement - Forgetting
default nordefault y— without an explicit default, behavior can vary across configuration tools; always state it - Confusing
boolwithtristate— if the code you’re gating can sensibly be a loadable module, usetristate, notbool, or you lose the ability to build it separately
Best Practices
- Prefer
depends onoverselectwhenever the dependency has further dependencies of its own - Always write a
helpblock — future maintainers (including future you) will thank you - Keep option names namespaced and descriptive, e.g.
EP_DEMO_*, to avoid collisions in large trees - Set sensible
defaultvalues so a freshdefconfigboots without manual tweaking
Performance And Security Considerations
From a performance angle, every bool-selected feature compiled into the main image adds to kernel size and, marginally, to boot time as more code is mapped and initialized. From a security angle, unnecessary tristate options left as loadable modules widen the attack surface if an attacker can trigger module auto-loading; production embedded builds commonly disable module loading entirely and bake in only what’s required via bool/y selections after auditing the dependency tree with select and depends on in mind.
Summary And Key Takeaways
- Kconfig options are declared with one of five types:
bool,tristate,int,hex, orstring .configis the flat, hidden file that stores every selection as aCONFIG_*variabledepends onhides an option until its prerequisite is satisfied by the userselectforce-enables another option automatically, and should be used sparingly
Conclusion
Understanding Kconfig’s data types and dependency keywords is one of those unglamorous skills that pays off every single time you bring up a new board or write a new driver. Once you know why an option is invisible, or why enabling one setting quietly pulled in three others, kernel configuration stops feeling like guesswork. This lecture is one part of our ongoing free linux kernel development course — the next lecture builds directly on this by walking through the configuration front-ends (menuconfig, defconfig files, and oldconfig) that turn all of this into a working .config.
Frequently Asked Questions
What is the difference between bool and tristate in Kconfig?
bool only allows built-in or disabled. tristate adds a third state that builds the code as a loadable kernel module.
Why is my Kconfig option not showing up in menuconfig?
Almost always an unmet depends on condition higher up the dependency chain. Enable the prerequisite first.
What does select do differently from depends on?
depends on requires the user to enable a prerequisite before your option appears. select automatically turns on another option for the user.
Can I use select for an option with its own dependencies?
It’s discouraged — select does not check the target’s own depends on chain, which can produce a broken configuration.
Where is the .config file located?
At the root of the kernel source tree, hidden by default; view it with ls -a.
What data type should I use for a buffer size option?
Use int for a plain decimal value, or hex if it’s more natural to express as a hexadecimal address or mask.
Is this lecture part of a full course?
Yes — it’s part of EmbeddedPathashala’s free linux kernel development course, which also covers toolchains, bootloaders, and device drivers.
Keep Learning For Free
Continue with the next lecture in this free embedded linux course to learn how menuconfig, defconfig, and oldconfig turn Kconfig entries into a working kernel build.
