BusyBox 根文件系统构建
BusyBox 是一个集成了大量的 Linux 命令和工具的软件,像 ls、 mv、 ifconfig 等命令 BusyBox 都会提供。 BusyBox 就是一个大的工具箱,这个工具箱里面集成了 Linux 的许多工具和命令。一般下载 BusyBox 的源码,然后配置 BusyBox,选择自己想要的功能,最后编译即可。
3.1 修改 Makefile,添加编译器
打开 busybox 的顶层 Makefile,添加 ARCH 和 CROSS_COMPILE的值,如下所示:
164 CROSS_COMPILE ?= arm-linux-gnueabihf-
190 ARCH ?= arm
3.2 配置 busybox
与我们编译 Uboot、 Linux kernel 一样,我们要先对 busybox 进行默认的配置,有以下几种配置选项:
①、 defconfig,缺省配置,也就是默认配置选项。
②、 allyesconfig,全选配置,也就是选中 busybox 的所有功能。
③、 allnoconfig,最小配置。
我们一般使用默认配置即可,因此使用如下命令先使用默认配置来配置一下 busybox:
make defconfig
通过图形化配置我们可以进一步选择自己想要的功能,输入如下命令打开图形化配置界面:
make menuconfig
- 确保取消选中
Build static binary (no shared libs)
,配置为动态编译:
Location:
-> Settings
-> Build static binary (no shared libs)
选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析。
- 启用vi编辑命令:
Location:
-> Settings
-> vi-style line editing commands
- 取消busybox精简指令配置:
默认会选中“Simplified modutils”,这里我们要取消勾选
Location:
-> Linux Module Utilities
-> Simplified modutils
- 确保选中“动态创建设备节点”配置选项
Location:
-> Linux System Utilities
-> mdev (16 kb) # 确保下面的全部选中,默认都是选中的
- 使能busybox 的 unicode 编码以支持中文
Location:
-> Settings
-> Support Unicode # 选中
-> Check $LC_ALL, $LC_CTYPE and $LANG environment variables # 选中
然后选择 “”,直到最后选择 “” 保存。
busybox 的配置就到此结束了,大家也可以根据自己的实际需求选择配置其他的选项,不过对于初学者笔者不建议再做其他的修改,可能会出现编译出错的情况发生。
- 保存配置文件.config为imx6ull_atk_defconfig
cp .config /home/sudeki/Workplace/atk/atk_rootfs/configs/imx6ull_atk_defconfig
3.3 编译 busybox
配置好 busybox 以后就可以编译了,我们可以指定编译结果的存放目录,这里我们将编译结果存放到创建的 rootfs 目录中,输入如下命令:
# 编译
make
# 安装
# COFIG_PREFIX 指定编译结果的存放目录
make install CONFIG_PREFIX=/home/sudeki/Workplace/linux/nfs/rootfs
编译完成以后会在 busybox 的所有工具和文件就会被安装到 rootfs 目录中, rootfs 目录内容如下图所示:
rootfs 目录下有 bin、 sbin 和 usr 这三个目录,以及 linuxrc 这个文件。前面说过 Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。
3.4 根文件系统完善
- 向 rootfs 的“/lib”目录添加库文件
在 rootfs 中创建一个名为“lib”的文件夹,命令如下:
mkdir lib
进入如下路径对应的目录:
注:我们搭建交叉编译环境的时候将交叉编译器存放到了“/usr/local/arm/”目录中。交叉编译器里面有很多的库文件,lib
库文件是从交叉编译器中获取的。
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
此目录下有很多的so(*是通配符)和.a 文件,这些就是库文件,将此目录下所有的so和.a文件都拷贝到 rootfs/lib 目录中, 拷贝命令如下:
cp *so* *.a /home/sudeki/Workplace/linux/nfs/rootfs/lib/ -d
后面的“-d”表示拷贝符号链接,这里有个比较特殊的库文件: ld-linux-armhf.so.3,此库文件也是个符号链接,相当于 Windows 下的快捷方式。会链接到库 ld-2.19-2014.08-1-git.so 上,输入命令“ls ld-linux-armhf.so.3 -l”查看此文件详细信息:
ls ld-linux-armhf.so.3 -l
ld-linuxarmhf.so.3 不能作为符号链接,否则的话在根文件系统中执行程序无法执行,所以我们需要重新复制 ld-linuxarmhf.so.3,只是不复制软链接即可,先将 rootfs/lib 中的 ld-linux-armhf.so.3 文件删除掉,命令如下:
rm ld-linux-armhf.so.3
然 后 重 新 进 入 到 /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/armlinux-gnueabihf/libc/lib 目录中,重新拷贝 ld-linux-armhf.so.3,命令如下:
cp ld-linux-armhf.so.3 /home/sudeki/Workplace/linux/nfs/rootfs/lib/
继续进入如下目录中:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
此目录下也有很多的的so和.a 库文件,我们将其也拷贝到 rootfs/lib 目录中,命令如下:
cp *so* *.a /home/sudeki/Workplace/linux/nfs/rootfs/lib/ -d
rootfs/lib 目录的库文件就这些了,完成以后的 rootfs/lib 目录如图
- 向 rootfs 的“usr/lib”目录添加库文件
在 rootfs 的 usr 目录下创建一个名为 lib 的目录,将如下目录中的库文件拷贝到 rootfs/usr/lib目录下:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/
usr/lib
mkdir lib
将此目录下的 so 和.a 库文件都拷贝到 rootfs/usr/lib 目录中,命令如下:
cp *so* *.a /home/sudeki/Workplace/linux/nfs/rootfs/usr/lib/ -d
完成以后的 rootfs/usr/lib 目录如图
至此,根文件系统的库文件就全部添加好了,可以使用“du”命令来查看一下 rootfs/lib 和rootfs/usr/lib 这两个目录的大小,命令如下:
# 进入根文件系统目录
cd rootfs
# 查看 lib 和 usr/lib 这两个目录的大小
du ./lib ./usr/lib/ -sh
- 创建其他文件夹
在根文件系统中创建其他文件夹,如 dev、 proc、 mnt、 sys、 tmp 和 root 等
mkdir dev proc mnt sys tmp root
- 创建/etc/init.d/rcS 文件
rcS 是个 shell 脚本, Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件的脚本文件。在 rootfs 中创建/etc/init.d/rcS 文件,然后在 rcS 中输入如下所示内容:
mkdir -p etc/init.d/
cd etc/init.d/
touch rcS
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
解析:
第 1 行,表示这是一个 shell 脚本。
第 3 行, PATH 环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或者可执行文件的时候就不会提示找不到文件这样的错误。
第 4 行, LD_LIBRARY_PATH 环境变量保存着库文件所在的目录。
第 5 行,使用 export 来导出上面这些环境变量,相当于声明一些“全局变量”。
第 7 行,使用 mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定,所以我们一会还要创建/etc/fstab 文件。
第 8 和 9 行,创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。
第 11 和 12 行,使用 mdev 来管理热插拔设备,通过这两行, Linux 内核就可以在/dev 目录下自动创建设备节点。
注:创建好文件/etc/init.d/rcS 以后一定要给其可执行权限!
chmod 777 rcS
- 创建/etc/fstab 文件
在 rootfs 中创建/etc/fstab 文件, fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,格式如下:
<file system> <mount point> <type> <options> <dump> <pass>
解析:
<file system>:要挂载的特殊的设备,也可以是块设备,比如/dev/sda 等等。
<mount point>:挂载点。
<type>:文件系统类型,比如 ext2、 ext3、 proc、 romfs、 tmpfs 等等。
<options>:挂载选项,在 Ubuntu 中输入“man mount”命令可以查看具体的选项。一般使用 defaults,也就是默认选项, defaults 包含了 rw、 suid、 dev、 exec、 auto、 nouser 和 async。
<dump>:为 1 的话表示允许备份,为 0 不备份,一般不备份,因此设置为 0。
<pass>:磁盘检查设置,为 0 表示不检查。根目录‘/’设置为 1,其他的都不能设置为 1,其他的分区从 2 开始。一般不在 fstab 中挂载根目录,因此这里一般设置为 0。
cd etc/
touch fstab
示例文件如下:
#<file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
- 创建/etc/inittab 文件
init 程序会读取/etc/inittab这个文件, inittab 由若干条指令组成。每条指令的结构都是一样的,由以“:”分隔的 4 个段组成,格式如下:
<id>:<runlevels>:<action>:<process>
<id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说, 有着特殊意义。对于 busybox 而言用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。
<runlevels>: 对 busybox 来说此项完全没用,所以空着。
<action>:动作,用于指定可能用到的动作。 busybox 支持的动作如表
<process>: 具体的动作,比如程序、脚本或命令等。
我们创建一个/etc/inittab,在里面输入如下内容:
#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
tty1::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
解析:
第 2 行,系统启动以后运行/etc/init.d/rcS 这个脚本文件。
第 3 行,将 console 作为控制台终端,也就是 ttymxc0。
第 4 行,重启的话运行/sbin/init。
第 5 行,按下 ctrl+alt+del 组合键的话就运行/sbin/reboot,看来 ctrl+alt+del 组合键用于重启系统。
第 6 行,关机的时候执行/bin/umount,也就是卸载各个文件系统。
第 7 行,关机的时候执行/sbin/swapoff,也就是关闭交换分区。
至此!根文件系统要创建的文件就已经全部完成了。