4. 内核裁剪基础:make menuconfig 使用、模块与内建的选择策略、裁剪掉不需要的驱动
内核裁剪,说白了就是给你的 Linux 系统「瘦身」。嵌入式设备资源有限,Flash 和 RAM 都金贵得很。你想想看,一个完整的内核动辄几十兆,塞进只有 8MB Flash 的板子里,根本不可能。所以,我们得学会怎么把不需要的东西统统砍掉。
我个人习惯,拿到一块新板子,第一件事不是急着写驱动,而是先跑一遍 make menuconfig,把能关的先关了。这就像装修前先砸墙,把非承重墙拆了,空间才够用。
4.1 make menuconfig 的界面与操作
在源码根目录下执行 make menuconfig,你会看到一个基于 ncurses 的图形界面。别被它复古的外表吓到,这玩意儿效率极高。
界面主要分三块:
- 顶部:操作提示栏,告诉你按什么键。
- 中间:配置树,所有内核选项都挂在这里。
- 底部:功能按钮,比如 Save、Load、Exit。
常用的快捷键就这几个:
| 按键 | 功能 |
|---|---|
| Y | 将选项编译进内核(内建) |
| M | 将选项编译为模块 |
| N | 不编译该选项 |
| Space | 循环切换 Y / M / N |
| / | 搜索选项(支持模糊匹配) |
| ? | 查看选项的帮助信息 |
我的小技巧: 遇到不认识的选项,先按 ? 看帮助。很多选项的 help 里会写明它依赖哪些硬件,或者建议你选 Y 还是 M。这比瞎猜靠谱多了。
4.2 模块与内建的选择策略
这是内核裁剪的核心问题:某个功能,到底该编进内核(Y),还是编成模块(M),或者直接砍掉(N)?
我总结了一个「三问决策法」:
- 这个功能,系统启动时必须要有吗? 比如根文件系统所在的磁盘驱动、串口驱动。这些必须编进内核,否则系统都起不来。
- 这个功能,我需要在运行时动态加载/卸载吗? 比如 USB 摄像头驱动、Wi-Fi 驱动。这些做成模块,插上设备时自动加载,拔掉时自动卸载,省内存。
- 这个功能,我这辈子都用不上吗? 比如你用的是 ARM 板,那 x86 相关的驱动统统选 N。别犹豫,砍掉。
下面这张图,是我自己画的一个决策流程,帮你快速判断:
核心原则:
- 内建 (Y):启动依赖、性能敏感、不会变动的功能。
- 模块 (M):热插拔设备、可选功能、调试工具。
- 不编译 (N):与硬件无关、用不到、过时的功能。
4.3 裁剪掉不需要的驱动
这是最花时间,但也最见功夫的环节。我刚开始做裁剪时,总怕砍错了导致系统起不来。后来我学乖了——先做减法,再做加法。
具体步骤是这样的:
- 确定目标硬件:列出板子上所有的外设芯片型号。比如网卡是 DM9000,音频是 WM8960,等等。
- 保留必须的:CPU 架构、内存管理、进程调度、文件系统、串口。这些是底线,不能动。
- 批量关闭:在
Device Drivers菜单下,把明显不相关的硬件驱动全部选 N。比如你的板子没有 PCIe 总线,那整个 PCIe 子系统都可以关掉。 - 按需开启:只把步骤 1 里列出的芯片驱动选上。能选模块的就选 M,不确定的先选 M。
- 编译测试:编译出内核和模块,烧到板子上跑一遍。如果某个功能不正常,再回来调整。
我曾经踩过的坑: 有一次我裁剪完内核,烧进去发现网卡不工作。查了半天,发现是
PHY 驱动没选。很多网卡驱动依赖底层的 PHY 驱动,但 menuconfig 里它们不在同一个菜单下。所以,一定要看驱动的依赖关系。按 / 搜索选项时,注意看 Depends on 那一行。
下面这张表,是我整理的一些常见可裁剪模块,供你参考:
| 子系统 | 常见可裁剪项 | 裁剪理由 |
|---|---|---|
| 网络 | IPV6、WEXT、无线网卡驱动 | 嵌入式设备通常只用 IPv4,WEXT 已被 cfg80211 取代 |
| 音频 | OSS 驱动、非板载声卡驱动 | 现在都用 ALSA,OSS 是过时的 API |
| USB | USB 打印机、USB 存储、USB 串口 | 除非你的设备需要这些功能,否则全关 |
| 文件系统 | NTFS、XFS、Btrfs、FAT(如果不用) | 嵌入式常用 ext4、squashfs、jffs2,其他可以砍 |
| 图形 | DRM 驱动(非本板卡)、FBDEV 驱动 | 只保留板子对应的显示驱动 |
| 虚拟化 | KVM、Xen、VirtualBox 驱动 | 嵌入式设备一般不跑虚拟机 |
4.4 实战:从零开始裁剪一个最小内核
光说不练假把式。我们拿一个常见的 ARM 开发板(比如 S3C2440)来走一遍流程。
执行 make ARCH=arm menuconfig,然后:
- 关闭架构无关的选项:
进入General setup,关掉Kernel .config support、Kernel log buffer size可以调小(比如 64KB)。 - 关闭不用的总线:
进入Bus support,关掉PCI、ISA、EISA。ARM 板一般只用 AMBA/AXI。 - 裁剪设备驱动:
进入Device Drivers,把Network device support里除了 DM9000 以外的网卡驱动全关。
把Input device support里除了键盘、触摸屏以外的全关。
把Graphics support里除了 LCD 控制器以外的全关。 - 精简文件系统:
进入File systems,只保留ext4、squashfs、proc、sysfs、tmpfs。其他全关。 - 保存退出:
按 Save,命名为.config,然后退出。
这样一轮操作下来,一个原本 3MB 的内核,能压缩到 1.2MB 左右。如果再用 LZMA 压缩,最终镜像可能只有 600KB。嗯,这才像嵌入式该有的样子。
我的习惯: 每次裁剪完,我都会把
.config 文件备份一份,命名为 config_<日期>_<备注>。这样万一改坏了,还能快速回退。另外,make savedefconfig 可以生成一个最小化的配置文件,方便版本管理。
内核裁剪不是一锤子买卖。随着项目推进,你可能需要添加新的驱动,或者发现某个功能其实用不到。所以,保持 .config 的整洁,定期 review,是个好习惯。