Linux:根文件系统构建

一、编译 BusyBox 构建根文件系统

1.创建BusyBox路径并解压

在这里插入图片描述

2.修改顶层Makefile

同 Uboot 和 Linux 移植一样,打开 busybox 的顶层 Makefile,添加 ARCH 和 CROSS_COMPILE
的值,如下所示:

CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

在这里插入图片描述在这里插入图片描述

3.修改 busybox 源码

我们需要修改 busybox 源码,取消 busybox 对中文显示的限制,打开文件 busybox-
1.29.0/libbb/printable_string.c,找到函数 printable_string,缩减后的函数内容如下:
在这里插入图片描述接着打开文件 busybox-1.29.0/libbb/unicode.c,找到如下内容:
在这里插入图片描述

4.配置busybox

busybox 也支持图形化配置,通过图形化配置我们可以进一步选择自己想要的功能,输入
如下命令打开图形化配置界面:
make menuconfig

1:Location:
-> Settings
-> Build static binary (no shared libs)
取消勾选

2:Location:
-> Settings
-> vi-style line editing commands

3:Location:
-> Linux Module Utilities
-> Simplified modutils
X

4:Location:
-> Linux System Utilities
-> mdev (16 kb) //确保下面的全部选中,默认都是选中的

5:Location:
-> Settings
-> Support Unicode //选中
-> Check $LC_ALL, $LC_CTYPE and $LANG environment variables //选中

5.编译busybox

配置好 busybox 以后就可以编译了,我们可以指定编译结果的存放目录,我们肯定要将编
译结果存放到前面创建的 rootfs 目录中,输入如下命令:

make install CONFIG_PREFIX=/home/sjh/linux/nfs/rootfs

在这里插入图片描述编译完成以后会在 busybox 的所有工具和文件就会被安装到 rootfs 目录中
在这里插入图片描述
rootfs 目录下有 bin、 sbin 和 usr 这三个目录,以及 linuxrc 这个文件。前面说过 Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。

6.向 rootfs 的“/lib”目录添加库文件

创建 lib文件

mkdir lib

进入如下路径对应的目录:

/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linuxgnueabihf/libc/lib

此目录下有很多的so(是通配符)和.a 文件,这些就是库文件,将此目录下所有的so*和.a
文件都拷贝到 rootfs/lib 目录中,拷贝命令如下:

cp *so* *.a /home/sjh/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”查看此文件详细信息d-linux-armhf.so.3 后面有个“->”,表示其是个软连接文件,链接
到文件 ld-2.19-2014.08-1-git.so,因为其是一个“快捷方式”,因此大小只有 24B。但是, ld-linuxarmhf.so.3 不能作为符号链接,否则的话在根文件系统中执行程序无法执行!所以我们需要 ldlinux-armhf.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/sjh/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/zuozhongkai/linux/nfs/rootfs/lib/ -d

rootfs/lib 目录的库文件就这些了,完成以后的 rootfs/lib 目录如图
在这里插入图片描述

7.向 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

将此目录下的 so 和.a 库文件都拷贝到 rootfs/usr/lib 目录中,命令如下:

cp *so* *.a /home/sjh/linux/nfs/rootfs/usr/lib/ -d

至此,根文件系统的库文件就全部添加好了,可以使用“du”命令来查看一下 rootfs/lib 和
rootfs/usr/lib 这两个目录的大小,命令如下:

cd rootfs //进入根文件系统目录
du ./lib ./usr/lib/ -sh //查看 lib 和 usr/lib 这两个目录的大小

在这里插入图片描述

创建其他文件夹

mkdir dev proc mnt sys tmp root

在这里插入图片描述

二、NFS挂载根文件系统

1.bootargs 环境变量配置

uboot 里面的 bootargs 环境变量会设置“root”的值,所以我们将 root 的值改为 NFS 挂载即可。
在 Linux 内核源码里面有相应的文档讲解如何设置,文档为 Documentation/filesystems/nfs/
nfsroot.txt,格式如下:

