build_embed_linux_system

基于Buildroot构建文件系统

使用BusyBox构建系统的方法,可以看到通过复杂的编译,目录创建,库移植和文件打包的流程,最后生成的还是仅支持系统命令的最小Linux文件系统。在真实的应用中,可能需要图形(qt),网络(mqtt、http),数据库(qslite、mysql),容器服务(docker);这就需要第三方库支持,也就是需要大量的移植工作(参考嵌入式Linux平台软件的交叉编译),处理繁杂的兼容性问题。

如何避免这些复杂的工作,提前将系统和第三方库以源码的形式整合;然后使用自动化脚本,配置文件的方式进行管理系统功能,实现自动化构建。Buildroot就是基于这个思路实现的。

本节目录如下。

dir_analysis

Buildroot是以BusyBox、Systemd等为核心,集成编译工具,第三方库,可执行文件和系统服务脚本的,用于文件系统的自动化构建方案。对于目前最新的Buildroot,是支持Uboot和Kernel编译构建的,不过个人不建议使用,Uboot和Kernel下载和编译时间很长。另外Buildroot支持版本一般是主线的分支,不一定支持用户的开发板,还需要单独的移植,一般作为文件系统的单独编译。

这里主要说明对于文件系统的编译实现,先讲解下目录中跟编译和构建息息相关的功能。

注意: 在编译Buildroot时,相应的编译工具lib也会导入到文件系统中,也就是后续系统中的支持库会和编译工具一致。使用extern toolchain情况比较简单,后续编译程序也用此toolchain即可。使用的是内部toolchain,那么后续的程序和交叉工具必须使用内部Buildroot的同一版本,否则可能因为库版本不匹配而无法执行。

compiler

download_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/

update_config

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/目录下,执行编译脚本。

compile_rootfs


#生成.config文件
make imx6ullrmk_defconfig

#开始编译
make -j6

注意1: Buildroot的make的编译过程包含两个方面,分别是软件下载和软件编译,其中软件下载可能是外网的软件,速度可能会比较慢,可以先下载下来后放置在根目录dl/下。

注意2: Buildroot中对应的软件在package/目录下,对应文件的.mk和.hash,如果希望替换成其它版本的软件,则两个文件都需要修改。

等待编译完成后,output/images目录下即为编译好的虚拟硬盘文件,直接使用即可,可以直接用mount命令挂载查看。

image

# 修改系统变量配置,修改文件/etc/profile
# 创建目录,并挂载文件系统
mkdir output/images/rootfs/
cd output/images
sudo mount -o loop rootfs.ext4 rootfs/

此时,就可以在rootfs中查看构建好的文件系统, 如果需要增加软件或者库支持,在Buildroot配置项中增加相应工具即可。

config_analysis

对于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的配置界面如下所示。

image

board_config

image

Target options定义平台相关的配置

toolchain

image

Toolchain 编译工具相关配置

system_config

image

System configuration 主要定义rootfs相关的配置定义,其它关键的定义如下所示。

third_packages

Target packages 编译选项用于控制支持第三方库内容。

image

其它配置选项根据实际需求配置。这里需要注意,Buildroot支持的第三方库是很多的,在此目录下查找并不方便,可以通过在任意界面下,输入”/”进行搜索,例如希望支持python3,则弹出框中搜索”PACKAGE_PYTHON3”即可。

image

可以看到,在路径Target packages > Interpreter lanaguages and scripting中可以看到python3,选中即可。

image

add_user_project

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文件,执行如下所示。

image

menu "User Application"
	source "package/helloworld/Config.in"
endmenu

此时执行make menuconfig就可以找到如何添加我们自己的应用。

make menuconfig

执行结果如下。

image

common_notes

notes-1

在Buildroot中修改busybox的配置选项

# 修改Buildroot的配置选项
make menuconfig

# 修改busybox的配置选项
make busybox-menuconfig

notes-2

解决Buildroot编译时下载过慢的问题

Buildroot在编译时,同步下载软件到dl目录下,编译结果则在output/host目录下,可以提前下载文件到dl目录,从而避免编译时下载过慢导致的失败问题。

notes-3

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

issues_fix

Buildroot是为了解决构建文件系统困难,来实现的自动化综合脚本项目;主要解决系统,库和程序之间的兼容性问题,如果一切顺利,会直接生成最终打包的文件系统。不过因为Linux系统版本,编译工具,安装第三方库版本的碎片化,Buildroot编译中出现错误仍然是存在的。当然这也并不是不可避免的,使用方案商提供的支持特定版本的SDK包和运行环境,一般已经解决了编译时的错误问题,入门阶段也建议使用这种方案。不过如果希望摆脱这种限制,希望不受PC Ubuntu系统,Buildroot的特定版本,编译器版本限制,就需要有解决编译issue的能力,这里给我的经验。

Buildroot编译异常主要是第三方库的编译失败,这里面主要有以下几类:

  1. 缺少依赖库,主要为提示找不到相应的头文件;这类比较简单,直接安装依赖库即可。
  2. 程序编译出错,这里面就需要去”build/host/”目录下找到第三方文件,根据编译错误分析,这个主要需要C/C++程序的排错能力,大部分原因是编译工具升级导致语法和错误检测的变化,一些写法不在兼容
  3. 执行脚本出错,主要是python和shell处理异常,这类比较复杂,有可能是python版本升级导致之前的一些写法不支持,或者执行出错;shell脚本则是处理不正确,导致编译失败

在Buildroot编译中去解决这些问题,需要有如下能力。

  1. 软件交叉编译经验和问题分析能力,参考嵌入式Linux平台软件的交叉编译
  2. C/C++语法基础,参考cplusplus_application
  3. Python和Shell脚本调试能力

在编译时遇到问题,可以自己结合第三方编译的经验分析解决;不过一定不要陷入非解决不可的逻辑中,浪费太多时间,适当可以去搜索引擎检索相应错误,获取去软件官网看是否有同样和问题和解决办法,当然也可以查找软件对应的Buildroot选项,先不支持,有需要可以单独移植,这些都是可行的解决办法。当然这些解决方法也要总结下来,避免下次遇到时已经遗忘;这样才能快速高效的解决问题,事半功倍。

next_chapter

返回目录

直接开始下一章节说明: 基于debian构建文件系统