16. Buildroot根文件系统的构建

注意

当前仅支持使用LubanCat_Gen_SDK构建基于RK3576和RK3562主芯片的鲁班猫板卡的buildroot镜像

注意

包含buildroot组件的LubanCat_Gen_SDK仅提供源码压缩包,可通过百度网盘获取。压缩包名称为LubanCat_Linux_Generic_Full_SDK.tgz,此源码压缩包无法通过网络进行在线更新。

错误

buildroot相关内容不提供技术支持,仅供有能力自行开发的用户使用!!!

buildroot相关内容不提供技术支持,仅供有能力自行开发的用户使用!!!

buildroot相关内容不提供技术支持,仅供有能力自行开发的用户使用!!!

16.1. 什么是Buildroot?

Buildroot是Linux平台上一个开源的嵌入式Linux系统自动构建框架。整个Buildroot是由Makefile脚本和Kconfig配置文件构成的。 你可以和编译Linux内核一样,通过buildroot配置,menuconfig修改,编译出一个完整的可以直接烧写到机器上运行的Linux系统软件。

借助LubanCat_Gen_SDK,可以更方便的进行Buildroot根文件系统的构建和Buildroot系统镜像的制作。

LubanCat_Gen_SDK使用了Buildroot-2024.02作为基础版本, 并在此基础上修改和添加了一些由Rockchip开发的适用于RK处理器软件包,以及由野火添加的适配LubanCat板卡功能的软件包, 其包含了基于Linux系统开发⽤到的各种系统源码,驱动,⼯具,应⽤软件包。

Buildroot 有以下⼏点优势:

  • 通过源码构建,有很⼤的灵活性;

  • ⽅便的交叉编译环境,可以进⾏快速构建;

  • ⽅便各系统组件配置及定制开发。

使⽤ Buildroot最出名的项目就是OpenWrt,由它制作出的镜像可以跑在搭载16Mb SPI Flash的路由器上, 系统基本没包含多余的东西。得益于Buildroot的简单化,整个Buildroot project 可以在⼀个git仓库维护。 Buildroot使⽤kconfig和make,⼀个defconfig配置代表⼀种BSP⽀持。

16.1.1. SDK目录说明

  • app:存放供buildroot构建使用的应用demo

  • buildroot:存放buildroot源码

  • external:存放供buildroot使用的第三方仓库

16.2. Buildroot构建

由于LubanCat_Gen_SDK中就已经包含了编译所需的Buildroot源码和工具链,可以直接进行编译。

在构建Buildroot根文件系统前,先要根据对应的板卡选择SDK配置文件

目前LubanCat_Gen_SDK中的buildroot项目支持以下板卡:

  • 鲁班猫1HS系列,使用RK3562/RK3562J(工业级)主芯片

  • 鲁班猫3系列,使用RK3576主芯片

1
2
3
4
5
# 选择将要构建的板卡使用的主芯片
./build.sh chip

# 选择将要使用的配置文件
./build.sh lunch
../../_images/buildroot-gen01.png

每个芯片可选的buildroot配置文件有两个,分别是:

  • LubanCat_(主芯片型号)_buildroot_extboot_defconfig

  • LubanCat_(主芯片型号)_buildroot_rkboot_defconfig

这两个配置文件的主要差异是使用的分区打包格式不同,导致功能有差异。 有关rkboot和extboot的详细差异请查看章节 LubanCat_Chip_SDK - extboot与rkboot分区对比 此处仅列出buildroot镜像的差异

分区格式

extboot

rkboot

支持板卡

所有使用同一主芯片的LubanCat板卡

指定型号的LubanCat板卡

配置文件

高度适配LubanCat板卡

基于官方配置简单修改,仅作为示例,无法直接使用

使用方式

直接使用

需要基于目标板卡修改设备树和buildroot配置文件

自动切换设备树

支持

不支持

设备树插件

支持

不支持

支持OTA

不支持

支持

功能适配

部分RK开发的特性不支持

完整支持

开发难度

高(学习和体验Buildroot)

