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 文件
2.3 make menuconfig 命令解释
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
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, 能把各种可剪裁的功能模块文件集中在一起, 你可以方便的配置,组装它们.形成不同的板级支持包