3、获取与解压Linux内核源码:从kernel.org下载源码、解压与目录结构分析、查看内核版本与补丁管理
做内核裁剪,第一步就是拿到源码。这事儿听起来简单,但里面有不少门道。我见过不少新手直接去GitHub上随便拉个分支就开始搞,结果编译出来一堆莫名其妙的问题——说白了,源头没搞对,后面全是坑。
3.1 从kernel.org下载源码
官方源头只有一个:kernel.org。这是Linus Torvalds本人维护的发布站点,所有主线内核的正式版本都从这里出来。
我个人习惯用wget下载,干净利落。举个例子,下载最新的稳定版6.6 LTS:
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.8.tar.xz
下载完后,第一件事不是解压,而是校验签名。你想想看,万一下载过程中被劫持或者文件损坏,后面几小时甚至几天的裁剪工作全白费。
# 校验SHA256
sha256sum linux-6.6.8.tar.xz
# 导入内核签名密钥并验证
gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
gpg --verify linux-6.6.8.tar.sign linux-6.6.8.tar.xz
这里有个细节:.tar.sign文件是对.tar(解压前的tar包)做的签名,不是对.tar.xz。所以验证前需要先把xz解压成tar,再验证签名。步骤稍微绕一点,但值得做。
3.2 解压与目录结构分析
解压命令很简单:
tar -xf linux-6.6.8.tar.xz
cd linux-6.6.8
解压完你会看到一个庞大的目录树。第一次接触的人可能会懵——这么多文件夹,从哪看起?
别急,我帮你理一下。内核源码的顶层目录其实很有规律,每个目录都有明确的职责:
| 目录/文件 | 作用 | 裁剪时重点关注 |
|---|---|---|
arch/ |
体系结构相关代码(x86、ARM、RISC-V等) | ✅ 必须关注,按目标平台裁剪 |
block/ |
块设备层(IO调度、分区管理等) | ✅ 嵌入式设备常裁剪 |
drivers/ |
设备驱动(最大目录,占源码一半以上) | ✅ 裁剪重灾区 |
fs/ |
文件系统实现(ext4、btrfs、vfat等) | ✅ 按需保留 |
include/ |
内核头文件 | ⚠️ 一般不动 |
init/ |
内核初始化代码 | ⚠️ 极少修改 |
kernel/ |
核心子系统(调度、信号、时间等) | ⚠️ 谨慎裁剪 |
mm/ |
内存管理 | ⚠️ 谨慎裁剪 |
net/ |
网络协议栈 | ✅ 按需裁剪 |
scripts/ |
编译脚本、配置工具 | ⚠️ 一般不动 |
tools/ |
用户态工具(perf、selftests等) | ❌ 裁剪时可删除 |
Documentation/ |
内核文档 | ❌ 裁剪时可删除 |
看到没?drivers/和arch/是裁剪的主战场。我做过一个IoT项目,最终内核镜像从12MB压到1.8MB,90%的裁剪量都来自这两个目录。
下面这张图能帮你快速建立内核源码的整体认知:
3.3 查看内核版本与补丁管理
解压完第一件事,确认你拿到的到底是什么版本。别信文件名,要看源码里的版本号:
# 方法一:看顶层Makefile
head -5 Makefile
# 输出示例:
# VERSION = 6
# PATCHLEVEL = 6
# SUBLEVEL = 8
# EXTRAVERSION =
# NAME = Hurr durr I'ma ninja sloth
这里VERSION.PATCHLEVEL.SUBLEVEL就是完整版本号:6.6.8。EXTRAVERSION如果为空,说明是正式发布版;如果有-rc1之类的后缀,那就是候选发布版——生产环境慎用。
还有一种更直接的方式:
# 方法二:用内核自带的脚本
make kernelversion
# 输出:6.6.8
说到补丁管理,这是内核裁剪里绕不开的环节。你拿到的主线内核是通用版本,但实际项目往往需要打上特定补丁——比如硬件BSP补丁、实时性补丁(PREEMPT_RT)、或者安全补丁。
补丁管理的核心原则:保持补丁可追溯、可回退。我见过最惨的案例是有人直接在源码里手动改,改完三个月后想升级内核版本,结果完全不知道改过哪些地方——等于重做。
- 永远用 quilt 或 git format-patch 管理补丁,不要直接改源码
- 每个补丁只做一件事,命名规范:
序号-模块-描述.patch - 维护一个 PATCHLIST 文件,记录每个补丁的来源、目的、适用版本
打补丁的典型流程:
# 假设你下载了 PREEMPT_RT 补丁
wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.6/patch-6.6.8-rt17.patch.xz
# 解压补丁
unxz patch-6.6.8-rt17.patch.xz
# 进入内核源码目录
cd linux-6.6.8
# 应用补丁(-p1 去掉补丁路径的第一级目录)
xzcat ../patch-6.6.8-rt17.patch.xz | patch -p1
# 验证补丁是否成功应用
find . -name "*.rej" # 如果有.rej文件,说明有冲突
patch --dry-run 做预演,确认没有冲突再真正应用。
查看当前已应用的补丁:
# 如果使用git管理
git log --oneline
# 如果使用quilt
quilt series
# 查看内核构建时显示的版本后缀
cat .config | grep CONFIG_LOCALVERSION
这里有个小技巧:我习惯在Makefile的EXTRAVERSION里加上自定义标识,比如-myproject-v1。这样编译出来的内核通过uname -r一眼就能看出是哪个版本、哪个项目的,调试时省去很多猜疑。
cp -a linux-6.6.8 linux-6.6.8-vanilla这样万一补丁打乱了,随时可以拿干净的源码重来,不用重新下载。
最后说一句:源码获取和解压只是起点,但这一步走得稳,后面裁剪、编译、调试才能顺。别嫌校验签名麻烦,别嫌目录结构复杂——这些都是内核开发的基本功,练熟了就是肌肉记忆。