4、根文件系统构建:BusyBox制作最小根文件系统、Yocto/Buildroot高级构建、文件系统优化与启动加速

根文件系统,说白了就是嵌入式Linux的「家」。

内核启动后,得有个地方放应用程序、库文件、配置文件、设备节点。这个「地方」就是根文件系统。我刚开始做医疗显微镜项目时,觉得随便搞个文件系统能跑就行。结果发现,启动慢、体积大、稳定性差,问题一堆。嗯,这章咱们就把根文件系统这件事彻底讲透。

4.1 BusyBox:最小根文件系统的基石

BusyBox是什么?它是个「瑞士军刀」。一个二进制文件,集成了两百多个Linux命令。ls、cp、mv、sh、init……全在里面。我习惯叫它「瘦身版Linux工具集」。

制作最小根文件系统,BusyBox是首选。为什么?因为它小。一个完整的BusyBox才几百KB,放在医疗显微镜这种资源受限的设备上,再合适不过了。

4.1.1 编译BusyBox

步骤其实不复杂。我带你走一遍:

# 下载源码
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xjf busybox-1.36.1.tar.bz2
cd busybox-1.36.1

# 配置
make menuconfig

# 关键配置项
# Settings -> Build static binary (no shared libs)  [建议不选,除非你静态编译]
# Settings -> Cross compiler prefix = arm-linux-gnueabihf-
# Settings -> Destination path for 'make install' = ../rootfs

# 编译并安装
make -j4
make install

这里有个坑。我曾经在配置时忘了指定交叉编译器前缀,结果编译出来的是x86版本,放到ARM板子上直接报「无法执行二进制文件」。你想想看,排查了半天才发现是架构不对,多耽误事。

注意:交叉编译器前缀一定要和你的内核、uboot保持一致。否则文件系统与内核不匹配,启动时会挂掉。

4.1.2 构建最小根文件系统目录结构

BusyBox安装完成后,会在目标目录生成bin、sbin、usr等目录。但这还不够。我们需要手动创建一些关键目录和文件:

cd ../rootfs
mkdir -p dev etc lib proc sys tmp var mnt root

这些目录各有用途:

  • dev:设备节点。没有它,你连串口都用不了。
  • etc:配置文件。inittab、fstab、passwd都在这里。
  • lib:动态库。如果BusyBox是动态编译的,这里必须有glibc或uClibc。
  • proc、sys:虚拟文件系统挂载点。内核信息、硬件状态全靠它们。

我个人习惯,还会在root下放一个「first_run.sh」脚本,用于首次启动时的初始化工作。比如校准触摸屏、设置网络参数等。

4.1.3 配置init进程

根文件系统启动后,内核会执行第一个用户空间程序——init。BusyBox自带init,但需要配置文件:

# etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

再创建rcS脚本:

# etc/init.d/rcS
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
mdev -s
echo "Welcome to Medical Microscope System"

记得给rcS加上执行权限:chmod +x etc/init.d/rcS。我曾经忘了这一步,启动后卡在「Kernel panic - not syncing: No init found」,排查了半小时才发现是脚本没权限。嗯,这种低级错误,犯过一次就记住了。

4.2 Yocto与Buildroot:高级构建工具

BusyBox适合快速原型。但如果你要构建一个完整的、可定制的、包含图形界面和医疗库的根文件系统,Yocto和Buildroot才是正解。

4.2.1 Buildroot:轻量级选择

Buildroot我用了很多年。它简单、直接、编译快。适合医疗显微镜这种中等复杂度的项目。

使用步骤:

# 下载
git clone https://git.buildroot.net/buildroot
cd buildroot

# 配置
make menuconfig

# 关键配置
# Target options -> Target Architecture = ARM (little endian)
# Toolchain -> Toolchain type = External toolchain
# System configuration -> Root filesystem overlay directory = ../my_overlay
# Filesystem images -> ext2/3/4, squashfs, tar

# 编译
make

Buildroot有个很贴心的功能:overlay目录。你可以把自定义的配置文件、脚本、应用程序放在my_overlay里,编译时会自动合并到根文件系统。我在项目中就用这个特性,把显微镜的校准参数和UI资源文件单独管理,方便版本迭代。

小技巧:Buildroot支持多种文件系统格式。医疗设备我推荐用squashfs(只读)配合overlayfs(可写层)。既保证了系统完整性,又能保存用户配置。

