buildroot 入门介绍


author: hjjdebug

date: 2026年 06月 12日 星期五 19:54:58 CST

descrip: buildroot 入门介绍


文章目录

  • [1. buildroot 是什么?](#1. buildroot 是什么?)
    • [1.1 下载地址: https://buildroot.org](#1.1 下载地址: https://buildroot.org)
    • [1.2 你怎么做到这块板子编一套bsp, 那块板子编另一套bsp,不同的板子编出不同的bsp?](#1.2 你怎么做到这块板子编一套bsp, 那块板子编另一套bsp,不同的板子编出不同的bsp?)
    • [1.3 菜单项那么多内容,不知道怎么点怎么办?](#1.3 菜单项那么多内容,不知道怎么点怎么办?)
    • [1.4 我怎么知道内置了哪些模板呢? 哪个适合我呢?](#1.4 我怎么知道内置了哪些模板呢? 哪个适合我呢?)
  • [2. buildroot 深层解析.](#2. buildroot 深层解析.)
    • [2.1 make list-defconfigs 命令解析](#2.1 make list-defconfigs 命令解析)
      • [2.1.1 先解释第一条命令: \$(call ...)](#2.1.1 先解释第一条命令: $(call ...))
      • [2.1.2 再解释第二条命令: (foreach ...)](#2.1.2 再解释第二条命令: (foreach ...))
    • [2.2 make qemu_x86_64_defconfig 命令解释](#2.2 make qemu_x86_64_defconfig 命令解释)
    • [2.3 make menuconfig 命令解释](#2.3 make menuconfig 命令解释)
    • [2.4 make 命令解释](#2.4 make 命令解释)

1. buildroot 是什么?

它是一个软件, 它是一个工具软件,它用来方便的构建嵌入式系统板载软件.

包括bootloader,内核,跟文件系统,应用. 以及交叉构建工具的生成.

1.1 下载地址: https://buildroot.org

目前长期稳定最新版本为

buildroot-2025.02.14.tar.xz

大小5.7M 很小.

设想一下,当今嵌入式系统横行天下, 天上飞的:卫星,飞行器,地上跑的:汽车,手机

家里用得:电视,空调 等等,等等.

这些设备其中都有一块电路板, 而单纯的板子是没有任何作用的,需要软件支撑才能工作.

而你说, 我能一键编出它们用的软件, 让这些硬件工作起来,你是不是很牛!

buildroot 就能做到一个make, 等待若干时间后, 完整的板级支持包(BSP)已经生成.

1.2 你怎么做到这块板子编一套bsp, 那块板子编另一套bsp,不同的板子编出不同的bsp?

那只需要 make menuconfig

会出来一个菜单,不过是字符界面形势的菜单,

你只要点菜就行了, 要这个,不要那个, 等等...

最后你点的会保留在.config 文件中, 再执行make就出对应的bsp了.

1.3 菜单项那么多内容,不知道怎么点怎么办?

开发人员为我们想好了,里面有套餐,你点套餐就可以了.

点了套餐,再用make menuconfig 调整几项(如果需要的话)来匹配你的板子. 再make就可以了.

例如:

make qemu_x86_64_defconfig (选中内置的模板项)

make menuconfig (可忽略,如果不需要调整config 项的话)

make

1.4 我怎么知道内置了哪些模板呢? 哪个适合我呢?

这点开发人员也替我们考虑到了.

make list-defconfigs

就能输出所有的内置模板名称.

2. buildroot 深层解析.

3 条命令就想走遍天下? 想的还是太简单了. 至少也要把3条命令的底层工作原理搞清楚吧.

否则你怎么灵活运用它呢? 你怎么剪裁菜单呢? 你怎么调整里边的细节呢? 例如代码下载不下来,

能不能换的网站呢? 能不能手工下载放到指定目录呢? 等等问题.

make 是由Makefile 支撑的, Makefile 是make 的脚本语言. 它指示的make 先构建这,在构建那.

Makefile 是知道构建流程的.

作为第一步, make help 显然应该作为起点. 不过这只是一个帮助信息.

90% 是简单的字符串照印. 不过有一个foreach 语句循环,后面再分析.

现在我们就倒序的来深挖一下make的过程

2.1 make list-defconfigs 命令解析

cpp 复制代码
list-defconfigs:
	$(call list-defconfigs,$(TOPDIR))
	$(foreach name,$(BR2_EXTERNAL_NAMES),\
		$(call list-defconfigs,$(BR2_EXTERNAL_$(name)_PATH),\
			$(BR2_EXTERNAL_$(name)_DESC))$(sep))

就这么短,但是能看的懂吗?

2.1.1 先解释第一条命令: $(call ...)

list-defconfig 是一个自定义命令,

其第1参数 TOPDIR := $(CURDIR)

而CURDIR 是makefile 的内置变量,是make启动时的目录名称

第2参数为空

自定义函数的模板时这样的. 这是Makefile 被读进去保留在数据库中的样子.

cpp 复制代码
# List the defconfig files
# $(1): base directory
# $(2): br2-external name, empty for bundled
define list-defconfigs
	@first=true; \
	for defconfig in $$([ -d $(1)/configs ] && find $(1)/configs -name '*_defconfig' |sort); do \
		[ -f "$${defconfig}" ] || continue; \
		if $${first}; then \
			if [ "$(2)" ]; then \
				printf 'External configs in "%s":\n' "$(call qstrip,$(2))"; \
			else \
				printf "Built-in configs:\n"; \
			fi; \
			first=false; \
		fi; \
		defconfig="$${defconfig#$(1)/configs/}"; \
		printf "  %-35s - Build for %s\n" "$${defconfig}" "$${defconfig%_defconfig}"; \
	done; \
	$${first} || printf "\n"
endef

当被call 调用,并代入(1),(2) 参数时,它会被展开成字符串. 借助remake实时跟踪可以知道

cpp 复制代码
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
first=true; for defconfig in $([ -d /home/hjj/source/arm64/buildroot/configs ] && find /home/hjj/source/arm64/buildroot/configs -name '*_defconfig' |sort); do [ -f "${defconfig}" ] || continue; if ${first}; then if [ "" ]; then printf 'External configs in "%s":\n' ""; else printf "Built-in configs:\n"; fi; first=false; fi; defconfig="${defconfig#/home/hjj/source/arm64/buildroot/configs/}"; printf "  %-35s - Build for %s\n" "${defconfig}" "${defconfig%_defconfig}"; done; ${first} || printf "\n"
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

这些被展开的字符串,将作为shell 脚本被执行,因为它们就处在构建目标的位置上.

而这段shell 脚本的功能,我来简单分析一下.

做一个for 循化.

如果./configs 目录存在,找到该目录下*_defconfig 文件并排序,依次处理

如果它(defconfig变量)是一个文件,不是文件继续下一个.

由于first 为真,打印一条"Build-in configs", 然后把first置为假防止循环打印.

把文件名去除目录.

用printf 打印文件名 Build for 文件名去掉右部_defconfig

2.1.2 再解释第二条命令: $(foreach ...)

复制代码
\$(foreach name,$(BR2_EXTERNAL_NAMES),\

由于 $(BR2_EXTERNAL_NAMES) 为空, 直接退出该语句

2.2 make qemu_x86_64_defconfig 命令解释

cpp 复制代码
1042 %_defconfig: $(BUILD_DIR)/buildroot-config/conf  outputmakefile                                                                                   
1043     @defconfig=$(or \                                                                                                                             
1044         $(firstword \                                                                                                                             
1045             $(foreach d, \                                                                                                                        
1046                 $(call reverse,$(TOPDIR) $(BR2_EXTERNAL_DIRS)), \                                                                                 
1047                 $(wildcard $(d)/configs/$@) \                                                                                                     
1048             ) \                                                                                                                                   
1049         ), \                                                                                                                                      
1050         $(error "Can't find $@") \                                                                                                                
1051     ); \                                                                                                                                          
1052     $(COMMON_CONFIG_ENV) BR2_DEFCONFIG=$${defconfig} \                                                                                            
1053         $< --defconfig=$${defconfig} $(CONFIG_CONFIG_IN)     

这段代码非常的难读,

前面设置了一堆环境变量之后,调用了

output/build/buildroot-config/conf Config.in

conf 是一个执行程序, Config.in 就是根目录下的Config.in, 1千多行配置输入.

因为脚本及参数可能都是不变的,而变化是环境变量(例如设置了输入文件名称等)

这其中处理细节我没有搞清楚,不过不影响理解.

总之conf处理完之后写入了.config 文件

cpp 复制代码
 1010 menuconfig: $(BUILD_DIR)/buildroot-config/mconf outputmakefile
 1011     @$(COMMON_CONFIG_ENV) $< $(CONFIG_CONFIG_IN)

 BR2_DEFCONFIG='' KCONFIG_AUTOCONFIG=/home/hjj/source/buildroot-2025.02.14/output/build/buildroot-config/auto.conf KCONFIG_AUTOHEADER=/home/hjj/sou\
 rce/buildroot-2025.02.14/output/build/buildroot-config/autoconf.h KCONFIG_TRISTATE=/home/hjj/source/buildroot-2025.02.14/output/build/buildroot-co\
 nfig/tristate.config BR2_CONFIG=/home/hjj/source/buildroot-2025.02.14/.config HOST_GCC_VERSION="15" BASE_DIR=/home/hjj/source/buildroot-2025.02.14\
 /output SKIP_LEGACY= /home/hjj/source/buildroot-2025.02.14/output/build/buildroot-config/mconf Config.in

其展开后前面是一堆变量设置,再调用mconf 程序, 输入参数还是Config.in

这样在mconf 程序控制下,在命令行界面选择菜单, 最后保存文件到.config

2.4 make 命令解释

敲make, 它就干起来了, 到底它是怎样干的,这些细节还是需要了解一下. 因为有时候我们也想手工控制一下.

也应该有个目标, 搞清楚目录级别的流程就可以了, 再搞清楚下载是怎样进行的.

make 默认的目标就是all了

这里边内容太多, 我解释不了太细致了. 来个小实验吧. 跑通了这个小实验,自己琢磨.

再package/下见demo 目录, 再创建demo.mk, 内容如下:

:~/source/buildroot-2025.02.14/package/demo$ ls

demo.mk

cpp 复制代码
$ cat demo.mk
# package/demo/demo.mk
DEMO_VERSION = 1.0.0
DEMO_SITE = https://example.com/demo
DEMO_SOURCE = demo-$(DEMO_VERSION).tar.gz

HOST_DEMO_DEPENDENCIES = host-m4
HOST_DEMO_CONF_OPTS = --enable-shared=no

# 核心:调用主机autotools模板,自动生成全套规则
$(eval $(host-autotools-package));

关键是那个宏定义,是下面这个文件.

cpp 复制代码
./package/pkg-autotools.mk
319:host-autotools-package = $(call inner-autotools-package,host-$(pkgname),$(call UPPERCASE,host-$(pkgname)),$(call UPPERCASE,$(pkgname)),host)

然后你执行 make host-demo

你看到它真的会从https://example.com/demo 网站下载文件, 当然是不可能下载成功的.

为了跳过下载, 我们在./dl 目录添加demo-1.0.0.tar.gz 文件 .

如果你给一个假文件,它会说格式不对.没法解压缩

给它一个真正的.tar.gz, 解开口,他说没法configure.

给它一个真正的autotools 打包的文件. 带./configure, 可make 的那一种.

敲make host-demo, 它真的调用configure, make, gcc 给出了正确的编译结果,其中gcc 带一大堆参数.

这一下对Makefile 的运行就很有内容要研究了

首先: demo.mk 是怎样被顶层Makefile 包含进来的?

顶层Makefile 543 行有包含

543 include (sort (wildcard package// .mk))

host-autotools-package 宏展开是pkgname 是怎样赋值的?

没看清楚! 对demo.mk 而言, 它的pkgname=demo

host-autotools-package 被展开成了什么?

可能被展开动态生成了几百条规则,文件越复杂生成的规则越复杂, 我没看懂,以后再研究吧.

先到这里吧.

再重复看make 的过程,可以先clean, 再make, 生成的log 如下:

cpp 复制代码
hjj@hjj-JIAOLONG-Series:~/source/buildroot-2025.02.14$ make host-demo-dirclean
rm -Rf /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0
hjj@hjj-JIAOLONG-Series:~/source/buildroot-2025.02.14$ make host-demo
WARNING: no hash file for demo-1.0.0.tar.gz
>>> host-demo 1.0.0 Extracting
gzip -d -c /home/hjj/source/buildroot-2025.02.14/dl/demo/demo-1.0.0.tar.gz | tar --strip-components=1 -C /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0   -xf -
>>> host-demo 1.0.0 Patching
>>> host-demo 1.0.0 Updating config.sub and config.guess
for file in config.guess config.sub; do for i in $(find /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0 -name $file); do cp support/gnuconfig/$file $i; done; done
>>> host-demo 1.0.0 Patching libtool
>>> host-demo 1.0.0 Configuring
(cd /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0/ && rm -rf config.cache; GIT_DIR=. PATH="/home/hjj/source/buildroot-2025.02.14/output/host/bin:/home/hjj/source/buildroot-2025.02.14/output/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" PKG_CONFIG="/home/hjj/source/buildroot-2025.02.14/output/host/bin/pkg-config" PKG_CONFIG_SYSROOT_DIR="/" PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 PKG_CONFIG_LIBDIR="/home/hjj/source/buildroot-2025.02.14/output/host/lib/pkgconfig:/home/hjj/source/buildroot-2025.02.14/output/host/share/pkgconfig" AR="/usr/bin/ar" AS="/usr/bin/as" LD="/usr/bin/ld" NM="/usr/bin/nm" CC="/usr/bin/gcc" GCC="/usr/bin/gcc" CXX="/usr/bin/g++" CPP="/usr/bin/cpp" OBJCOPY="/usr/bin/objcopy" RANLIB="/usr/bin/ranlib" CPPFLAGS="-I/home/hjj/source/buildroot-2025.02.14/output/host/include" CFLAGS="-O2 -I/home/hjj/source/buildroot-2025.02.14/output/host/include" CXXFLAGS="-O2 -I/home/hjj/source/buildroot-2025.02.14/output/host/include" LDFLAGS="-L/home/hjj/source/buildroot-2025.02.14/output/host/lib -Wl,-rpath,/home/hjj/source/buildroot-2025.02.14/output/host/lib" INTLTOOL_PERL=/usr/bin/perl  CONFIG_SITE=/dev/null ./configure --prefix="/home/hjj/source/buildroot-2025.02.14/output/host" --sysconfdir="/home/hjj/source/buildroot-2025.02.14/output/host/etc" --localstatedir="/home/hjj/source/buildroot-2025.02.14/output/host/var" --enable-shared --disable-static --disable-gtk-doc --disable-gtk-doc-html --disable-doc --disable-docs --disable-documentation --disable-debug --with-xmlto=no --with-fop=no --disable-nls --disable-dependency-tracking  --enable-shared=no )
configure: WARNING: unrecognized options: --enable-shared, --disable-static, --disable-gtk-doc, --disable-gtk-doc-html, --disable-doc, --disable-docs, --disable-documentation, --disable-debug, --with-xmlto, --with-fop, --disable-nls, --enable-shared
checking for a BSD-compatible install... /usr/bin/install -c
checking whether sleep supports fractional seconds... yes
checking filesystem timestamp resolution... 0.01
checking whether build environment is sane... yes
checking for a race-free mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking xargs -n works... yes
checking whether UID '1000' is supported by ustar format... yes
checking whether GID '1000' is supported by ustar format... yes
checking how to create a ustar tar archive... gnutar
checking for gcc... /usr/bin/gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether /usr/bin/gcc accepts -g... yes
checking for /usr/bin/gcc option to enable C11 features... none needed
checking whether /usr/bin/gcc understands -c and -o together... yes
checking whether make supports the include directive... yes (GNU style)
checking dependency style of /usr/bin/gcc... none
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands
configure: WARNING: unrecognized options: --enable-shared, --disable-static, --disable-gtk-doc, --disable-gtk-doc-html, --disable-doc, --disable-docs, --disable-documentation, --disable-debug, --with-xmlto, --with-fop, --disable-nls, --enable-shared
>>> host-demo 1.0.0 Building
GIT_DIR=. PATH="/home/hjj/source/buildroot-2025.02.14/output/host/bin:/home/hjj/source/buildroot-2025.02.14/output/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" PKG_CONFIG="/home/hjj/source/buildroot-2025.02.14/output/host/bin/pkg-config" PKG_CONFIG_SYSROOT_DIR="/" PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 PKG_CONFIG_LIBDIR="/home/hjj/source/buildroot-2025.02.14/output/host/lib/pkgconfig:/home/hjj/source/buildroot-2025.02.14/output/host/share/pkgconfig"  /usr/bin/make -j33  -C /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0/
make[2]: Nothing to be done for 'all'.
>>> host-demo 1.0.0 Installing to host directory
GIT_DIR=. PATH="/home/hjj/source/buildroot-2025.02.14/output/host/bin:/home/hjj/source/buildroot-2025.02.14/output/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" PKG_CONFIG="/home/hjj/source/buildroot-2025.02.14/output/host/bin/pkg-config" PKG_CONFIG_SYSROOT_DIR="/" PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 PKG_CONFIG_LIBDIR="/home/hjj/source/buildroot-2025.02.14/output/host/lib/pkgconfig:/home/hjj/source/buildroot-2025.02.14/output/host/share/pkgconfig"  /usr/bin/make -j33 install -C /home/hjj/source/buildroot-2025.02.14/output/build/host-demo-1.0.0/
make[3]: Nothing to be done for 'install-data-am'.
 /usr/bin/mkdir -p '/home/hjj/source/buildroot-2025.02.14/output/host/bin'
  /usr/bin/install -c demo '/home/hjj/source/buildroot-2025.02.14/output/host/bin'

总之,buildroot 依据一个复杂的Makefile, 能把各种可剪裁的功能模块文件集中在一起, 你可以方便的配置,组装它们.形成不同的板级支持包

相关推荐
hjjdebug4 小时前
buildroot Makefile include *.mk 的玄机.
makefile·buildroot
ScilogyHunter2 天前
Buildroot完全指南:从入门到实战
linux·嵌入式·buildroot
secret_to_me5 天前
buildRoot编译rootfs实战
linux·c语言·c++·ubuntu·电脑·buildroot
Zevalin爱灰灰5 天前
makefile从入门到实战 第一章 认识makefile(二)
makefile
Zevalin爱灰灰6 天前
makefile从入门到实战 第一章 认识makefile(一)
linux·makefile
A_humble_scholar6 天前
Linux(三)深入理解 Makefile:自动变量、增量编译原理与文件时间属性
linux·服务器·c++·makefile
sulikey11 天前
个人Linux操作系统学习笔记4 - makefile
linux·makefile·make·构建
Irissgwe20 天前
二、Linux基础开发工具(2)
linux·makefile·gcc·g++·
量子炒饭大师24 天前
【Linux系统编程】——【自动化构建-make/Makefile】拒绝手动编译!构建你的赛博代码加工厂,重塑逻辑矩阵效率极限
linux·运维·自动化·makefile·make·自动化构建