使用BusyBox构建系统的方法,可以看到通过复杂的编译,目录创建,库移植和文件打包的流程,最后生成的还是仅支持系统命令的最小Linux文件系统。在真实的应用中,可能需要图形(qt),网络(mqtt、http),数据库(qslite、mysql),容器服务(docker);这就需要第三方库支持,也就是需要大量的移植工作(参考嵌入式Linux平台软件的交叉编译),处理繁杂的兼容性问题。
如何避免这些复杂的工作,提前将系统和第三方库以源码的形式整合;然后使用自动化脚本,配置文件的方式进行管理系统功能,实现自动化构建。Buildroot就是基于这个思路实现的。
本节目录如下。
Buildroot是以BusyBox、Systemd等为核心,集成编译工具,第三方库,可执行文件和系统服务脚本的,用于文件系统的自动化构建方案。对于目前最新的Buildroot,是支持Uboot和Kernel编译构建的,不过个人不建议使用,Uboot和Kernel下载和编译时间很长。另外Buildroot支持版本一般是主线的分支,不一定支持用户的开发板,还需要单独的移植,一般作为文件系统的单独编译。
这里主要说明对于文件系统的编译实现,先讲解下目录中跟编译和构建息息相关的功能。
注意: 在编译Buildroot时,相应的编译工具lib也会导入到文件系统中,也就是后续系统中的支持库会和编译工具一致。使用extern toolchain情况比较简单,后续编译程序也用此toolchain即可。使用的是内部toolchain,那么后续的程序和交叉工具必须使用内部Buildroot的同一版本,否则可能因为库版本不匹配而无法执行。
# 下载buildroot
wget https://buildroot.org/downloads/buildroot-2024.02.1.tar.gz
tar -xvf buildroot-2024.02.1.tar.gz
cd buildroot-2024.02.1/
Buildroot的构建和uboot,kernel类似,支持默认配置文件,也支持通过菜单修改,这里使用默认配置文件导入的方式,定义文件名为configs/imx6ull_user_defconfig, 内容如下:
# 更新配置文件
vim configs/imx6ullrmk_defconfig
############# imx6ullrmk_defconfig #############
# architecture
BR2_arm=y
BR2_cortex_a7=y
BR2_ARM_FPU_NEON_VFPV4=y
#
# Toolchain
#
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y
BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y
BR2_TOOLCHAIN_EXTERNAL_PATH="/home/freedom/sdk/arm/support/compiler"
BR2_PACKAGE_PROVIDES_TOOLCHAIN_EXTERNAL="toolchain-external-custom"
BR2_TOOLCHAIN_EXTERNAL_PREFIX="arm-none-linux-gnueabihf"
BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="arm-none-linux-gnueabihf"
BR2_TOOLCHAIN_EXTERNAL_GCC_11=y
BR2_TOOLCHAIN_EXTERNAL_HEADERS_4_20=y
BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC=y
BR2_TOOLCHAIN_EXTERNAL_CXX=y
BR2_TOOLCHAIN_EXTERNAL_FORTRAN=y
BR2_TOOLCHAIN_EXTERNAL_OPENMP=y
BR2_TOOLCHAIN_EXTERNAL_INET_RPC=n
BR2_TARGET_ROOTFS_EXT2_SIZE="1G"
BR2_KERNEL_MIRROR="https://mirrors.kernel.org/pub"
# system
BR2_TARGET_GENERIC_GETTY_PORT="ttymxc0"
# filesystem / image
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
# System configuration
BR2_TARGET_GENERIC_HOSTNAME="freedom"
BR2_TARGET_GENERIC_ISSUE="Welcome to freedom"
BR2_TARGET_GENERIC_ROOT_PASSWD="root"
将上述文件放置在Buildroot/configs/目录下,执行编译脚本。
#生成.config文件
make imx6ullrmk_defconfig
#开始编译
make -j6
注意1: Buildroot的make的编译过程包含两个方面,分别是软件下载和软件编译,其中软件下载可能是外网的软件,速度可能会比较慢,可以先下载下来后放置在根目录dl/下。
注意2: Buildroot中对应的软件在package/目录下,对应文件的.mk和.hash,如果希望替换成其它版本的软件,则两个文件都需要修改。
等待编译完成后,output/images目录下即为编译好的虚拟硬盘文件,直接使用即可,可以直接用mount命令挂载查看。
# 修改系统变量配置,修改文件/etc/profile
# 创建目录,并挂载文件系统
mkdir output/images/rootfs/
cd output/images
sudo mount -o loop rootfs.ext4 rootfs/
此时,就可以在rootfs中查看构建好的文件系统, 如果需要增加软件或者库支持,在Buildroot配置项中增加相应工具即可。
对于Buildroot同样支持通过界面管理文件系统配置,进入Buildroot输入make help可以看到Buildroot支持的功能,这里精简比较关键的功能进行说明。
Cleaning:
clean - 删除编译生成的文件和目录
distclean - 删除所有的非源码文件,包含(.config)
Build:
all - 编译整个系统
toolchain - 编译toolchain
Configuration:
menuconfig - 进入界面配置
savedefconfig - 保存当前的menuconfig配置,写入到BR2_DEFCONFIG指定的文件
Package-specific:
<pkg> - 单独编译和安装指定软件
<pkg>-dirclean - 清除对应APP的编译目录
<pkg>-rebuild - 单独重新编译对应APP
busybox:
busybox-menuconfig - 运行busybox的菜单界面
busybox-update-config - 保存当前的busybox到package/busybox/busybox.config或者BUSYBOX_KCONFIG_FILE指定的文件
Documentation:
manual - 以所有格式构建手册
graph-build - 生成构建时间的图表
graph-size - 生成文件系统大小的统计信息
Miscellaneous:
make O=dir - 将所有输出文件(包括 .config 文件)定位到指定的 "dir" 目录中。
对于用户来说,主要使用make menuconfig和make busybox-menuconfig两个命令,前者用于修改Buildroot的配置选项,后者用于修改busybox的配置选项。
# 进入Buildroot配置界面
make menuconfig
# 进入busybox配置界面
make busybox-menuconfig
其中Buildroot的配置界面如下所示。
Target options定义平台相关的配置
Toolchain 编译工具相关配置
System configuration 主要定义rootfs相关的配置定义,其它关键的定义如下所示。
Target packages 编译选项用于控制支持第三方库内容。
其它配置选项根据实际需求配置。这里需要注意,Buildroot支持的第三方库是很多的,在此目录下查找并不方便,可以通过在任意界面下,输入”/”进行搜索,例如希望支持python3,则弹出框中搜索”PACKAGE_PYTHON3”即可。
可以看到,在路径Target packages > Interpreter lanaguages and scripting中可以看到python3,选中即可。
Buildroot支持添加用户自定义工程,主要流程如下。
# /package/helloworld/helloworld.mk
################################################################################
#
# helloworld
#
################################################################################
# HELLOWORLD_SITE定义自定义文件存在的目录(这里为dl/helloworld)
HELLOWORLD_VERSION:= 1.0.0
HELLOWORLD_SITE:= $(CURDIR)/dl/helloworld
HELLOWORLD_SITE_METHOD:=local
HELLOWORLD_INSTALL_TARGET:=YES
define HELLOWORLD_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(@D) all
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/helloworld $(TARGET_DIR)/bin
endef
define HELLOWORLD_PERMISSIONS
/bin/helloworld f 4755 0 0 - - - - -
endef
$(eval $(generic-package))
# helloworld/config.in
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
help
add local app helloworld.
// dl/helloworld/helloworld.c
#include <stdio.h>
void main(void)
{
printf("Hello world.\n");
}
// dl/helloworld/Makefile
CPPFLAGS +=
LDLIBS +=
all: helloworld
helloworld: helloworld.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
clean:
rm -f *.o helloworld
.PHONY: all clean
此时可以使用make helloworld尝试编译安装自己添加的package,执行脚本如下。
make helloworld
此时可以看到编译成功,在output/host/bin目录下生成了helloworld文件,执行如下所示。
menu "User Application"
source "package/helloworld/Config.in"
endmenu
此时执行make menuconfig就可以找到如何添加我们自己的应用。
make menuconfig
执行结果如下。
在Buildroot中修改busybox的配置选项
# 修改Buildroot的配置选项
make menuconfig
# 修改busybox的配置选项
make busybox-menuconfig
解决Buildroot编译时下载过慢的问题
Buildroot在编译时,同步下载软件到dl目录下,编译结果则在output/host目录下,可以提前下载文件到dl目录,从而避免编译时下载过慢导致的失败问题。
Buildroot如何控制软件安装版本,添加不支持的软件编译方法
Buildroot的菜单可以控制软件是否安装,不过具体的版本在package下定义,以ace为例。如果希望更改版本,则需要修改ace.mk和ace.hash中修改
# /package/ace/ace.mk
ACE_VERSION = 7.1.1
# /package/ace/ace.hash
# 更改hash设计变量
# From https://download.dre.vanderbilt.edu/previous_versions/ACE-7.1.1.tar.bz2.md5:
md5 6c86ec6c7879703783b9749d5409a67f ACE-7.1.1.tar.bz2
# Locally Computed:
sha256 fe5fdeab1dddf4fdd99f73c59420886cf61ca2ce92adf2cc6b612b752986df62 ACE-7.1.1.tar.bz2
sha256 687bf9d16119e0caf6fb5c18214928fd6ea0da10df91e906255b7613af8061d8 COPYING
Buildroot是为了解决构建文件系统困难,来实现的自动化综合脚本项目;主要解决系统,库和程序之间的兼容性问题,如果一切顺利,会直接生成最终打包的文件系统。不过因为Linux系统版本,编译工具,安装第三方库版本的碎片化,Buildroot编译中出现错误仍然是存在的。当然这也并不是不可避免的,使用方案商提供的支持特定版本的SDK包和运行环境,一般已经解决了编译时的错误问题,入门阶段也建议使用这种方案。不过如果希望摆脱这种限制,希望不受PC Ubuntu系统,Buildroot的特定版本,编译器版本限制,就需要有解决编译issue的能力,这里给我的经验。
Buildroot编译异常主要是第三方库的编译失败,这里面主要有以下几类:
在Buildroot编译中去解决这些问题,需要有如下能力。
在编译时遇到问题,可以自己结合第三方编译的经验分析解决;不过一定不要陷入非解决不可的逻辑中,浪费太多时间,适当可以去搜索引擎检索相应错误,获取去软件官网看是否有同样和问题和解决办法,当然也可以查找软件对应的Buildroot选项,先不支持,有需要可以单独移植,这些都是可行的解决办法。当然这些解决方法也要总结下来,避免下次遇到时已经遗忘;这样才能快速高效的解决问题,事半功倍。
直接开始下一章节说明: 基于debian构建文件系统