3. SDK工程结构解析
拿到一个 SDK 压缩包后,很多人的第一反应是直接解压、找 README、敲 make。但真正决定你能否顺利发布根文件系统版本的,不是命令本身,而是你是否理解 SDK 的目录布局与构建系统之间的映射关系。SDK 不是一堆源码的简单堆叠,它是一套“配置驱动 + 分层构建 + 产物归集”的工程体系。本节将带你从目录结构入手,逐步定位根文件系统源码,并理清构建系统与配置文件之间的依赖链路。
一、典型 SDK 目录布局:三层结构
绝大多数嵌入式 SDK(如 Buildroot、Yocto、OpenWrt、厂商定制 SDK)都遵循相似的三层布局:顶层工程层、构建系统层、源码与产物层。理解这三层,是后续所有操作的基础。
- 顶层工程层:包含
Makefile、build.sh、README、LICENSE、configs/等。它是用户入口,负责环境检查、配置加载和构建调度。 - 构建系统层:如
buildroot/、yocto/、openwrt/或厂商自研的build/目录。它包含包管理、交叉编译工具链、镜像生成规则。 - 源码与产物层:
package/、source/、output/、images/、rootfs/等。这里存放第三方包源码、编译中间件和最终可烧录镜像。
下面这张结构关系图展示了一个典型 SDK 的目录布局及其内部依赖方向,请重点观察“配置如何驱动构建、构建如何产出 rootfs”这条主线。
二、根文件系统源码位置:三个关键目录
根文件系统(rootfs)不是单一文件,而是一棵目录树。它的源码通常分布在三个位置,理解它们的分工,才能精准修改。
| 目录 | 作用 | 典型内容 | 是否直接修改 |
|---|---|---|---|
fs/ 或 target/ |
根文件系统骨架定义 | 目录结构、权限、设备节点、启动脚本 | 是,核心修改区 |
package/ |
软件包安装规则 | 每个包的 .mk、Config.in、安装路径 |
是,增删软件包 |
output/rootfs/ |
编译后生成的根文件系统 | 最终目录树、库文件、可执行文件 | 否,由构建生成 |
以 Buildroot 为例,fs/ 下常见 skeleton/、common/、initramfs/ 等子目录。其中 skeleton/ 是根文件系统的最小骨架,包含 /etc/init.d/rcS、/dev、/proc 等挂载点。而 package/ 下的每个包通过 INSTALL_TARGET_CMDS 决定文件安装到 rootfs 的哪个位置。
三、构建系统与配置文件的关系
构建系统与配置文件之间是“读取—解析—执行”的关系。以 Buildroot 为例,配置层级如下:
- 板级默认配置:
configs/xxx_defconfig,定义芯片架构、工具链、内核版本、rootfs 格式。 - 包级配置:
package/xxx/Config.in,定义该包是否可选、依赖关系、版本号。 - 当前生效配置:
.config,由make xxx_defconfig生成,是构建系统实际读取的文件。 - 构建规则:
package/xxx/xxx.mk,定义下载、解压、编译、安装的具体命令。
执行 make 时,构建系统先读取 .config,再遍历 package/ 下所有 .mk 文件,根据配置决定哪些包被编译、安装到 rootfs 的哪些路径。最终由 fs/ 下的规则将 output/target/ 打包成镜像。
# 典型构建流程(Buildroot 风格)
make xxx_defconfig # 生成 .config
make menuconfig # 可选:交互式调整
make -j$(nproc) # 编译所有选中包
make rootfs-ext4 # 单独生成 ext4 根文件系统镜像
ls output/images/ # 查看最终产物
四、案例与常见误区
案例场景:某产品需要将默认的 /etc/init.d/rcS 替换为自定义启动脚本,并增加一个 myapp 到 /usr/bin。正确做法是:在 fs/skeleton/etc/init.d/ 下修改 rcS,在 package/myapp/ 下新增 Config.in 和 myapp.mk,并在 myapp.mk 中写入 INSTALL_TARGET_CMDS 将二进制安装到 $(TARGET_DIR)/usr/bin。最后在 defconfig 中打开 BR2_PACKAGE_MYAPP=y。
- 直接修改
output/target/下的文件——下次make会被覆盖,必须改源码层。 - 把
.config当作永久配置——它由defconfig生成,应修改defconfig而非直接改.config。 - 忽略
package/的依赖声明——缺少DEPENDENCIES会导致编译顺序错误。 - 在
fs/中硬编码绝对路径——应使用$(TARGET_DIR)等变量,保证可移植性。
总结来说,SDK 工程结构解析的核心就是三句话:顶层管入口,构建系统管规则,源码与产物层管结果。根文件系统的源码位置集中在 fs/ 和 package/,而构建系统与配置文件之间通过 defconfig → .config → .mk → rootfs 这条链路紧密耦合。掌握这条链路,你就掌握了 SDK 版本工程的主动权。