超高(资深开发者进行功能高度定制)

有关rkboot配置文件的修改,将会在本章后面的内容介绍

选择了exboot分区的配置文件之后,就可以开始编译构建了。

1
2
3
4
5
# 一键编译完整的Buildroot系统镜像
./build.sh

# 只构建Buildroot根文件系统
./build.sh buildroot
../../_images/buildroot-gen02.png ../../_images/buildroot-gen03.png

提示

在buildroot构建时,会下载大量的软件包源码存放在buildroot/dl目录下, 我们已经将buildroot默认的软件源修改为国内镜像源,但是由于仍然有部分源码服务器位于国外, 所以编译时请保证网络畅通和较高的源码压缩包下载速度,否则会导致构建时间过长或构建失败。

buildroot的构建目录在buildroot/output目录下,这里存放了所有被编译的软件包的源码和构建文件。 通过配置文件的命名来区分不同方案的构建目录,这样可以支持多个方案切换而不用清空构建好的内容,提升开发效率。

buildroot/output/latest指向最后一次构建的方案路径,以rockchip_rk3576_lubancat为例

  • build:软件包源码解压及编译的目录,包括宿主机所需的⼯具和目标系统所需的软件包

  • host:包含交叉编译工具链、构建工具和宿主机所使用的工具

  • images:最终生成的buildroot相关镜像保存目录

  • staging:目标系统的开发环境,包含编译软件包所需的库和头文件,软链接到了host/aarch64-buildroot-linux-gnu/sysroot目录

  • target:根文件系统环境,软件包编译后生成的产物将会被安装到这里,最终打包为根文件系统镜像。

构建生成的buildroot根文件系统镜像:buildroot/output/latest/images/rootfs.ext4

一键构建完成的完整系统镜像:output/firmware/update.img

16.3. Buildroot开发流程

16.3.1. 修改Buildroot配置文件

buildroot的每一个配置文件就是一个构建方案,配置文件保存在buildroot/configs目录下

鲁班猫板卡使用的配置文件是:

  • rockchip_rk3576_lubancat_defconfig

  • rockchip_rk3562_lubancat_defconfig

通过观察配置文件,发现配置文件使用了 #include “xxx.config” 的方式来引用其他配置文件。 这是由于Rockchip对配置文件的格式做了修改,便于用户切换预定义的组件。

除 #include 外的其他内容就是野火针对LubanCat板卡做的修改。

可以手动修改configs目录下的配置文件,也可以使用SDK提供的配置文件修改命令。 对于rk这套#include没有深入了解的不建议手动修改,以防止配置出现冲突。

1
2
# SDK配置
./build.sh bconfig

Buildroot使用kconfig进行配置,其使用方法与kernel的配置基本相同,可以按层级打开或关闭配置,也可以直接搜索

../../_images/buildroot04.png

当修改完成配置以后,多次按Esc键,退出图形配置界面,如果提示是否保存配置文件,选择Yes

../../_images/buildroot05.png

使用./build.sh bconfig修改完成配置文件以后,会自动覆盖原有的配置文件。

16.3.2. buildroot构建清理

由于buildroot的构建机制导致所有生成的文件都会被安装到target目录下并打包成rootfs镜像。 当修改配置文件之后,buildroot仅会将新选择的软件包编译并安装,如果在配置文件中移除了一些软件包, 或者由于依赖关系,一些软件包已经不再需要时,buildroot不会主动去清理这些软件包。

并且,buildroot不会去检测软件包是否被修改,如果修改了某个已经编译过的软件包的内容,在构建时不会重新构建这个修改过的软件包。

为了让修改能被应用,可以先清理之前构建时生成的文件。

根据之前对输出目录的介绍,可知build和target目录一定要清理,images目录下的内容会被覆盖, host目录为宿主机使用的工具一般不用清理。

由于Rockchip对buildroot的make进行了修改,有些原生buildroot支持的make命令无法使用,这里可以使用手动删除的方法。

