嵌入式Linux系统中根文件系统构建方式

简介: 嵌入式Linux系统中根文件系统构建方式

1. 根文件系统布局


9424f9a799cb4fab82d0279ee1ac12d3.png

嵌入式 Linux 根文件系统布局,建议还是按照FHS标准来安排,事实上大多数嵌入式Linux都是这样做的。但是,嵌入式系统可能并不需要桌面/服务器那样庞大系统的全部目录,可以酌情对系统进行精简,以简化Linux的使用。如嵌入式Linux文件系统中通常不会放置内核源码,因而存的 常不会放置内核源码,因而存的 常不会放置内核源码,因而存放源码的/usr/src目录是不必要的, 甚至连头文件也不需要,即/usr/include目录也不必要;但是/bin、/dev 、/etc、/lib 、/proc 、/sbin、/usr几个目录是不可或缺的。

所以,允许嵌入式 Linux 对系统目录结构进行精简,以适应具体用场合的需求,一个典型的嵌入式Linux根文件系统目录如下所示:

2aa4c379b104e1407167a18331a65cda.png

要构建一个可用的Linux根文件系统,需要的二进制和库都不少,完全从零开始也是不现实的,推荐参考其它现有可用的文件系统,在原基础上按需修改;或者使用文件系统制作工具如 BusyBox 来实现文件系统的生成。


2. 使用BusyBox生成二进制工具


2.1. 获取BusyBox源码

Busybox的官方源码下载路径为:https://busybox.net/downloads/。这里以下载busybox-1.29.3.tar.bz2为例。


2.2. 配置BusyBox

解压源码,进入根目录

$ tar jxvf busybox-1.29.3.tar.bz2
$ cd busybox-1.29.3/


首先,执行:

$ make menuconfig


进入图形化配置界面:

4aaba8953453c58a8fb66839a5da1c03.png

2.2.1.选择编译静态库

进入Settings --->使用空格键选择编译静态库

--- Build Options                                             
[*] Build static binary (no shared libs)  


如图:

e977563b2f1063600ade15fdc6b990bb.png


2.2.2.选择交叉编译工具链

在Settings ---> 设置项下,填写交叉编译工具链前缀

1056a211f4a8b65a2bdfe00966c8870e.png


2-2-3. 选择安装目录

在Settings --->设置项下,找到

--- Installation Options ("make install" behavior) 
    What kind of applet links to install (as soft-links)  --->  
(./_install) Destination path for 'make install' (NEW)  


默认为当前目录下目录,这里我使用默认_install目录:

39612d54063afeb416544312fb69621d.png


2-2-4. 编译安装

退出保存后,执行编译make,大概几分钟后编译完成,执行make install,很快就会安装完成:

2f8c9c7da591d3d48f5d044b6163e983.png

入_install目录,查看生成的文件

242cd0703ed349f00150f6346f11bcb8.png

新建一个目录用来存放制作的根文件系统,可以命名为rootfs。将利用BusyBox生成的二进制文件及目录,即_install目录下的所有文件及目录复制到rootfs目录下。


3. 构建根文件系统


使用BusyBox编译后,仅有 bin、sbin、usr这 3个目录和软链接linuxrc,目录里都是二进制命令工具,这还不足以构成 一个可用的根文件系统,必须进行其它完善工作,才能构建一个可用的根文件系统。


3-1. 完善目录结构

根据典型嵌入式Linux根文件系统目录,在rootfs目录中创建其他目录

$ mkdir dev etc lib proc sys tmp var


3-2. 添加C运行库文件

库文件可直接从交叉工具链获取,一般在工具链的libc/lib/目录下。我这里是在ubuntu下安装的Linaro的交叉工具链:

444814a6af6a0f08c6ee8b43da61c51a.png

库文件是在/usr/arm-linux-gnueabihf/lib/目录下,拷贝动态链接库文件(.so文件)到新制作的根文件系统根目录下/lib目录里:

