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 来配置。进去之后,你会看到密密麻麻的选项。别慌,按这个思路来:

  1. General setup:保留基础功能,去掉内核调试、追踪、性能分析。这些在产线上没用。
  2. Enable loadable module support:这个要开。模块化是好习惯。
  3. Processor type and features:选对你的CPU型号。ARM就选ARM,别选x86。
  4. Device Drivers:这是大头。只留你硬件上有的设备。比如你的HMI用SPI触摸屏,那就只留SPI驱动和触摸屏驱动。网卡驱动、声卡驱动、显卡驱动,没有就全关。
  5. File systems:只留你用的文件系统。我一般用UBIFS或ext4。其他的像NTFS、XFS、Btrfs,统统关掉。
  6. 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文件,描述从哪里下载、怎么编译、依赖什么。

构建最小系统的步骤:

  1. 下载Yocto源码:git clone git://git.yoctoproject.org/poky
  2. 初始化环境:source oe-init-build-env
  3. 配置 local.conf:设置MACHINE(目标平台)、DISTRO(发行版类型)
  4. 添加需要的层:比如meta-qt5(Qt支持)、meta-openembedded(额外软件包)
  5. 运行 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秒。