找到选择的配置文件对应的输出目录,如rockchip_rk3576_lubancat_defconfig对应的输出目录是buildroot/output/rockchip_rk3576_lubancat, 删除这个目录下对应的要清理的目录即可

16.3.3. Rootfs-Overlay

除了通过软件包向根文件系统安装文件以外,还可以通过rootfs-overlay的方式, 在rootfs镜像打包前将文件覆盖到target目录中。

rootfs-overlay方式主要是用来覆盖或写入一些配置文件或脚本。

可以通过buildroot的BR2_ROOTFS_OVERLAY选项来进行配置,例如 rockchip_rk3562_lubancat_defconfig 配置文件

1
BR2_ROOTFS_OVERLAY="board/rockchip/common/base board/rockchip/rk3562/fs-overlay/ board/rockchip/common/lubancat/"

设置了三个路径,中间用空格隔开,在buildroot打包镜像前会按顺序进行覆盖,在配置时需要注意文件覆盖顺序。

16.3.4. 编译单个软件包

如前文所说,buildroot不会去检测软件包是否被修改,如果修改了某个已经编译过的软件包的内容,在构建时不会重新构建这个修改过的软件包。

由于buildroot的编译过程很慢,如果每次都清除整个build目录重新编译,这将耗费大量时间,尤其是使用软件包较多的项目。

可以只对单个软件包进行操作。命令格式为 make <package>-<command>

source

从网络获取源代码

depends

构建和安装构建此软件包所需的依赖

extract

将源代码放在包构建⽬录中(解压、复制源代码等)

patch

应⽤补丁,如果有的话

configure

运⾏configure命令,仅部分软件包支持

build

运⾏编译命令

install-staging

安装软件包

install

执行build和install-staging

show-depends

显⽰构建软件包所需的依赖

clean

从host和target⽬录中卸载软件;仅部分软件包支持

dirclean

删除整个包构建⽬录

rebuild

重新运⾏编译命令

reconfigure

重新运⾏配置命令

reinstall

重新安装软件包

在buildroot目录下执行以下命令,以vim软件包为例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 获取软件包,如果本地dl目录中不存在会从网络获取
make vim-source

# 解压软件包到build目录,然后向解压到build目录的软件包打补丁
# 常常在软件包开发调试时使用
make vim-extract
make vim-patch

# 编译软件包
make vim-configure
make vim-build
make vim-install

# 清除软件包
make vim-dirclean

# 重新编译软件包
make vim-reconfigure
make vim-rebuild
make vim-reinstall

16.3.5. 添加新的软件包

在buildroot的开发过程中,有时需要添加一些自己的软件包,这里以野火为LubanCat板卡添加的lbc-firmware软件包为例

在合适的位置创建一个目录,为了和Rockchip的修改统一,在buildroot/package/rockchip目录下创建lbc-firmware目录

16.3.5.1. Config.in

将软件包加入buildroot配置工具的管理

1
2
3
4
config BR2_PACKAGE_LBC_FIRMWARE
   bool "lbc-firmware"
   help
     copy lubancat firmware to rootfs

添加Config.in文件以后,就可以通过buildroot的menuconfig的BR2_PACKAGE_LBC_FIRMWARE来选择开启和关闭配置项。

这里需要注意,配置选项的命令需要遵循一定的规则,软件包的开启和关闭一般以 BR2_PACKAGE_(软件包所在目录的全大写)

除了开启或关闭软件包之外,还可以添加选项来配置软件包的编译条件,这里的示例比较简单,更复杂的可以参考buildroot其他软件包的Config.in

16.3.5.2. .mk

.mk文件对软件包的下载、配置、构建、安装等细节进行了描述。mk⽂件的内容比较灵活,需要根据实际软件包的编译工具使⽤不同的结构。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
LBC_FIRMWARE_VERSION = 1.0
LBC_FIRMWARE_SITE_METHOD = local
LBC_FIRMWARE_SITE = $(TOPDIR)/../external/firmware
FIRMWARE_DIR := $(TARGET_DIR)/lib/firmware