root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>

“proto=tcp”表示使用 TCP 协议,“rw”表示 nfs 挂载的根文件系统为可读可写。 启动开发
板,进入 uboot 命令行模式,然后重新设置 bootargs 环境变量,命令如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.28.100:/home/sjh/linux/nfs/rootfs,proto=tcp rw ip=192.168.28.135:192.168.28.100:192.168.28.1:255.255.255.0::eth0:off'
 //设置 bootargs
saveenv 
//保存环境变量

设置好以后使用“boot”命令启动 Linux 内核
在这里插入图片描述
也能够创建文件
在这里插入图片描述
有错误提示需要继续完善,看下面步骤3
在这里插入图片描述

如NFS无法挂载

如果是 ubuntu18 版本,或者串口打印信息提示 VFS: Unable to mount root fs via NFS, trying
floppy.或者或者报错 Loading:*ww ERROR:File lookup fail 的,或者 mount.nfs: mount system call
failed
可能就是 uboot 支持的协议与 NFS 支持的协议不同导致报错,可以进行如下修改:
在 ubuntu 的==/etc/default/nfs-kernel-server== 文件中,按照如下图箭头所指的部分进行修改,改
完后保存退出,再执行指令 sudo service nfs-kernel-server restart重启 NFS 服务。
在这里插入图片描述

三.完善根文件系统

1 创建/etc/init.d/rcS 文件

在这里插入图片描述

rcS 是个 shell 脚本, Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件
的脚本文件。在 rootfs 中创建/etc/init.d/rcS 文件,然后在 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 目录
下自动创建设备节点。关于 mdev 的详细内容可以参考 busybox 中的 docs/mdev.txt 文档。

使用如下命令给予/ec/init.d/rcS 可执行权限:

chmod 777 rcS

设置好以后就重新启动 Linux 内核

在这里插入图片描述
可以看到,提示找不到/etc/fstab 文件,还有一些其他的错误,我们先把/etc/fstab这个错误解决了。说不定把这个问题解决以后其他的错误也就解决了。前面我们说了“mount -a”挂载所有根文件系统的时候需要读取/etc/fstab,因为/etc、 fstab 里面定义了该挂载哪些文件,好了,接下来就是创建/etc/fstab 文件。

2.创建/etc/fstab 文件

在 rootfs 中创建/etc/fstab 文件, fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,格式如下

file system mount point type
在这里插入图片描述
在这里插入图片描述
可以看出,启动成功,而且没有任何错误提示。但是我们要还需要创建一个
文件/etc/inittab。

3.创建/etc/inittab 文件

inittab 的详细内容可以参考 busybox 下的文件 examples/inittab。 init 程序会读取/etc/inittab
这个文件, inittab 由若干条指令组成。每条指令的结构都是一样的,由以“:”分隔的 4 个段组
成,格式如下:

id runlevels action process
id:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说, 有着特殊意义。
对于 busybox 而言用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控
制 tty。
runlevels: 对 busybox 来说此项完全没用,所以空着。
action:动作,用于指定process可能用到的动作。 busybox 支持的动作如表 38.4.3.1 所
示:

动作描述
sysinit在系统初始化的时候 process 才会执行一次
respawn当 process 终止以后马上启动一个新的。
askfirst和 respawn 类似,在运行 process 之前在控制台上显示“Please press Enter to activatethis console.”。只要用户按下“Enter”键以后才会执行 process。
wait告诉 init,要等待相应的进程执行完以后才能继续执行。
once仅执行一次,而且不会等待 process 执行完成。
restart当 init 重启的时候才会执行 procee。
ctrlaltdel当按下 ctrl+alt+del 组合键才会执行 process。
shutdown关机的时候执行 process。

