Rockchip RK3588 - Rockchip Linux SDK Buildroot文件系统构建
----------------------------------------------------------------------------------------------------------------------------
开发板 :ArmSoM-Sige7开发板
eMMC :64GB
LPDDR4 :8GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot :2017.09
linux :5.10
----------------------------------------------------------------------------------------------------------------------------
一、Buildroot文件系统
在《Rockchip RK3588 - Rockchip Linux SDK编译》中我们对Buildroot进行了简单的介绍,并一键全自动编译生成了buildroot文件系统。
1.1 Buildroot系统
Buildroot 是Linux平台上一个开源的嵌入式Linux系统自动构建框架。整个Buildroot是由Makefile脚本和Kconfig配置文件构成的。可通过Buildroot配置,编译出一个完整的可以直接烧写到机器上运行的Linux系统软件。
Buildroot有以下几点优势:
- 通过源码构建,有很大的灵活性;
- 方便的交叉编译环境,可以进行快速构建,容易上手;
- 提供系统各组件的配置,方便定制开发。
使用Buildroot的project最出名的就是Openwrt。可以看到,由它制作出的镜像可以跑在搭载16 Mb SPINOR的路由器上,系统基本没包含多余的东西。 这就是得益于Buildroot的简单化。整个Buildroot工程在一个git维护。
Buildroot使用kconfig和make,一个defconfig配置代表一种BSP支持。Buildroot 本身不具备扩展能力,用户需要自己通过脚本来完成工作。这些列出来的特点,都是和Yocto不同的地方。
注意:Buildroot默认使用Busybox来制作根文件系统。
1.2 Buildroot框架
Rockchip Linux SDK的Buildroot系统,其包含了基于Linux系统开发用到的各种系统源码,驱动,工具,应用软件包。
其目录结构如下:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll
drwxr-xr-x 2 root root 4096 6月 9 12:58 arch/
drwxr-xr-x 2 root root 4096 6月 9 12:58 archives/
drwxr-xr-x 75 root root 4096 6月 9 12:58 board/
drwxr-xr-x 26 root root 4096 6月 9 12:58 boot/
drwxr-xr-x 2 root root 4096 6月 9 12:58 build/
-rw-r--r-- 1 root root 454027 6月 9 12:58 CHANGES
-rw-r--r-- 1 root root 29466 6月 9 12:58 Config.in
-rw-r--r-- 1 root root 135314 6月 9 12:58 Config.in.legacy
drwxr-xr-x 3 root root 20480 6月 9 12:58 configs/
-rw-r--r-- 1 root root 18767 6月 9 12:58 COPYING
-rw-r--r-- 1 root root 1198 6月 9 12:58 .defconfig
-rw-r--r-- 1 root root 72437 6月 9 12:58 DEVELOPERS
drwxr-xr-x 176 root root 4096 6月 11 19:57 dl/
drwxr-xr-x 5 root root 4096 6月 9 12:58 docs/
lrwxrwxrwx 1 root root 17 6月 9 12:58 envsetup.sh -> build/envsetup.sh*
-rw-r--r-- 1 root root 96 6月 9 12:58 .flake8
drwxr-xr-x 20 root root 4096 6月 9 12:58 fs/
-rw-r--r-- 1 root root 125 6月 9 12:58 .gitignore
-rw-r--r-- 1 root root 721 6月 9 12:58 .gitlab-ci.yml
drwxr-xr-x 3 root root 4096 6月 9 12:58 linux/
-rw-r--r-- 1 root root 47335 6月 9 12:58 Makefile
-rw-r--r-- 1 root root 2292 6月 9 12:58 Makefile.legacy
drwxr-xr-x 5 root root 4096 6月 18 01:24 output/
drwxr-xr-x 2594 root root 73728 6月 9 12:58 package/
-rw-r--r-- 1 root root 1075 6月 9 12:58 README
-rw-r--r-- 1 root root 644 6月 9 12:58 README.rockchip
drwxr-xr-x 13 root root 4096 6月 9 12:58 support/
drwxr-xr-x 3 root root 4096 6月 9 12:58 system/
drwxr-xr-x 5 root root 4096 6月 9 12:58 toolchain/
drwxr-xr-x 3 root root 4096 6月 9 12:58 utils/
1.2.1 目录介绍
这里我们只介绍一些重要的目录,其中:
arch: 存放CPU架构相关的配置脚本,如arm/mips/x86,这些CPU相关的配置,在制作工具链时,编译uboot和kernel时很关键;board:这个目录包含了针对特定开发板的配置文件和补丁。每块开发板都有自己的子目录,里面可能包含特定的配置文件、设备树文件、补丁以及其他相关文件;这些文件帮助Buildroot在不同的硬件平台上进行适配和配置,以生成针对特定开发板的嵌入式linux系统;boot:这个目录包含与引导加载程序相关的文件和脚本。它通常包括引导加载程序(如u-boot)、引导配置文件、引导脚本等;Buildroot可以在这里生成和配置引导加载程序以及相关的启动文件;configs: 放置开发板的一些配置,这些配置文件以_defconfig结尾,比如rockchip_rk3358_recovery_defconfig;dl:存放从互联网下载的源代码及应用软件的压缩包,比如zip、glic、busybox、alsa-lib、alsa-plugins等;docs:存放相关的参考文档;fs:存放各种文件系统的源代码,它控制着根文件系统的创建和各类文件系统映像的生成(如ext2、squashfs等);linux:存放着linux kernel的自动构建脚本,它用于下载、配置、编译linux内核;output:这个目录是构建输出目录,包含所有构建过程中生成的文件,如交叉编译工具链、内核映像、根文件系统等。默认情况下,这个目录不在源码树中,而是在构建时生成的,可以通过配置来改变其位置;package:这个目录包含Buildroot支持的所有软件包的目录结构;每个软件包都有自己的子目录,包括描述如何下载、配置、编译和安装该软件包的元数据和Makefile;support:这个目录包含一些支持脚本和工具。例如:scripts/:包含各种辅助脚本,如生成配置文件、下载源代码等;kconfig/:包含与Kconfig系统相关的文件,用于配置Buildroot构建系统;
system:这个目录包含与基本系统配置相关的文件和脚本,例如初始化脚本、设备表、主机名等;toolchain:这个目录包含工具链的构建和配置文件。工具链通常包括编译器、链接器、库和头文件,它们是构建其他软件包所必需的;utils:一些工具。
Rockchip Linux SDK集成了Buildroot第三方包下载机制,确保客户能够有效下载。现在采用了更灵活的机制, 在原生dl基础上增加archives目录,预置第三方包。同时如果无法连接Google,将切换到使用国内的kgithub镜像,并优先从mk脚本指定的源下载,如果失败将尝试mk脚本和defconfig配置的镜像源,最后才是官方备份源。
在官方树中,大多数源码都是使用wget来获取;只有小部分通过他们的git,mercurial或者svn储存库。
1.2.2 框架介绍
Buildroot提供了函数框架和变量命令框架,采用它的框架编写的app_pkg.mk这种Makefile格式的自动构建脚本,将被package/pkg-generic.mk这个核心脚本展开填充到buildroot主目录下的Makefile中去。
最后make all执行Buildroot主目录下的Makefile,生成你想要的image。 package/pkg-generic.mk中通过调用同目录下的pkg-download.mk、pkg-utils.mk文件,已经自动实现了下载、解压、依赖包下载编译等一系列机械化的流程。
只要需要按照格式写Makefile脚本app_pkg.mk,填充下载地址,链接依赖库的名字等一些特有的构建细节即可。
总而言之,Buildroot本身提供构建流程的框架,开发者按照格式写脚本,提供必要的构建细节,配置整个系统,最后自动构建出你的系统。
Buildroot的配置(即make menuconfig所看到的配置)通过Config.in串联起来,起点在根目录Config.in中,该文件包含了各个模块目录下的Config.in文件:
mainmenu "Buildroot $BR2_VERSION Configuration"
......
source "toolchain/Config.in"
source "system/Config.in"
source "linux/Config.in"
source "package/Config.in"
source "fs/Config.in"
source "boot/Config.in"
source "package/Config.in.host"
source "Config.in.legacy"
# br2-external menus definitions
source "$BR2_BASE_DIR/.br2-external.in.menus"
其中:
| 配置选项 | Config.in位置 |
|---|---|
| Target options | arch/Config.in |
| Build options | Config.in |
| Toolchain | toolchain/Config.in |
| System configuration | system/Config.in |
| Kernel | linux/Config.in |
| Target packages | package/Config.in |
| Target packages->Busybox | |
| Filesystem images | fs/Config.in |
| Bootloaders | boot/Config.in |
| Host utilities | package/Config.in.host |
| Legacy config options | Config.in.legacy |
1.3 Buildroot配置
同内核编译有点类似,首先需要选择一个单板的配置,单板的默认配置在configs目录下。
也可以通过如下命令列出来,然后选择具体平台编译;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo -s source envsetup.sh
比如这里选择rockchip_rk3588_defconfig;
#include "base/base.config"
#include "chips/rk3588_aarch64.config"
#include "font/chinese.config"
#include "fs/exfat.config"
#include "fs/ntfs.config"
#include "fs/vfat.config"
#include "gpu/gpu.config"
#include "multimedia/audio.config"
#include "multimedia/camera.config"
#include "multimedia/gst/audio.config"
#include "multimedia/gst/camera.config"
#include "multimedia/gst/rtsp.config"
#include "multimedia/gst/video.config"
#include "multimedia/mpp.config"
#include "wifibt/bt.config"
#include "wifibt/wireless.config"
#include "benchmark.config"
#include "chromium.config"
#include "debug.config"
#include "npu2.config"
#include "powermanager.config"
#include "test.config"
#include "weston.config"
或者直接执行如下命令:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make rockchip_rk3588_defconfig
GEN /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/Makefile
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/build/parse_defconfig.sh /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/configs/rockchip_rk3588_defconfig /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/.config.in
Parsing defconfig: /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/configs/rockchip_rk3588_defconfig
Using configs/rockchip/base/kernel.config as base
Merging configs/rockchip/fs/e2fs.config
Merging configs/rockchip/base/common.config
Merging configs/rockchip/base/base.config
Merging configs/rockchip/chips/rk3588.config
Value of BR2_ROOTFS_OVERLAY is redefined by configs/rockchip/chips/rk3588.config:
Previous value: BR2_ROOTFS_OVERLAY="board/rockchip/common/base"
Modify value: BR2_ROOTFS_OVERLAY+="board/rockchip/rk3588/fs-overlay/"
New value: BR2_ROOTFS_OVERLAY="board/rockchip/common/base board/rockchip/rk3588/fs-overlay/"
Merging configs/rockchip/chips/rk3588_aarch64.config
Merging configs/rockchip/font/font.config
Merging configs/rockchip/font/chinese.config
Merging configs/rockchip/fs/exfat.config
Merging configs/rockchip/fs/ntfs.config
Merging configs/rockchip/fs/vfat.config
Merging configs/rockchip/gpu/gpu.config
Merging configs/rockchip/multimedia/audio.config
Merging configs/rockchip/multimedia/camera.config
Merging configs/rockchip/multimedia/gst/audio.config
Merging configs/rockchip/multimedia/gst/camera.config
Merging configs/rockchip/multimedia/gst/rtsp.config
Merging configs/rockchip/multimedia/gst/video.config
Merging configs/rockchip/multimedia/mpp.config
Merging configs/rockchip/wifibt/bt.config
Merging configs/rockchip/wifibt/network.config
Merging configs/rockchip/wifibt/wireless.config
Merging configs/rockchip/benchmark.config
Merging configs/rockchip/chromium.config
Merging configs/rockchip/debug.config
Merging configs/rockchip/npu2.config
Merging configs/rockchip/powermanager.config
Merging configs/rockchip/test.config
Merging configs/rockchip/weston.config
Merging /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/configs/rockchip_rk3588_defconfig
#
# merged configuration written to /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/.config.in (needs make)
#
BR2_DEFCONFIG='' KCONFIG_AUTOCONFIG=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/buildroot-config/auto.conf KCONFIG_AUTOHEADER=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/buildroot-config/autoconf.h KCONFIG_TRISTATE=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/buildroot-config/tristate.config BR2_CONFIG=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/.config HOST_GCC_VERSION="9" BASE_DIR=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588 SKIP_LEGACY= CUSTOM_KERNEL_VERSION="5.10" BR2_DEFCONFIG=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/configs/rockchip_rk3588_defconfig /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/buildroot-config/conf --defconfig=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/.config.in Config.in
#
# configuration written to /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/.config
#
在目录output/rockchip_rk3588生成.config文件。
接着我们需要执行make menuconfig做一些配置。
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make menuconfig