4.2.2 Yocto:企业级方案

Yocto比Buildroot复杂得多,但灵活性和可维护性也强得多。如果你要量产医疗显微镜,Yocto是更稳妥的选择。

Yocto的核心概念是「层」(Layer)。你可以把BSP层、应用层、GUI层分开管理。我参与的一个项目,BSP由硬件团队维护,应用层由软件团队维护,互不干扰。

一个典型的Yocto项目结构:

meta-microscope/          # 自定义层
├── conf/
│   └── layer.conf
├── recipes-core/
│   └── microscope-image/
│       ├── microscope-image.bb
│       └── files/
│           ├── inittab
│           └── rc.local
├── recipes-graphics/
│   └── qt5/
│       └── qt5-opengl_%.bbappend
└── recipes-bsp/
    └── u-boot/
        └── u-boot_%.bbappend

Yocto的编译时间确实长。第一次编译可能要几个小时。但好处是,一旦配置好,后续的增量编译很快。而且Yocto生成的根文件系统,所有依赖都自动解决,不会出现「缺库」这种烦心事。

4.3 文件系统优化与启动加速

医疗显微镜对启动时间有要求。病人等着做检查,你不能让设备启动两分钟吧?我见过一个项目,启动花了45秒,被客户直接退货。所以,优化启动速度是必修课。

4.3.1 文件系统体积优化

体积越小,加载越快。怎么瘦身?

  • 删除不必要的命令:BusyBox配置时,只选需要的。比如医疗设备不需要ftp、telnet,去掉。
  • 使用uClibc或musl:比glibc小得多。我测试过,musl编译的BusyBox体积减少40%。
  • 剥离调试符号arm-linux-strip --strip-unneeded 可以干掉二进制文件中的调试信息。
  • 压缩文件系统:squashfs配合LZ4压缩,体积小且解压快。
实战数据:我优化过一个项目,根文件系统从32MB降到8MB,启动时间从28秒降到11秒。主要手段就是换musl库和去掉无用命令。

4.3.2 启动流程优化

启动加速不只是压缩文件系统。整个启动链都要优化:

阶段 优化方法 效果
Bootloader 减少延时、去掉不必要的硬件初始化 节省1-2秒
内核 裁剪驱动、使用LZ4压缩内核 节省2-3秒
根文件系统 使用squashfs、并行初始化服务 节省3-5秒
应用程序 延迟加载、预链接 节省1-2秒

我个人最推荐的一个优化点是:并行启动服务。传统的init是串行执行rcS脚本,一个服务卡住,后面的全等。改用BusyBox的start-stop-daemon配合后台运行,可以大幅缩短启动时间。

4.3.3 使用initramfs加速

initramfs是把根文件系统打包进内核镜像。内核启动时直接解压到内存,省去了挂载存储设备的时间。

配置方法:

# 内核配置
General setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support
    -> Initramfs source file(s) = ../rootfs.cpio.gz

initramfs的缺点是占用内存。如果你的设备内存只有64MB,可能不太合适。但医疗显微镜一般配256MB以上,用initramfs完全没问题。

注意:initramfs中的文件系统是只读的。如果需要保存用户配置,必须挂载一个可写分区(比如用overlayfs)。我曾经犯过这个错——用initramfs启动后,发现WiFi密码保存不了,折腾了半天才想起来没挂载可写层。

4.4 实战:医疗显微镜根文件系统构建清单

好了,理论讲完了。我给你一个可以直接用的清单:

  1. 选择工具:快速原型用BusyBox,量产用Yocto或Buildroot。
  2. 配置内核:确保支持你选的文件系统格式(ext4、squashfs、overlayfs)。
  3. 构建根文件系统:包含必要的库、设备节点、配置文件。
  4. 优化体积:strip、压缩、去掉无用组件。
  5. 优化启动:并行初始化、initramfs、延迟加载。
  6. 测试验证:用QEMU模拟启动,确认无报错。再烧录到真机。

最后说一句。根文件系统不是「一次构建,终身使用」。随着功能迭代,文件系统也要持续优化。我每个季度都会重新审视一次根文件系统的配置,看看有没有可以精简的地方。毕竟,医疗设备对稳定性和启动速度的要求,永远没有上限。