本篇文章基于builtroot 2021.11.1版本。
buildroot是什么,我们为什么要使用buildroot。
buildroot是一个编译框架,主要用来交叉编译嵌入式linux系统,可以很方便的一键式编译生成loader(u-boot)、rootfs、uImage等镜像。
在不使用编译框架的情况下,我们需要手动管理和编译loader、roofs、kernel,其中环境搭建、源码配置等工作重复而繁杂,使用编译框架可以帮助我们完成一键式编译。
buildroot官网:https://buildroot.org
buildroot是以makefile为基本结构的编译框架,只支持在linux环境下运行,编译时使用普通用户权限,无需root权限。
在编译环境中,以下工具是必须的,一般linux发行版都已经默认安装,无需过分关注。
which
sed
make (version 3.81 or any later)
binutils
build-essential (only for Debian based systems)
gcc (version 4.8 or any later)
g++ (version 4.8 or any later)
bash
patch
gzip
bzip2
perl (version 5.8.7 or any later)
tar
- [ ] List item
cpio
unzip
rsync
file (must be in /usr/bin/file)
bc
可以选择网站下载压缩包或者使用git下载。
下载方式1: 在window下登陆https://buildroot.org/download.html
下载压缩包,在linux环境下curl -O https://buildroot.org/downloads/Vagrantfile; vagrant up
。
下载方式2: git clone git://git.buildroot.net/buildroot
或git clone https://git.buildroot.net/buildroot
以树莓派4B为例
使用builtroot的第一步是生成一个配置文件,builtroot将根据配置文件编译生成镜像,与编译linux时的.config类似。生成配置文件的方式有两种:
make menuconfig
,可以看到如下配置: │ │ Target options ---> 配置目标平台的架构,如aarch64
│ │ Build options ---> 配置编译选项,如源代码位置、编译debug信息等
│ │ Toolchain ---> 配置编译链,交叉编译选择、编译优化等级等
│ │ System configuration ---> 配置编译出的系统配置,主要和rootfs相关
│ │ Kernel ---> 目标内核的编译配置
│ │ Target packages ---> 主要是busybox编译,选择编入哪些工具
│ │ Filesystem images ---> 选择rootfs的文件类型
│ │ Bootloaders ---> 编译loader,常用的为u-boot
│ │ Host utilities ---> 编译服务器的工具配置
│ │ Legacy config options ---> 选择其它库,如opencv、python等
│ │
make raspberrypi4_64_defconfig
,即可使用树莓派默认配置,如果需要在默认配置上进一步修改配置,可按照手动配置的方法。配置完成后,在builtroot目录下执行make
,根据机器配置时间大约在30分钟-60分钟。
make命令一般会执行下面几步:
使用raspberrypi4_64_defconfig配置时,builtroot会自动从github-raspi仓库拉取源码,然后进行编译。如果编译服务器无法连接网络,可以在配置中修改Build options和Kernel ,指定已有的内核源码路径。
编译生成的成果物存放在output目录中,目录列表如下:
build ---> 下载的源代码、编译链等
host ---> 编译好的工具链、库等
images ---> 编译出的镜像成果物
staging ---> 工具链的符号链接,不用关注
target ---> 包含完整的目标roofs
一般来说,我们只需要关心images下的成果物即可,以树莓派为例,images文件夹下会有bcm2711-rpi-4-b.dtb boot.vfat Image rootfs.ext2 rootfs.ext4 rpi-firmware sdcard.img
这些文件,将其拷贝到树莓派的tf卡。
– 以hello_world驱动为例–
config BR2_PACKAGE_HELLO_WORLD
bool "hello_world"
depends on BR2_LINUX_KERNEL
help
Test for adding driver in buildroot
comment "hello_world driver needs a Linux kernel to be built"
depends on !BR2_LINUX_KERNEL
################################################################
#
# hello_world
#
################################################################
HELLO_WORLD_VERSION = 1.0
HELLO_WORLD_SITE_METHOD = local
HELLO_WORLD_SITE = $(TOPDIR)/dl/hello_world
HELLO_WORLD_LICENSE = GPL-2.0
HELLO_WORLD_LICENSE_FILES = LICENSE
$(eval $(kernel-module))
$(eval $(generic-package))
menu "My driver"
source "package/hello_world/Config.in"
endmenu
在dl目录中创建hello_world目录
在dl/hello_world中增加驱动代码hello_world.c,示例如下:
#include
#include
#include
static int __init hello_init(void)
{
pr_info("hello driver init!\n");
return 0;
}
static void __exit hello_exit(void)
{
pr_info("hello driver exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
7、在./dl/hello-world中增加Makefile文件,示例如下:
CC ?= arm-none-linux-gnueabi-gcc
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /home/baitianio/work/qemu/buildroot/output/build/linux-5.15.16
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~core.depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := hello-world.o
endif
在buildroot目录下执行make menuconfig,进入Target packages->Hardware handling配置界面后,选上hello-world配置项;
执行make编译(如果想单独编译此驱动的话,可执行make hello-world命令),编译成功后生成的hello-world.ko驱动文件会集成到文件系统中的/lib/modules/3.1.0-EmbedSky/extra目录中;
在目标机上只需要执行modprobe hello-world即可加载驱动;
!!!注意,rebuild单独模块时,需要先执行 make hello_world-dirclean清除之前的编译!!!
编译链是一系列编译工具的集合,包括编译器、链接器、标准库、调试器、反汇编工具等。builtroot提供了两种编译链方式,内置编译链(Buildroot toolchain)和外部编译链(External toolchain),可以通过Toolchain type进行选择。
Toolchain --->
Toolchain type