define LBC_FIRMWARE_INSTALL_TARGET_CMDS
   mkdir -p $(TARGET_DIR)/lib/firmware
   cp -r $(LBC_FIRMWARE_SITE)/* $(FIRMWARE_DIR)
endef

$(eval $(generic-package))

.mk文件的文件名应与软件包所在的目录一致,如软件包配置文件保存的目录是lbc-firmware,则mk的名称应该是lbc-firmware.mk。

在mk文件内,配置项的名称也与mk文件的名称保持一致,但是要使用字母全部大写的格式,并且要将分隔符 - 变为分隔符 _

  • VERSION:软件包的版本

  • SITE_METHOD:软件包源码保存地址的类型,local为本地软件包,还有git、svn等,如果不指定默认为tarball

  • SITE:软件包源码路径,local需要指定本地路径,git、svn、tarball等还要指定网址,如果不指定的话默认从buildroot自己的软件源中下载。

  • INSTALL_TARGET_CMDS:软件包安装命令

这里简单对mk文件的配置进行了说明,如果有更复杂的功能需要实现,可以参考其他软件包的mk文件或查看buildroot官方文档

16.4. rkboot配置文件的修改

根据前文描述,rkboot配置仅基于官方配置进行了简单适配,以使资深开发者在LubanCat板卡上进行Rockchip原生buildroot固件的开发。

注意

此配置选项不提供任何技术支持,仅提供给有开发能力的用户使用

为了进一步适配用户手中的LubanCat板卡,需要对一些文件及配置进行修改。

16.4.1. LubanCat_(主芯片型号)_buildroot_rkboot_defconfig

此文件为SDK配置文件

1
2
3
4
5
6
7
8
9
RK_ROOTFS_HOSTNAME_CUSTOM=y
RK_ROOTFS_HOSTNAME="LubanCat"
RK_ROOTFS_INSTALL_MODULES=y
# RK_WIFIBT is not set
RK_UBOOT_SPL=y
RK_KERNEL_PREFERRED="6.1"
RK_KERNEL_CFG="lubancat_linux_rk3576_defconfig"
RK_KERNEL_DTS_NAME="rk3576-lubancat-generic"
RK_USE_FIT_IMG=y
  • RK_ROOTFS_HOSTNAME:设置hostname为LubanCat

  • RK_ROOTFS_INSTALL_MODULES:将内核编译的ko文件安装到rootfs

  • # RK_WIFIBT is not set:不使用rk-wifibt驱动,使用内核中的

  • RK_KERNEL_PREFERRED:指定内核版本为6.1

  • RK_KERNEL_CFG:指定内核配置文件为lubancat_linux_rk3576_defconfig,根据芯片选择

  • RK_KERNEL_DTS_NAME:设备树名称

用户需要将RK_KERNEL_DTS_NAME修改为自己板卡的设备树,具体名称可以查看:kernel-6.1/arch/arm64/boot/dts/rockchip/Makefile

RK_KERNEL_CFG不建议修改,如果要增删内核驱动的话用./build.sh kconfig直接修改已经指定的配置文件即可。

16.4.2. buildroot配置文件

rkboot使用了Rockchip官方的buildroot配置文件,未进行修改。配置文件保存在buildroot/configs目录下

用户如果要修改配置文件可以使用./build.sh bconfig去修改。

LubanCat的修改内容可以参考 rockchip_(主芯片型号)_lubancat_defconfig

16.4.3. 板卡设备树

由于rkboot不支持设备树插件,因此一些硬件功能需要用户自行添加并编译到镜像中。

打开前面配置文件指定的设备树,此处以LubanCat-3为例。打开文件kernel-6.1/arch/arm64/boot/dts/rockchip/rk3576-lubancat-3.dts

在设备树文件靠前的位置,已经添加了一些常用的外设配置,通过#include的方式引用。

1
2
3
4
5
// #include "rk3576-lubancat-3-dsi-1080x1920-5-5inch-ebf410125.dtsi"
// #include "rk3576-lubancat-3-dsi-1024x600-7inch-ebf410173.dtsi"
// #include "rk3576-lubancat-3-dsi-800x1280-10-1inch-ebf410177.dtsi"

#include "rk3576-lubancat-3-csi.dtsi"

如上所示,#include了几个dtsi文件,其中有三个屏幕配置,需要将实际使用的屏幕配置取消注释(删除//)。

需要注意,一般同一类型的dtsi文件同一时间只可开启一个,上方代码中有三个使用dsi接口的不同屏幕,就只能选择一个。 如果配置了两个不同的dsi接口,则有时可以同时开启两个(还需根据其他情况具体决定)。

除此还要注意,有些dtsi文件原本是搭配设备树插件使用的,里面的节点并未“okay”而是处于“disabled”的状态。 这时就需要参考设备树插件来开启对应的节点。

打开kernel-6.1/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3.txt文件, 这里保存了所有LubanCat-3板卡所能使用的设备树插件的列表。 设备树插件保存在kernel-6.1/arch/arm64/boot/dts/rockchip/overlay目录下

如果要在设备树中开启相应的功能,可以参考设备树插件中配置的设备树节点手动在板卡设备树中开启。

例如设备树插件rk3576-lubancat-3-dp-disabled-ovetlay.dts的作用是关闭Type-C接口的DP视频输出, 源文件内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/display/drm_mipi_dsi.h>
#include <dt-bindings/interrupt-controller/irq.h>

/ {
   fragment@0 {
      target = <&dp>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@1 {
      target = <&dp0>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@2 {
      target = <&dp0_in_vp0>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@3 {
      target = <&dp0_in_vp1>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@4 {
      target = <&dp0_in_vp2>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@5 {
      target = <&vp1>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@6 {
      target = <&route_dp0>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@7 {
      target = <&dp0_sound>;

      __overlay__ {
            status = "disabled";
      };
   };
   fragment@8 {
      target = <&spdif_tx3>;

      __overlay__ {
            status = "disabled";
      };
   };
};

那么如何移植到板卡设备树rk3576-lubancat-3.dts中呢?需要在板卡设备树中搜索所有设备树插件里 target = <&xxx>; 对应的节点, 例如在rk3576-lubancat-3.dts中搜索 &dp ,将 &dp 中的 status 改为和设备树插件一致。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
&dp {
   status = "disabled";
};

&dp0 {
   status = "disabled";
};

&dp0_in_vp0 {
   status = "disabled";
};

&dp0_in_vp1 {
   status = "disabled";
};

&dp0_in_vp2 {
   status = "disabled";
};

&vp1 {
   status = "disabled";
};

&route_dp0 {
   status = "disabled";
   connect = <&vp1_out_dp0>;
};

&dp0_sound {
   status = "disabled";
};

&spdif_tx3 {
   status = "disabled";
};

有时会出现在板卡设备树没有设备树插件中同样节点的情况,这时在板卡设备树的最后手动追加即可

例如设备树插件rk3576-lubancat-uart8-m2-overlay.dts的功能是开启uart8并使用m2这一组引脚

设备树插件内容如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/dts-v1/;
/plugin/;

/ {
   fragment@0 {
      target = <&uart8>;

      __overlay__ {
         status = "okay";
         pinctrl-names = "default";
         pinctrl-0 = <&uart8m2_xfer>;
      };
   };
};

在板卡设备树rk3576-lubancat-3.dts中搜索发现并没有 &uart8 这个节点,此时就需要在板卡设备树的最后手动追加

将设备树插件中的对应节点复制,删除画红线的部分,最后整理一下格式

../../_images/buildroot-fixdts.png
1
2
3
4
5
&uart8 {
   status = "okay";
   pinctrl-names = "default";
   pinctrl-0 = <&uart8m2_xfer>;
};

修改完设备树以后使用 ./build.sh kernel命令重新打包boot分区就会应用修改后的设备树

16.5. 参考资料

《Rockchip_Developer_Guide_Buildroot_CN.pdf》

《The Buildroot user manual》 https://buildroot.org/downloads/manual/manual.html