以下内容源于网络资源的学习与整理,如有侵权请告知删除。
在前面的理论分析的基础上,我们开始从零开始构建一个根文件系统。
构建根文件系统的步骤:
首先,在形式上创建一些空目录。
然后,利用busybox软件来生成bin/、sbin/、/linuxrc这三个目录文件。
接着,构建与修改etc目录下的文件(包括inittab文件、rcS文件、profile文件、fstab文件、shadow文件、passwd文件等)。
最后,构建lib目录(即把交叉编译工具链的动态链接库复制到根文件系统的lib目录)。
我们通过NFS方式来挂载这个文件夹形式的根文件系统,以验证其可用性。
后续也可以将它制作成镜像文件并烧录到Flash中,参见博客制作ext2格式的根文件系统镜像。
1、在形式上创建一些空目录
由博文根文件系统的目录结构可知,根文件系统一般由/dev、/etc、/lib、/usr、/var、/proc、/tmp、/home、/root、/mnt、/bin、/sbin、/sys等目录(这些目录有些是最小根文件系统必需的,有些不是必需的),以及/linuxrc文件组成。
我们先创建一个文件夹“rootfs_xjh”,然后在该文件夹内创建以上文件夹。至于/bin、/sbin目录,以及/linuxrc文件,它们是由busybox生成的,可以生成后再拷贝到文件夹“rootfs_xjh”里。
2、使用busybox生成bin/、sbin/、usr/目录与linuxrc文件
步骤1、获取busybox源码
busybox是开源项目,版本差异不大;这里选择busybox-1.24.1版本。
步骤2、解压后修改Makefile
将Makefile中的ARCH、CROSS_COMPILE修改如下:
ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin//arm-none-linux-gnueabi-
步骤3、配置busybox
先“make defconfig”,然后“make menuconfig”,按照下面指示进行配置。
Busybox Settings--->
Build Options--->
[*]Build BusyBox as a static binary(no shared libs)
Busybox Library Tuning--->
[*]vi-style line editing commands
[*]Fancy shell prompts
Linux Module Utilities--->
[ ]Simplified modutils
[*]insmod
[*]rmmod
[*]lsmod
[*]modprobe
[*]depmod
Linux System Utilities--->
[*]mdev
[*]Support /etc/mdev.conf
[*]Support subdirs/symlinks
[*]Support regular expressions substitutions when renaming dev
[*]Support command execution at device addition/removal
[*]Support loading of firmwares
步骤4、编译与安装
(1)执行“make”时出现错误如下。
coreutils/lib.a(sync.o): In function `sync_main':
sync.c:(.text.sync_main+0x78): undefined reference to `syncfs'
collect2: ld returned 1 exit status
make: *** [busybox_unstripped] Error 1
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1$
因为此文件与主功能无关,所以我们可以把这文件屏蔽掉,操作方法如下:
【1】确定sync.c文件的位置。在此目录下find -name "sync.c",知道其在./coreutils/sync.c。
【2】在coreutils目录下的Kbuild文件中查找“sync.o”,可知由宏CONFIG_SYNC来控制是否编译。
lib-$(CONFIG_ID) += id.o
lib-$(CONFIG_SHUF) += shuf.o //这里,第23行
lib-$(CONFIG_SYNC) += sync.o
lib-$(CONFIG_TAIL) += tail.o
【3】在make menuconfig中,输入“/”以查找“SYNC”,转到其位置,选择为N。
(2)再次执行make进行编译,然后执行“make install”,或者直接“make && make install”。
安装目录默认在busybox-1.24.1/_install,我们也可以在make menuconfig时设置安装目录:
Busybox Settings --->
Installation Options ("make install" behavior) --->
安装成功后,busybox-1.24.1/_install目录下有bin/、sbin/、linuxrc、usr/这个四个目录或文件。其中linuxrc,以及bin/、sbin/、usr/bin/、usr/sbin/目录下的命令都指向了bin/busybox,如下所示。
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/_install$ ls
bin linuxrc sbin usr
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/_install$ ls linuxrc -l
lrwxrwxrwx 1 root root 11 三月 24 22:08 linuxrc -> bin/busybox
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/_install$ cd bin/
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/_install/bin$ ls -l
total 1932
lrwxrwxrwx 1 root root 7 三月 24 22:08 ash -> busybox
lrwxrwxrwx 1 root root 7 三月 24 22:08 base64 -> busybox
-rwxr-xr-x 1 root root 1977812 三月 24 22:08 busybox
lrwxrwxrwx 1 root root 7 三月 24 22:08 cat -> busybox
lrwxrwxrwx 1 root root 7 三月 24 22:08 catv -> busybox
lrwxrwxrwx 1 root root 7 三月 24 22:08 chattr -> busybox
lrwxrwxrwx 1 root root 7 三月 24 22:08 chgrp -> busybox
#忽略部分输出
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/_install/bin$
步骤5:将目录bin/、sbin/、usr/以及文件linuxrc拷贝到rootfs_xjh文件夹
sudo cp bin/ sbin/ usr/ linuxrc /home/xjh/iot/embedded_basic/rootfs/rootfs_xjh/ -raf
3、构建etc目录
etc目录主要用来存放服务启动脚本与配置脚本。
该目录下的文件较多,制作过程比较繁琐,但该目录下的文件的构成相对固定。
构建etc目录,主要工作是从busybox中拷贝一些文件到etc/目录下,并对这些文件进行一些修改。
步骤1、将busybox/examples/bootfloopy/etc/中的文件拷贝到rootfs_xjh/etc/目录
busybox/examples/bootfloopy/etc目录下有fstab、init.d、inittab、profile四个文件或目录。
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/examples/bootfloppy/etc$ ls -F
fstab init.d/ inittab profile
xjh@ubuntu:~/iot/embedded_basic/rootfs/busybox/busybox-1.24.1/examples/bootfloppy/etc$
步骤2:修改rootfs_xjh/etc/inittab文件
(1)如果需要开机免登陆而直接进入shell,则修改如下。“::askfirst:-/bin/sh”表示系统启动后,如果按回车就执行/bin/sh而出现命令行,从而不会出现登录界面。
::sysinit:/etc/init.d/rcS
#::respawn:-/bin/sh 屏蔽掉
#tty2::askfirst:-/bin/sh 屏蔽掉
::askfirst:-/bin/sh #新添加
::ctrlaltdel:/bin/umount -a -r
[ 6.561035] Looking up port of RPC 100005/1 on 192.168.1.141
[ 6.617172] VFS: Mounted root (nfs filesystem) on device 0:12.
[ 6.621609] Freeing init memory: 540K
Please press Enter to activate this console.
[root@ZHUJI ]#
[root@ZHUJI ]#
[root@ZHUJI ]#
对于“[root@ZHUJI ]#”,其中用户名root与passwd文件有关,而主机名ZHUJI与/etc/init.d/rc.S文件有关(见下面的描述)。
(2)如果需要开机时登陆用户,则设置如下。“::respawn:-/bin/login”表示系统启动的时候会提示用户登录。至于是否还需要输入密码,则要看shadow文件第一行代码的第一个冒号和第二个冒号之间是否有加密的密码。如果没有,则只要输入用户名root然后回车即可,不需要输入密码;如果有则和拷贝源的密码一样。
::sysinit:/etc/init.d/rcS
#::respawn:-/bin/sh 屏蔽掉
#tty2::askfirst:-/bin/sh 屏蔽掉
::respawn:-/bin/login #新添加
::ctrlaltdel:/bin/umount -a -r
步骤3、设置用户名与密码设置
下面操作的前提,是步骤2的时候选择(2),即开机时需要验证用户账号与密码。
将虚拟机linux系统里的/etc/passwd、/etc/group、/etc/shadow拷贝到rootf_xjh/etc/目录下,然后修改三个文件的相关内容。
(1)修改passwd文件
只保存与root相关的行,修改passwd文件内容为“root:x:0:0:root:/root:/bin/sh”(没双引号,而且因为busybox不支持bash,这里的/bin/bash要改为/bin/sh)。
(2)修改group文件
只保存与root相关的行,修改group文件内容为“root:x:0:root”(没双引号)。
(3)修改shadow文件
只保存与root相关的行,而且与root相关的行不需要更改(此时登陆密码和拷贝源的密码一致),或者可以清除这行第一个冒号和第二个冒号之间的内容(登陆时只需要输入root这个用户名然后回车即可,无需密码)。
//第一个冒号和第二个冒号之间的内容是加密后的密码
root:$7$.KKrGMfb$M2qiFqy1dNaMVv9LVfk/0Fex4EDrLu5ladkTR0mZ6SrMvlvJHjTSF30/KwRNVjPhMJQn04qzIV9wQwujCIgCm.:17463:0:99999:7:::
步骤4、修改rootfs_xjh/etc/profile文件
# Ash profile
# vim: syntax=sh
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]\# '
PATH=$PATH
HOSTNAME=`/bin/hostname`
export USER LOGNAME PS1 PATH
步骤5、修改rootfs_xjh/etc/fstab文件
我们在这个文件中添加以下内容(作为挂载点的空目录需要先建立):
#<file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /var tmpfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
步骤6、修改rootfs_xjh/etc/init.d/rc.S文件
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
mount -a
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
#-F选项表示指定/etc/sysconfig/HOSTNAME这个文件为主机名配置文件
#/bin/hostname -F /etc/sysconfig/HOSTNAME
# hostname xxx ,表示设置当前系统的主机名为xxx
/bin/hostname ZHUJI
ifconfig eth0 192.168.1.100
4、构建lib目录
由根文件系统的目录结构_天糊土的博客-CSDN博客可知,/lib目录在根文件系统中也是不能省略的。该目录存放着操作系统中的动态和静态链接库文件。我们构建/lib目录,主要工作是将动态链接库复制到rootfs_xjh/lib目录。
动态链接库位于虚拟机linux系统的/usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib/目录。其他的一些交叉编译工具链的动态链接库的目录不一定在此,需要查找时可以“ find -name "*.so" ”。复制时要注意参数用-rdf,主要目的就是符号链接复制过来还是符号链接,即:
cp /usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib/*so* /home/xjh/iot/embedded_basic/rootfs/rootfs_xjh/lib/ -rdf
为什么复制的是交叉编译工具链的动态链接库,而非gcc的动态链接库呢?这是因为根文件系统是在板子上工作的,即动态链接库的使用是在arm体系架构中,而非虚拟机的Intel 80386。也就是说,如果使用gcc编译则可以在虚拟机中运行,但不能在开发板运行;如果要在开发板运行则需要用arm-linux-gcc来编译,但此时编译得到的文件不能在虚拟机运行。
我们可以用“file xx”命令来查看一个可执行程序是哪个架构的。
另外,动态链接库的文件中包含着调试符号信息,这些符号信息在运行时是没用的,而且会占用一定空间。在传统的嵌入式系统中Flash空间是有限的,为了节省空间常常把这些符号信息去掉。去掉符号的命令是“ arm-linux-strip *so* ”。