文章目录
- 一、根文件系统是什么?
- 二、根文件目录
- 1.bin目录
- 2.etc
- 3.lib
- 4.mnt
- 5.proc
- 6.sys
- 7.usr
- 8.dev
- 9.opt
- 10.var
- 三.使用工具Busybox构建根文件系统
- 1.rootfs文件夹创建
- 2.在makefile中添加交叉编译器
- 3.busybox 中文字符支持
- 4.配置 默认busybox
- 5.使用图形界面配置busybox
- 6.编译
- 四.将库文件添加到编译后的目录
- 1.向 rootfs 的“/lib”目录添加库文件
- 2.向 rootfs 的“usr/lib”目录添加库文件
- 3.检查lib是否都正常复制到rootfs/lib,rootfs/usr/lib,和大小验证
- 4.补全其他文件夹
- 5.初步测试
- 6.文件补充
一、根文件系统是什么?
💦根文件系统也称rootfs,在学习STM32的过程中,与SD卡通讯过,涉及到
FATFS系统,根文件系统与FATFS是否一致呢,答案是不同的。
💦根文件系统,简单来说就是一系列文件的集合,文件包括“图片,软件,配置文件,驱动库”等等,在Linux中,内核就是通过调用根文件系统运行的 ,Linux系统内核没有那么大,其他的都是根文件系统。
那么这个根文件系统是怎么来的呢,需要自己构建。
二、根文件目录
💦既然根文件系统需要自己构建,在构建前,肯定需要了解,根文件系统有哪些东西,换种说法就是有哪些目录。
💦举例:以Ubuntu系统为例
1.bin目录
💦bin目录,通过目录名字,应该可以能想到 此目录,存放bin 文件,bin 文件也就是可执行文件。所以此目录下存放着系统需要的可执行文件,大多都是一些命令,比如 ls、mv 等命令。并且此目录下的命令所有的客户都可以使用。
比如,cp,ls命令等。
2.etc
💦此目录下存放着各种配置文件,比如在Ubuntu系统中,配置环境变量的profile文件。在构建自己的根文件系统的时候,需要哪些配置文件加入哪些,其他的不用不需要添加。这样自己构建的嵌入式 Linux 下此目录会很简洁。
3.lib
💦lib 是 library 的简称,也就是库的意思,因此此目录下存放着 Linux 所必须的库文件。比如C库,或者其他的第三方的库文件,这些库文件是共享库,命令和用户编写的应用程序要使用这些库文件。
4.mnt
💦l临时挂载目录,一般是空目录,可以在此目录下创建空的子目录,比如/mnt/sd、/mnt/usb,这样就可以将 SD 卡或者 U 盘挂载到/mnt/sd 或者/mnt/usb 目录中。
5.proc
sweat_drops:此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点,proc是个虚拟文件系统,没有实际的存储设备。proc 里面的文件都是临时存在的,一般用来存储系统运行信息文件。
6.sys
💦系统启动以后此目录作为 sysfs 文件系统的挂载点,sysfs 是一个类似于 proc 文件系统的特殊文件系统,sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。
7.usr
💦要注意,usr 不是 user 的缩写,而是 Unix Software Resource 的缩写,也就是 Unix 操作系统软件资源目录。补充个小知识点,方便类比记忆,那就是 Linux 一般被称为类 Unix 操作系统,苹果的 MacOS也是类 Unix 操作系统。既然是软件资源目录,因此/usr 目录下也存放着很多软件,一般系统安装完成以后此目录占用的空间最多。
8.dev
💦dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备文件。在 Linux 下一切皆文件,即使是硬件设备,也是以文件的形式存在的,比如/dev/ttymxc0(I.MX6ULL 根目录会有此文件)就表示 I.MX6ULL 的串口 0,我们要想通过串口 0发送或者接收数据就要操作文件/dev/ttymxc0,通过对文件/dev/ttymxc0 的读写操作来实现串口
0 的数据收发。
9.opt
💦可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。
10.var
💦此目录存放一些可以改变的数据。
💦注意:其他的目录是Ubuntu系统的目录,不用了解太深。
三.使用工具Busybox构建根文件系统
💦Busybox是比较基础的根文件系统工具,有比较好用的buildroot,yocto等比较先进的工具流程比较完善,对学习来说,性价比低。
1.rootfs文件夹创建
将编译后的文件都放在这个rootfs文件夹中并解压缩,最后使用nfs服务挂载。
2.在makefile中添加交叉编译器
💦修改ARCH
💦修改CROSS_COMPILE 这个一定要使用绝对目录,arm-linux-gnueabihf-安装的目录。
💦注意:arm-linux-gnueabihf-后边不要有空格
CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
3.busybox 中文字符支持
💦需要修改libbb文件夹下的 printable_string.c文件。
💦在函数printable_string中将大于0x7f的语句屏蔽掉。
const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
💦需要修改libbb文件夹下的 unicode.c文件,在unicode_conv_to_printable2中屏蔽掉大于0x7f的语句。
static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
4.配置 默认busybox
💦busybox跟我们编译 Uboot、Linux kernel 一样,编译器先对 busybox 进行默认的配置,有以下几种配置选项:
①、defconfig,缺省配置,也就是默认配置选项。
②、allyesconfig,全选配置,也就是选中 busybox 的所有功能。
③、allnoconfig,最小配置。
常用选项默认配置
make defconfig
💦注意:编译的过程中会有很多错误,解决办法,给busybox目录赋予权限。
💦编译成功会生成.config文件。
5.使用图形界面配置busybox
命令如下:
make menuconfig
💦选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。
动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析。
💦保存退出。
6.编译
💦编译指令如下:
make install CONFIG_PREFIX=/home/che/linux/nfsfile/rootfs
💦生成文件如下。
四.将库文件添加到编译后的目录
1.向 rootfs 的“/lib”目录添加库文件
💦Linux 中的应用程序运行都是需要动态库的,由于我们编译的时候使用的是动态库编译,编译后的文件是缺少动态库的,所以我们需要向根文件系统中添加动态库。
当然了也可以编译成静态的,但是静态的可执行文件会很大。
添加动态库的方法:
💦在 rootfs 中创建一个名为“lib”的文件夹,命令如下:
sudo mkdir lib
💦lib 文件夹创建好了,库文件从哪里来呢?lib 库文件是从交叉编译器中获取,在安装
交叉编译环境的时候,将交叉编译器存放到了“/usr/local/arm/”目录中。
sweat_drops:交叉编译器里面有很多的库文件,这些库文件具体是做什么的,作为初学者肯定不知道,既然不知道那就先把所有的库文件都放到我们的根文件系统中,后期知道了可以进行裁剪。
💦第一个目录:/arm-linux-gnueabihf/libc/lib
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
💦在上述目录中输入下面指令:
cp *so* *.a /home/che/linux/nfsfile/rootfs/lib/ -d //-d表示复制符号连接
💦补充:符号连接的含义是相当于windows中的快捷方式,它也链接着一个文件,输入下方指令查看。
ls ld-linux-armhf.so.3 -l
💦如果根文件系统中存在这个ld-linux-armhf.so.3符号链接,运行时会报错,所以解决方法是将其在roots/lib目录中删除,在交叉编译器中从新复制一个到roots/lib目录中,在查看其变成正常的文件了。
💦注意:其他的符号链接则可以正常运行。
💦第二个目录:/arm-linux-gnueabihf/lib
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
💦在上述目录中输入下面指令:也要加入-d复制符号链接
cp *so* *.a /home/che/linux/nfsfile/rootfs/lib/ -d
2.向 rootfs 的“usr/lib”目录添加库文件
💦在 rootfs /usr中创建一个名为“lib”的文件夹,命令如下:
mkdir lib
💦目录如下:/arm-linux-gnueabihf/libc/usr/lib
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
💦在上述目录中输入下面指令:
cp *so* *.a /home/che/linux/nfsfile/rootfs/usr/lib/ -d
3.检查lib是否都正常复制到rootfs/lib,rootfs/usr/lib,和大小验证
💦检查大小,指令如下:
du ./lib ./usr/lib -sh
4.补全其他文件夹
💦在根文件系统中创建其他文件夹,如 dev、proc、mnt、sys、tmp 和 root 等
5.初步测试
💦测试方法:使用nfs进行网络挂载根文件系统,原因是根文件系统很大的,如果每次修改文件都需要烧录,太浪费时间,使用nfs的好处是每次修改文件,直接复制到nfs的挂载目录即可,等Linux系统启动后就会通过nfs挂载根文件系统。
💦前提条件:
1)网络要能正常使用,nfs可以正常使用,注意nfs要支持v2版本,内核版本不要太高
2)修改uboot的bootargs 环境变量的值。
3)bootcmd设置tftp从Ubuntu系统加载zImage,dtb。
💦开始设置:nsf挂载
💦在 Linux 内核源码里面有相应的文档讲解如何设置,文档为 Documentation/filesystems/nfs/
nfsroot.txt
💦格式如下:bootargs 环境变量设置格式
root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>
<server-ip>:服务器 IP 地址,也就是存放根文件系统主机的 IP 地址,那就是 Ubuntu 的 IP
地址,比如我的 Ubuntu 主机 IP 地址为 192.168.1.50250。
<root-dir>:根文件系统的存放路径,比如我的就是/home/che/linux/nfsfile/rootfs。
<nfs-options>:NFS 的其他可选选项,一般不设置。
<client-ip>:客户端 IP 地址,也就是我们开发板的 IP 地址,Linux 内核启动以后就会使用
此 IP 地址来配置开发板。此地址一定要和 Ubuntu 主机在同一个网段内,并且没有被其他的设
备使用,在 Ubuntu 中使用 ping 命令 ping 一下就知道要设置的 IP 地址有没有被使用,如果不能
ping 通就说明没有被使用,那么就可以设置为开发板的 IP 地址,比如我就可以设置为
192.168.1.20。
<server-ip>:服务器 IP 地址。
<gw-ip>:网关地址,我的就是 192.168.1.255。
<netmask>:子网掩码,我的就是 255.255.255.0。
<hostname>:客户机的名字,一般不设置,此值可以空着。
<device>:设备名,也就是网卡名,一般是 eth0,eth1….,I.MX6U-ALPHA 开
发板的 ENET2 为 eth0,ENET1 为 eth1。如果你的电脑只有一个网卡,那么基本只能是 eth0。
这里我们使用 ENET2,所以网卡名就是 eth0。
<autoconf>:自动配置,一般不使用,所以设置为 off。
<dns0-ip>:DNS0 服务器 IP 地址,不使用。
<dns1-ip>:DNS1 服务器 IP 地址,不使用。
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.20:/home/che/linux/nfsfile/rootfs ip=192.168.1.50:192.168.1.20:192.168.1.1:255.255.255.0::eth0:off'
💦成功后界面如下:
💦VFS:Mounted root (nfs filesystem)readonly on device 安装只读系统,因为在设置bootargs变量的时候,没有设置全,修改bootargs变量加入rw功能。
bootargs=console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.20:/home/che/linux/nfsfile/rootfs,proto=tcp rw ip=192.168.1.50:192.168.1.20:192.168.1.1:255.255.255.0::eth0:off
💦可以创建文件了
6.文件补充
文件系统启动的时候
报错一如下:
💦解决办法:
💦缺啥补啥,先创建个etc目录,因为使用nfs挂载Ubuntu系统中rootfs,所以在Ubuntu系统中操作就可以,
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
/sbin是绝对路径,$PATH加上以前的环境变量
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
$LD_LIBRARY_PATH加上以前的lib库
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
💦解析:
💦PATH 环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或者可执行文件的时候就不会提示找不到文件这样的错误。
💦LD_LIBRARY_PATH 环境变量保存着库文件所在的目录。
💦使用 export 来导出上面这些环境变量,相当于声明一些“全局变量”。
💦使用 mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定,所以我们一会还要创建/etc/fstab 文件。
💦创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。
💦使用 mdev 来管理热插拔设备,通过这两行,Linux 内核就可以在/dev 目录下自动创建设备节点。关于 mdev 的详细内容可以参考 busybox 中的 docs/mdev.txt 文档。
💦复杂的 rcS 文件也是借助其他工具创建的,比如 buildroot 等。
💦报错二如下:
💦“mount -a”挂载所有根文件系统的时候需要读取/etc/fstab,因为/etc/fstab 里面定义了该挂载哪些文件,所以需要创建/etc/fstab 文件并指明需要挂载系统类型。
💦fstab内容如下:
💦最后在创建/etc/inittab 文件,此文件的作用解析如下:
💦init是Linux系统操作中不可缺少的程序之一。是一个由内核启动的用户级进程。
Linux系统的启动过程为:加电自检–>根据BIOS中的设置从指定的设备启动–>找到设备MBR中的bootloader引导启动系统–>启动kernel–>启动init进程
💦我们看到,Linux系统启动的最后是启动init进程,而init进程是怎么工作的呢?init进程就是根据/etc/inittab这个文件来在不同的运行级别启动相应的进程或执行相应的操作。
💦对于busybox而言格式如下:
💦inittab内容如下:最好用vim编译器编写。