4、Linux内核裁剪:内核配置工具的使用与驱动精简策略
好,咱们进入正题。内核裁剪这事儿,说白了就是给POS机“瘦身”。你想想看,一个完整的Linux内核动辄几百兆,塞进嵌入式设备里,不光占地方,跑起来也费劲。我当年第一次给一款老式热敏打印机做内核移植时,就吃过这个亏——编译出来的内核镜像太大,Flash根本装不下。后来老老实实把配置工具摸透了,才算是入了门。
4.1 内核配置工具:menuconfig与xconfig
Linux内核的配置方式有好几种,但咱们嵌入式开发最常用的,就是menuconfig和xconfig。我个人习惯用menuconfig,因为它基于终端,不需要图形界面,在服务器上也能跑。而xconfig是基于Qt的图形化工具,看着更直观,但需要装一堆依赖库。
4.1.1 menuconfig的基本操作
进入内核源码目录,执行:
make menuconfig
你会看到一个蓝底白字的菜单界面。操作很简单:
- 方向键:上下移动光标
- Enter:进入子菜单
- Y:将该功能编译进内核(静态编译)
- M:编译成模块(模块化编译)
- N:不编译该功能
- ?:查看帮助信息
嗯,这里要注意一点:Y和M的区别,直接决定了你的内核大小和灵活性。我见过不少新手一上来全选Y,结果内核编译出来比原版还大。
.config文件。如果你不确定某个选项的作用,按?键看帮助,里面会告诉你这个驱动依赖哪些其他选项。
4.1.2 xconfig的图形化优势
如果你在开发机上装了图形界面,可以试试xconfig:
make xconfig
它把配置项分成了左右两栏,左边是分类树,右边是具体选项。搜索功能也很方便——按Ctrl+F就能搜到你要的驱动。我个人觉得,当你要批量检查某个驱动是否被选中时,xconfig比menuconfig效率高不少。
4.2 模块化编译 vs 静态编译:怎么选?
这是内核裁剪的核心问题。说白了,就是“把驱动塞进内核”还是“让驱动独立成文件”。
| 对比项 | 静态编译(Y) | 模块化编译(M) |
|---|---|---|
| 内核体积 | 大 | 小 |
| 启动速度 | 快(无需加载模块) | 慢(需加载模块) |
| 灵活性 | 低(改驱动需重编内核) | 高(可动态加载/卸载) |
| 内存占用 | 始终占用 | 按需加载 |
| 适用场景 | 核心驱动、启动必需 | 外设驱动、调试阶段 |
我在项目中遇到过这样一个情况:某款POS机的触摸屏驱动,在量产阶段发现有个bug需要修复。如果当初是静态编译的,就得重新编译整个内核,再刷机。但如果是模块化编译的,我只需要替换一个.ko文件,然后insmod一下就行。你想想看,哪个更省事?
- 把CPU、内存控制器、中断控制器这些核心部件静态编译。
- 把触摸屏、Wi-Fi、蓝牙、音频这些外设驱动编译成模块。
- 调试阶段多用模块,量产前再评估哪些可以静态编译。
4.3 文件系统驱动的精简策略
文件系统驱动这块,是内核裁剪的重灾区。很多嵌入式设备根本用不上ext4、btrfs、xfs这些复杂的文件系统。我见过一个项目,内核里光文件系统驱动就占了2MB,而实际只用到了FAT32和YAFFS2。
4.3.1 按需选择文件系统类型
POS机常用的文件系统就那么几种:
- FAT32:用于SD卡、U盘等可移动存储
- YAFFS2:用于NAND Flash,专门为嵌入式设计
- UBIFS:用于MLC NAND,支持磨损均衡
- ext4:如果你用eMMC,可以考虑,但体积较大
在menuconfig中,进入File systems菜单,把不需要的文件系统全部取消。比如:
File systems --->
[ ] Btrfs filesystem support
[ ] XFS filesystem support
[ ] Reiserfs support
[*] FAT (DOS/Windows) filesystem support
[*] YAFFS2 filesystem support
4.3.2 精简文件系统特性
就算你选定了某个文件系统,它里面还有很多子选项可以裁剪。比如FAT文件系统,你可以关掉:
- VFAT(长文件名支持)——如果只存短文件名,可以关掉
- FAT的调试信息
- FAT的NLS(语言编码)支持——只保留你需要的编码
我曾经在一个项目中,把FAT文件系统的体积从300KB砍到了80KB。怎么做到的?就是把这些子选项一个个检查,只保留必须的。
4.3.3 使用initramfs减少根文件系统依赖
如果你想让内核更小,可以考虑用initramfs。它把根文件系统的一部分打包进内核镜像里,启动时直接解压到内存。这样就不需要挂载真实的存储设备了。
配置方法:
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/path/to/initramfs) Initramfs source file(s)
嗯,这里要注意:initramfs的大小要控制好,太大了反而拖慢启动速度。我一般控制在2MB以内。
4.4 实战:一个POS机内核的裁剪案例
最后,我分享一个实际案例。某款手持POS机的硬件配置如下:
- CPU:ARM Cortex-A7,单核
- 内存:128MB DDR3
- 存储:256MB NAND Flash
- 外设:触摸屏、热敏打印机、磁条卡读卡器、Wi-Fi
原始内核镜像大小:4.2MB。经过裁剪后:1.8MB。具体做了哪些操作?
- 关掉了所有不用的架构支持(只保留ARM)
- 关掉了网络协议栈中不用的部分(比如IPv6、IPSec)
- 文件系统只保留YAFFS2和FAT32
- 触摸屏和打印机驱动编译成模块
- 关掉了内核调试信息和printk
你看,其实没什么高深的技术,就是一个个选项去检查,去试。我刚开始做的时候也觉得很繁琐,但做多了就熟练了。说白了,内核裁剪就是个“做减法”的过程——去掉你不需要的,留下你必需的。
CONFIG_DEVTMPFS,导致系统启动后/dev目录是空的,所有设备都找不到。后来查了半天才发现是这个选项没开。所以,裁剪的时候一定要保留devtmpfs和sysfs,它们是设备管理的基础。
好了,这一章的内容就到这里。下一章我们会讲内核编译的优化技巧,包括如何用ccache加速编译、如何生成最小化的内核镜像。到时候见。