Buildroot是一个简单、高效且易于使用的工具,可以使用它自动构建一个Linux系统。

1.搭建编译环境

buildroot构建Linux系统可以使用内部工具(默认),也可以使用外部工具,这里在Ubuntu上以默认配置的内部工具为例,简单搭建一下开发环境:

1 $ sudo apt update
2 $ sudo apt install build-essential vim flex bison bc texinfo libc6-dev libssl-dev libncurses5-dev gawk zip unzip git wget curl axel file p7zip-full u-boot-tools liblz4-dev

2.下载Buildroot

下载方式有很多,简单列举3种,比如:

2.1 从官方网页下载

[下载] [https://buildroot.org/]

2.2 从官网仓库下载

$ git clone git://git.buildroot.net/buildroot

或者

$ git clone https://git.buildroot.net/buildroot

2.3 从github下载

$ git clone https://github.com/buildroot/buildroot.git

3. 配置、编译buildroot

官方文档:

[跳转] [https://buildroot.org/downloads/manual/manual.text]

下载后目录如下:

CHANGES  Config.in         DEVELOPERS  Makefile         README.md  board  configs  fs     output   support  toolchain
COPYING  Config.in.legacy  LICENSE     Makefile.legacy  arch       boot   docs     linux  package  system   utils

其中,configs中保存了支持项目的配置文件,我们也可以通过如下命令查看支持的项目配置:

$ make list-defconfigs

以树莓派3b为例,配置:

$ make raspberrypi3_64_defconfig

调整配置:

$ make menuconfig

编译:

$ make -j4 2>&1 | tee build.log

另外,还有一些其它配置,和编译方法:

单独配置内核:

$ make linux-menuconfig

单独编译内核:

$ make linux -j4

另外,还有一些常见的举例:

$ make uboot-menuconfig
$ make uboot -j4

$ make busybox-menuconfig
$ make busybox -j4

$ make uclibc-menuconfig
$ make ublibc -j4

4. 开发技巧

构建修改

buildroot构建时会从网络下载源码压缩包,然后解压编译,编译内容既有target端,也有host端,我一般会把它们划分成3个部分,buildroot、dl、output。

这3个部分我放在同一级目录,buildroot中就是原本从git仓库下载的内容,dl是下载源码压缩包存储的地方,output是解压后源码和编译文件,配置文件,目标文件等存放的地方。

首先,修改buildroot根目录Makefile,我下载这个版本的buildroot中一共修改了3处output,就是把$(CURDIR)/output改成$(CURDIR)/../output。

(其实不修改也可以,这样用make o=../output,但是每次输入嫌麻烦)。

@@ -36,7 +36,7 @@
 # or avoid confusing packages that can use the O=<dir> syntax for out-of-tree
 # build by preventing it from being forwarded to sub-make calls.
 ifneq ("$(origin O)", "command line")
-O := $(CURDIR)/output
+O := $(CURDIR)/../output
 endif

 # Check if the current Buildroot execution meets all the pre-requisites.
@@ -160,7 +160,7 @@

 # Set variables related to in-tree or out-of-tree build.
 # Here, both $(O) and $(CURDIR) are absolute canonical paths.
-ifeq ($(O),$(CURDIR)/output)
+ifeq ($(O),$(CURDIR)/../output)
 CONFIG_DIR := $(CURDIR)
 NEED_WRAPPER =
 else
@@ -1079,7 +1079,7 @@

 .PHONY: distclean
 distclean: clean
-ifeq ($(O),$(CURDIR)/output)
+ifeq ($(O),$(CURDIR)/../output)
        rm -rf $(O)
 endif
        rm -rf $(TOPDIR)/dl $(BR2_CONFIG) $(CONFIG_DIR)/.config.old $(CONFIG_DIR)/..config.tmp \

然后,修改menuconfig

$ make raspberrypi3_64_defconfig
$ make menuconfig

menuconfig中做如下修改:

Build options  --->
    ($(TOPDIR)/../dl) Download dir

之后,就可以编译了。有些源码文件可能国内网络下载不了,自己想办法科学,上网下载了放到dl对应的目录下(如果没有对应目录,则自己在dl下新建)。

成功编译之后,包括linux源码在内的解压源码都在output/build目录下。

内核开发

我写了个arm32的编译脚本,把脚本放到linux源码根目录,使用脚本可以应付简单内核开发。

(版本不同,项目不同,自行参考脚本修改)。

[build_arm2.sh]

1 #!/bin/bash
 2 
 3 ####################################
 4 # Example:
 5 #   ./build_arm2.sh -j4
 6 #   ./build_arm2.sh menuconfig
 7 #   ./build_arm2.sh dtbs
 8 #   ./build_arm2.sh modules
 9 #   ./build_arm2.sh clean
10 ####################################
11 
12 # Buildroot source path.
13 SOURCE_PATH=/home/linux/buildroot
14 
15 # Build architecture.
16 ARM_ARCH=arm
17 
18 # Cross compilation toolchain.
19 ARM_GCC=output/host/bin/arm-buildroot-linux-uclibcgnueabihf-
20 
21 # Build parameter.
22 BUILD_PARAM=
23 
24 if [ -n "$1" ] && [ "-h" == $1 ]; then
25     echo "[Example]:";
26     echo "  ./build_arm2.sh -j4";
27     echo "  ./build_arm2.sh menuconfig";
28     echo "  ./build_arm2.sh dtbs";
29     echo "  ./build_arm2.sh modules";
30     echo "  ./build_arm2.sh clean";
31 elif [ -n "$1" ]; then
32     BUILD_PARAM=$1
33 fi
34 
35 START_TIME=`date +%T`
36 
37 make ${BUILD_PARAM} ARCH=${ARM_ARCH} CROSS_COMPILE=${SOURCE_PATH}/${ARM_GCC}
38 
39 END_TIME=`date +%T`
40 
41 echo "======== Completed. Elapsed time: [${START_TIME}] ~ [${END_TIME}]. ========";

驱动开发

写了个Makefile,仅供参考,根据实际版本和项目自行修改:

[Makefile]

1 # Need build object.
 2 MODULE = leds-gpio
 3 
 4 # Buildroot source path.
 5 SOURCE_PATH = /home/linux/buildroot
 6 
 7 # Build architecture.
 8 ARM_ARCH = arm
 9 
10 # Cross compilation toolchain.
11 ARM_GCC = output/host/bin/arm-buildroot-linux-uclibcgnueabihf-
12 
13 # Define kernel path.
14 KERNEL_PATH = output/build/linux-5.12.2
15 
16 # Define current path.
17 CUR_PATH = $(shell pwd)
18 
19 
20 all:
21     make -C ${SOURCE_PATH}/$(KERNEL_PATH) M=$(CUR_PATH) ARCH=${ARM_ARCH} CROSS_COMPILE=${SOURCE_PATH}/${ARM_GCC} modules
22 
23 clean:
24     make -C ${SOURCE_PATH}/$(KERNEL_PATH) M=$(CUR_PATH) ARCH=${ARM_ARCH} CROSS_COMPILE=${SOURCE_PATH}/${ARM_GCC} clean
25 
26 # Define build object.
27 obj-m = $(MODULE).o

应用开发

写了个Makefile,自行参考修改:

[Makefile]

1 # Application object.
 2 APP_OBJ = hello
 3 
 4 # Buildroot source path.
 5 SOURCE_PATH = /home/linux/buildroot
 6 
 7 # Cross compilation toolchain.
 8 ARM_GCC = output/host/bin/arm-buildroot-linux-uclibcgnueabihf
 9 
10 all:
11     ${SOURCE_PATH}/${ARM_GCC}-gcc -o $(APP_OBJ) $(APP_OBJ).c
12 
13 clean:
14     $(RM) $(APP_OBJ)

向rootfs中添加文件

我们写了驱动和应用,需要添加到rootfs中,方法有很多,文件共享,samba,nfs,tftp,磁盘,挂载,这里简单介绍挂载:

$ sudo mount rootfs.ext2 /mnt
$ sudo cp leds-gpio.ko /mnt/root
$ sudo umount /mnt