首先还是想吐槽下,我一个做应用软件的为啥要会做根文件系统。于是抱着学习的态度研究一下,记录下。
必要目录(八大目录):
bin目录:存放普通用户的命令
sbin目录:存放超级用户的命令
usr目录:存放各种其他命令
lib目录:存放各种动态库(无需静态库)
静态库只需在上位机编译程序时使用
etc目录:存放各种配置文件
dev目录:存放设备文件(跟驱动相关)
proc目录:作为procfs虚拟文件系统的入口(跟驱动相关)
sys目录:作为sysfs虚拟文件系统的入口(跟驱动相关)
可选目录:
home目录:作为普通用户的主目录
root目录:作为root用户的主目录
var目录:作为保存临时文件
mnt目录:作为U盘/TF卡/SD卡的挂接点
...
方法一:你可以亲自写各种命令和库(手动滑稽)
方法二:利用开源软件busybox来制作根文件系统
程序员偷懒原则使我选择二。
tar -xvf busybox-1.31.0.tar.bz2 //得到busybox-1.31.0源码目录
mv busybox-1.31.0 busybox //重命名
cd ./busybox //进入busybox源码根目录
vim Makefile +190
将: ARCH ?= $(SUBARCH) //让busybox支持ARM架构
修改为:ARCH = arm
vim Makefile +164
将: CROSS_COMPILE ?=
修改为:CROSS_COMPILE=arm-linux-gnueabi- //指定编译busybox使用的交叉编译器
保存退出
make menuconfig //对busybox源码进行配置
Busybox Setting
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
Busybox Library Tuning:配置busybox vi风格
Linux Module Utilities:加载卸载模块命令
Linux System Utilities:一些系统的命令,如内核打印消息dmesg,分区命令fdisk。
保存配置退出,之后就是
make -j4 //开始交叉编译busybox
make install //安装busybox编译出来的二进制目标文件统一的拷贝到一个指定的目录中
ls _install/ //安装busybox生成的目标文件默认都会拷贝
此时有bin sbin usr linuxrc这几个目录
说明:
bin:普通用户的命令
sbin:超级用户命令
usr:又包括两个目录
sbin:超级用户命令
bin: 普通用户命令
linuxrc:将来内核挂接根文件系统rootfs以后, 内核启动的第一个程序(init=/linuxrc),将来此程序自动调用/sbin/init第一号进程
ls _install/bin/* -lh //查看各种命令文件的属性
ls _install/sbin/* -lh
ls _install/usr/bin/* -lh
ls _install/usr/sbin/* -lh
ls _install/linuxrc -lh
结论:交叉编译busybox仅仅生成了一个可执行文件_install/bin/busybox,而其余命令都是busybox这个可执行程序的软连接而已
结论:busybox仅仅提供各种命令而已!
file _install/bin/busybox //查看编译busybox生成的二进制文件的属性是否是ARM架构
mkdir dev proc sys lib etc //创建必要目录
mkdir home root var mnt //创建可选目录
注意,在make menuconfig的时候可以将执行文件编译成静态的,但考虑到静态库程序过于庞大且以后应用程序要用到动态库还是讲解下添加动态库,不要选择静态编译。
Busybox Settings--->
Build Options--->
[ ]Build BusyBox as a static binary(no shared libs)
//获取依赖的库
arm-linux-gnueabi--readelf -d _install/bin/busybox
到交叉编译器的/arm-linux-gnueabi/lib拷贝到_install/lib/下,软连接和源文件都要拷贝
明确:配置文件和脚本文件位于根文件系统的etc必要目录下
6.1.系统启动的必要配置文件inittab
vim _install/etc/inittab 添加如下内容
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::ctrlaltdel:-/sbin/reboot
#umount all filesystem
::shutdown:/bin/umount -a -r
#restart init process
::restart:/sbin/init
sysinit表示的是一种条件:表示在系统跑起来最先执行的程序。
/etc/init.d/rcS 这里面试shell脚本,就是用来执行脚本程序的
respawn:启动了一个shell程序用户可以输入各种命令
shutdown:就代表在关机的时候执行后面的程序/bin/umount -r -a
就是关机的时候,把所有的根文件系统中的文件全部卸载掉。
讲解:从系统启动流程角度来看inittab如何被使用的:上电->CPU首先运行uboot->uboot做硬件初始化 ->uboot利用bootcmd从某个地方加载内核到内存 ->uboot利用bootargs给内核传递启动参数,告诉内核将来要挂接的根文件系统在哪里 ->uboot从内存启动内核->内核正式运行,uboot生命结束 ->内核也是一个大程序,玩命的各种七大子系统初始化->内核最后根据bootargs来到某个地方挂接根文件系统 ->一旦挂接成功,内核启动根文件系统/sbin/init第一号 进程->init第一个号进程运行,第一号进程打开etc/inittab配置文件,init进程首先找到inittab文件中的sysinit关键字 一旦找到此关键字,init进程创建一个子进程->子进程执行 sysinit指定的脚本/etc/init.d/rcS,父进程init等待子进程结束->子进程执行完rcS脚本以后,父进程init继续执行->init第一号进程继续在inittab文件中找respawn关键字找到以后,同样init再次创建一个子进程来执行respawn关键字指定的程序/bin/sh,至此启动了一个shell程序用户可以输入各种命令,父进程init继续等待子进程的结束。
6.2.系统启动必要的脚本文件rcS
mkdir _install/etc/init.d
vim _install/etc/init.d/rcS 添加如下内容
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
/bin/hostname ljw
mount -a
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
/bin/hotplug
ifconfig eth0 192.168.1.10
PATH //导出环境变量,就是你运行的应用程序的时候,操作系统在环境变量的目录中寻找应用程序
runlevel=S //设置操作系统处于单用户模式、
umask 022 //(1)umask是Linux的一个命令,作用是设置Linux系统的umask值,(2)umask值决定当前用户的权限。
/bin/hostname ljw //设置机器名字ljw
mount -a //挂载所有的设备驱动程序
echo /sbin/mdev > /proc/sys/kernel/hotplug
//调用mdev管理程序动态的创建插拔设备。kernel在每次设备出现变动时调用上面一句传递进去的用户空间应用程序/sbin/mdev来处理对应的信息,进而mdev操作/dev目录下的设备,进行添加或删除
mdev -s //内核就可以在/dev目录下自动创建设备节点
ifconfig eth0 192.168.1.10 //设置本机IP地址(有网卡的话)
保存退出
chmod 777 etc/init.d/rcS
6.3.系统启动必要配置文件fstab(file system table)
vim _install/etc/fstab 添加如下内容
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
保存退出。
说明:
以上三句话跟驱动自动创建设备文件相关!/proc,/sys,/dev三大必要目录下的内容都是内核自己创建,无需程序员关注,并且这三大必要目录下的内容都是存在于内存中,掉电会丢失!
将procfs虚拟文件系统挂接到/proc必要目录,将来访问/proc目录下的内容就是在访问procfs虚拟文件系统
将sysfs虚拟文件系统挂接到/sys必要目录,将来访问/sys目录下的内容就是在访问sysfs虚拟文件系统
将tmpfs虚拟文件系统挂接到/dev必要目录,将来访问/dev目录下的内容就是在访问tmpfs虚拟文件系统
cd _install/
arm-cortex_a9-linux-gnueabi-strip lib/*
du /opt/rootfs -lh
总结:
产品研发阶段,不要进行strip优化体积,否则不能进行调试
产品发布阶段,必须strip优化体积
至此:最小根文件系统rootfs制作完毕