3、操作系统裁剪:Linux内核裁剪原理、Yocto/Buildroot构建最小系统、移除不必要的服务
好,咱们进入第三章。这一章我估计是很多朋友最想听的——操作系统裁剪。
你想想看,一个标准的Linux发行版,动不动几百兆甚至上G。放在HMI上?太奢侈了。HMI的硬件资源就那么点,Flash可能就256MB,内存128MB。你塞个Ubuntu进去,系统还没跑起来,资源就耗光了。
说白了,工业HMI不需要桌面特效,不需要办公软件,不需要浏览器。它只需要:显示画面、处理触摸、跑通信协议、控制IO。其他的,都是累赘。
3.1 Linux内核裁剪原理
内核裁剪,核心思路就一句话:用不到的模块,一个都不要。
我刚开始做裁剪时,犯过一个低级错误。我直接把所有驱动都编进内核,想着“反正用不到也不会跑”。结果呢?内核镜像从4MB膨胀到12MB,启动时间多了3秒。后来我才明白,驱动虽然不加载,但初始化代码会执行,内存也会被占用。
核心原则:
- 能编成模块的,不要编进内核
- 用不到的模块,直接去掉
- 文件系统支持,只留你用的那个
- 网络协议栈,HMI一般只需要TCP/IP
具体怎么做?我习惯用 make menuconfig 来配置。进去之后,你会看到密密麻麻的选项。别慌,按这个思路来:
- General setup:保留基础功能,去掉内核调试、追踪、性能分析。这些在产线上没用。
- Enable loadable module support:这个要开。模块化是好习惯。
- Processor type and features:选对你的CPU型号。ARM就选ARM,别选x86。
- Device Drivers:这是大头。只留你硬件上有的设备。比如你的HMI用SPI触摸屏,那就只留SPI驱动和触摸屏驱动。网卡驱动、声卡驱动、显卡驱动,没有就全关。
- File systems:只留你用的文件系统。我一般用UBIFS或ext4。其他的像NTFS、XFS、Btrfs,统统关掉。
- Networking support:保留TCP/IP,去掉IPX、AX.25、蓝牙、Wi-Fi(除非你需要)。
我的小技巧:
裁剪完后,用 make savedefconfig 生成一个最小配置文件。下次换平台,直接拿这个改,省事。
3.2 Yocto/Buildroot构建最小系统
内核裁剪完了,接下来是构建整个系统。这里有两个主流工具:Yocto和Buildroot。我两个都用过,说说我的感受。
3.2.1 Buildroot:轻量级,适合小团队
Buildroot,说白了就是一个自动化编译脚本。你配置好目标平台、选择软件包,它帮你把交叉编译工具链、内核、根文件系统全部搞定。
我个人的习惯是:
- 用
make menuconfig配置 - Target options:选对架构(ARM、ARM64、x86等)
- Toolchain:用Buildroot自带的,或者外部的
- System configuration:设置主机名、root密码、启动脚本
- Target packages:只选你需要的。比如HMI需要Qt,那就选上Qt。不需要的,一个都不要勾
举个例子,一个最小HMI系统的软件包列表:
# 必须的
busybox # 基础命令
qt5base # 图形界面
tslib # 触摸屏校准
libmodbus # Modbus通信
libgpiod # GPIO控制
# 可选的
dropbear # SSH(调试用)
i2c-tools # I2C调试
strace # 调试工具(产线上去掉)
Buildroot编译完,输出三个文件:zImage(内核)、rootfs.cpio.uboot(根文件系统)、.dtb(设备树)。加起来不到20MB。嗯,这才像话。
3.2.2 Yocto:企业级,适合复杂项目
Yocto比Buildroot复杂得多,但功能也强大得多。它用BitBake作为构建引擎,支持层(Layer)的概念。
我记得第一次用Yocto时,被它的配置方式搞晕了。后来才明白,Yocto的核心是配方(Recipe)。每个软件包都有一个.bb文件,描述从哪里下载、怎么编译、依赖什么。
构建最小系统的步骤:
- 下载Yocto源码:
git clone git://git.yoctoproject.org/poky - 初始化环境:
source oe-init-build-env - 配置
local.conf:设置MACHINE(目标平台)、DISTRO(发行版类型) - 添加需要的层:比如meta-qt5(Qt支持)、meta-openembedded(额外软件包)
- 运行
bitbake core-image-minimal或自定义镜像
注意:
Yocto第一次编译会下载大量源码,耗时很长。我建议你搭一个本地镜像服务器,或者用预编译的sstate缓存。不然每次clean build,等得你想哭。
3.3 移除不必要的服务
系统构建好了,但里面还有很多默认启动的服务。这些服务,大部分HMI都用不上。
我列一个典型的“黑名单”:
| 服务名称 | 作用 | HMI是否需要 |
|---|---|---|
| syslogd | 系统日志 | 调试时需要,产线上去掉 |
| crond | 定时任务 | 一般不需要 |
| bluetoothd | 蓝牙服务 | 不需要 |
| NetworkManager | 网络管理 | 不需要,用静态IP即可 |
| avahi-daemon | 零配置网络 | 不需要 |
| systemd-journald | 日志服务 | 可以精简 |
怎么移除?我一般用两种方法:
- Buildroot:在
target_skeleton里直接删掉对应的init脚本,或者在配置里取消勾选 - Yocto:在自定义镜像的.bb文件里,用
IMAGE_INSTALL_remove去掉不需要的包
举个例子,Yocto里移除不需要的服务:
IMAGE_INSTALL_remove = " \
packagegroup-core-boot \
systemd-extra-utils \
avahi-daemon \
bluez5 \
cronie \
"
避坑指南:
我曾经在产线上遇到一个问题:HMI启动后,触摸屏没反应。查了半天,发现是 systemd-logind 服务占用了输入设备。关掉它,问题解决。所以,移除服务时一定要测试,别一刀切。
好了,这一章的内容就这些。内核裁剪、系统构建、服务移除,这三步走完,你的HMI系统应该能控制在30MB以内,启动时间10秒左右。下一章,我们聊聊启动优化——怎么把这10秒再压缩到5秒。