$ cp -a  /usr/arm-linux-gnueabihf/lib/*so* ./lib/


47a29b2b3322492ec93818aa72089da4.png

这里只是拷贝动态链接库。一般开发程序使用动态编译需要板子上动态库的支持才能运行,所以拷贝动态库。而静态库一般在静态编译的时候用到,由于交叉编译的工作放在了PC上所以板子上不需要静态库,所以没有必要拷贝,这样还可以减小根文件系统的体积。

一般使用gcc编译后的可执行文件、目标文件和动态库都带有调试信息和符号信息,这些在调试的时候用到,但是却增大了文件的大小。通常在PC上调试,或者调试时使用这些带有调试信息和符号信息的库文件,程序发布后使用去掉这些信息的库文件,可以大大缩小根文件系统的体积。这里我们去掉这些信息,方法是使用strip工具:

$ arm-linux-gnueabihf-strip ./*


3-3. 添加初始化配置脚本

初始化配置脚本放在在/etc目录下,用于系统启动所需的初始化配置脚本。BusyBox提供了一些初始化范例脚本,在examples/bootfloppy/etc/目录下。将这些配置文件复制到 ”目录下。将这些配置文件复制到 ”目录下。将这些配置文件复制到新制作的根文件系统etc目录下

cp -a ../busybox/busybox-1.29.3/examples/bootfloppy/etc/* etc/


添加后如图所示:

c97ae1bdae588f5130ce44558a4c085a.png

3-3-1. 修改/etc/inittab文件

/etc/inittab文件是init进程解析的配置文件,通过这个配置文件决定执行哪个进程,何时执行。将文件修改为:

# 系统启动时
::sysinit:/etc/init.d/rcS
# 系统启动按下Enter键时
::askfirst:-/bin/sh
# 按下Ctrl+Alt+Del键时
::ctrlaltdel:/sbin/reboot
# 系统关机时
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
# 系统重启时
::restart:/sbin/init


以上内容定义了系统启动时,关机时,重启时,按下Ctrl+Alt+Del键时执行的进程。

3-3-2. 修改/etc/init.d/rcS文件

#! /bin/sh
# 挂载 /etc/fstab 中定义的所有文件系统
/bin/mount -a
# 挂载虚拟的devpts文件系统用于用于伪终端设备
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 使用mdev动态管理u盘和鼠标等热插拔设备
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
# 扫描并创建节点
/sbin/mdev -s


3-3-3. 修改/etc/fstab文件

/etc/fstab文件存放的是文件系统信息。在系统启动后执行/etc/init.d/rcS文件里/bin/mount -a命令时,自动挂载这些文件系统。内容如下:

# <file system>    <mount point>    <type>    <options>    <dump>    <pass>     
proc                  /proc          proc     defaults       0         0
sysfs                 /sys           sysfs    defaults       0         0
tmpfs                 /tmp           tmpfs    defaults       0         0
tmpfs                 /dev           tmpfs    defaults       0         0


注:这里我们挂载的文件系统有三个proc、sysfs和tmpfs,在内核中proc和sysfs默认都支持,而tmpfs是没有支持的,我们需要添加tmpfs的支持。


3-3-4. 修改/etc/profile文件

/etc/profile文件作用是设置环境变量,每个用户登录时都会运行它。将文件内容修改为:

# 主机名
export HOSTNAME=zyz
# 用户名
export USER=root
# 用户目录
export HOME=/root
# 终端默认提示符
export PS1="[$USER@$HOSTNAME:\$PWD]\# "    
# 环境变量
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
# 动态库路径
export LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH


因为指定了root用户的家目录为/root,所以需要创建该目录,否则执行cd ~时会失败

$ mkdir root


登录系统后效果为:

...
Please press Enter to activate this console.
[root@zyz:/]#
[root@zyz:/]# cd ~
[root@zyz:/root]#
[root@zyz:/root]# echo $PATH
/bin:/sbin:/usr/bin:/usr/sbin


至此,根文件系统就基本构建好了。


4. 制作根文件系统镜像


4-1. 根文件系统类型

如果文件系统已经布局完成, 则可以发到目标中了。通常会制作一个镜像然后通过某种方式固化到目标系统中,具体采用什么样的形发布需要根据资源状况、内核情况和系统需求等方面进行裁决:

(1)硬件方面,至少需要考虑主存储介质的类型和大小如Flash是NOR Flash还是NAND Flash,RAM的大小等。

(2)内核方面, 则需考虑所裁剪后的支持哪些文件系统采用中最合适, 能满足性、速度等要求。

(3)系统需求方面,要考虑运行速度、是否可写压缩等因素。常见的可用于根文件系统类型有ramdisk 、cramfs、jffs2 、yaffs/yaffs2和ubifs等,各类型的特性如表所列。

2769ae7ea88a533b390e117aedff7601.png

尽管文件系统固件以某一种文件系统的镜像发布,但是整个文件系统实际上还是并存多种逻辑文件系统的。例如,一个系统根文件系统以ubifs挂载,但是/dev目录却是以tmpfs挂载的、/sys目录挂载的是sysfs文件系统。现在,似乎ubifs是一种趋势。


4-2. 制作UBIFS根文件系统镜像

Linux下制作UBIFS的命令有两个,mkfs.ubifs和ubinize。mkfs.ubifs,将一个目录制作为UBIFS文件系统。使用范例:

$ mkfs.ubifs -m 2048 -e 128KiB -c 4096 -r ./rootfs -o rootfs.ubifs


其中:

-r, -d, --root=DIR       build file system from directory DIR(目录)
-m, --min-io-size=SIZE   minimum I/O unit size(最小输入输出单元大小)
-e, --leb-size=SIZE      logical erase block size(逻辑擦除块大小)
-c, --max-leb-cnt=COUNT  maximum logical erase block count(最大逻辑擦除块数目)
-o, --output=FILE        output to FILE(输出文件)


所以制作ubifs镜像文件,需要知道3个关键参数,即最小输入输出单元大小,逻辑擦除块大小,最大逻辑擦除块数目,其中最大逻辑擦除块数目可由Flash分区大小和逻辑擦除块大小计算出来,这些信息可以通过u-boot命令查看:

=> mtdparts default
=> ubi part rootfs


ubinize,将mkfs.ubifs制作的UBIFS文件系统制作成含有卷标的可以直接烧写在Flash上的镜像。使用范例:

$ ubinize -m 2048 -p 128KiB ubinize.cfg -o rootfs_ubifs.img


其中:

-o, --output=<file name>     output file name(输出文件)
-p, --peb-size=<bytes>       size of the physical eraseblock of the flash(物理擦除块大小)
                             this UBI image is created for in bytes,
                             kilobytes (KiB), or megabytes (MiB)
                             (mandatory parameter)
-m, --min-io-size=<bytes>    minimum input/output unit size of the flash
                             in bytes


这里需要两个参数物理擦除块大小和最小输入输出单元大小。ubinize.cfg是配置文件,内容如下:

[ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_size=1024MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize


说明:

[ubifs]
mode=ubi
image=rootfs.ubifs       # mkfs.ubi生成的源镜像 
vol_id=0                 # 卷号
vol_size=1024MiB         # 卷大小,一般要设置的比分区大,防止有坏块
vol_type=dynamic         # 卷类型,动态卷
vol_name=rootfs          # 卷名,rootfs
vol_flags=autoresize     # 自动大小


目录
相关文章
|
1天前
|
存储 缓存 数据管理
深入理解 Linux 文件系统的层次结构
【4月更文挑战第30天】 本文旨在探讨和解析 Linux 操作系统中文件系统的结构与原理。不同于通常的摘要,我们将直接深入到文件系统的核心概念,包括其目录结构、关键组件以及它们如何相互作用以支持 Linux 操作系统的功能。通过剖析文件系统的层次性设计,我们能够更好地理解其在数据管理、用户权限控制和系统安全性方面的重要性。
|
1天前
|
Web App开发 监控 Unix
Linux 常用命令汇总(七):进程管理 & 系统权限 & 用户授权
Linux 常用命令汇总(七):进程管理 & 系统权限 & 用户授权
|
1天前
|
存储 Linux
深入探索Linux文件系统:属性、路径与隐藏之谜
深入探索Linux文件系统:属性、路径与隐藏之谜
11 1
|
1天前
|
存储 Unix Linux
【Linux系统编程】基础指令(三)
【Linux系统编程】基础指令(三)
|
1天前
|
Linux
【Linux系统编程】基础指令(二)(下)
【Linux系统编程】基础指令(二)
|
1天前
|
Linux C语言
【Linux系统编程】基础指令(二)(上)
【Linux系统编程】基础指令(二)
|
1天前
|
Linux
【Linux系统编程】基础指令(一)(下)
【Linux系统编程】基础指令(一)
|
21天前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
112 0
|
8月前
|
缓存 Ubuntu Linux
Vim编辑器入门指南:安装、基本操作和高级技巧详解 | 适用于Linux系统
Vim编辑器入门指南:安装、基本操作和高级技巧详解 | 适用于Linux系统
298 0
|
8天前
|
Linux 开发工具 Android开发
Docker系列(1)安装Linux系统编译Android源码
Docker系列(1)安装Linux系统编译Android源码
14 0