process: 具体的动作,比如程序、脚本或命令等。
参考 busybox 的 examples/inittab 文件,我们也创建一个/etc/inittab,在里面输入如下内容:

#etc/inittab
::sysinit:/etc/init.d/rcS
console::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,也就是关闭交换分区。
/etc/inittab 文件创建好以后就可以重启开发板即可,至此!根文件系统要创建的文件就已经
全部完成了。接下来就要对根文件系统进行其他的测试,比如我们自己编写的软件运行是否正
常、是否支持软件开机自启动、中文支持是否正常以及能不能链接等。

4.根文件系统其他功能测试

1.软件运行测试

我们使用 Linux 的目的就是运行我们自己的软件,我们编译的应用软件一般都使用动态库,
使用动态库的话应用软件体积就很小,但是得提供库文件,库文件我们已经添加到了根文件系
统中。我们编写一个小小的测试软件来测试一下库文件是否工作正常,在根文件系统下创建一
个名为“drivers”的文件夹,以后我们学习 Linux 驱动的时候就把所有的实验文件放到这个文
件夹里面。
新建一个 hello.c 文件,在 hello.c 里面输入如下内容:

#include <stdio.h>
int main(void)
{
	while(1) 
	{
		printf("hello world!\r\n");
		sleep(2);
	}
	return 0;
}

hello.c 内容很简单,就是循环输出“hello world”, sleep 相当于 Linux 的延时函数,单位为
秒,所以 sleep(2)就是延时 2 秒。编写好以后就是编译,因为我们是要在 ARM 芯片上运行的,
所以要用交叉编译器去编译,也就是使用 arm-linux-gnueabihf-gcc 编译,命令如下:

arm-linux-gnueabihf-gcc hello.c -o hello

file hello //查看 hello 的文件类型以及编码格式

在这里插入图片描述

hello 是个 32 位的 LSB 可执行文件, ARM 架构的,并且是动态链接的。所以我们编译出
来的 hello 文件没有问题。将其拷贝到 rootfs/drivers 目录下,在开发板中输入如下命令来执行这
个可执行文件:

cd /drivers //进入 drivers 目录
./hello //执行 hello

在这里插入图片描述

可以看出, hello 这个软件运行正常,说明我们的根文件系统中的共享库是没问题的,要想终止 hello 的运行,按下“ctrl+c”组合键即可。此时大家应该能感觉到, hello 执行的时候终端是没法用的,除非使用“ctrl+c”来关闭 hello,那么有没有办法既能让 hello 正常运行,而且终端能够正常使用?那肯定是有的,让 hello 进入后台运行就行了,让一个软件进入后台的方法很
简单,运行软件的时候加上“&”即可,比如“./hello &”就是让 hello 在后台运行。在后台运行的软件可以使用“kill -9 pid(进程 ID)”命令来关闭掉,首先使用“ps”命令查看要关闭的软件 PID 是多少, ps 命令用于查看所有当前正在运行的进程,并且会给出进程的 PID。输入“ps”命令
在这里插入图片描述
从图 可以看出 hello 对应的 PID 为 166,因此我们使用如下命令关闭在后台运行的
hello 软件:

kill -9 81

2.中文字符测试

1.xshell配置UTF-8格式

在这里插入图片描述

2.Ubuntu创建测试文件

在这里插入图片描述

3.xshell测试

在这里插入图片描述

3.开机自启动测试

测试 hello 软件的时候都是等 Linux 启动进入根文件系统以后手动输入命令“./hello”来完成的。我们一般做好产品以后都是需要开机自动启动相应的软件,本节我们就以hello 这个软件为例,讲解一下如何实现开机自启动。前面我们说过了,进入根文件系统的时候会运行/etc/init.d/rcS 这个 shell 脚本,因此我们可以在这个脚本里面添加自启动相关内容。添加

cd /drivers
./hello &
cd /

在这里插入图片描述
reboot重启开发板,程序开始运行
在这里插入图片描述

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值