一、Busybox简介
【特点】
(1-1)开源项目
Busybox是一个开源项目,遵循GPL v2协议。Busybox将众多的UNIX命令集合进了一个很小的可执行程序中,可以用来替代GNU fileutils、shellutils等工具集。Busybox中各种命令与相应的GNU工具相比,所能提供的选项比较少,但是对于一般的应用场景也足够了。Busybox主要用于嵌入式系统的开发中。
(1-2)程序本体较小
Busybox在编写过程中对文件大小进行了优化,并考虑了系统资源有限(比如内存等)的情况。与一般的GNU工具集动辄几M的体积相比,动态链接的Busybox只有几百K,即使是采用静态链接也只有1.M左右。Busybox按模块设计,可以很容易地加入、去除某些命令,或增减命令的某些选项。
(1-3)使用简单
在创建根文件系统的时候,如果使用Busybox来创建根文件系统,使用起来较为方便,只需要在/dev目录下创建必要的设备节点,在/etc目录下增加一些配置文件即可,当然如果Busybox是动态链接的,那么还需要在/lib目录下包含相关的运行库文件。
【官方资源】
URL:https://busybox.net/
Web页面:
【注】本文所记录内容时 使用的busybox版本为:1.29.0
二、Busybox源码目录结构
上图是Busybox的目录中的目录和文件。
序号 | 目录名称 | 功能说明 |
---|---|---|
1 | applets | 实现applets框架的文件。目录中包含了几个main()的文件 |
2 | applets_sh | 此目录包含了几个作为shell脚本实现的applet示例。在“make install”时不会被自动安装,需要使用时,手动处理 |
3 | arch | 包含用于不同体系架构的makefile文件。约束busybox在不同架构体系下的编译构建过程 |
4 | archival | 与压缩相关命令的实现源文件。 |
5 | configs | busybox自带的默认配置文件 |
6 | console-tools | 与控制台相关的一些命令 |
7 | coreutils | 常用的一些核心命令。例如chgrp、rm等 |
8 | debianutils | 针对Debian的套件。 |
9 | e2fsprogs | 针对Linux Ext2 FS prog的命令。例如chattr、lsattr |
10 | editors | 常用的编辑命令。例如diff、vi等 |
11 | findutils | 用于查找的命令 |
12 | include | busybox项目的头文件 |
13 | init | init进程的实现源码目录 |
14 | klibc-utils | klibc命令套件 |
15 | libbb | 与busybox实现相关的库文件 |
16 | libpwdgrp | libpwdgrp相关的命令 |
17 | loginutils | 与用户管理相关的命令 |
18 | mailutils | 与mail相关的命令套件 |
19 | miscutils | 该文件下是一些杂项命令,针对特定应用场景 |
20 | modutils | 与模块相关的命令 |
21 | networking | 与网络相关的命令,例如arp |
22 | printutils | Print相关的命令 |
23 | procps | 与内存、进程相关的命令 |
24 | runit | 与Runit实现相关的命令 |
25 | shell | 与shell相关的命令 |
26 | sysklogd | 系统日志记录工具相关的命令 |
27 | util-linux | Linux下常用的命令,主要与文件系统操作相关的命令。 |
三、busybox的init进程
在linux内核启动的最后阶段,会调用run_init_process()函数启动用户空间进程,对于Busybox来说,它同样将提供一个init程序,满足linux内核最后阶段的启动跳转。只要run_init_process()创建进程成功,那么此函数将不会返回了,从而从内核态进入了用户态进程。
busybox的init程序的描述源文件位于源代码下的init/init.c文件中。
核心功能的由init_main函数实现,此函数中内容较多,将在文章《busybox的init_main函数》中分析
int init_main(int argc UNUSED_PARAM, char **argv)
{
INIT_G();
if (argv[1] && strcmp(argv[1], "-q") == 0) {
return kill(1, SIGHUP);
}
#if DEBUG_SEGV_HANDLER
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
#endif
if (!DEBUG_INIT) {
sigprocmask_allsigs(SIG_BLOCK);
/* ........................... */
四、编译busybox过程总结
在准备编译前,可以先参考INSTALL、README以及examples目录和docs目录下的文件。获取到相关的构建说明、安装说明和一些使用的示例。
总体来说,编译busybox与linux、以及u-boot的过程类似:
(1)使用
make menuconfig
先在宿主机上编译出用于配置busybox的图像化界面
这个过程中,可能会由于缺少一些库(例如ncurses)而报错,这时将其安装即可解决。
对于嵌入式系统环境,是需要使用与嵌入式系统相关联的【交叉编译器】来进行编译,所以,这里需要指定用于编译busybox的交叉编译器。
在busybox源码目录下的顶层makefile文件中添加:
CROSS_COMPILE ?= #交叉编译器的路径
ARCH ?= arm #对应的架构,这里以arm为例
(经测试,笔者的1.29版本busybox可以在图形项中配置交叉编译器的路径,较低版本的可能需要手动指定)
(2)指定busybox编译后的安装路径。
从上图我们可以看出,Busybox默认的安装路径是源代码目录的_install目录(该目录不存在,安装的时候自动创建)。
(3)可以更加实际情况设置busybox的动态/静态编译
笔者本文使用的【静态编译】
(4)使用make 编译
(5)使用make install进行安装,完成后如下图:
使用静态编译构建出的busybox 软件本体有1.4M大小左右
总结一下busybox的编译构建过程:
1、使用make menuconfig构建出图形配置界面。
2、通过配置图形配置界面的选项配置busybox的安装路径、编译工具、命令功能使能等。生成.config配置文件
3、使用make编译busybox
4、使用make install命令安装由busybox生成的根文件系统
5、完善根文件系统
6、使用和测试根文件系统