Chapter 2: Building the 6.x Linux Kernel from Source (Part 1)
Building the Linux Kernel from Source: A Long Journey
Building the Linux kernel from source is the most hardcore way to kick off your kernel development journey.
Don't be fooled by those fancy graphical install tools—beneath that thin veneer lies one of the most important software engineering projects in the world. This topic is so vast that it has to be split into two chapters. This is part one; the next one is on its way.
⚠️ Prerequisites: Are You Really Ready?
If you haven't set up your workspace yet, do not proceed to the next step.
In the previous "Online Chapter," we spent a lot of time covering environment setup—which docs to read, which tools to install, and how to configure GitHub. If you skipped that step, it's not too late to go back and do it now. This isn't bureaucracy; it's to prevent you from questioning your life choices in front of a terminal spewing errors.
The mission for this chapter and the next is crystal clear: build a modern Linux kernel from scratch using source code.
In this chapter, we'll cover the basics first:
- Understanding the weird timeline of kernel version numbers;
- Understanding how the kernel is developed step by step (and what happens if you miss the bus);
- Figuring out what on earth "Mainline Kernel," "LTS," and "vendor kernels" actually mean.
Then, we'll get our hands dirty:
- Downloading the vanilla kernel source code;
- Extracting it to see what 30 million lines of code actually look like;
- The most crucial step: configuring it.
Finally, we'll spend some time hacking into the Kconfig system—the "gatekeeper" that decides which code makes it into the kernel—and even add our own menu item.
Minimal Systems Theory: How Linux Actually Boots
Before we start, we need to reach a consensus.
Any Linux system that actually boots—whether it's the Tianhe-1 supercomputer or the Raspberry Pi sitting on your desk—requires the same three "essentials":
- Bootloader: The first guy to wake up and get to work, responsible for waking up the kernel.
- OS Kernel: The main character we're going to tinker with.
- Root Filesystem (Rootfs): The massive collection of libraries, configurations, and tools the kernel needs after booting.
There are also two "optional extras," but they are practically standard on embedded platforms like ARM:
- Device Tree Blob (DTB): A "hardware manual" prepared for ARM, telling the kernel what peripherals are on the board.
- Initramfs: A mini-filesystem stuffed into memory, used to mount the real root filesystem or load essential drivers.
In these two chapters, we only do one thing: build that OS kernel. We'll leave the pitfalls of the Root Filesystem for later. In the next chapter, we'll briefly touch on x86 GRUB bootloader configuration, just so you can actually boot the thing.
A complete x86 build process takes about 6 to 7 steps. In this chapter, we only cover the first 3 steps, leaving the rest for the next chapter.
Preliminaries: Don't Rush to Type Commands, Understand the Rules First
Before we begin, a few things must be made clear. These aren't just technical details; they are the "unwritten rules" of the Linux world.
The Decentralized "Office"
The Linux kernel isn't developed behind closed doors by some big company; it's a completely decentralized, globally collaborative monster.
If you had to point to an "office," it would be the Linux Foundation. It handles the legal and funding issues, while the Kernel Organization is responsible for distributing the code to the world for free (https://www.kernel.org).
There's a common misconception here: does the GPL license prohibit making money? Dead wrong. The GPL never prevents developers from charging money. Linus and the Foundation choose to distribute it for free, but that doesn't stop companies like Red Hat and SUSE from taking the kernel and selling support, subscriptions, and SaaS. As long as the source code is ultimately made public, how you commercialize it is up to you.
Understanding the Linux Kernel Version Naming Convention
Take a look at your terminal, type uname -r, and what does that string of characters mean?
On our Ubuntu 22.04 virtual machine, it looks something like this:
$ uname -r
5.19.0-40-generic
Behind this string lies a strict syntax. The version number format for modern Linux kernels is as follows:
major#.minor#[.patchlevel][-EXTRAVERSION]
Or in simpler algebraic terms: w.x[.y][-z].
The parts in square brackets are optional. Let's break down this 5.19.0-40-generic:
- Major # (w):
5— The major version number; we're now in the 6.x era. - Minor # (x):
19— The minor version number. - [patchlevel] (y):
0— The patch level (also known as the revision). - [-EXTRAVERSION] (-z):
-40-generic— A specific version identifier.genericindicates this is the Ubuntu generic version.
⚠️ Note: Distribution kernels (like Ubuntu's) might add their own tweaks and don't strictly follow this naming convention. But the vanilla kernels published on https://www.kernel.org/ strictly abide by these rules.
Echoes of History: The Even-Odd Legend
Before the 2.6 kernel (aka ancient times), the minor version number had a hidden trick:
- Even numbers: Stable releases (e.g., 2.4, 2.6).
- Odd numbers: Development/test releases (e.g., 2.5).
But now? This rule is gone. Today's version numbers are only related to time, not functionality.
The "Fingers-and-toes releases"
Linus once joked that his versioning strategy is "counting fingers and toes."
When a minor version number (x) reaches around 20 (10 fingers + 10 toes), he increments the major version number (w) by 1.
- 3.0 to 3.19 (20 minor versions)
- 4.0 to 4.19 (20 minor versions)
- 5.0 to 5.19 (20 minor versions)
- 6.0 …
The interval between each minor version is about 6 to 10 weeks. This isn't feature-driven; it's organic evolution.
Kernel Development Workflow: From Merge Window to Release
Many people think kernel development is "writing whatever comes to mind" with no structure. This is a massive misunderstanding.
Kernel development has an extremely strict sense of rhythm. To understand this rhythm, we can look at the kernel's Git history.
Viewing the Git History
Assume you've cloned the latest Linus mainline tree. With the following command, you can see a clear timeline:
$ git log --date-order --tags --simplify-by-decoration \
--pretty=format:'%ai %h %d'
2023-04-23 12:02:52 -0700 457391b03803 (tag: v6.3)
2023-04-16 15:23:53 -0700 6a8f57ae2eb0 (tag: v6.3-rc7)
2023-04-09 11:15:57 -0700 09a9639e56c0 (tag: v6.3-rc6)
[...]
2022-10-16 15:36:24 -0700 9abf2313adc1 (tag: v6.1-rc1)
2022-10-02 14:09:07 -0700 4fe89d07dcc2 (tag: v6.0)
This command only works on a Git tree. Here, we're purely demonstrating the evolution process.
In this output, you can see a complete lifecycle:
- v6.0 release: The previous stable release.
- v6.1-rc1: The merge window closes, and bug fixing begins.
- v6.1-rc7 / -rc8: Release candidates, continuous testing and patching.
- v6.1: The final stable release.
Two Key Phases on the Timeline
1. Merge Window — Only 2 Weeks
When v6.0 is released (October 2, 2022), a two-week merge window immediately opens.
This is the craziest moment for the entire community. Subsystem maintainers will dump all the new code they've been hoarding into mainline all at once. If you want to add a new feature, this is your only chance.
2. Bugfix Window — 6 to 10 Weeks
Two weeks later (October 16, 2022), the merge window closes. v6.1-rc1 is born.
For the following days, any new features are locked out. You can only fix bugs, revert problematic code, and resolve regressions.
This process lasts anywhere from 6 to 10 weeks, until Linus and the core maintainers feel "this is good enough," and v6.1 is officially released.
What if You Miss the Merge Window?
If you miss a window (e.g., you didn't get your code merged in time), you have only one choice: wait.
Wait for the next window, about 2.5 to 3 months later. This is the kernel developer's version of "letting go."
Exploring the Types of Kernel Source Trees
The kernel doesn't have just one version. In this massive ecosystem, there are several different source trees, each with its own purpose.
1. Mainline / Stable
This is the queen bee. All features eventually converge into Mainline, and Mainline gets patched to become Stable releases. This is usually the foundation for enterprise distributions.
2. Long-Term Support (LTS)
These are the "extra stable" releases. Maintainers commit to continuously patching them for a long period (usually starting at 2 years, or even longer).
By convention, the last kernel released in December of each year is selected as the LTS release. The 6.1 LTS we use in this book plays exactly this role, with a projected lifespan of 4 years (2022.12 - 2026.12).
3. -next Trees
This is the "bleeding edge." If you plan to submit code to the kernel, you must work on the linux-next tree. This is the collection of all patches preparing to enter the next merge window. It's highly unstable and not suitable for production environments, but it's a necessary stepping stone for contributors.
4. Distribution Kernels
The kernels used by Red Hat, Ubuntu, Debian, and others. These are usually based on a specific Stable/LTS release, plus a massive pile of their own patches and drivers.
This is also why sometimes you see a certain cloud vendor still using a 4.x kernel—don't rush to mock it for being outdated; they might have already backported tens of thousands of the latest security patches.
5. SoC Vendor Kernels
Kernels maintained by ARM and embedded vendors. This is a disaster zone.
Chip manufacturers usually base their work on an (often very old) LTS kernel, then stuff it with their own BSP and proprietary drivers. This causes their kernels to diverge massively from mainline, making maintenance an absolute nightmare.
Best practice: If you're doing embedded development, try to use modern build systems like Yocto, which help smooth out these differences.
6. Super LTS (SLTS)
This is for "civilian infrastructure" (like power grids and dams). The SLTS kernels maintained by the CIP project have support cycles lasting 10 years or more. If the device you're building is going to sit there untouched for 20 years, this is what you need to pay attention to.
⚠️ Important Update: LTS Has Been Shortened
In September 2023, Linus and company announced big news: future LTS maintenance cycles might be shortened to 2 years.
Why?
- Nobody actually uses kernels that old: Many vendors maintain their own branches anyway.
- Maintainers are burned out: Simultaneously maintaining 7 LTS versions (4.14, 4.19... 6.6) and constantly backporting patches leads to an exponential increase in workload.
However, the 6.1 LTS we use in this book should still hang on until December 2026, which is more than enough for you to tinker with.
Which Kernel Should You Actually Run?
This is a trick question, but the kernel community heavyweights have given the standard answer:
"Run the latest stable release." — Jon Corbet, 2023
"You need to upgrade continuously. If you try to cherry-pick patches, you'll just end up with a freak that is neither secure nor free of known bugs." — Greg Kroah-Hartman
Don't try to be your own "distribution." Let the experts do the gatekeeping for you.
Starting the Build: First 3 Steps in Practice
Alright, enough theory. Now we officially begin the journey of building a 6.x kernel.
We've broken the entire build process down into 6-7 steps. In this chapter, we only do the first three:
- Fetch the source code.
- Extract the source code.
- Configure the kernel (this is the main event).
Steps 4-7 (compiling, installing modules, configuring the bootloader, and installing the kernel) are left for the next chapter.
Step 1 – Fetch the Linux Kernel Source Code
You have two choices:
- Download a tarball: Suitable for most people who just want to learn or use a specific version.
- Clone the Git repository: Suitable for those who want to contribute code or track the latest version.
For this book, we choose the first method: download the 6.1.25 LTS tarball.
Method A: Direct Download
The simplest method is to use wget or curl:
wget --https-only -O ~/Downloads/linux-6.1.25.tar.xz \
https://mirrors.edge.kernel.org/pub/linux/kernel/v6.x/linux-6.1.25.tar.xz
This will throw a ~130MB source tarball into your ~/Downloads.
Method B: Clone the Git Repository (Optional)
If you want to experience the bleeding edge, or want to see what linux-next looks like:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
⚠️ Note: The complete kernel Git history is massive; cloning it takes a very long time and a lot of disk space (several GB). If you just want to take a quick look, you can use --depth 1 for a shallow clone.
If you want to get a stable branch:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd linux-stable
For this book, we still recommend the first method—downloading the definitive 6.1.25 version. This keeps everyone's environment consistent and prevents unexpected issues.
Step 2 – Extract the Kernel Source Tree
Assume you now have that linux-6.1.25.tar.xz file in hand.
Extract it:
# 简单粗暴法:解压到当前目录
tar xf ~/Downloads/linux-6.1.25.tar.xz
# 推荐法:解压到一个专门的工作目录
mkdir -p ~/kernels
tar xf ~/Downloads/linux-6.1.25.tar.xz --directory=~/kernels/
Now, under your ~/kernels/linux-6.1.25/, lies the legendary universe of 30 million lines of code.
To make subsequent operations easier, let's set an environment variable:
export LKP_KSRC=~/kernels/linux-6.1.25
⚠️ Don't use GUI extraction tools: Seriously, practice using the tar command. In the future, when you're on a server or in a pure terminal environment (like a VM connected via SSH), you'll thank yourself for this habit.
📖 Bonus: A Quick Glance at the Source Tree Structure
Before we officially configure things, let's spend a minute (literally one minute) to see what's inside this behemoth.
It's like buying a Lego set and checking the parts list on the instructions before you start building.
$ du -h .
1.5G .
About 1.5 GB.
Where is that legendary version number defined? Take a look at the Makefile in the root directory:
$ head Makefile
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 1
SUBLEVEL = 25
EXTRAVERSION =
NAME = Hurr durr I'ma ninja sloth
See, 6.1.25 is right here. That NAME is the codename for each kernel version (Linus's quirky sense of humor).
Below is a minimalist "map" telling you roughly where things are:
| Directory/File | What it does |
|---|---|
| kernel/ | The core of the core: scheduler, signals, cgroups, module management. |
| mm/ | Memory Management. |
| fs/ | Filesystems: the VFS virtual layer, ext4, btrfs, nfs are all here. |
| drivers/ | Drivers. This is the largest chunk and the fastest-changing area. |
| net/ | Network Stack. The soul of TCP/IP lives here. |
| block/ | Block device I/O layer and caching. |
| crypto/ | Cryptographic algorithm libraries. |
| init/ | Kernel initialization code. The legendary start_kernel() is in init/main.c. |
| usr/ | Code used to generate the initramfs. |
| arch/ | Architecture-specific code. x86, arm, arm64, riscv... they're all here. |
| Documentation/ | Official documentation. Stop Googling randomly; the answer is probably here. |
A quick glance is enough; no need to memorize it. You're going to get lost in these directories many times in the future—that's perfectly normal.
Step 3 – Configure the Linux Kernel
This is the most crucial step.
The reason the Linux kernel can run on a smartphone and also on a supercomputer all comes down to this step: configuration.
Without configuration, you'd face thousands of configuration options. If configured incorrectly, the kernel might not boot, or it might be missing critical features (like networking or USB).
The core of configuration is a system called Kconfig, which is responsible for generating a hidden file called .config.
A Minimal Intro to Kconfig / Kbuild
There's a set of infrastructure working silently in the background:
- Kconfig: Responsible for that "menu interface." It reads
Kconfigfiles, displays options, and handles dependencies (e.g., you can only select B if A is selected). - Kbuild: Responsible for compilation. It reads
.configfiles and decides which files to compile based on their contents.
All configurations ultimately converge into a single file:
.config (located right in the root directory of the source tree).
In this file, all configuration items look like this:
CONFIG_FOO=y # y = 编进内核镜像
CONFIG_BAR=m # m = 做成模块
CONFIG_BAZ=n # n = 不要这个功能
y (yes) means this feature will be hard-coded into the kernel image; it's available at boot, but it increases the size.
m (module) means it's built as a .ko file, to be loaded when needed.
n (no) means this thing is invisible to you.
Getting an Initial Configuration: Three Paths
For beginners, manually writing a .config from scratch is impossible. We usually start from one of three points:
- Vendor configuration: Directly copy the configuration currently in use by the system.
- Default configuration: Let the kernel give you a generic configuration (usually very large).
- Streamlined configuration: Generate one based on the modules currently loaded on your system.
Strategy 1: The Vendor's Configuration (Safe but Bloated)
If you're on Ubuntu and want to compile your own kernel, the safest bet is to use what you have now:
make mrproper
cp /boot/config-$(uname -r) ${LKP_KSRC}/.config
This generates a massive .config with everything included. This guarantees the kernel will boot, but the compile time will be very long, and the size will be huge.
Strategy 2: Default Configuration
make defconfig
This provides a standard configuration based on your CPU architecture (e.g., x86_64).
Strategy 3: Streamlined Configuration — Recommended for Learners
If you want to practice or want a slimmer kernel, you can use localmodconfig.
Its logic is: look at which modules are currently loaded in my system (lsmod), and only compile those features in.
# 先把当前加载的模块列表存下来
lsmod > /tmp/lsmod.now
# 基于这个列表生成配置
cd ${LKP_KSRC}
make LSMOD=/tmp/lsmod.now localmodconfig
During the process, if the new kernel (6.1.25) has new options that the old kernel (5.19) didn't have, it will ask you. At that point, just mash Enter (to accept the defaults).
Ultimately, you'll get a .config file. This is your custom recipe.
Step 4 (Actually a Continuation of Step 3) – Tweaking the Configuration
Once you have .config, we usually still need to fine-tune it.
This is where the legendary tool comes in: make menuconfig.
Launching the Graphical Menu
cd ${LKP_KSRC}
make menuconfig
You'll see a blue, ncurses-based graphical interface (which also works over SSH).
Navigation and Operations
- Arrow keys: Move around.
- Enter: Enter a submenu.
- Space: Toggle state (cycles through
y,m,n). /(slash): Search (e.g., search for the driver you're looking for).- Esc Esc: Exit the current menu.
Symbol Guide
[ ]: Not compiled.[*]: Compiled into the kernel.<M>: Compiled as a module.---: Forced to be compiled into the kernel (usually a dependency).
Hands-on Demo: Enabling .config Viewing Support
Let's do a small experiment to enable a very useful feature: allowing the kernel to view its own configuration at runtime.
- Enter the menu.
- Find General setup -> Kernel .config support.
- Change it from
<M>(module) to[*](built-in). - Select Enable access to .config through /proc/config.gz right below it, and toggle it to
[*]. - Exit and save.
This enables two configuration macros:
CONFIG_IKCONFIG=yCONFIG_IKCONFIG_PROC=y
Later, when the kernel is running, you can just zcat /proc/config.gz to see its compile-time options, which is incredibly helpful for debugging.
Advanced Configuration: Scripting and Differencing
If you're doing automated builds, the menuconfig interactive interface might not be suitable for you.
Modifying Configurations via Scripts
The kernel source tree comes with a built-in script: scripts/config.
You can directly modify .config from the command line:
# 禁用某个选项
./scripts/config --disable IKCONFIG
# 启用某个选项
./scripts/config --enable IKCONFIG
# 查看某个选项的状态
./scripts/config --state IKCONFIG
# 输出: y
⚠️ Note: Modifying configurations with scripts is like swinging a knife in the dark—it doesn't care about dependencies. Remember to run a compile test after making changes.
Viewing Configuration Differences
You've changed a bunch of settings and want to see exactly what was altered? Use diffconfig:
./scripts/diffconfig .config.old .config
It will list which options changed and what their values were changed to, making it clear at a glance.
Security Hardening: Kconfig Hardened Check
If you're doing security or building products, the security of your kernel configuration is paramount.
There's a tool called kconfig-hardened-check specifically designed to check whether your kernel configuration aligns with the security recommendations of the KSPP (Kernel Self Protection Project).
# 安装
git clone https://github.com/a13xp0p0v/kconfig-hardened-check
cd kconfig-hardened-check
# 检查你的 .config
python3 kconfig-hardened-check.py --config ${LKP_KSRC}/.config
It will tell you where weak points are enabled and what should be hardened, such as CONFIG_BUG_ON_DATA_CORRUPTION and the like.
Customizing the Kconfig Menu: Adding Your Own Name
Suppose you wrote an awesome driver or feature and want to add it to the kernel menu. How do you do that?
This actually involves two steps:
- Kconfig: Tell the menu system there's a new option.
- Makefile: Tell the build system where the corresponding code is.
Experiment: Adding an "LKP Test Option"
Let's do this for real. We'll add our own option inside the General setup menu.
-
Back up the file:
cp init/Kconfig init/Kconfig.orig -
Edit the file: Find
init/Kconfig. Find an empty spot (e.g., nearLOCALVERSION_AUTO), and insert this block:config LKP_OPTION1bool "Test case for LKP 2e book/Ch 2: creating ..."default nhelpThis is a dummy test option added for learning purposes.Selecting this does absolutely nothing except provethat you know how to edit Kconfig files.config: Defines a macro calledCONFIG_LKP_OPTION1.bool: This is a boolean option (on/off).help: The lines below it are the help documentation.
-
Verify the modification:
make menuconfigGo into General setup, scroll down, and you should see your new option!
-
Enable it: Select it, press Space to turn it into
[*]. Save and exit. -
Check the result:
grep "LKP_OPTION1" .config# CONFIG_LKP_OPTION1=yCongratulations, you just hacked into the Linux kernel build system.
-
Associate the code (Advanced): If you actually wrote code (e.g.,
lkp_test.c), you'd also need to modify the Makefile:In
init/Makefile(or the Makefile in the directory where your code lives), add:obj-$(CONFIG_LKP_OPTION1) += lkp_test.oThis way, when you select
Y, it gets compiled into the kernel; when you selectN, the compiler ignores it.
Chapter Summary
We covered quite a bit in this chapter.
First, we figured out where the 6.x kernel version numbers come from—Linus counted them on his fingers and toes, and they represent time, not features. We also learned what LTS is and why you should choose it.
Then, we got our hands dirty: we downloaded the source code, extracted it, and spent a minute getting familiar with the layout of these 30 million lines of code.
Most importantly, we spent a lot of time understanding Kconfig and Kbuild—the cornerstones of building the kernel. We learned how to get a base configuration (using defconfig or localmodconfig), how to tweak it with make menuconfig, and even how to write our own Kconfig script to add a menu item to the kernel.
Now, in your working directory, you should have a configured kernel source tree with a .config file filled with your choices.
Don't rest just yet. In the next chapter, we're going to press that red button.
We're going to run make.
We're going to turn these 30 million lines of code into a single binary file.
We're going to install it into the system, reboot, and watch the scrolling logs turn into the name of your very own compiled kernel.
That's the real "Hello World."
Exercises
Exercise 1: Version Number Archaeology ⭐ (Understanding)
Find a Linux machine you have access to (cloud server, VM, WSL—anything goes), and run uname -r.
- What is its version number?
- Is it a Stable release, or a distribution-modified version? How can you tell?
- If it's a 5.x kernel, can you guess roughly what year it was released? (Hint: count your fingers)
Exercise 2: Configuration Option Hunting ⭐⭐ (Application)
Use the / search function in make menuconfig to find the following options, and record their locations and dependencies:
CONFIG_KASAN(Kernel Address Sanitizer)CONFIG_DEBUG_INFO_BTF(eBPF related)- Find a driver related to your computer's hardware (like a WiFi or graphics driver), and see what it depends on.
Exercise 3: Custom Module Build ⭐⭐⭐ (Hands-on)
This one is tricky. If you pull it off, it proves you really get it.
- Write a very simple kernel module (just
initandexitfunctions that print Hello World). - Put this file into the
drivers/char/directory of the kernel source tree. - Modify the
MakefileandKconfigin that directory so you can select your module throughmake menuconfig. - Compile it as a module (.ko) and successfully load it.
Hint: You need to refer to how other drivers in that directory are written.
Appendix: Common Commands Cheat Sheet
# 1. 准备环境(清理旧的配置)
make mrproper
# 2. 获取当前系统的模块列表(用于精简配置)
lsmod > /tmp/lsmod.now
# 3. 生成本地化配置(仅包含当前硬件需要的驱动)
make LSMOD=/tmp/lsmod.now localmodconfig
# 4. 打开图形化配置界面
make menuconfig
# 5. 查看配置差异(改完配置后)
./scripts/diffconfig .config.old .config
# 6. 脚本化修改配置(例如开启 IKCONFIG)
./scripts/config --enable IKCONFIG
./scripts/config --enable IKCONFIG_PROC
# 7. 检查内核配置安全性(需安装工具)
kconfig-hardened-check --config .config
Exercises
Exercise 1: Understanding
Question: Based on the Linux kernel version naming convention 'w.x[.y][-z]', what do the various numbers and characters in the kernel version '6.1.25-custom' represent? Please explain why the major version number changed from 5 to 6 using the "fingers-and-toes model."
Answer & Analysis
Answer: w=6 (Major version), x=1 (Minor version), y=25 (Patch level/Revision), -z=-custom (Extra version/Local version).
According to the "fingers-and-toes" model, when the minor version number (x) accumulates to around 20 (i.e., from 0 to 19, the total number of fingers and toes), the major version number (w) is incremented. Therefore, the kernel evolved from 5.19 to 6.0.
Analysis: This question tests your understanding of the kernel version number structure and evolution rules.
- Version Number Structure: It follows the major.minor.patchlevel-extraversion format.
- Fingers-and-toes Model: This is a loosely time-based version evolution strategy. Linus metaphorically compared it to counting on your fingers and toes, advancing to the next digit after using all 20. Historically, the 3.x, 4.x, and 5.x series all ended their major version cycles at the 20th minor version (e.g., 5.19 was followed by 6.0). This doesn't imply a massive architectural change, but rather an organic evolution.
Exercise 2: Application
Question: In the Kconfig language of the kernel build system, depends on and select are two common dependency mechanisms. Please briefly describe the difference between these two mechanisms, and explain why it is generally recommended to prioritize using depends on over select when writing configuration options?
Answer & Analysis
Answer: Difference:
depends on(Forward dependency): The current option depends on the specified option. If the dependency is not met (is n), the current option will be invisible or unselectable.select(Reverse dependency/Auto-selection): When the current option is selected, it automatically forces the selection of another option (whether the user realizes it or not).
Reason for the Recommendation:
select forcefully enables implicit dependencies, which can lead to users unintentionally enabling unwanted or incompatible code, increasing kernel size or causing conflicts. depends on, on the other hand, presents the dependency to the user, requiring them to actively resolve it, which better aligns with modular design principles.
Analysis: This question tests best practices when actually writing kernel configurations (for BSP or driver development).
depends onis a "visibility constraint." For example,depends on NETmeans this option will only appear in the menu if the networking subsystem is enabled.selectis a "forced transitive dependency." For example, selecting a USB storage driver might automaticallyselectSCSI support.- The risk is that if the option being
selecthas its own dependency conflicts, the user might face complex configuration errors. Therefore, unless it's absolutely necessary to enable certain underlying infrastructure (like a bus or core library), you should avoid usingselect.
Exercise 3: Thinking
Question: Suppose you are a systems engineer at an embedded company, planning an industrial control device based on a new ARM SoC with an expected product lifecycle of 10 years. You need to choose an appropriate Linux kernel source tree as your foundation.
Option A: Use the SoC vendor-provided vendor kernel based on an older LTS (including BSP drivers). Option B: Use the latest mainline LTS kernel (e.g., 6.1 LTS) and integrate the BSP layer using tools like Yocto.
Please analyze the pros and cons of choosing Option B, considering kernel maintenance cycles, technical debt, and security.
Answer & Analysis
Answer: Conclusion: You should choose Option B (Latest LTS kernel + Yocto/Community integration).
Pros (Reasons):
- Long-term support and maintainability: Vendor kernels are usually based on a specific old version and forked. Long-term maintenance faces "technical debt" and makes it hard to keep up with upstream security patches. Mainline LTS (like 6.1) has community support, and projects like Yocto can provide continuous metadata updates.
- Security: Industrial devices need to run long-term. Old kernels easily accumulate unpatched CVE vulnerabilities. Mainline LTS receives security fixes much faster.
- Driver updates: By leveraging the Device Tree mechanism, it's easier to port the vendor's hardware support to a new kernel without relying on the vendor's modified old kernel source code.
Cons (Challenges):
- Initial development cost: If the SoC vendor hasn't submitted their drivers to mainline, you might need to port the drivers or write device trees yourself.
- Compatibility risks: The APIs in the new kernel might have changed, requiring you to verify the compatibility of all BSP components.
Analysis: This question tests your comprehensive thinking regarding the kernel ecosystem, supply chain security, and engineering architecture.
- SoC Vendor Kernels: Although "ready to use out of the box," they are often one-off efforts. Once the vendor stops supporting that old kernel, the product faces massive security risks and upgrade difficulties.
- Mainline LTS Strategy: This aligns with the "upstream first" principle. Although the barrier to entry is higher, by utilizing
Device Tree(decoupling hardware descriptions from code) and modern build systems (Yocto/Buildroot), you can achieve long-term, sustainable maintenance, which is crucial for industrial devices with a 10-year lifecycle. - Super LTS (SLTS): The CIP SLTS mentioned in the chapter is also one of the solutions to this problem. It's usually an ultra-long maintenance branch based on a mainline LTS, and Option B fits this mindset much better.
Key Takeaways
Understanding the Linux kernel's strict development rhythm and versioning rules is the first required course before building. Modern kernel development follows a fixed "merge window" and "bugfix window" cycle. New features are only accepted during the two weeks the merge window is open; the rest of the time is dedicated solely to bug fixes. Version numbers (like 6.1) no longer use the old even/odd stable/development distinction, but instead follow a time-based "organic evolution." For builders, choosing an LTS (Long-Term Support) release (like the 6.1 used in this book) is usually the best practice for balancing stability and maintenance cycles, ensuring you receive continuous security patch support over years of use.
The cornerstone of kernel building lies in mastering the Kconfig/Kbuild configuration system, which determines what code gets compiled and how. The reason the kernel can adapt to everything from smartphones to supercomputers comes entirely down to this customization step. The core configuration ultimately converges into the .config file in the root directory, where the y (compiled into the kernel), m (compiled as a module), and n (not compiled) states dictate the kernel's feature set and size. Blindly writing this file manually isn't feasible; the best practice is to use your current system's configuration (like /boot/config-xxx) or a default configuration as a starting point.
Fetching the source code and extracting it correctly is the first practical step. We recommend downloading a definitive version's tarball (like linux-6.1.25.tar.xz) directly from Kernel.org to avoid the massive time and space overhead of cloning the full Git repository. Once extracted, the source tree presents a highly structured layout, with core code like the scheduler (kernel/), memory management (mm/), drivers (drivers/), and architecture-specific code (arch/) each handling its own responsibilities. Understanding this directory structure is like checking the Lego parts list—it's the foundation for making targeted modifications or developing drivers later.
For learners or developers, using make menuconfig is the most intuitive and effective way to adjust configurations. This ncurses-based graphical interface allows users to fine-tune kernel options through searching and navigation, such as enabling Kernel .config support so you can view the current configuration at runtime via /proc/config.gz. For automated builds, you need to master script tools like scripts/config to modify .config, and use diffconfig to check configuration changes, ensuring only necessary features are enabled to reduce kernel size.
True kernel customization capability is demonstrated by being able to "hack into" the build system—that is, integrating custom code or options into the kernel menu by