跳转至

根文件系统构建

概述

根文件系统(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
1
2
3
4
5
6
7
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
1
2
3
4
5
6
7
8
9
# 克隆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
1
2
3
4
5
6
7
# 将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
1
2
3
4
5
6
::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
1
2
3
4
5
# <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

Text Only
root:x:0:

/etc/shells

Text Only
/bin/sh
/bin/ash

共享库处理

查找依赖库

Bash
1
2
3
4
5
6
7
# 查看程序依赖的库
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
1
2
3
4
5
# 查找动态链接器
arm-linux-gnueabihf-readelf -l busybox | grep interpreter

# 复制动态链接器
cp /path/to/toolchain/lib/ld-linux-*.so* $ROOTFS/lib/

库加载器配置

Bash
1
2
3
4
5
6
# 创建/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
1
2
3
4
5
# 安装mtd-utils
sudo apt install mtd-utils

# 生成JFFS2镜像
mkfs.jffs2 -r $ROOTFS -o rootfs.jffs2 -e 0x10000 --pad=0x400000

UBIFS镜像(用于Flash)

Bash
1
2
3
4
5
# 生成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
1
2
3
4
5
6
7
[ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize

CPIO镜像(用于initramfs)

Bash
1
2
3
4
5
6
7
8
# 生成cpio镜像
cd $ROOTFS
find . | cpio -o -H newc > ../rootfs.cpio

# 压缩
gzip ../rootfs.cpio
# 或
lzma ../rootfs.cpio

使用initramfs

内核配置

Text Only
1
2
3
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
1
2
3
4
5
6
7
8
# 安装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
1
2
3
4
5
# 编译程序
arm-linux-gnueabihf-gcc -static -o myapp myapp.c

# 复制到rootfs
cp myapp $ROOTFS/usr/bin/

动态编译程序

Bash
1
2
3
4
5
6
# 编译程序
arm-linux-gnueabihf-gcc -o myapp myapp.c

# 复制程序和依赖库
cp myapp $ROOTFS/usr/bin/
# 复制依赖库到$ROOTFS/lib/

最小化优化

使用BusyBox替换完整工具

Bash
1
2
3
# BusyBox已包含常用命令
ls -la $ROOTFS/bin/
# 大部分命令都是BusyBox的符号链接

删除不需要的文件

Bash
1
2
3
4
5
6
7
8
# 删除调试符号
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
1
2
3
# 设置正确的权限
sudo chown -R root:root $ROOTFS
sudo chmod 755 $ROOTFS/bin $ROOTFS/sbin

参考资料