第4章:输出产物解析

Buildroot 编译完了,output 目录里到底装了啥?

说实话,我第一次用 Buildroot 的时候,编译完直接懵了。output 目录下文件一大堆,哪些是我们要的?哪些是中间产物?今天我就带你把这个目录扒个底朝天。

4.1 output 目录结构总览

先看整体结构。Buildroot 默认的 output 目录长这样:

output/
├── build/          # 每个软件包的编译目录
├── host/           # 主机工具链和交叉编译工具
├── images/         # 最终生成的镜像文件(重点!)
├── staging/        # 目标系统的头文件和库
├── target/         # 目标文件系统的根目录
└── graphs/         # 编译依赖图(可选)

嗯,这里要注意:images 目录才是我们的宝贝。其他目录说白了都是中间产物,除非你要调试或者二次开发,否则平时不用管。

核心结论:你最终要烧录到板子上的东西,全在 output/images/ 里。

4.2 images 目录详解

我们拿一个典型的 ARM 板子(比如树莓派 3)来举例。编译完成后,images 目录大概长这样:

output/images/
├── bcm2710-rpi-3-b.dtb    # 设备树文件
├── boot.vfat               # boot 分区镜像(FAT32)
├── rootfs.ext2             # rootfs 镜像(ext2格式)
├── rootfs.ext4             # rootfs 镜像(ext4格式)
├── rootfs.tar              # rootfs 打包文件
├── sdcard.img              # 完整的 SD 卡镜像(一键烧录)
├── u-boot.bin              # U-Boot 引导程序
├── zImage                  # 压缩后的内核镜像
└── rpi-firmware/           # 树莓派专用固件

我习惯把这些文件分成三类:

类别 文件 说明
Bootloader u-boot.bin、rpi-firmware/ 引导程序,负责加载内核
Kernel zImage、*.dtb Linux 内核和设备树
Rootfs rootfs.ext4、rootfs.tar 根文件系统

你想想看,嵌入式系统启动就三步:Bootloader 跑起来 → 加载内核 → 挂载根文件系统。这三个文件正好对应这三个阶段。

4.3 各镜像文件深度解析

4.3.1 Bootloader:u-boot.bin

U-Boot 是嵌入式 Linux 最常用的引导程序。它负责初始化硬件、加载内核到内存、然后跳转执行。

我在项目中遇到过一个问题:U-Boot 编译出来有 500KB,但板子的 SPI Flash 只有 256KB。怎么办?

两种思路:

  • 裁剪 U-Boot:去掉不需要的驱动和命令
  • 改用 SPL:分两阶段加载,SPL 只做最小初始化

Buildroot 里可以通过配置 BR2_TARGET_UBOOT_SPL=y 来启用 SPL 模式。

4.3.2 Kernel:zImage + DTB

zImage 是自解压的内核镜像。DTB(设备树)是描述硬件信息的二进制文件。

为什么内核和硬件信息要分开?

因为同一份内核可以跑在不同板子上,只要换 DTB 文件就行。我维护过 5 款不同硬件,共用同一份内核镜像,只换 DTB,省了不少事。

小技巧:查看 DTB 里的硬件信息,可以用 dtc -I dtb -O dts xxx.dtb 反编译成可读的 DTS 文件。

4.3.3 Rootfs:rootfs.ext4 / rootfs.tar

根文件系统是整个系统的灵魂。Buildroot 支持多种格式:

  • ext2/ext4:适合 SD 卡、eMMC 等块设备
  • squashfs:只读压缩文件系统,适合 Flash
  • jffs2/ubifs:专门针对 NAND Flash 设计的文件系统
  • tar:打包格式,方便解压到已有分区

我个人习惯:开发阶段用 ext4,方便调试;量产阶段用 squashfs,防篡改还省空间。

4.4 SD 卡烧录实战

好,理论说完了,咱们直接上手烧录。

4.4.1 方法一:使用 sdcard.img 一键烧录

如果你在 Buildroot 配置中启用了 BR2_PACKAGE_HOST_GENIMAGEBR2_ROOTFS_POST_IMAGE_SCRIPT,编译完成后会自动生成一个完整的 sdcard.img

烧录命令就一行:

# 假设 SD 卡设备是 /dev/sdb(注意!别搞错盘符)
sudo dd if=output/images/sdcard.img of=/dev/sdb bs=4M status=progress
sync

警告:我曾经手滑把 /dev/sdb 写成了 /dev/sda,结果把电脑硬盘给覆盖了。血的教训!烧录前一定用 lsblk 确认设备名。

4.4.2 方法二:手动分区烧录

有时候你需要自定义分区布局,那就手动来:

# 1. 分区(以 2GB SD 卡为例)
sudo fdisk /dev/sdb
# 创建两个分区:
#   /dev/sdb1: 64MB, FAT32, 类型 c (boot)
#   /dev/sdb2: 剩余空间, Linux, 类型 83 (rootfs)

# 2. 格式化
sudo mkfs.vfat /dev/sdb1
sudo mkfs.ext4 /dev/sdb2

# 3. 烧录 boot 分区
sudo mount /dev/sdb1 /mnt/boot
sudo cp output/images/zImage /mnt/boot/
sudo cp output/images/*.dtb /mnt/boot/
sudo cp output/images/u-boot.bin /mnt/boot/
sudo umount /mnt/boot

# 4. 烧录 rootfs 分区
sudo mount /dev/sdb2 /mnt/rootfs
sudo tar -xvf output/images/rootfs.tar -C /mnt/rootfs
sudo umount /mnt/rootfs

手动分区的好处是灵活。比如 boot 分区你想用 ext4 而不是 FAT32?没问题,自己改就行。

4.4.3 验证烧录结果

烧录完别急着拔卡,先验证一下:

# 检查分区表
sudo fdisk -l /dev/sdb

# 检查 boot 分区内容
sudo mount /dev/sdb1 /mnt
ls /mnt
# 应该能看到 zImage、*.dtb、u-boot.bin 等文件
sudo umount /mnt

# 检查 rootfs 分区
sudo mount /dev/sdb2 /mnt
ls /mnt
# 应该能看到 bin、etc、lib、usr 等目录
sudo umount /mnt

插到板子上,上电,看串口输出。如果看到 U-Boot 启动信息,然后内核开始解压,最后出现登录提示符...恭喜你,系统跑起来了!

4.5 本章知识体系

下面这张图总结了 output 目录的核心逻辑:

Buildroot 输出产物与烧录流程 Buildroot 编译 output/images/ 目录 Bootloader u-boot.bin Kernel zImage + *.dtb Rootfs rootfs.ext4 SD 卡烧录(dd / 手动分区)

从这张图可以看得很清楚:Buildroot 编译完成后,output/images/ 里产出三类核心文件,最终通过烧录工具写入 SD 卡。板子上电后,Bootloader → Kernel → Rootfs 依次加载,系统就起来了。

我的建议:刚开始学的时候,先用 sdcard.img 一键烧录,跑通了再尝试手动分区。这样能快速建立信心,也方便排查问题。

好了,output 目录和烧录方法就讲到这里。记住一句话:images 目录是终点,其他目录是过程。下次编译完,直接去 images 里找你要的文件就行。


公众号:蓝海资料掘金营,微信deep3321