1、SDK根文件系统概述
各位同学好,我是你们的SDK发布工程师。今天咱们正式开始这门课的第一章——根文件系统概述。
说实话,我刚开始做嵌入式Linux时,对根文件系统的理解也很模糊。那时候总觉得,不就是一堆文件夹和文件吗?直到有一次,我发布的SDK在客户板子上启动到一半就挂了,日志停在"Kernel panic - not syncing: VFS: Unable to mount root fs"……嗯,从那以后,我再也不敢小看根文件系统了。
1.1 什么是根文件系统
根文件系统,英文叫 Root Filesystem,简称 rootfs。它不是什么高深的概念,说白了就是Linux内核启动后挂载的第一个文件系统。
你想想看,Linux内核本身只是一个"光杆司令"。它知道怎么管理CPU、内存、外设,但它不知道去哪里找应用程序、库文件、配置文件。根文件系统就是给内核指路的——告诉它:"你的家在这里,你的孩子(进程)在这里,你的家当(设备节点)也在这里。"
根文件系统至少包含以下几样东西:
- 目录结构——经典的 /bin、/sbin、/etc、/usr、/var 等
- init 程序——内核启动后运行的第一个用户态进程
- C 库——所有应用程序的"地基",比如 glibc 或 musl
- 设备节点——/dev 下的各种设备文件
- 配置文件——/etc 下的网络、服务、启动脚本等
核心要点:没有根文件系统,Linux内核就是个空壳。它启动后会直接 panic,连个错误提示都来不及给你看全。
1.2 根文件系统在嵌入式Linux中的角色
嵌入式Linux和桌面Linux不一样。桌面Linux的根文件系统通常装在大硬盘上,空间管够。但嵌入式设备呢?Flash 空间可能只有 8MB、16MB,甚至更少。这时候根文件系统的角色就变得非常特殊。
我个人习惯把根文件系统在嵌入式中的角色归纳为三点:
- 系统启动的"最后一公里"——内核启动后,根文件系统负责拉起 init 进程,然后 init 再拉起所有服务。这一环断了,整个系统就废了。
- 用户态程序的"家"——所有你写的应用程序、第三方库、脚本,都得放在根文件系统里。没有它,你的代码就是一堆死文件。
- 资源受限环境下的"精打细算"——嵌入式根文件系统必须瘦身。我在项目中遇到过,一个客户要求根文件系统总大小不超过 4MB,还得跑 Web 服务器和 MQTT 客户端。那段时间我天天跟 busybox 和 musl 打交道,硬是把一个 20MB 的系统压缩到了 3.8MB。
为什么会这样?因为嵌入式设备的 Flash 芯片不仅容量小,而且写入次数有限。你不可能像 PC 那样随便装个几百 MB 的 Ubuntu。所以,嵌入式根文件系统的设计哲学就是:够用就好,多一个字节都是浪费。
我的经验:刚开始做嵌入式 SDK 的同学,最容易犯的错误就是把桌面 Linux 的根文件系统直接搬过来。结果发现 Flash 装不下,或者启动后内存不够用。记住,嵌入式不是"缩小版"的桌面,它是"定制版"的。
1.3 SDK版本号命名规范
好了,聊完了根文件系统本身,咱们来说说 SDK 版本号。你可能觉得版本号就是个数字,随便写写就行。但我告诉你,版本号命名不规范,后续维护会非常痛苦。
我曾经接手过一个项目,版本号叫 "v1.2.3_final_final2"。你猜后来发生了什么?客户反馈了一个 bug,我们花了三天才搞清楚他用的到底是哪个版本。从那以后,我定了一条铁律:版本号必须语义化、可追溯、无歧义。
我推荐使用 语义化版本号(Semantic Versioning),格式如下:
主版本号.次版本号.修订号[-预发布号][+构建元数据]
举个例子:2.1.0-rc1+build20240315
具体规则:
| 字段 | 含义 | 什么时候改 |
|---|---|---|
| 主版本号 | 不兼容的 API 或重大架构变更 | 比如根文件系统从 BusyBox 换成了 Buildroot,或者 init 系统从 SysV 换成了 systemd |
| 次版本号 | 向下兼容的功能新增 | 比如新增了一个网络配置工具,或者添加了对新硬件的支持 |
| 修订号 | 向下兼容的问题修复 | 比如修复了某个驱动在特定板子上的 bug |
| 预发布号 | alpha / beta / rc 等测试版本 | 内部测试时使用,正式发布时去掉 |
| 构建元数据 | 构建时间、CI 流水线编号等 | 用于追溯,不影响版本优先级 |
注意:预发布号的版本优先级低于正式版。比如 1.0.0-rc1 的优先级低于 1.0.0。这一点在自动化升级脚本中特别容易踩坑,我曾经就因为搞反了优先级,导致一批设备从 rc 版"升级"到了旧版……
另外,我建议在 SDK 的根目录下放一个 VERSION 文件,内容就一行版本号。这样无论是脚本读取还是人工查看,都非常方便。
# 示例:SDK 根目录下的 VERSION 文件
2.1.0-rc1+build20240315
本章知识体系
下面这张图,是我画的本章节知识结构。你可以把它当作一个"地图",方便后续复习。
这张图把本章的三个核心知识点串在了一起。你可以看到,根文件系统是什么、它在嵌入式中的角色、以及版本号怎么命名,这三者是环环相扣的。后面几章,我们会一步步深入每个细节。