3. 内核配置与编译系统
内核裁剪,说白了就是给Linux内核做「瘦身手术」。你想想看,一个通用内核里塞了几千个驱动和功能模块,但你的ARM板子可能只需要其中不到10%。把不需要的砍掉,内核就能跑得更快、占得更少、启动时间更短。
我在项目里遇到过一块Flash只有8MB的工业控制板,通用内核根本塞不进去。那次之后,我算是把内核裁剪这门手艺彻底练熟了。
make menuconfig:图形化配置入门
配置内核最常用的工具就是 make menuconfig。它基于ncurses库,在终端里给你一个图形界面。操作起来很简单:
# 进入内核源码目录
cd linux-5.10.y
# 加载默认配置(针对ARM架构)
make ARCH=arm defconfig
# 启动图形化配置界面
make ARCH=arm menuconfig
界面里你会看到三层结构:
- 主菜单:按功能分类的大项,比如General setup、Device Drivers
- 子菜单:按Enter进入,里面是具体的配置项
- 配置项:三种状态——
[*](built-in)、[M](模块)、[ ](禁用)
操作小技巧:按 / 键可以搜索配置项名称,输入 CONFIG_MMC 就能快速定位SD卡驱动。我经常用这个功能,比手动翻菜单快多了。
内核模块 vs built-in:到底怎么选?
这是裁剪时最纠结的问题。我画了一张图帮你理清思路:
我个人的经验法则很简单:
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 根文件系统驱动(MMC/SD、NAND Flash) | built-in | 内核启动时需要挂载根文件系统,模块还没加载 |
| 网络协议栈、调度器核心 | built-in | 系统运行的基础,不能卸载 |
| USB、WiFi、蓝牙驱动 | 模块 | 设备可能热插拔,按需加载 |
| 调试工具、测试驱动 | 模块 | 开发阶段频繁修改,模块化方便替换 |
| 不常用的硬件驱动 | 禁用 | 裁剪掉,节省空间 |
我曾经踩过的坑:有一次我把SD卡驱动配成了模块,结果内核启动后根文件系统在SD卡上,模块还没加载,系统直接panic了。嗯,从那以后我记住了——根文件系统所在的存储设备驱动,必须built-in。
裁剪原则与最小系统概念
什么叫最小系统?就是能让你的ARM板子正常启动、跑起应用程序的最简内核配置。我总结了一套「三步裁剪法」:
- 先跑起来:用默认配置编译,确认板子能正常启动
- 再砍掉:逐项禁用不需要的功能,每改一次就编译测试
- 最后优化:把模块化的驱动按需加载,进一步缩小内核体积
裁剪时记住这几个原则:
- 架构相关不能动:CPU型号、内存映射、中断控制器这些,动了就起不来
- 启动路径必须通:从bootloader到内核解压,再到挂载根文件系统,这条链上的驱动一个都不能少
- 按需配置驱动:你的板子上有什么硬件,就配什么驱动。多一个都不要
- 文件系统支持要精简:只用你实际用的文件系统类型,比如ext4、squashfs
最小系统清单(ARM Cortex-A系列):
- CPU架构:ARMv7-A或ARMv8-A
- 定时器:ARM Generic Timer
- 中断控制器:GIC v2/v3
- 串口驱动:用于控制台输出
- 存储驱动:MMC/SD或NAND Flash
- 根文件系统:ext4或squashfs
- 网络协议栈:TCP/IP(如果需要网络)
保存与加载配置文件
配置好内核后,一定要保存配置。我见过太多人配了半天,结果忘了保存,下次从头再来。
# 保存当前配置到默认位置
make ARCH=arm savedefconfig
# 或者手动复制
cp .config arch/arm/configs/my_board_defconfig
# 下次加载
make ARCH=arm my_board_defconfig
savedefconfig 命令会生成一个精简版的配置文件,只保留与默认值不同的选项。这个文件可读性更好,也方便版本管理。
我个人习惯把不同阶段的配置都保存下来:
| 配置文件 | 用途 |
|---|---|
defconfig |
板级默认配置,用于日常开发 |
minimal_defconfig |
最小系统配置,用于生产环境 |
debug_defconfig |
开启调试选项,用于问题排查 |
版本管理小技巧:把 defconfig 文件提交到Git仓库,每次修改都记录变更。这样出了问题可以快速回退到上一个可用版本。我在团队里推行这个做法后,再也没出现过「谁改了配置导致起不来」的扯皮情况。
最后提醒一句:裁剪不是一锤子买卖。随着项目推进,你可能需要添加新功能、支持新硬件。每次修改配置后,都重新编译测试一遍。别偷懒,这个习惯能帮你省下大把调试时间。