1.3.1 配置Target options
需要配置的项目和其对应的内容如下:
Target options --->
Target Architecture (AArch64 (little endian)) --->
(X) AArch64 (little endian)
( ) AArch64 (big endian)
......
Target Architecture Variant (cortex-A76/A55 big.LITTLE) --->
( ) cortex-A76
(X) cortex-A76/A55 big.LITTLE
......
Floating point strategy (Auto) --->
(X) Auto
( ) VFPv2
......
MMU Page Size (4KB) --->
(X) 4KB
( ) 64KB
Target Binary Format (ELF) --->
(X) ELF
其中:
- 目标架构:
ARM64; - 目标架构变体:
cortex-A76/A55 big.LITTLE; - 浮点策略:
Auto; - 目标二进制格式:
ELF。
1.3.2 配置Toolchain
Toolchain --->
Toolchain type (Buildroot toolchain) --->
(X) Buildroot toolchain
( ) External toolchain
glibc version (glibc latest) --->
(X) glibc latest
( ) glibc 2.28
.......
这里工具链直接使用toolchain-buildroot即可,当然也可以用自己的交叉编译器。
1.3.3 配置System configuration
此选项用于设置一些系统配置,比如开发板名字、欢迎语、用户名、密码等。需要配置的项目和其对应的内容如下:
System configuration --->
(rk3588) System hostname // 平台名字
(Welcome to rk3588 Buildroot) System banner // 欢迎语
Passwords encoding (sha-256) --->
(X) sha-256
( ) sha-512
Init system (BusyBox) ---> // 使用 busybox
(X) BusyBox
( ) systemV
......
/dev management (Dynamic using devtmpfs + eudev) ---> // 使用 eudev
( ) Dynamic using devtmpfs + mdev
(X) Dynamic using devtmpfs + eudev
......
[*] Enable root login with password (NEW) // 使能登录密码
(rockchip) Root password // 登录密码
......
1.3.4 配置Filesystem images
此选项配置我们最终制作的根文件系统为什么格式的,配置如下:
Filesystem images --->
[*] cpio the root filesystem (for use as an initial RAM filesystem)
[*] ext2/3/4 root filesystem // 如果是 EMMC 或 SD 卡的话就用 ext3/ext4
ext2/3/4 variant (ext4) ---> // 选择 ext4 格式
......
( ) ext3
(X) ext4
(auto) exact size //ext4 格式根文件系统 可以根据实际情况修改, 也可以设置为auto
[*] squashfs root filesystem
[*] pad to a 4K boundary
Compression algorithm (gzip) --->
(X) gzip
( ) lz4
......
[*] tar the root filesystem
Compression method (no compression) --->
(X) no compression
( ) gzip
......
[ ] ubi image containing an ubifs/squashfs root filesystem // 如果使用 NAND 的话就用 ubifs
[ ] ubifs root filesystem
[ ] yaffs2 root filesystem
......
buildroot可以直接制作出ext4格式的根文件系统,但是一般我们会自行往根文件系统里面添加很多其他的文件,所以产品开发完成以后需要自行打包根文件系统,然后烧写到开发板里面。
1.3.5 禁止编译Linux内核和uboot
buildroot不仅仅能构建根文件系统,也可以编译linux内核和uboot。我们一般都不会使用buildroot下载的linux内核和uboot,因为buildroot下载的linux和uboot官方源码,里面会缺少很多驱动文件,而且最新的linux内核和uboot会对编译器版本号有要求,可能导致编译失败。
因此我们需要配置buildroot,关闭linux内核和uboot的编译,只使用buildroot来构建根文件系统,配置如下:
Kernel --->
[ ] Linux Kernel // 不要选择编译Linux Kernel选项
......
Bootloaders --->
[ ] U-Boot // 不要选择编译U-Boot选项
......
1.3.6 编译Target packages
此选项用于配置要选择的第三方库或软件、比如alsa-utils、 ffmpeg、 iperf等工具,这里我们先只选择内核的模块加载相关软件,配置如下:
Target packages --->
Hardware Platforms --->
[*] Rockchip Platform --->
Rockchip SoC (rk3588) --->
( ) rk3358 chip
(X) rk3588 chip
......
[*] Rockchip Camera Engine For ISP
Rockchip BSP packages ---> // Rockchip板级支持包,很重要
[*] Rockchip Camera Engine 3A service run in booting
Specify a directory to store xml speed up bin (disabled) --->
() Rockchip Camera Engine IQ xml file
[ ] rockchip common algorithm
[*] gstreamer1-rockchip
[*] A rockchip-mpp V4L2 wrapper plugin for chromium V4L2 VDA
[ ] Rockchip NPU power control for linux
[ ] Rockchip NPU power control combine for linux
[ ] rk n4 camera
[ ] Rockchip recovery for linux
[ ] rknpu
[ ] rknpu pcie
[ ] rknpu2
[ ] rknn_demo
[*] rockchip script
() default PCM
[ ] rkscript iodomain notice script
......
[ ] Rockchip rkupdate for linux
[*] rkwifibt
[ ] Enable static
[ ] rkwifibt wireless applicantion
[*] rockchip-alsa-config
[*] rockchip-rga
[*] prefer using rockchip-rga
[*] rockchip-mali
......
[*] wayland winsys
[*] GBM
[*] OpenGL EGL
[*] OpenGL EGL Wayland
[*] OpenGL ES
[*] OpenCL
[ ] Vulkan
[*] rockchip-mpp --->
......
-*- BusyBox
Audio and video applications --->
.......
Compressors and decompressors --->
.......
Filesystem and flash utilities --->
.......
System tools --->
[*] kmod // 使能内核模块相关命令
......
......
上面包含了若干库的配置,但是我们实际上较为关心的就是和硬件驱动相关的库,即Rockchip BSP packages中的配置项。
Rockchip提供的这些软件包位于package/rockchip目录下;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll package/rockchip/
drwxr-xr-x 2 root root 4096 6月 9 12:58 camera-engine-rkaiq/
drwxr-xr-x 2 root root 4096 6月 9 12:58 camera-engine-rkisp/
drwxr-xr-x 2 root root 4096 6月 9 12:58 common_algorithm/
-rw-r--r-- 1 root root 3908 6月 9 12:58 Config.in
drwxr-xr-x 2 root root 4096 6月 9 12:58 gstreamer1-rockchip/
drwxr-xr-x 2 root root 4096 6月 9 12:58 libv4l-rkmpp/
drwxr-xr-x 2 root root 4096 6月 9 12:58 n4/
drwxr-xr-x 2 root root 4096 6月 9 12:58 npu_powerctrl/
drwxr-xr-x 2 root root 4096 6月 9 12:58 npu_powerctrl_combine/
drwxr-xr-x 2 root root 4096 6月 9 12:58 recovery/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rkadk/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rknn_demo/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rknpu/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rknpu2/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rknpu-fw/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rkscript/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rktoolkit/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rkupdate/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rkwifibt/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rkwifibt-app/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-alsa-config/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-mali/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-mali-nvr/
-rw-r--r-- 1 root root 52 6月 9 12:58 rockchip.mk
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-mpp/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-rga/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-test/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockchip-uac-app/
drwxr-xr-x 2 root root 4096 6月 9 12:58 rockit/
drwxr-xr-x 2 root root 4096 6月 9 12:58 slt_gpu_light/
drwxr-xr-x 3 root root 4096 6月 9 12:58 tee-user-app/
1.3.7 保存配置
和uboot、 kernel 一样,通过图形化界面配置好buildroot以后最好保存一下配置项,防止清除工程以后将配置项给删除掉。 buildroot的默认配置项都保存在configs目录下,配置完成以后移动到Save按回车保存到 .config,移动到 Exit 按回车退出。
接着我们执行如下命令保存配置,可以生成一个新的默认配置文件(defconfig),这个文件会基于当前配置生成,并且只包含当前确实需要的配置选项,移除了所有未被使用的选项;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make savedefconfig
将配置文件拷贝到configs目录:
root@ubuntu:/work/sambashare/rk3588/recovery/buildroot-2024.02.4# cp defconfig ./configs/rockchip_rk3588_defconfig
将修改保存到配置文件 configs/rockchip_rk3588_defconfig。
1.4 make命令使用
过make help可以看到buildroot下make的使用细节,包括对package、uclibc、busybox、linux以及文档生成等配置。
Cleaning:
clean - delete all files created by build
distclean - delete all non-source files (including .config)
Build:
all - make world
toolchain - build toolchain
sdk - build relocatable SDK
reinstall - reinstall all
Configuration:
menuconfig - interactive curses-based configurator
nconfig - interactive ncurses-based configurator
xconfig - interactive Qt-based configurator
gconfig - interactive GTK-based configurator
oldconfig - resolve any unresolved symbols in .config
syncconfig - Same as oldconfig, but quietly, additionally update deps
olddefconfig - Same as syncconfig but sets new symbols to their default value
randconfig - New config with random answer to all options
defconfig - New config with default answer to all options;
BR2_DEFCONFIG, if set on the command line, is used as input
savedefconfig - Save current config to BR2_DEFCONFIG (minimal config)
update-defconfig - Same as savedefconfig, but with fragments
allyesconfig - New config where all options are accepted with yes
allnoconfig - New config where all options are answered with no
alldefconfig - New config where all options are set to default
randpackageconfig - New config with random answer to package options
allyespackageconfig - New config where pkg options are accepted with yes
allnopackageconfig - New config where package options are answered with no
Package-specific:
<pkg> - Build and install <pkg> and all its dependencies
<pkg>-source - Only download the source files for <pkg>
<pkg>-extract - Extract <pkg> sources
<pkg>-patch - Apply patches to <pkg>
<pkg>-depends - Build <pkg>'s dependencies
<pkg>-configure - Build <pkg> up to the configure step
<pkg>-build - Build <pkg> up to the build step
<pkg>-show-info - generate info about <pkg>, as a JSON blurb
<pkg>-show-depends - List packages on which <pkg> depends
<pkg>-show-rdepends - List packages which have <pkg> as a dependency
<pkg>-show-recursive-depends
- Recursively list packages on which <pkg> depends
<pkg>-show-recursive-rdepends
- Recursively list packages which have <pkg> as a dependency
<pkg>-graph-depends - Generate a graph of <pkg>'s dependencies
<pkg>-graph-rdepends - Generate a graph of <pkg>'s reverse dependencies
<pkg>-dirclean - Remove <pkg> build directory
<pkg>-reconfigure - Restart the build from the configure step
<pkg>-rebuild - Restart the build from the build step
<pkg>-reinstall - Restart the build from the install step
busybox:
busybox-menuconfig - Run busybox menuconfig
busybox-xconfig - Run busybox xconfig
busybox-gconfig - Run busybox gconfig
busybox-update-config - Save the busybox configuration as a full .config file
to package/busybox/busybox.config
(or override with BUSYBOX_KCONFIG_FILE)
Documentation:
manual - build manual in all formats
manual-html - build manual in HTML
manual-split-html - build manual in split HTML
manual-pdf - build manual in PDF
manual-text - build manual in text
manual-epub - build manual in ePub
graph-build - generate graphs of the build times
graph-depends - generate graph of the dependency tree
graph-size - generate stats of the filesystem size
list-defconfigs - list all defconfigs (pre-configured minimal systems)
Miscellaneous:
source - download all sources needed for offline-build
external-deps - list external packages used
legal-info - generate info about license compliance
show-info - generate info about packages, as a JSON blurb
pkg-stats - generate info about packages as JSON and HTML
missing-cpe - generate XML snippets for missing CPE identifiers
printvars - dump internal variables selected with VARS=...
make V=0|1 - 0 => quiet build (default), 1 => verbose build
make O=dir - Locate all output files in "dir", including .config
For further details, see README, generate the Buildroot manual, or consult
it on-line at http://buildroot.org/docs.html
1.4.1 busybox配置
当执行buildroot编译会自动下载busybox压缩包, buildroot下载的源码压缩包都存放在dl目录下,在dl目录下就有一个叫做busybox的文件夹,此目录下保存着busybox压缩包,如下图所示:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll dl/busybox/
-rw-r--r-- 1 root root 2523487 6月 11 02:44 busybox-1.36.0.tar.bz2
-rw-r--r-- 1 root root 0 6月 11 02:44 .lock
进入busybox图形化配置界面:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make busybox-menuconfig
此处可以进行busybox的配置,配置完成后,移动到 Exit 按回车退出,在弹窗页面选择 Yes 保存到 .config。
保存配置文件:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make busybox-update-config
将修改保存到配置文件 board/rockchip/common/base/busybox.config。
配置完成后如果我们想单独编译并安装busybox的话执行下面命令即可:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make busybox
编译完成以后重新编译buildroot,主要是对其进行打包,输入如下命令:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8
1.4.2 buildroot编译
配置好buildroot后,如需编译buildroot,运行如下命令即可:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8
运行 make 进行编译时,会执行以下过程:
- 下载源码;
- 配置、编译、安装交叉编译工具链;
- 配置、编译、安装选择的软件包;
- 按选择的格式生成根文件系统;
编译大概需要十几个小时,耐心等待。编译完成后,在编译输出目录 output/rockchip_rk3588 会生成子目录,说明如下:
build: 除了交叉编译的工具链之外的所有组件,包括Buildroot所需主机工具和选择的软件包,这个目录包含所有软件包源码;host:包含为主机编译的工具的安装,这些工具是正确执行Buildroot所必需的,包括交叉编译工具
链;images:所有镜像(文件系统,比如ext2/4、squashfs、cpio等格式镜像)存储目录;staging:其中的层次结构类似于根文件系统层次结构。这个目录包含了安装交叉编译工具链和为目标选择的所有用户空间包,但是,这个目录不是用来成为目标的根文件系统:它包含许多开发文件、未剥离的二进制文件和库,这些文件和库也非常多,对嵌入式系统来说是很大的;这些开发文件用于为所依赖的目标提供编译库和应用程序需要的其他库;target: 几乎包含了目标的完整根文件系统:除了/dev/目录中的设备文件,所有需要的东西都是存在(Buildroot不能创建它们,因为Buildroot不会以root身份运行,也不希望以root身份运行)。此外,它没有正确的权限(例如,busybox二进制文件的setuid),因此,该目录不应该用于你的目标;相反,您应该使用images/目录中构建的映像之一;如果你需要在根文件系统中用NFS挂载外部镜像,必须用root用户在images/目录中生成镜像,相比对于staging/,target/只包含运行所选目标应用程序所需的文件和库:开发文件(头文件)不存在,二进制文件被剥离。
查看output/rockchip_rk3588目录:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.init
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.jpeg
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.linux
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.menus
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.openssl
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.paths
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.skeleton
-rw-r--r-- 1 root root 82 6月 19 22:39 .br2-external.in.toolchains
-rw-r--r-- 1 root root 162 6月 19 22:39 .br2-external.mk
drwxr-xr-x 235 root root 12288 6月 19 22:42 build/
-rw-r--r-- 1 root root 140337 6月 19 22:34 .config
-rw------- 1 root root 8569 6月 19 22:18 .config.in
-rw-r--r-- 1 root root 140337 6月 19 22:30 .config.old
-rw-r--r-- 1 root root 140337 6月 18 00:23 .config.orig
-rw-r--r-- 1 root root 105085 6月 19 22:36 ..config.tmp
drwxr-xr-x 12 root root 4096 6月 18 01:17 host/
drwxr-xr-x 2 root root 4096 6月 19 22:43 images/
-rw-r--r-- 1 root root 681 6月 19 22:36 Makefile
lrwxrwxrwx 1 root root 122 6月 18 01:24 staging -> /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/aarch64-buildroot-linux-gnu/sysroot/
drwxr-xr-x 19 root root 4096 6月 9 12:58 target/
包含压缩好的根文件系统镜像文件位于 output/rockchip_rk3588/images目录下;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/images/
-rw-r--r-- 1 root root 616497664 6月 19 22:42 rootfs.cpio
-rw-r--r-- 1 root root 274253269 6月 19 22:43 rootfs.cpio.gz
-rw-r--r-- 1 root root 763363328 6月 19 22:43 rootfs.ext2
lrwxrwxrwx 1 root root 11 6月 19 22:43 rootfs.ext4 -> rootfs.ext2
-rw-r--r-- 1 root root 275308544 6月 19 22:43 rootfs.squashfs
-rw-r--r-- 1 root root 625326080 6月 19 22:44 rootfs.tar
查看编译好的根文件系统:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/target/
lrwxrwxrwx 1 root root 7 6月 18 00:28 bin -> usr/bin/
-rw-r--r-- 1 root root 489 6月 9 12:58 busybox.fragment
lrwxrwxrwx 1 root root 8 6月 19 22:42 data -> userdata/
drwxr-xr-x 4 root root 4096 6月 9 12:58 dev/
drwxr-xr-x 22 root root 4096 6月 9 12:58 etc/
drwxr-xr-x 2 root root 4096 6月 19 22:42 info/
lrwxrwxrwx 1 root root 7 6月 18 00:28 lib -> usr/lib/
lrwxrwxrwx 1 root root 3 6月 18 00:28 lib64 -> lib/
lrwxrwxrwx 1 root root 11 6月 18 00:49 linuxrc -> bin/busybox*
drwxr-xr-x 11 root root 4096 6月 18 01:18 media/
drwxr-xr-x 5 root root 4096 6月 19 22:42 mnt/
drwxr-xr-x 2 root root 4096 6月 18 01:22 oem/
drwxr-xr-x 3 root root 4096 6月 18 01:18 opt/
drwxr-xr-x 2 root root 4096 6月 9 12:58 proc/
drwxr-xr-x 15 root root 4096 6月 19 22:40 rockchip-test/
drwxr-xr-x 2 root root 4096 6月 9 12:58 root/
drwxr-xr-x 3 root root 4096 6月 18 00:38 run/
lrwxrwxrwx 1 root root 8 6月 18 00:28 sbin -> usr/sbin/
lrwxrwxrwx 1 root root 10 6月 19 22:42 sdcard -> mnt/sdcard/
-rw-r--r-- 1 root root 0 6月 9 12:58 .skip_fsck
drwxr-xr-x 4 root root 4096 6月 18 01:22 sys/
drwxr-xr-x 3 root root 4096 6月 19 22:42 system/
-rw-r--r-- 1 root root 1336 6月 18 00:28 THIS_IS_NOT_YOUR_ROOT_FILESYSTEM
drwxr-xr-x 4 root root 4096 6月 18 01:21 tmp/
lrwxrwxrwx 1 root root 9 6月 19 22:42 udisk -> mnt/udisk/
drwxr-xr-x 2 root root 4096 6月 18 01:22 userdata/
drwxr-xr-x 7 root root 4096 6月 19 22:42 usr/
drwxr-xr-x 5 root root 4096 6月 18 00:51 var/
lrwxrwxrwx 1 root root 6 6月 19 22:42 vendor -> system/
1.4.3 编译目标包
我们可以执行 make <pkg> 单独编译某个软件包。软件包的编译主要包括下载,解压,打补丁,构建依赖,配置,编译,安装等过程,具体可以查看 package/pkg-generic.mk;
- 下载:
Buildroot会根据配置package/<package>/<package>.mk,自动从网络获取对应的软件包,包括一些第三方库,插件,实用工具等,放在dl/目录; - 解压:软件包会解压在
output/rockchip_rk3588/build/<package>-<version>目录下; - 打补丁:补丁集中放在
package/<packgae>/目录,Buildroot会在解压软件包后为其打上相应的补丁。如果要修改源码,可以通过打补丁的方式进行修改; - 构建依赖:构建和安装构建软件包所需的所有相依性;
- 配置:运行
configure命令,如果有的话; - 编译:运行编译命令;
- 安装:编译完成后,会将需要的编译生成文件拷贝到
output/rockchip_rk3588/target/某个目录。
对于某个软件包,我们可以通过 make <pkg>-<target> 调用软件包构建中的某一步骤,如下:
Package-specific:
<pkg> - Build and install <pkg> and all its dependencies
<pkg>-source - Only download the source files for <pkg>
<pkg>-extract - Extract <pkg> sources
<pkg>-patch - Apply patches to <pkg>
<pkg>-depends - Build <pkg>'s dependencies
<pkg>-configure - Build <pkg> up to the configure step
<pkg>-build - Build <pkg> up to the build step
<pkg>-show-info - generate info about <pkg>, as a JSON blurb
<pkg>-show-depends - List packages on which <pkg> depends
<pkg>-show-rdepends - List packages which have <pkg> as a dependency
<pkg>-show-recursive-depends
- Recursively list packages on which <pkg> depends
<pkg>-show-recursive-rdepends
- Recursively list packages which have <pkg> as a dependency
<pkg>-graph-depends - Generate a graph of <pkg>'s dependencies
<pkg>-graph-rdepends - Generate a graph of <pkg>'s reverse dependencies
<pkg>-dirclean - Remove <pkg> build directory
<pkg>-reconfigure - Restart the build from the configure step
<pkg>-rebuild - Restart the build from the build step
<pkg>-reinstall - Restart the build from the install step
可以看到除了之前介绍的,,还有一些其他有用的目标;
show-depends:显示构建软件包所需的依赖性;clean:运行软件包的清除命令,也可以从目标和暂存目录中卸载软件;注意,这并不是针对所有包实现的;dirclean:删除整个包构建目录;reconfigure:从配置步骤重新启动构建;rebuild:从构建步骤重新启动构建;reinstall:从安装步骤重新启动构建。
需要注意的是:在开发过程中,若修改了某个软件包的源码,Buildroot是不会重新编译该软件包的。可以按如下方式操作:
make <package>-rebuild
# 或者
# 删除软件包的编译输出目录
rm -rf output/rockchip_rk3588/build/<package>-<version>
# 编译
make <pkg>
1.4.4 完全重建
当通过make menuconfig,make xconfig或其他配置工具之一更改系统配置时,Buildroot不会尝试检测应重建系统的哪些部分。
在某些情况下,Buildroot应该重建整个系统,在某些情况下,仅应重建软件包的特定子集。但是以完全可靠的方式检测到这一点非常困难,因此Buildroot开发人员已决定不尝试这样做。
何时需要完全重建:
- 更改目标体系结构配置时,需要完全重建;
- 更改工具链配置时,需要完全重建;
- 将其他软件包添加到配置中时,不一定需要完全重建;
- 从配置中删除软件包时,
Buildroot不会执行任何特殊操作。它不会从目标根文件系统或工具链中删除此软件包安装的文件。需要完全重建才能删除这些文件; - 更改软件包的子选项时,不会自动重建软件包;
- 对根文件系统框架进行更改时,需要完全重建。
一般而言,当你遇到构建错误并且不确定所做的配置更改可能带来的后果时,请进行完全重建。具体说明可以查看文档 docs/manual/rebuilding-packages.txt。
重建方式有两种:
(1) 直接删除编译输出目录,之后重新进行配置、编译;
rm -rf output/
(2) 执行如下命令,会删除编译输出并重新编译;
make clean all
1.5 交叉编译工具
Buildroot提供了不同的交叉编译工具链构建解决方案:
- 内部工具链后端,在配置界面中称为
Buildroot工具链; - 外部工具链后端,在配置界面中称为外部工具链.
注意:Rockchip Linux SDK默认使用内部工具链。
1.5.1 内部工具链端
内部工具链后端是内置的后端,在构建之前,Buildroot自己构建了一个交叉编译的工具链。
用于目标嵌入式系统的用户空间应用程序和库,这个后端是Buildroot的历史后端,并且仅限于uClibc C库的使用(i.e,glibc和eglibc C库不受此后端支持,请参阅外部工具链后端和跨界工具链后端解决方案使用glibc或eglibc)。
优点:
- 与
Buildroot有良好的兼容性; - 快速,只构建必要的东西;
缺点:
- 在进行清洁工作时,需要重建工具链,这需要时间。如果你想减少你的构建时间,考虑使用外部工具链后端;
- 仅限于
uClibc C库。
Buildroot编译完成后,会在 output/rockchip_rk3588/host/ 目录下,生成交叉编译工具,我们可以用来编译目标程序;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/host/
drwxr-xr-x 7 root root 4096 6月 18 00:37 aarch64-buildroot-linux-gnu/
drwxr-xr-x 2 root root 12288 6月 18 01:21 bin/
drwxr-xr-x 3 root root 4096 6月 18 00:26 doc/
-rw-r--r-- 1 root root 3100 6月 18 00:52 environment-setup
drwxr-xr-x 5 root root 4096 6月 18 01:21 etc/
drwxr-xr-x 33 root root 4096 6月 18 01:21 include/
drwxr-xr-x 14 root root 12288 6月 18 01:21 lib/
lrwxrwxrwx 1 root root 3 6月 18 00:18 lib64 -> lib/
drwxr-xr-x 5 root root 4096 6月 18 01:20 libexec/
drwxr-xr-x 3 root root 4096 6月 18 01:17 man/
drwxr-xr-x 2 root root 4096 6月 18 01:07 sbin/
drwxr-xr-x 35 root root 4096 6月 18 01:20 share/
lrwxrwxrwx 1 root root 1 6月 18 00:18 usr -> ./
交叉编译工具为bin目录;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ls output/rockchip_rk3588/host/bin/ | grep aarch64
aarch64-buildroot-linux-gnu-addr2line
aarch64-buildroot-linux-gnu-ar
aarch64-buildroot-linux-gnu-as
aarch64-buildroot-linux-gnu-c++
aarch64-buildroot-linux-gnu-c++.br_real
aarch64-buildroot-linux-gnu-cc
aarch64-buildroot-linux-gnu-cc.br_real
aarch64-buildroot-linux-gnu-c++filt
........
aarch64-linux-addr2line
aarch64-linux-ar
aarch64-linux-as
aarch64-linux-c++
aarch64-linux-c++.br_real
aarch64-linux-cc
aarch64-linux-cc.br_real
........
输入命令查看:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ./output/rockchip_rk3588/host/bin/aarch64-linux-gcc --version
aarch64-linux-gcc.br_real (Buildroot -g28f720bc5-dirty) 12.3.0
Copyright © 2022 Free Software Foundation, Inc.
接下来我们演示一个编译示例程序,简单的编写一个helloworld.c文件:
#include <stdio.h>
void main(void)
{
printf("Hello world.\n");
}
进行编译:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo ./output/rockchip_rk3588/host/bin/aarch64-buildroot-linux-gnu-gcc helloworld.c -o helloworld
将可执行程序helloworld拷贝到开发板,运行./helloworld,则会看到打印信息 Hello World.。
1.5.2 外部工具链端
外部工具链后端允许使用现有的预构建交叉编译工具链。Buildroot能识别几种常见的交叉编译工具链(从ARM的Linaro,ARM的Sourcery CodeBench,x86,x86-64,PowerPC,MIPS和SuperH,来自ADI的Blackfin工具链, Xilinx用于Microblaze的工具链,等等。) 并且能够自动下载它们,或者它可以指向一个自定义的工具链,可以在本地下载或安装。
优点:
- 允许使用知名的、经过良好测试的交叉编译工具链;
- 避免交叉编译工具链的构建时间,这在嵌入式
Linux系统的总体构建时间中通常非常重要; - 不局限于
uClibc:glibc和eglibc工具链得到了支持;
缺点:
- 如果你的预构建的外部工具链有缺陷,可能很难从工具链供应商那里得到解决方案,除非你构建外部工具使用交叉的工具链。
Rockchip Linux SDK目录内置交叉编译,当Buildroot外部工具链使用Rockchip Linux SDK prebuilts目录预置交叉编译,如下:
| 目录 | 说明 |
|---|---|
| prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-nonelinux- gnu |
gcc arm 10.3.1 64位工具链 |
| prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linuxgnueabihf | gcc arm 10.3.1 32位工具链 |
对应版本:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp# prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc -v
......
gcc 版本 10.3.1 20210621 (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29))
1.6 rootfs-overlay
rootfs-overly是一个相当不错的功能,它能够在目标文件系统编译完成后将指定文件覆盖到某个目录。
通过这种方式,我们可以方便地添加或修改一些文件到根文件系统。
假设我们要在根文件系统的 /etc/ 目录下添加文件 overlay-test,可以按如下步骤操作:
1.6.1 设置rootfs-overlay根目录
打开配置菜单 make menuconfig,通过设置 BR2_ROOTFS_OVERLAY 选项,添加用于覆盖的根目录。
对于rk3588,默认已添加了目录 board/rockchip/rk3588/fs-overlay/;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll board/rockchip/rk3588/fs-overlay/
-rw-r--r-- 1 root root 0 6月 9 12:58 .empty
drwxr-xr-x 3 root root 4096 6月 9 12:58 etc/
-rw-r--r-- 1 root root 0 6月 9 12:58 .skip_fsck
drwxr-xr-x 3 root root 4096 6月 9 12:58 usr/
1.6.2 添加文件到覆盖目录
我们可以执行如下命令:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ cd board/rockchip/rk3288/fs-overlay/
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ mkdir etc/
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ touch etc/overlay-test
1.6.3 编译根文件系统
执行如下命令:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8
1.6.4 下载根文件系统
将编译好的根文件系统 output/rockchip_rk3588/images/rootfs.ext2 下载到开发板。
启动开发板,可以看到已添加文件 /etc/overlay-test。
也可以通过查看 target/ 目录,验证是否添加成功:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/target/etc/overlay-test
二、新增本地源码包
开发过程中,Buildroot自带的软件包有时可能无法满足我们的需求,为此我们需要添加自定义的软件包。
Buildroot支持多种格式的软件包,包括generic-package、cmake-package、autotools-package等,我们以generic-package举例说明。
要添加自己的本地源码包,:
- 首先创建工程目录,比如这里演示使用的
helloworld目录; - 接着
helloworld里面添加Config.in和helloworld.mk; - 最后在
package/Config.in中添加指向新增helloworld目录的Config.in。
2.1 创建工程目录
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo mkdir package/helloworld
2.2 helloworld目录
2.2.1 Config.in
在helloworld目录新建Config.in,内容如下:
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
help
This is a demo to add local app.
只有在BR2_PACKAGE_HELLOWORLD=y条件下,才会调用helloworld.mk进行编译。
2.2.2 helloworld.mk
buildroot编译helloworld所需要的设置helloworld.mk,包括源码位置、安装目录、权限设置等。
在helloworld目录新建helloworld.mk,内容如下:
################################################################################
#
# helloworld
#
################################################################################
ifeq ($(BR2_PACKAGE_HELLOWORLD), y)
HELLOWORLD_VERSION:=1.0.0
HELLOWORLD_SITE=$(TOPDIR)/../external/helloworld
HELLOWORLD_SITE_METHOD=local
define HELLOWORLD_BUILD_CMDS
$(TARGET_MAKE_ENV) $(MAKE) CC=$(TARGET_CC) CXX=$(TARGET_CXX) -C $(@D)
endef
define HELLOWORLD_CLEAN_CMDS
$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) clean
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) install
endef
define HELLOWORLD_UNINSTALL_TARGET_CMDS
$(TARGET_MAKE_ENV) $(MAKE) -C $(@D) uninstall
endef
$(eval $(generic-package))
endif
注意:上面的HELLOWORLD的开头也是必须的。
如果源码在git上,需要如下设置:
HELLOWORLD_VERSION:=master--------------------------------------仓库分支名称
HELLOWORLD_SITE:=http://.../dma.git-----------------------------仓库git地址
HELLOWORLD_SITE_METHOD:=git-------------------------------------获取源码的方式
_VERSION结尾的变量是源码的版本号;_SITE_METHOD结尾的变量是源码下载方法;_SITE结尾变量是源码下载地址。
_BUILD_CMDS结尾的变量会在buildroot框架编译的时候执行,用于给源码的Makefile传递编译选项和链接选项,调用源码的Makefile。
_INSTALL_TARGET_CMDS结尾的变量是在编译完之后,自动安装执行,一般是让buildroot把编译出来的的bin或lib拷贝到指定目录。
(eval(generic-package)) 最核心的就是这个东西了,一定不能够漏了,不然源码不会被编译,这个函数就是把整个.mk构建脚本,通过Buildroot框架的方式,展开到Buildroot/目录下的Makfile中,生成的构建目标。
2.2.3 创建源码目录
上文的helloworld.mk文件里已经指定了源码目录 external/helloworld。
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo mkdir -p external/helloworld
在external/helloworld目录下简单的编写一个helloworld.c文件:
#include <stdio.h>
void main(void)
{
printf("Hello world.\n");
}
然后编写Makefile文件:
CPPFLAGS +=
LDLIBS +=
all: helloworld
analyzestack: helloworld.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
clean:
rm -f *.o helloworld
.PHONY: install
install:
cp -f helloworld $(TARGET_DIR)/usr/bin/
.PHONY: uninstall
uninstall:
rm -f $(TARGET_DIR)/usr/bin/helloworld
.PHONY: all clean
由于在helloworld.mk中指定了命令CLEAN、INSTALL、UNINSTALL,因此这里需要配置目标install、clean、uninstall。
2.2.4 添加package/Config.in入口
在 package/Config.in 末尾添加一行:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo vim package/Config.in
menu "Target packages"
......
menu "Private package"
source "package/helloworld/Config.in"
endmenu
endmenu
2.3 配置软件包
打开配置菜单 :
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make menuconfig
通过Target packages -> Private package进入,选中helloworld。
保存配置:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make savedefconfig
对helloworld的配置就会保存到rockchip_rk3588_defconfig中;
BR2_PACKAGE_HELLOWORLD=y
2.4 编译
编译命令如下:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make helloworld
>>> helloworld 1.0.0 Syncing from source dir /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/helloworld
rsync -au --chmod=u=rwX,go=rX --exclude .svn --exclude .git --exclude .hg --exclude .bzr --exclude CVS /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/helloworld/ /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0
>>> helloworld 1.0.0 Configuring
>>> helloworld 1.0.0 Building
PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make -j7 CC=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin/aarch64-buildroot-linux-gnu-gcc CXX=/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin/aarch64-buildroot-linux-gnu-g++ -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0
make[1]: 进入目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0”
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin/aarch64-buildroot-linux-gnu-gcc -c -o helloworld.o helloworld.c
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin/aarch64-buildroot-linux-gnu-gcc helloworld.o -o helloworld
make[1]: 离开目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0”
>>> helloworld 1.0.0 Installing to target
PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make -j7 -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0 install
make[1]: 进入目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0”
cp -f helloworld /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/target/usr/bin/
make[1]: 离开目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588/build/helloworld-1.0.0”
编译完成后:
-
源码都会被拷贝到
output/rockchip_rk3588/build/helloworld-1.0.0文件夹中; -
生成的
bin文件拷贝到output/rockchip_rk3588/target/bin/helloworld,这个文件会打包到文件系统中;
打包进根文件系统镜像:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make
如果需要清空相应的源文件:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make helloworld-dirclean
如果修改源码,重新编译软件包:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make helloworld-rebuild
2.5 编译输出
2.5.1 build
在output/rockchip_rk3588/build/helloworld-1.0.0/可以看到helloworld包的源码;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/build/helloworld-1.0.0/
-rwxr-xr-x 1 root root 794 6月 20 00:17 .build.sh*
-rwxr-xr-x 1 root root 158 6月 20 00:17 .configure.sh*
-rwxr-xr-x 1 root root 759 6月 20 00:17 .deploy.sh*
-rw-r--r-- 1 root root 0 6月 20 00:17 .files-list-host.txt
-rw-r--r-- 1 root root 0 6月 20 00:17 .files-list-images.txt
-rw-r--r-- 1 root root 0 6月 20 00:17 .files-list-staging.txt
-rw-r--r-- 1 root root 21 6月 20 00:17 .files-list-target.txt
-rw-r--r-- 1 root root 32 6月 20 00:17 .files-list.txt
-rwxr-xr-x 1 root root 8928 6月 20 00:17 helloworld*
-rw-r--r-- 1 root root 20480 6月 20 00:17 helloworld-1.0.0.tar
-rw-r--r-- 1 root root 70 6月 19 23:57 helloworld.c
-rw-r--r-- 1 root root 1608 6月 20 00:17 helloworld.o
-rw-r--r-- 1 root root 306 6月 20 00:15 Makefile
-rw-r--r-- 1 root root 0 6月 20 00:17 .stamp_built
-rw-r--r-- 1 root root 0 6月 20 00:17 .stamp_configured
-rw-r--r-- 1 root root 0 6月 20 00:17 .stamp_installed
-rw-r--r-- 1 root root 0 6月 20 00:17 .stamp_rsynced
-rw-r--r-- 1 root root 0 6月 20 00:17 .stamp_target_installed
-rwxr-xr-x 1 root root 2712 6月 20 00:17 .target_install.sh*
-rwxr-xr-x 1 root root 939 6月 20 00:17 .update.sh*
2.5.2 target
编译的helloworld程序被安装到根文件系统的/usr/bin目录;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588/target/usr/bin/helloworld
-rwxr-xr-x 1 root root 8928 6月 20 00:17 output/rockchip_rk3588/target/usr/bin/helloworld*
三、buildroot系统测试
我们可以按照《Rockchip RK3588 - Rockchip Linux SDK编译》介绍的刷机方案将buildroot根文件系统烧录到开发板。
Buildroot默认使用基于wayland协议的weston drm来作为显示后端。如下图:
这些Weston应用提供了一些状态栏和背景等基础功能配置,如Chromium浏览器、Terminal终端、Launchers配置,摄像头预览,多路视频,GPU,鼠标等demo。如需更多Demo可以通过/etc/xdg/weston/weston.ini.d/*配置添加即可。
这里我的开发板ip地址为192.168.0.100,我们通过MobaXterm工具远程链接开发板,输入账号及密码:root/rockchip。
3.1 查看系统
接着查看操作系统信息:
root@rk3588-buildroot:/# uname -a
Linux rk3588-buildroot 5.10.160 #2 SMP Tue Jun 11 22:51:41 CST 2024 aarch64 GNU/Linux
root@rk3588-buildroot:/# ls -l
total 62
lrwxrwxrwx 1 root root 7 Jun 10 18:23 bin -> usr/bin
-rw-r--r-- 1 root root 489 Jun 9 04:58 busybox.fragment
lrwxrwxrwx 1 root root 8 Jun 11 14:58 data -> userdata
drwxr-xr-x 15 root root 4580 Jun 16 03:29 dev
drwxr-xr-x 23 root root 4096 Jun 16 03:13 etc
drwxr-xr-x 2 root root 4096 Jun 11 14:58 info
lrwxrwxrwx 1 root root 7 Jun 10 18:23 lib -> usr/lib
lrwxrwxrwx 1 root root 3 Jun 10 18:23 lib64 -> lib
lrwxrwxrwx 1 root root 11 Jun 10 18:45 linuxrc -> bin/busybox
drwx------ 2 root root 16384 Jun 11 14:59 lost+found
drwxr-xr-x 11 root root 4096 Jun 10 19:16 media
drwxr-xr-x 5 root root 4096 Jun 11 14:58 mnt
drwxr-xr-x 3 root root 1024 Jun 16 03:29 oem
drwxr-xr-x 3 root root 4096 Jun 10 19:16 opt
dr-xr-xr-x 264 root root 0 Jun 16 03:29 proc
drwxr-xr-x 15 root root 4096 Jun 11 14:52 rockchip-test
drwx------ 2 root root 4096 Jun 9 04:58 root
drwxr-xr-x 11 root root 540 Jun 16 03:29 run
lrwxrwxrwx 1 root root 8 Jun 10 18:23 sbin -> usr/sbin
lrwxrwxrwx 1 root root 10 Jun 11 14:58 sdcard -> mnt/sdcard
dr-xr-xr-x 15 root root 0 Jun 16 03:29 sys
drwxr-xr-x 3 root root 4096 Jun 11 14:58 system
drwxrwxrwt 7 root root 260 Jun 16 03:29 tmp
lrwxrwxrwx 1 root root 9 Jun 11 14:58 udisk -> mnt/udisk
drwxr-xr-x 5 root root 1024 Jun 16 03:29 userdata
drwxr-xr-x 7 root root 4096 Jun 11 14:58 usr
drwxr-xr-x 6 root root 4096 Jun 11 14:59 var
lrwxrwxrwx 1 root root 6 Jun 11 14:58 vendor -> system
3.2 查看设备
查看eMMC块设备文件:
root@rk3588-buildroot:~# ls /dev/mmc* -l
brw-rw---- 1 root disk 179, 0 Jun 16 03:29 /dev/mmcblk0
brw-rw---- 1 root disk 179, 32 Jun 16 03:29 /dev/mmcblk0boot0
brw-rw---- 1 root disk 179, 64 Jun 16 03:29 /dev/mmcblk0boot1
brw-rw---- 1 root disk 179, 1 Jun 16 03:29 /dev/mmcblk0p1
brw-rw---- 1 root disk 179, 2 Jun 16 03:29 /dev/mmcblk0p2
brw-rw---- 1 root disk 179, 3 Jun 16 03:29 /dev/mmcblk0p3
brw-rw---- 1 root disk 179, 4 Jun 16 03:29 /dev/mmcblk0p4
brw-rw---- 1 root disk 179, 5 Jun 16 03:29 /dev/mmcblk0p5
brw-rw---- 1 root disk 179, 6 Jun 16 03:29 /dev/mmcblk0p6
brw-rw---- 1 root disk 179, 7 Jun 16 03:29 /dev/mmcblk0p7
brw-rw---- 1 root disk 179, 8 Jun 16 03:29 /dev/mmcblk0p8
crw------- 1 root root 236, 0 Jun 16 03:29 /dev/mmcblk0rpmb
这里一共有11个块设备节点和1个字符设备节点;其中:
/dev/mmcblk0表示的是eMMC这个设备,其主设备号为179,次设备号为0;mmcblk0boot0和mmcblk0boot1对应两个Boot Area Partition;每一个Boot Area Partition大小都是4MB;mmcblk0rpmb则为RPMB Partition;大小为4MB;mmcblk0px为User Data Area划分出来的SW Partitions;实际上就是通过解析GPT分区表创建的分区,分区编号依次为1,2,3,4,5,6,7,8,依次对应parameter.txt中各个分区;
使用cat /proc/partitions,可以查看全部分区信息:
root@rk3588-buildroot:~# cat /proc/partitions
major minor #blocks name
1 0 4096 ram0
179 0 61079552 mmcblk0
179 1 4096 mmcblk0p1
179 2 4096 mmcblk0p2
179 3 65536 mmcblk0p3
179 4 131072 mmcblk0p4
179 5 32768 mmcblk0p5
179 6 14680064 mmcblk0p6
179 7 131072 mmcblk0p7
179 8 46022639 mmcblk0p8
其中blocks表示分区的容量,每个blocks是1KB。这里:
mmcblk0p1对应uboot分区,大小为4MB;mmcblk0p2对应misc分区,大小为4MB;mmcblk0p3对应boot分区,大小为64MB;mmcblk0p4对应recovery分区,大小为128MB;mmcblk0p5对应backup分区,大小为32MB;mmcblk0p6对应rootfs分区,大小为14GB;mmcblk0p7对应oem分区,大小为128MB;mmcblk0p8对应userdata分区,大小为剩余所有空间;
3.2.1 查看磁盘空间
这里我们可以通过df -hT查看磁盘空间信息;
root@rk3588-buildroot:~# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/root ext4 14G 598M 13G 5% /
devtmpfs devtmpfs 3.9G 8.0K 3.9G 1% /dev
tmpfs tmpfs 3.9G 108K 3.9G 1% /tmp
tmpfs tmpfs 3.9G 580K 3.9G 1% /run
tmpfs tmpfs 3.9G 304K 3.9G 1% /var/log
tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
/dev/mmcblk0p7 ext4 121M 12M 103M 11% /oem
/dev/mmcblk0p8 ext4 43G 309K 42G 1% /userdata
显示内容参数说明:
Filesystem:文件系统;Type:文件系统类型;Size: 分区大小;Used: 已使用容量;Avail: 还可以使用的容量;Use%: 已用百分比;Mounted on: 挂载点;
可以看到/dev/root挂载在根目录/,总容量为14GB,已使用空间为598MB,剩余可用空间为13GB,已使用空间占总容量的比例为5%。
此外,/dev/mmcblk0p7挂载在/oem目录:给厂家使用,存放厂家的APP或数据;
/dev/mmcblk0p8挂载在/userdata目录:供APP临时生成文件或给最终用户使用。
3.2.2 parted
使用parted命令查看分区布局;
root@rk3588-buildroot:~# parted /dev/mmcblk0 print
Model: MMC ARV11X (sd/mmc)
Disk /dev/mmcblk0: 62.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 8389kB 12.6MB 4194kB uboot
2 12.6MB 16.8MB 4194kB misc
3 16.8MB 83.9MB 67.1MB boot
4 83.9MB 218MB 134MB recovery
5 218MB 252MB 33.6MB backup
6 252MB 15.3GB 15.0GB ext4 rootfs
7 15.3GB 15.4GB 134MB ext4 oem
8 15.4GB 62.5GB 47.1GB ext4 userdata
其中:
uboot分区的序号为1,对应的设备节点为/dev/mmcblk0p1;boot分区的序号为3,对应的设备节点为/dev/mmcblk0p3;rootfs分区的序号为6,对应的设备节点为/dev/mmcblk0p6;oem分区的序号为7,对应的设备节点为/dev/mmcblk0p7;userdata分区的序号为8,对应的设备节点为/dev/mmcblk0p8;
3.3 升级固件
3.3.1 制作固件
按照正常的固件编译流程,制作用于升级的固件,可以参考《Rockchip RK3588 - Rockchip Linux SDK编译》。
升级固件不一定要全分区升级,可修改 package-file 文件,将不要升级的分区去掉,这样可以减少升级包的大小。
例如,执行如下命令(可参考文件tools/linux/Linux_Pack_Firmware/rockdev/rk3588-package-file):
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh edit-package-file
将 rootfs的相对路径改为 RESERVED,这样就不会打包根文件系统,即不升级根文件系统分区。
# NAME PATH
package-file package-file
parameter parameter.txt
bootloader MiniLoaderAll.bin
uboot uboot.img
misc misc.img
boot boot.img
recovery recovery.img
backup RESERVED
rootfs rootfs.img
oem oem.img
userdata RESERVED
注意: 若将升级固件放至设备的 /userdata/ 目录,则不要打包 userdata.img将image/userdata.img改为RESERVED。
执行如下命令生成统一固件;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh updateimg
将制作好的升级固件拷贝到U盘、TF卡或者开发版的/userdata/目录下。
我们可以将统一镜像复制到/work/tftpwork目录下:
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ cp ./rockdev/update.img /work/tftpboot/
开发板从ubuntu tftp服务器下载统一镜像:
root@rk3588-buildroot:/userdata# tftp -g -l update.img 192.168.0.200
3.3.2 升级
接下来我们采用updateEngine升级模式对固件进行升级,在命令行执行如下命令;
root@rk3588-buildroot:/userdata# updateEngine --image_url=/userdata/update.img --misc=update --savepath=/userdata/update.img --reboot
root@rk3588-buildroot:/userdata# LOG_DEBUG: uiTag = 57464b52.
LOG_DEBUG: usSize = 66.
LOG_DEBUG: dwVersion = 1000000.
LOG_DEBUG: btMajor = 1, btMinor = 0, usSmall = 00.
LOG_DEBUG: dwBootOffset = 66.
LOG_DEBUG: dwBootSize = 731c0.
LOG_DEBUG: dwFWOffset = 73226.
LOG_DEBUG: dwFWSize = 33b51004.
LOG_DEBUG: tag = 1178684242
LOG_DEBUG: size = 867504128
LOG_DEBUG: machine_model = RK3588
......
LOG_DEBUG: file = oem.img
LOG_DEBUG: offset = 850518566
LOG_DEBUG: flash_offset = 29851648
LOG_DEBUG: usespace = 8524
LOG_DEBUG: size = 17457152
11f321ac3531c393092001a4a555ed68
46a1507531c328bd6cd710c5f7391fe8
46a1507531c328bd6cd710c5f7391fe8
等待升级完成,升级成功后开发版会重新启动进入系统。
注意:具体可以参考《Rockchip RK3588 - Rockchip Linux Recovery升级》。
3.4 Weston应用
Weston是Wayland开源显示协议的官方参考实现,Rockchip Buildroot SDK的显示服务默认使用Weston drm后端。
3.4.1 客户端
基于Wayland上使用的weston客户端相关应用:
root@rk3588-buildroot:/usr/bin# ls weston*
weston weston-flower weston-simple-egl
weston-calibration-helper.sh weston-fullscreen weston-simple-shm
weston-calibrator weston-image weston-simple-touch
weston-clickdot weston-multi-resource weston-smoke
weston-cliptest weston-presentation-shm weston-stacking
weston-confine weston-resizor weston-subsurfaces
weston-content_protection weston-scaler weston-tablet
weston-debug weston-screenshooter weston-terminal
weston-dnd weston-simple-damage weston-touch-calibrator
weston-editor weston-simple-dmabuf-egl weston-transformed
weston-eventdemo weston-simple-dmabuf-v4l
3.4.2 配置方式
Buildroot SDK中Weston的配置方式有以下几种:
- 启动参数:即启动
Weston时命令所带参数,如weston --tty=2,位于/etc/init.d/S49weston,对应SDK代码中位置为:
package/weston/S49weston; weston.ini配置文件:位于/etc/xdg/weston/weston.ini及/etc/xdg/weston/weston.ini.d/下的.ini文件,对应SDK代码中位置如:board/rockchip/common/overlays/10-weston/etc/xdg/weston/weston.ini;参考:《https://fossies.org/linux/weston/man/weston.ini.man》;- 特殊环境变量:此类环境变量一般设置在
/etc/profile.d/weston.sh,对应SDK代码中位置package/weston/weston.sh; - 动态配置文件:对于
drm后端显示功能,Buildroot SDK中的Weston提供一些动态配置支持,默认路为/tmp/.weston_drm.conf,可以通过环境变量WESTON_DRM_CONFIG指定; udev rules:Weston中输入设备的部分配置需要通过udev rules。
有关weson.ini配置可以参考文章:《Rockchip Buildroot Developer Guide》。
参考文章
[1] Buildroot根文件系统构建
[2] Debian根文件系统构建
[3] 官方网站:Buildroot - 让嵌入式 Linux 变得简单
[4] buildroot使用介绍
[5] Firefly-RK3288 Buildroot 开发
[7] Rockchip Buildroot Developer Guide

浙公网安备 33010602011771号