4、Linux内核裁剪:内核配置工具的使用与驱动精简策略

好,咱们进入正题。内核裁剪这事儿,说白了就是给POS机“瘦身”。你想想看,一个完整的Linux内核动辄几百兆,塞进嵌入式设备里,不光占地方,跑起来也费劲。我当年第一次给一款老式热敏打印机做内核移植时,就吃过这个亏——编译出来的内核镜像太大,Flash根本装不下。后来老老实实把配置工具摸透了,才算是入了门。

4.1 内核配置工具:menuconfig与xconfig

Linux内核的配置方式有好几种,但咱们嵌入式开发最常用的,就是menuconfigxconfig。我个人习惯用menuconfig,因为它基于终端,不需要图形界面,在服务器上也能跑。而xconfig是基于Qt的图形化工具,看着更直观,但需要装一堆依赖库。

4.1.1 menuconfig的基本操作

进入内核源码目录,执行:

make menuconfig

你会看到一个蓝底白字的菜单界面。操作很简单:

  • 方向键:上下移动光标
  • Enter:进入子菜单
  • Y:将该功能编译进内核(静态编译)
  • M:编译成模块(模块化编译)
  • N:不编译该功能
  • ?:查看帮助信息

嗯,这里要注意一点:YM的区别,直接决定了你的内核大小和灵活性。我见过不少新手一上来全选Y,结果内核编译出来比原版还大。

我的小技巧:每次修改配置后,记得保存为.config文件。如果你不确定某个选项的作用,按?键看帮助,里面会告诉你这个驱动依赖哪些其他选项。

4.1.2 xconfig的图形化优势

如果你在开发机上装了图形界面,可以试试xconfig

make xconfig

它把配置项分成了左右两栏,左边是分类树,右边是具体选项。搜索功能也很方便——按Ctrl+F就能搜到你要的驱动。我个人觉得,当你要批量检查某个驱动是否被选中时,xconfigmenuconfig效率高不少。

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。怎么做到的?就是把这些子选项一个个检查,只保留必须的。

注意:裁剪文件系统驱动时,一定要先确认你的存储介质类型。比如,如果你用的是NAND Flash,却把YAFFS2或UBIFS给裁掉了,那系统根本起不来。我有个同事就犯过这个错,折腾了一天才发现是文件系统驱动没编进去。

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。具体做了哪些操作?

  1. 关掉了所有不用的架构支持(只保留ARM)
  2. 关掉了网络协议栈中不用的部分(比如IPv6、IPSec)
  3. 文件系统只保留YAFFS2和FAT32
  4. 触摸屏和打印机驱动编译成模块
  5. 关掉了内核调试信息和printk

你看,其实没什么高深的技术,就是一个个选项去检查,去试。我刚开始做的时候也觉得很繁琐,但做多了就熟练了。说白了,内核裁剪就是个“做减法”的过程——去掉你不需要的,留下你必需的。

避坑指南:我曾经因为关掉了CONFIG_DEVTMPFS,导致系统启动后/dev目录是空的,所有设备都找不到。后来查了半天才发现是这个选项没开。所以,裁剪的时候一定要保留devtmpfssysfs,它们是设备管理的基础。

好了,这一章的内容就到这里。下一章我们会讲内核编译的优化技巧,包括如何用ccache加速编译、如何生成最小化的内核镜像。到时候见。