4、内核配置与裁剪:内核Kconfig详解,基于项目需求裁剪内核模块,减少镜像体积
内核裁剪,说白了就是给Linux内核做「瘦身手术」。
很多刚入行的朋友觉得内核配置就是跑个make menuconfig,然后一路默认。嗯,我刚开始也这么干过。直到有一次,一个只有64MB Flash的IoT项目,默认内核镜像直接塞爆了存储空间——那次加班到凌晨三点,才意识到内核裁剪不是「要不要做」,而是「必须做」。
4.1 Kconfig语法速通:看懂内核的「菜单源码」
Kconfig是内核配置系统的「菜单描述语言」。你看到的menuconfig界面,背后全是Kconfig文件在驱动。
先看一个最简例子:
config MY_DRIVER
bool "Enable My Custom Driver"
default n
help
This is a custom driver for project X.
这段代码定义了一个开关选项。我来拆解一下:
- config:关键字,声明一个配置项
- MY_DRIVER:宏名称,最终会变成
CONFIG_MY_DRIVER - bool:类型,表示二选一(y/n)
- default n:默认关闭
- help:帮助信息
实际项目中,Kconfig的写法要复杂得多。我整理了一份常用类型对照表:
| 类型 | 含义 | 典型场景 |
|---|---|---|
bool |
二选一(y/n) | 功能开关、驱动启用 |
tristate |
三选一(y/m/n) | 可编译为模块的驱动 |
int |
整数输入 | 缓冲区大小、超时时间 |
hex |
十六进制输入 | 内存地址、寄存器偏移 |
string |
字符串输入 | 设备路径、固件名称 |
bool + default n。只有那些需要按需加载的第三方驱动,才用tristate。这样能避免「不小心把驱动编进内核」的尴尬。
4.2 依赖与反向依赖:别让配置「打架」
Kconfig最让人头疼的,就是依赖关系。我曾经在一个项目中,明明关了某个功能,编译时却报错说依赖缺失——查了半天,发现是另一个选项反向依赖了它。
看这个例子:
config USB_STORAGE
tristate "USB Mass Storage support"
depends on USB
config USB_STORAGE_REALTEK
tristate "Realtek USB Card Reader"
depends on USB_STORAGE
select SCSI
这里有两个关键点:
- depends on:前置依赖。USB_STORAGE必须等USB开启后才能选
- select:反向依赖。选了Realtek读卡器,会自动把SCSI选上
你想想看,select其实是个「强制拉入」的机制。用得好可以简化配置,用不好就会引入一堆你根本不需要的东西。
select了一个REGULATOR驱动,结果它又select了I2C,I2C又select了GPIO……最后内核镜像比原来大了30%。所以我的建议是:能用depends on就别用select,除非你非常清楚依赖链的终点。
4.3 基于项目需求裁剪:从「全功能」到「刚刚好」
裁剪内核,不是盲目删东西。你得先搞清楚:你的硬件上有什么?你的业务需要什么?
我一般按这个流程走:
- 跑一次默认配置,生成
.config - 统计镜像大小,记录基线
- 逐模块审查,关闭不需要的驱动
- 反复编译验证,确保功能正常
下面这张图,是我做裁剪时的核心思路:
4.4 高频裁剪点:哪些模块最「占地方」?
根据我的项目经验,下面这几个地方是「减肥重灾区」:
| 子系统 | 典型裁剪项 | 可节省空间 |
|---|---|---|
| 网络协议栈 | IPv6、IPSec、802.11、蓝牙 | 200KB ~ 1MB |
| 文件系统 | NTFS、XFS、Btrfs、FUSE | 300KB ~ 800KB |
| 驱动 | 显卡、声卡、网卡(非目标硬件) | 500KB ~ 2MB |
| 调试特性 | printk、debugfs、trace、lockdep | 100KB ~ 500KB |
| 虚拟化 | KVM、Xen、容器相关 | 200KB ~ 600KB |
4.5 裁剪后的验证:别把「能用的」裁掉了
裁剪最怕什么?最怕把系统裁「残」了。
我建议你做三件事:
- 功能测试:所有业务功能跑一遍,确保驱动正常加载
- 启动日志检查:看
dmesg里有没有failed to probe之类的错误 - 对比
.config:用diff对比裁剪前后的配置文件,确认没有误删
.config备份一份。万一裁坏了,cp回来就行,不用重新配。
4.6 用make savedefconfig生成最小配置
手动裁剪完,.config文件可能还有几千行。怎么把它变成「最小可读」的版本?
用这个命令:
make savedefconfig
它会生成一个defconfig文件,只保留非默认值的选项。说白了,就是「只记录你改过的东西」。
举个例子,原始.config有3000行,savedefconfig之后可能只剩50行。这个文件可以直接放到Buildroot的board/目录下,作为项目的默认内核配置。
savedefconfig生成的配置,依赖内核版本。换内核版本时,最好重新生成一次。我吃过这个亏——升级内核后,旧defconfig直接编译不过。
4.7 本章小结
内核裁剪,说白了就是「做减法」。但减法不是乱减,你得懂Kconfig的语法,理清依赖关系,然后基于硬件清单和业务需求,一刀一刀地裁。
我个人习惯是:先裁掉所有不用的驱动,再关掉调试特性,最后优化文件系统和网络协议栈。每裁一步,编译一次,验证一次。虽然慢,但稳。
嗯,记住一句话:能跑的最小内核,才是最好的内核。