在物联网和嵌入式设备飞速发展的今天,如何快速、高效地构建一个精简、稳定且高度定制化的Linux操作系统,成为了开发者面临的关键挑战。Buildroot,作为一个简单、高效且功能强大的嵌入式Linux系统构建工具,正为此而生。
本内容旨在为您提供一份关于Buildroot的全面指南。我们不仅会手把手地带您完成一个完整嵌入式OS的配置、编译,更将深入其内部,揭开自动化构建过程的神秘面纱,理解其背后的工作原理。通过理论与实践的结合,您将获得从“使用者”到“掌控者”的蜕变,能够为您的特定硬件和应用场景,量身打造最合适的根文件系统。
一、 buildroot工具简介
1.1 工具简介
官网首页对buildroot的定义,和特点有非常明确的介绍。
1. buildroot的宗旨为了让嵌入式linux开发更容易。
2. 方便管理,为嵌入式设备生成交叉编译工具链,文件系统,交叉编译bootloader和kernel image。
3. 简单易用,所有配置通过像linux一样的menuconfig,gconfig和xconfig。
4. 支持丰富的package资源,构建需要的rootfs。
buildroot原则上是一个嵌入式自动构建框架,可以编译内核、U-boot、根文件系统。但是 buildroot 下载的 linux 和 uboot官方源码,里面会缺少很多驱动文件,而且最新的 linux 内核和 uboot 会对编译器版本号有要求,可能导致编译失败。所以一般uboot和linux内核都是厂家提供, buildroot主要用来编译生成根文件系统。
buildroot 源码可以从 buildroot 官网下载,官网地址为 buildroot.org/。
本文是基于buildroot-2025.08.2进行测试。
1.2 buildroot源码目录
buildroot的目录结构如下:
├── arch: 存放CPU架构相关的配置脚本,如arm/mips/x86,这些CPU相关的配置
├── board 存放了一些默认开发板的配置补丁之类的
├── boot Bootloader 相关包和配置。
├── CHANGES
├── Config.in 系统级的配置菜单定义
├── Config.in.legacy
├── configs: 预置的配置文件仓库,放置已有开发板的配置文件.
├── COPYING
├── DEVELOPERS
├── dl: 存放下载的源代码及应用软件的压缩包.
├── docs: 存放相关的参考文档.
├── fs: 文件系统格式的生成器。
├── linux: 存放着Linux内核的构建规则。
├── Makefile 整个Buildroot系统的引擎和入口
├── Makefile.legacy
├── output: 构建产物目录.
│ ├── build: 所有组件(工具链、软件包、内核等)的构建目录。
│ ├── host: 为宿主机编译的工具和库,包括交叉编译工具链。
│ ├── images: 存放着编译好的uboot.bin, zImage, rootfs等镜像文件,可烧写到板子里
│ ├── staging 类似根文件系统的布局,包含所有已编译包的开发文件(头文件和库)
│ └── target: 用来制作rootfs文件系统,里面放着Linux系统基本的目录结构,以及编译好的应用库和bin可执行文件. (buildroot根据用户配置把.ko .so .bin文件安装到对应的目录下去,根据用户的配置安装指定位置)
├── package:下面放着软件包的配置文件, Config.in和soft_name.mk,soft_name.mk是构建脚本,用Makefile语法精确定义了如何下载、配置、编译和安装这个软件包。
├── README
├── support
├── system 根文件系统的全局配置。
└── toolchain 工具链的构建和集成。
这个结构清晰地展现了Buildroot作为一个构建系统的核心逻辑:以配置为输入,通过Makefile驱动,在package, boot, linux, toolchain等核心目录中完成编译,最终在output目录输出镜像。按照Buildroot本身提供构建流程的框架,开发者按照格式写脚本,提供必要的构建细节,配置整个系统,最后自动构建出嵌入式系统。
二、 编译流程
2.1 基本操作
1.编译配置:make menuconfig
2.根据芯片平台进行配置;
3.make开始编译;
2.2 导入编译工具链
Buildroot为交叉编译工具链提供了两种解决方案:
内部工具链 (Internal toolchain backend),在配置界面中称为Buildroot工具链(Buildroot toolchain)。
外部工具链 (External toolchain backend),在配置界面中称为外部工具链(External toolchain)。
使用Toolchain菜单中的Toolchain Type选项可以在这两个解决方案之间进行选择。选择了一个解决方案,就会出现相应的后续配置选项。
选择Buildroot toolchain代表要从零开始用原材料软件包自动构造工具链,过程比较复杂,本文不做详细介绍。
一般使用的都是芯片厂家提供的编译工具链,选择External toolchain
外部工具链后端允许使用现有的预构建的交叉编译工具链。Buildroot支持许多著名的交叉编译工具链(从Linaro for ARM、Sourcery CodeBench for ARM、x86-64、PowerPC和MIPS),并且能够自动下载它们,或者它可以指向一个定制的工具链,可以下载或在本地安装。
目前,有三个解决方案来使用外部工具链:
1.使用预定义的外部工具链概要文件,并让Buildroot下载、提取和安装工具链。Buildroot已经知道一些CodeSourcery和Linaro工具链。只需在Toolchain中从可用的工具链概要文件中选择工具链概要文件。这绝对是最简单的解决方案。
2.使用一个预定义的外部工具链概要文件,但是不必让Buildroot下载和提取工具链,可以配置Buildroot工具链安装在位置。只需在Toolchain中选择工具链配置文件,取消选择自动下载工具链,并在Toolchain path文本条目中填写交叉编译工具链的路径。
3.使用完全自定义的外部工具链。这对于使用crosstool-NG或Buildroot本身生成的工具链特别有用。为此,在Toolchain列表中选择Custom toolchain解决方案。需要填充Toolchain path、Toolchain prefix和External toolchain C library选项。然后,需要配置Buildroot外部编译工具链支持什么。如果编译工具链使用glibc库,只配置是否支持c++,以及它是否有内置的RPC支持。如果编译工具链使用了uClibc库,需要配置是否支持RPC、宽字符、区域设置、程序调用、线程和c++。在执行make的开始,Buildroot 编译时会核对所选择的选项是否与工具链配置匹配。
以rk3588为例,以rk3588为例自动构建编译工具链配置:
使用本地编译工具链配置,已在本地部署的rk3588的编译工具链地址为: /opt/toolchains/rockchip_rk3588/bin/aarch64-buildroot-linux-gnu-gcc
配置如下:
配置完编译工具链后就可以开始编译了。
2.3 系统&文件系统配置
在System configuration配置项下可以对根文件系统下部分初始化配置进行配置,例如默认的shell工具、系统工具路径、登陆是否需要密码等;
在Filesystem images中可以对根文件系统的相关内容进行配置,比如说ext4等文件系统格式,根文件系统采用的文件系统类型等等。
2.4 Target packages配置
此选项用于配置要选择的第三方库或软件、比如 alsa-utils、ffmpeg、iperf、ftp、ssh等工具,可以按需选择。
busybox是构建根文件系统的瑞士军刀, 在构建根文件系统的时候也是要用到 busybox 的,但是buildroot的make menuconfig无法直接配置 busybox 。在 buildroot下打开 busybox 的配置界面输入如下命令:
make busybox-menuconfig
即可进入busybox配置界面。
2.5编译结果
输入make指令后,接下来就是编译过程,编译完成后将会在output/target/下生成编译结果,所有的工具和动态库会按照根文件系统目录进行安装。
根据文件系统配置打包后的根文件系统镜像输出到output/images/路径下。
2.6编译原理
每个软件包在package路径下都有一个对应的文件夹,里面存放了相应的config.in、xxx.mk、xxx.patch等文件;config.in是配置文件,通过make menuconfig进行配置使能,选择是否编译;而.mk文件就是编译文件,每个动态库的编译安装过程可以分为下载、解压、patch、配置、编译、安装等步骤,每个步骤完成后都会在output/build/xxx/文件夹下生成一个标志文件,比如说下载标志:.stamp_downloaded。每个步骤执行前都会检查标志文件,判断是否继续执行。
buildroot的编译流程是先从.mk文件中读取XXX_LIB_SITE这个库的下载路径,下载存放到dl/xxx/路径。
然后从dl/xxx/xxx.tar下解压出源码到output/build/xxx,如果有patch文件则自动进行patch过程,然后利用本身的配置文件(如果有的话)覆盖output/build/xxx下的配置文件,在开始编译连接完成后安装到output/相应文件夹下。
Buildroot提供了函数框架和变量命令框架,采用它的框架编写的app_pkg.mk这种Makefile格式的自动构建脚本,将被package/pkg-generic.mk 这个核心脚本展开填充到buildroot主目录下的Makefile中去。最后make all执行Buildroot主目录下的Makefile,生成想要的image。
package/pkg-generic.mk中通过调用同目录下的pkg-download.mk、pkg-utils.mk文件,已经帮自动实现了下载、解压、依赖包下载编译等一系列机械化的流程。只要需要按照格式写Makefile脚app_pkg.mk,填充下载地址,链接依赖库的名字等一些特有的构建细节即可。
三、 多平台配置管理
实际使用中,buildroot肯定需要用于多个芯片平台的编译;buildroot支持以下配置管理指令:
在配置完成后可以将该平台的配置保存到configs文件夹,make menuconfig中配置保存路径的配置如下图所示,然后运行make savedefconfig即可完成配置的保存,
然后通过 make test_rk3588_defconfig可以导入相应配置。
四、 问题记录
问题1 : 依赖问题
Makefile:543: *** libiconv is in the dependency chain of dosfstools that has added it to its _DEPENDENCIES variable without selecting it or depending on it from Config.in. Stop.
问题原因:dosfstools依赖libiconv,libiconv库未使能;
解决方法: .config中的libiconv相关配置项要打开:
BR2_PACKAGE_LIBICONV=y
问题2 : 编译工具链版本问题
Incorrect selection of kernel headers: expected 4.4.x, got 4.6.x
原因是在交叉编译器路径下有一个内核版本代码
buildroot在执行check-kernel-headers.sh时会检测这这个内核版本代码
#define LINUX_VERSION_CODE 263680
/opt/trans-toolchains/aarch64-rk3308-linux/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/aarch64-linux-gnu/libc/usr/include/linux/version.h
#define LINUX_VERSION_CODE 263680
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
263680 = 0x40600(h)
所以移位得到4.6.x的内核版本
解决办法1 : 修改version.h
假如当前版本为3.2.x
通过计算得知LINUX_VERSION_CODE 应该为197120
197120 = 30200(h)
移位后为3.2.x。
#define LINUX_VERSION_CODE 197120
解决方法2
Buildroot下make menuconfig中改内核版本为4.6和编译器版本对应即可
问题3: 全局动态库依赖问题 问题原因:增加自定义库时,定义了对-lssl的依赖:
TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib64/ -lcrypto -lssl
会影响到所有库的依赖,导致Make clean后重新编译发现无法编译;
解决方法:
修改为: