根文件系统构建
概述
根文件系统(Root Filesystem)是Linux系统启动后挂载的第一个文件系统,包含系统运行所需的所有文件和目录结构。
文件系统目录结构
| Text Only |
|---|
| / 根目录
├── bin 用户命令(所有用户可用)
├── sbin 系统管理命令
├── lib 共享库
├── etc 配置文件
├── dev 设备文件
├── proc 进程信息(虚拟文件系统)
├── sys 系统信息(虚拟文件系统)
├── tmp 临时文件
├── var 可变数据
├── usr 用户程序
│ ├── bin 用户应用程序
│ ├── lib 应用库
│ └── share 共享数据
├── home 用户主目录
└── root root用户主目录
|
构建方法
方法一:BusyBox构建
BusyBox是一个集成了常用Linux命令的工具集,适合构建最小文件系统。
| Bash |
|---|
| # 下载BusyBox
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xvf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
# 配置BusyBox
make defconfig # 默认配置
make menuconfig # 自定义配置
# 静态编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- install
|
BusyBox配置选项:
| Text Only |
|---|
| Busybox Settings --->
General Configuration --->
[*] Don't use /usr
Build Options --->
[*] Build static binary (no shared libs) # 静态编译
Installation Options --->
(./_install) BusyBox installation prefix
|
方法二:Buildroot构建
Buildroot是一个自动化构建工具,可生成完整的嵌入式Linux系统。
| Bash |
|---|
| # 下载Buildroot
wget https://buildroot.org/downloads/buildroot-2023.11.tar.gz
tar xvf buildroot-2023.11.tar.gz
cd buildroot-2023.11
# 配置
make menuconfig
# 编译
make
|
Buildroot配置:
| Text Only |
|---|
| Target options --->
Target Architecture (ARM (little endian))
Target Architecture Variant (cortex-A7)
Toolchain --->
Toolchain type (External toolchain)
Toolchain (Custom toolchain)
System configuration --->
Root filesystem type (ext2/3/4)
Filesystem images --->
[*] ext2/3/4 root filesystem
ext2/3/4 variant (ext4)
|
方法三:Yocto构建
Yocto项目提供了一套完整的嵌入式Linux构建框架。
| Bash |
|---|
| # 克隆Yocto
git clone git://git.yoctoproject.org/poky
cd poky
# 初始化环境
source oe-init-build-env
# 编译
bitbake core-image-minimal
|
手动构建根文件系统
创建目录结构
| Bash |
|---|
| ROOTFS=/path/to/rootfs
mkdir -p $ROOTFS/{bin,sbin,lib,etc,dev,proc,sys,tmp,var,usr,home,root}
# 创建usr子目录
mkdir -p $ROOTFS/usr/{bin,lib,sbin,share}
# 创建设备节点
mkdir -p $ROOTFS/dev
sudo mknod $ROOTFS/dev/console c 5 1
sudo mknod $ROOTFS/dev/null c 1 3
sudo mknod $ROOTFS/dev/zero c 1 5
sudo mknod $ROOTFS/dev/tty c 5 0
sudo mknod $ROOTFS/dev/tty0 c 4 0
sudo mknod $ROOTFS/dev/tty1 c 4 1
|
安装BusyBox
| Bash |
|---|
| # 将BusyBox安装到rootfs
cp -r busybox-1.36.1/_install/* $ROOTFS/
# 创建符号链接(如果使用动态编译)
# 复制共享库
arm-linux-gnueabihf-readelf -d $ROOTFS/bin/busybox | grep NEEDED
cp /path/to/toolchain/lib/*.so* $ROOTFS/lib/
|
配置文件
/etc/inittab
| Text Only |
|---|
| ::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
::shutdown:/bin/umount -a -r
::shutdown:/bin/sync
|
/etc/init.d/rcS
| Bash |
|---|
| #!/bin/sh
# 挂载虚拟文件系统
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
# 创建设备节点
mkdir -p /dev/pts
mount -t devpts none /dev/pts
# 配置网络
ifconfig lo 127.0.0.1 up
ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up
# 启动服务
echo "Welcome to Embedded Linux"
|
| Bash |
|---|
| chmod +x $ROOTFS/etc/init.d/rcS
|
/etc/fstab
| Text Only |
|---|
| # <device> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devtmpfs /dev devtmpfs defaults 0 0
/dev/mmcblk0p2 / ext4 defaults 0 1
|
/etc/passwd
| Text Only |
|---|
| root:x:0:0:root:/root:/bin/sh
|
/etc/group
/etc/shells
共享库处理
查找依赖库
| Bash |
|---|
| # 查看程序依赖的库
arm-linux-gnueabihf-readelf -d busybox | grep NEEDED
# 复制所有依赖库
for lib in $(arm-linux-gnueabihf-readelf -d busybox | grep NEEDED | awk '{print $5}' | tr -d '[]'); do
find /path/to/toolchain -name "$lib" -exec cp {} $ROOTFS/lib/ \;
done
|
复制动态链接器
| Bash |
|---|
| # 查找动态链接器
arm-linux-gnueabihf-readelf -l busybox | grep interpreter
# 复制动态链接器
cp /path/to/toolchain/lib/ld-linux-*.so* $ROOTFS/lib/
|
库加载器配置
| Bash |
|---|
| # 创建/etc/ld.so.conf
echo "/lib" > $ROOTFS/etc/ld.so.conf
echo "/usr/lib" >> $ROOTFS/etc/ld.so.conf
# 运行ldconfig(需要交叉编译版本)
ldconfig -r $ROOTFS
|
文件系统镜像制作
ext2/ext3/ext4镜像
| Bash |
|---|
| # 创建空镜像文件
dd if=/dev/zero of=rootfs.ext4 bs=1M count=64
# 格式化
mke2fs -t ext4 rootfs.ext4
# 挂载并复制
sudo mount -o loop rootfs.ext4 /mnt
sudo cp -r $ROOTFS/* /mnt/
sudo umount /mnt
# 或使用工具直接生成
genext2fs -b 65536 -d $ROOTFS rootfs.ext4
|
JFFS2镜像(用于Flash)
| Bash |
|---|
| # 安装mtd-utils
sudo apt install mtd-utils
# 生成JFFS2镜像
mkfs.jffs2 -r $ROOTFS -o rootfs.jffs2 -e 0x10000 --pad=0x400000
|
UBIFS镜像(用于Flash)
| Bash |
|---|
| # 生成UBIFS镜像
mkfs.ubifs -r $ROOTFS -o rootfs.ubifs -m 2048 -e 126KiB -c 4096
# 创建UBI镜像
ubinize -o rootfs.ubi -m 2048 -p 128KiB -s 2048 ubinize.cfg
|
ubinize.cfg:
| INI |
|---|
| [ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize
|
CPIO镜像(用于initramfs)
| Bash |
|---|
| # 生成cpio镜像
cd $ROOTFS
find . | cpio -o -H newc > ../rootfs.cpio
# 压缩
gzip ../rootfs.cpio
# 或
lzma ../rootfs.cpio
|
使用initramfs
内核配置
| Text Only |
|---|
| General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/path/to/rootfs.cpio.gz) Initramfs source file(s)
|
启动参数
| Text Only |
|---|
| bootargs=console=ttyS0,115200 rdinit=/sbin/init
|
NFS根文件系统
服务端配置
| Bash |
|---|
| # 安装NFS服务
sudo apt install nfs-kernel-server
# 配置导出目录
echo "/path/to/rootfs *(rw,sync,no_root_squash,no_subtree_check)" >> /etc/exports
# 重启NFS服务
sudo systemctl restart nfs-kernel-server
|
客户端启动参数
| Text Only |
|---|
| bootargs=console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.1:/path/to/rootfs ip=192.168.1.100:192.168.1.1:192.168.1.1:255.255.255.0::eth0:off
|
添加应用程序
静态编译程序
| Bash |
|---|
| # 编译程序
arm-linux-gnueabihf-gcc -static -o myapp myapp.c
# 复制到rootfs
cp myapp $ROOTFS/usr/bin/
|
动态编译程序
| Bash |
|---|
| # 编译程序
arm-linux-gnueabihf-gcc -o myapp myapp.c
# 复制程序和依赖库
cp myapp $ROOTFS/usr/bin/
# 复制依赖库到$ROOTFS/lib/
|
最小化优化
使用BusyBox替换完整工具
| Bash |
|---|
| # BusyBox已包含常用命令
ls -la $ROOTFS/bin/
# 大部分命令都是BusyBox的符号链接
|
删除不需要的文件
| Bash |
|---|
| # 删除调试符号
find $ROOTFS -name "*.so*" -exec strip {} \;
find $ROOTFS/bin -type f -exec strip {} \;
# 删除文档
rm -rf $ROOTFS/usr/share/doc
rm -rf $ROOTFS/usr/share/man
rm -rf $ROOTFS/usr/share/info
|
常见问题
启动失败:Kernel panic
| Text Only |
|---|
| Kernel panic - not syncing: VFS: Unable to mount root fs
|
解决:检查内核是否支持根文件系统类型、启动参数是否正确
缺少库文件
| Text Only |
|---|
| error while loading shared libraries: libxxx.so.1
|
解决:复制缺少的库到/lib目录
权限问题
| Bash |
|---|
| # 设置正确的权限
sudo chown -R root:root $ROOTFS
sudo chmod 755 $ROOTFS/bin $ROOTFS/sbin
|
参考资料