1. 理解根文件系统与RK3568开发基础
在嵌入式Linux开发中,根文件系统(rootfs)扮演着操作系统基石的角色。简单来说,它就像Windows的C盘,包含了系统运行所需的所有关键文件和目录结构。RK3568作为瑞芯微推出的高性能处理器,广泛应用于智能硬件领域,其开发流程中根文件系统的定制尤为关键。
我第一次接触RK3568开发板时,发现官方提供的Ubuntu根文件系统镜像往往包含了许多用不到的软件包。比如一个标准的Ubuntu 20.04镜像可能包含办公套件、多媒体工具等,而实际产品可能只需要基础的命令行工具。这种"肥胖"的系统不仅占用宝贵存储空间,还会影响启动速度和运行效率。
根文件系统的典型目录结构包括:
- /bin和/sbin:存放基础命令工具
- /etc:系统配置文件
- /lib:共享库文件
- /usr:用户程序和数据
- /dev:设备文件
- /proc和/sys:虚拟文件系统
在RK3568平台上,完整的系统镜像通常包含三个核心部分:
- U-Boot引导程序
- Linux内核镜像(含设备树)
- 根文件系统镜像
开发过程中最常见的痛点就是根文件系统镜像过大导致烧写失败。我遇到过多次因为rootfs.img超过分区设置大小而导致系统无法启动的情况,这也是为什么我们需要掌握定制和优化根文件系统的技能。
2. 从运行系统中导出原始根文件系统
2.1 准备工作与环境配置
假设我们已经在RK3568开发板上部署了Ubuntu系统并安装了必要的应用程序,现在需要将这个"黄金系统"导出为可复用的根文件系统镜像。我推荐使用Firefly官方提供的导出工具链,这比手动操作更可靠。
首先确保开发板联网,然后执行以下命令安装必要工具:
sudo apt update sudo apt install fireflydev -y选择存储介质时有几个注意事项:
- 建议使用至少8GB的U盘或移动硬盘
- 存储设备需要格式化为EXT4文件系统
- 避免使用FAT32格式(有4GB单文件限制)
格式化存储设备的命令示例:
sudo umount /dev/sdX # 先卸载设备 sudo mkfs.ext4 /dev/sdX sudo e2label /dev/sdX RK3568_ROOTFS # 给设备设置易识别的标签2.2 执行根文件系统导出
挂载准备好的存储设备后,使用fireflydev提供的导出脚本:
sudo ff_export_rootfs /media/your_username/RK3568_ROOTFS这个导出过程实际上做了以下几件事:
- 清理apt缓存和临时文件(相当于执行apt clean)
- 排除/proc、/sys等虚拟文件系统
- 保留文件权限和属性
- 将整个系统打包为.img映像文件
导出时间取决于系统大小,在我的测试中:
- 基础Ubuntu系统约需10分钟
- 安装了大量应用的系统可能需30分钟以上
完成后,你会在存储设备上看到类似Ubuntu20.04.5LTS_Firefly_ext4_20230314.img的文件。但这里有个坑:导出的镜像会占用整个分区空间(比如8GB),而实际文件可能只有3GB。这就是为什么我们需要后续的优化步骤。
3. 根文件系统映像的精简与优化
3.1 分析映像文件的实际使用情况
首先检查导出的.img文件实际占用的空间:
sudo dumpe2fs -h Ubuntu20.04.5LTS_Firefly_ext4_20230314.img | grep 'Block count'对比实际使用的空间:
sudo mount -o loop Ubuntu20.04.5LTS_Firefly_ext4_20230314.img /mnt du -sh /mnt sudo umount /mnt在我的案例中,一个7.8GB的镜像实际只使用了2.9GB空间,这意味着有近5GB的"虚胖"。
3.2 手动精简映像文件大小
传统方法如resize2fs效果有限,我推荐更彻底的手动重建方法:
- 创建精确大小的新映像文件:
dd if=/dev/zero of=rootfs_optimized.img bs=1M count=3000 # 创建3GB文件 mkfs.ext4 rootfs_optimized.img- 挂载新旧两个映像:
mkdir -p /mnt/{old,new} sudo mount -o loop Ubuntu20.04.5LTS_Firefly_ext4_20230314.img /mnt/old sudo mount -o loop rootfs_optimized.img /mnt/new- 复制文件(关键步骤!):
sudo cp -a /mnt/old/* /mnt/new/ sync这里必须使用-a参数保留所有文件属性,否则可能导致系统无法启动。我曾因为漏掉这个参数调试了整整一天。
- 检查并卸载:
df -h /mnt/new sudo umount /mnt/{old,new}3.3 进阶优化技巧
除了空间优化,还可以进一步精简系统:
- 删除无用语言包:
sudo mount -o loop rootfs_optimized.img /mnt sudo find /mnt/usr/share/locale -mindepth 1 -maxdepth 1 ! -name 'en*' -exec rm -rf {} +- 清理文档和手册:
sudo rm -rf /mnt/usr/share/{doc,man}- 优化库文件:
sudo find /mnt -name '*.a' -delete sudo strip /mnt/usr/lib/* 2>/dev/null || true这些操作可以再节省200-500MB空间,但要注意测试系统功能完整性。
4. 集成到SDK编译流程
4.1 准备编译环境
将优化后的rootfs_optimized.img重命名为SDK预期的文件名:
mv rootfs_optimized.img rk356x_ubuntu_rootfs.img把文件放入SDK目录结构中的正确位置:
icore-3568jq/ ├── ubuntu_rootfs/ │ └── rk356x_ubuntu_rootfs.img ├── kernel/ └── u-boot/4.2 执行完整编译
进入SDK根目录执行:
./build.sh all编译过程会经历多个阶段:
- U-Boot编译:生成引导加载程序
- Kernel编译:生成内核镜像和设备树
- 打包阶段:将所有组件整合为烧写镜像
我建议首次编译时添加-jN参数加速(N=CPU核心数×1.5):
./build.sh all -j$(($(nproc)*3/2))4.3 处理常见编译问题
- 分区大小不匹配:修改
parameter-ubuntu-fit.txt中的rootfs分区大小 - 文件系统校验失败:确保镜像格式为EXT4且未被压缩
- 依赖缺失:执行
sudo apt install build-essential libssl-dev
编译成功后,输出文件通常位于:
rockdev/pack/UEJR-004-MIPI_Rk356x_vX.X.X_日期.img5. 验证与烧写优化后的系统
5.1 使用QEMU进行快速验证
在烧写到实体设备前,建议先用QEMU验证:
sudo apt install qemu-user-static mkdir -p /mnt/rootfs sudo mount -o loop rk356x_ubuntu_rootfs.img /mnt/rootfs sudo cp /usr/bin/qemu-aarch64-static /mnt/rootfs/usr/bin/ sudo chroot /mnt/rootfs /bin/bash在chroot环境中可以测试基础命令、网络功能等。退出时记得:
exit sudo umount /mnt/rootfs5.2 烧写到RK3568开发板
- 使设备进入Loader模式(通常按住Recovery键上电)
- 使用RKDevTool选择生成的.img文件
- 执行擦除Flash后烧写
烧写过程中常见的两个坑:
- USB连接不稳定:尽量使用主机后置USB接口
- 镜像过大:检查是否已正确优化根文件系统大小
5.3 启动后的优化检查
系统首次启动后,建议检查:
df -h # 查看分区挂载情况 journalctl -b # 检查启动日志 systemctl list-units --failed # 检查失败服务我在实际项目中总结的几点经验:
- 首次启动后立即执行
apt update && apt upgrade - 设置合理的swap分区(特别是内存有限的设备)
- 禁用不必要的系统服务(如蓝牙、ModemManager)
通过这样完整的流程,我们不仅能得到精简高效的根文件系统,还能完全掌握从导出到部署的全过程。记得每次修改都要做好版本标记,我习惯用日期+特性缩写的方式命名镜像,比如rk356x_rootfs_20230809_minimal.img。当需要回滚时,这种命名规范能节省大量时间。