第2章:源码获取与目录结构

好,咱们正式开始动手。这一章我带你看看Buildroot的源码怎么拿,以及拿到手后那一堆文件夹到底是干嘛的。

说实话,我第一次接触Buildroot时,也被它的目录结构吓了一跳。心想:这玩意儿怎么这么多文件夹?后来用熟了才发现,每个目录都有它存在的道理。

2.1 从Git仓库获取Buildroot

获取源码的方式很简单。我个人习惯直接用git clone,这样方便后续切换版本。

git clone https://git.buildroot.net/buildroot
cd buildroot

嗯,这里要注意:你拿到的默认是master分支,也就是开发版。我建议你切到一个稳定版本,比如:

git checkout 2024.02.x

为什么?我在项目中吃过亏。有一次用master分支,结果某个包突然更新了API,整个编译链全崩了。从那以后,我都是先看发布页,选一个LTS版本。

我的习惯: 用 git tag 查看所有版本号,选最新的稳定版。比如 2024.02.x 就是2024年2月的版本,比较靠谱。

2.2 顶层目录结构解析

克隆完后,你执行 ls -l 会看到一堆文件和文件夹。别慌,我带你一个个看。

目录/文件 作用
arch/ 架构相关的配置,比如ARM、x86、RISC-V
board/ 板级支持包,存放具体开发板的配置和脚本
boot/ 引导加载程序,比如U-Boot、Barebox
configs/ 默认配置文件,类似 defconfig
docs/ 文档,包括手册和开发指南
fs/ 文件系统构建逻辑,比如ext4、squashfs
linux/ Linux内核的构建配置
package/ 所有软件包的构建脚本,这是核心
support/ 辅助工具和脚本,比如依赖检查
toolchain/ 工具链相关,包括gcc、binutils、glibc
utils/ 一些实用工具,比如scanpypi
Makefile 顶层Makefile,整个构建的入口
Config.in 顶层Kconfig配置菜单

你看,其实结构很清晰。顶层就这几个核心目录。我刚开始时总记不住,后来画了个图:配置入口在Config.in,构建入口在Makefile,具体实现在各个子目录

2.3 board/ 目录:板级支持

这个目录存放的是具体开发板的配置。比如树莓派、BeagleBone、QEMU模拟器等等。

board/
├── raspberrypi/
│   ├── config.txt
│   ├── cmdline.txt
│   └── post-build.sh
├── beaglebone/
│   ├── uEnv.txt
│   └── post-image.sh
└── qemu/
    ├── aarch64-virt/
    └── x86_64/

每个板子目录下,通常有:

  • 配置文件:比如树莓派的config.txt
  • 后处理脚本:post-build.sh、post-image.sh
  • 设备树:dts文件

我记得有一次做项目,客户要求修改启动参数。我直接在board/raspberrypi/cmdline.txt里改,然后重新编译,搞定。方便得很。

重点: board/ 目录是你定制板子的主战场。如果你要支持一块新板子,就在这里新建一个文件夹。

2.4 configs/ 目录:默认配置

这个目录存放的是各种开发板的默认配置。说白了,就是 make menuconfig 后的保存结果。

configs/
├── raspberrypi4_64_defconfig
├── beaglebone_defconfig
├── qemu_aarch64_virt_defconfig
└── stm32mp157_dk_defconfig

使用方式很简单:

make raspberrypi4_64_defconfig

这条命令会把配置加载到 .config 文件里。然后你就可以 make 了。

嗯,这里有个坑:不要直接修改 .config 文件。我刚开始时图省事,手动改了 .config,结果下次 make 时被覆盖了。正确做法是:修改 defconfig 文件,或者用 make savedefconfig 保存。

避坑指南: 我曾经在 .config 里加了一堆自定义选项,结果执行 make clean 后全没了。从那以后,我都是把自定义配置写到 board/ 目录下的片段文件里,然后用 BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES 引用。

2.5 package/ 目录:软件包管理

这是Buildroot的核心目录。每个软件包都有一个子目录,里面包含:

  • Config.in:包的Kconfig配置选项
  • *.mk:Makefile构建规则
  • *.hash:源码校验文件
  • patches/:补丁文件(可选)

举个例子,看看 busybox 包:

package/busybox/
├── Config.in
├── busybox.mk
├── busybox.hash
├── S01busybox
└── patches/
    └── 0001-fix-something.patch

我个人觉得,理解 package/ 目录是掌握Buildroot的关键。你想想看,整个嵌入式系统就是由这些包堆起来的。内核是一个包,busybox是一个包,openssh也是一个包。

如果你想添加一个新包,比如 libgpiod,就在 package/ 下新建一个目录,写 Config.in 和 .mk 文件。具体怎么写,我们后面章节会详细讲。

2.6 toolchain/ 目录:工具链

工具链是编译器的集合。Buildroot支持两种方式:

  • 内部工具链:Buildroot自己编译gcc、binutils、glibc
  • 外部工具链:使用预编译的工具链,比如Linaro、ARM官方

toolchain/ 目录下就是这些逻辑:

toolchain/
├── toolchain-buildroot/
│   ├── Config.in
│   └── toolchain-buildroot.mk
├── toolchain-external/
│   ├── Config.in
│   └── toolchain-external.mk
└── helpers.mk

我建议新手先用外部工具链。为什么?因为编译工具链太慢了。我第一次编译内部工具链,等了整整两个小时。后来改用Linaro的预编译版,10分钟搞定。

我的经验: 在 menuconfig 里选择 "Toolchain -> Toolchain type -> External toolchain",然后选 "Linaro ARM" 或 "ARM EABI"。省时省力。

2.7 其他重要目录

还有几个目录,虽然不常用,但关键时刻能救命:

  • boot/:引导加载程序。如果你要换U-Boot版本,来这里改。
  • linux/:内核配置。这里只放内核的构建逻辑,具体补丁在 board/ 里。
  • fs/:文件系统类型。比如你要用squashfs还是ext4,在这里配置。
  • support/:辅助脚本。比如依赖检查、下载工具。

我记得有一次,客户要求用squashfs文件系统。我直接去 fs/squashfs/ 下看配置,发现有个压缩选项。调成lz4后,启动速度快了30%。

2.8 本章小结

好了,这一章我们看了Buildroot的目录结构。说白了,记住几个关键点:

  • configs/ 是配置入口,选板子用
  • board/ 是板级定制,改启动参数用
  • package/ 是软件包,加功能用
  • toolchain/ 是编译器,选工具链用

下一章,我们开始实战:用menuconfig配置一个最小系统。到时候你会看到,这些目录是怎么协同工作的。

嗯,如果你现在就想动手,可以试试:make qemu_x86_64_defconfig && make。等编译完,用 qemu-system-x86_64 -kernel output/images/bzImage -hda output/images/rootfs.ext2 启动看看。相信我,看到内核跑起来的那一刻,你会觉得一切都值了。