嵌入式linux根文件系统制作--busybox

busybox是构造文件系统最常用的软件工具包,它被非常形象地称为嵌入式Linux系统中的“瑞士军刀”,因为它将许多常用的Linux命令和工具结合到了一个单独的可执行程序(busybox)中。
虽然与相应的GNU工具比较起来,busybox所提供的功能和参数略少,但在比较小的系统(例如启动盘)或者嵌入式系统中已经足够了。
busybox在设计上就充分考虑了硬件资源受限的特殊工作环境。它采用一种很巧妙的办法减少自己的体积:所有的命令都通过“插件”的方式集中到一个可执行文件中,在实际应用过程中通过不同的符号链接来确定到底要执行哪个操作。采用单一执行文件的方式最大限度地共享了程序代码,甚至连文件头、内存中的程序控制块等其他系统资源都共享了,对于资源比较紧张的系统来说,真是最合适不过了。在busybox的编译过程中,可以非常方便地加减它的“插件”,最后的符号链接也可以由编译系统自动生成。

目的:

理清楚 根文件系统的制作流程。所以,这里不纠结细节。

系统环境及工具:

操作系统:Ubuntu12.04
交叉编译工具:arm-linux-gcc4.4.3
busybox源码包:busybox-1.25.0.tar.bz2

根文件系统制作–busybox配置编译安装:

动态链接的busybox只有几百K,即使静态链接的也只有1MB左右。
在创建一个最小的根文件系统时,使用busybox的话,只需要在/dev目录下创建必要的设备节点、在/etc目录下创建一些配置文件就可以了;如果busybox使用动态链接的话,还需要在/lib目录下包含库文件。
这里选择动态链接。

解压源码包:

#tar -jxvf busybox-1.25.0.tar.bz2

修改Makefile配置

进入busybox-1.25.0目录,修改Makefile文件如下:

ARCH ?= arm
CROSS_COMPILE ?= /usr/local/arm/4.4.3/bin/arm-linux- (与你自己主机的arm-linux-gcc安装目录一样)

配置BusyBox

#make menuconfig

Busybox Settings —>
Build Options —>
[*]Build shared libbusybox
[ ] Produce a binary for each applet, linked against libbusybox
[ ] Produce additional busybox binary linked against libbusybox

Busybox Settings —>
Installation Options (“make install” behavior) —>
(/nfsdir/tools/rootfs) BusyBox installation prefix // 编译生成文件的存放路径
注意:如果你是在虚拟机上安装busybox,安装不可直接执行make INSTALL,必须在虚拟机下自己创建一个文件夹,将安装路径指向这个文件夹的路径。再执行 make CONFIG_PREFIX=/path/from/root install 否则会破坏系统。
其他都保持默认
关于需要注意的一些选项说明如下:
Busybox Settings —>
Build Options —>
[ ] Build BusyBox as a static binary (no shared libs) (NEW)
这个意思是运行busybox才动态链接库,busybox需要的库要我们提供

Busybox Settings —>
Installation Options (“make install” behavior) —>
What kind of applet links to install (as soft-links) —>
设置busybox生成后各种命令均为指向busybox主程序的软链接

Busybox Settings —>
Busybox Library Tuning —>
(255) History size
[*] History saving (NEW) // 支持历史记录
[*] Tab completion (NEW) // 支持Tab补全操作

选项Applets就是将busybox支持的几百个命令分门别类,我们可以在各个门类下选择想要的命令。

编译安装

#make
#make install

构建根文件系统

至此busubox的安装就完成了,现在查看/nfsdir/tools/rootfs文件夹,会发现多了下面几个文件:
bin linuxrc sbin usr
可以在bin目录查看,busybox只有970K

创建其他所需文件夹(根据FHS标准)

mkdir dev etc home lib media mnt opt proc sys tmp var root

添加相应的库

需要添加的库是从编译busybox所使用的交叉编译工具里拷贝的,但交叉编译工具里的库文件很多,不必全部拷贝。
那么我们怎么知道哪些库是需要的呢?
可以用一下方法确定

[root@localhost bin]# arm-linux-readelf -d busybox 
Dynamic section at offset 0xf16b4 contains 25 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

而ld-linux.so.3属于固有需要的库,所以busybox至少需要三个库:ld-linux.so.3、libm.so.6、libc.so.6

下面要睁大眼睛了,上面的库都是链接文件,不要把链接文件拷进去了,真正的文件没拷贝
[root@localhost lib]# ls -l libc.so.6
lrwxrwxrwx 1 root root 11 Apr 23 21:13 libc.so.6 -> libc-2.8.so

[root@localhost lib]# ls -l libm.so.6
lrwxrwxrwx 1 root root 11 Apr 23 21:13 libm.so.6 -> libm-2.8.so

[root@localhost lib]# ls -l ld-linux.so.3
lrwxrwxrwx 1 root root 9 Apr 23 21:13 ld-linux.so.3 -> ld-2.8.so

所以要把ld-linux.so.3、libm.so.6、libc.so.6和libc-2.8.so、libm-2.8.so、ld-2.8.so都拷贝到/lib下。
但是上面的这几个库只是busybox运行所需要的库,这个时候系统虽然可以启动,但会出现下面的打印信息:

feed_wdg: error while loading shared libraries: libgcc_s.so.1: cannot open shared object file: No such file or directory

这个意思是由于缺少libgcc_s.so.1库,导致看门狗程序启动不了,然后看到开发板过以后重启了,所以要想正常运行还需要拷贝libgcc_s.so和libgcc_s.so.1

但是实际使用的时候要一个一个去查看嘛,这样太麻烦了,所以一般把正常需要的库都拷贝到/lib下,这样也不会太大,包括:
ld-linux:动态链接库,必需
libc: 标准c函数库,必需
libm: 数学库,一般需要
libdl: 用于动态装载共享库,较少用到
libcrypt: 加密附加库,需要认证的程序用到,较少用
libpthread: POSIX线程库,一般需要

添加配置文件(即/etc下的文件)

1、添加inittab文件:
仿照busybox的example/inittab文件,创建/linuxrc的初始化配置文件/etc/inittab
该文件中指定linuxrc初始化完成后运行/etc/init.d.rcS脚本。然后在console运行一个shell,该shell不需要登陆。

# /etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::once:/usr/sbin/telnetd -l /bin/login
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

2、添加init.d/rcS文件

#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH
#
#       Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
mount -a                            # 挂载在/etc/fstab中定义的所有挂载点
mkdir -p /dev/pts                   #为telnetd创建pts目录
mount -t devpts devpts /dev/pts     #挂载pts目录
echo /sbin/mdev > /proc/sys/kernel/hotplug # 设置热插拔事件处理程序为mdev
mdev -s                             #设备节点维护程序mdev初始化
mkdir -p /var/lock

hwclock -s
feed_wdg &

ifconfig lo 127.0.0.1           
ifconfig eth0 192.168.2.99

/bin/hostname -F /etc/HOSTNAME

3、添加HOSTNAME文件,
内容就是代表主机名,可以随意定,如:
Blue
4、添加fstab文件:

#device         mount-point     type    options         dump    fsck order
proc            /proc           proc    defaults                0       0
tmpfs           /tmp            tmpfs   defaults                0       0
sysfs           /sys            sysfs   defaults                0       0
tmpfs           /dev            tmpfs   defaults                0       0
var             /dev            tmpfs   defaults                0       0
ramfs           /dev            ramfs   defaults                0       0

5、添加profile文件
根据inittab文件的内容console::askfirst:-/bin/sh,
在启动脚本etc/init.d/rcS执行完后将在终端启动一个shell。Shell启动过程中会根据文件/etc/profile配置登陆环境。
所以需要添加profile文件,内容如下:

USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h \W]# '      # 这个显示的是命令行下的主机名和用户名格式,如:[root@Blue etc]#
PATH=$PATH

HOSTNAME=`/bin/hostname`

export USER LOGNAME PS1 PATH

6、添加group和passwd文件:
group内容如下:

root:x:0:root

passwd内容如下:

root::0:0:root:/:/bin/sh

到此/etc配置完毕,包含如下:
HOSTNAME fstab group init.d inittab passwd profile

在/dev/下创建设备节点:

mknod console c 5 1
mknod null c 1 3

至此,/nfsdir/tools/rootfs目录下就是一个非常小的根文件系统,开发板可以将它作为网络根文件系统直接启动。如果要烧入开发板,还需要将它制作为一个文件,称为映像文件。
所谓制作文件系统映像文件,就是将一个目录下的所有内容,按照一定的格式存放到一个文件中,这个文件可以直接烧写到存储设备上去。当系统启动后,挂接这个设备,就可以看到与原来目录一致的内容。
制作不同类型的文件系统映像文件,需要使用不同的工具。

制作yaffs2文件系统映像文件

进入到/nfsdir/tools/(根文件系统的上次目录)

[root@localhost tools]# mkyaffs2image rootfs root.bin  /* mkyaffs2image工具是交叉编译工具自带的*/

生成的root.bin镜像可直接拷贝到nand flash的文件系统分区,接下来就可以直接启动了

制作jffs2文件系统映像文件

mkfs.jffs2 -n -s 512 -e 16KiB -d rootfs -o root.jffs2

命令中,“-n”表示不要在每个擦除块上都加上清除标志,“-s 512”指明一页大小为512字节,“-e 16KiB”指明一个擦除块大小为16KB,“-d”表示根文件系统目录,“-o”表示输出文件。

上面只是制作了一个最简单的文件系统,实际可以根据自己的需要添加启动程序、丰富自己的配置及功能等

编译错误解决参考

1、make出现如下错误:

miscutils/nandwrite.c: In function 'nandwrite_main':
miscutils/nandwrite.c:151: error: 'MTD_FILE_MODE_RAW' undeclared (first use in this?function)
miscutils/nandwrite.c:151: error: (Each undeclared identifier is reported only once
miscutils/nandwrite.c:151: error: for each function it appears in.)
scripts/Makefile.build:197: recipe for target 'miscutils/nandwrite.o' failed
make[1]: *** [miscutils/nandwrite.o] Error 1
Makefile:742: recipe for target 'miscutils' failed
make: *** [miscutils] Error 2

解决办法:

MTD_FILE_MODE_RAW在/usr/include/mtd/mtd-abi.h中定义。将/usr/include/mtd/mtd-abi.h拷贝到busybox的include文件中。

#gedit miscutils/nandwrite.c 

修改头文件如下:

#include "libbb.h"
#include "mtd-abi.h"
#include <mtd/mtd-user.h>

编译可以通过。

2、继续make,出现如下错误:

util-linux/blkdiscard.c: In function 'blkdiscard_main':
util-linux/blkdiscard.c:72: error: 'BLKSECDISCARD' undeclared (first use in this function)
util-linux/blkdiscard.c:72: error: (Each undeclared identifier is reported only once
util-linux/blkdiscard.c:72: error: for each function it appears in.)
scripts/Makefile.build:197: recipe for target 'util-linux/blkdiscard.o' failed
make[1]: *** [util-linux/blkdiscard.o] Error 1
Makefile:742: recipe for target 'util-linux' failed
make: *** [util-linux] Error 2

解决办法:
BLKSECDISCARD在/usr/include/linux/fs.h中定义,方法如上所述,将/usr/include/linux/fs.h拷贝到busybox的include文件中linux下。

#gedit util-linux/blkdiscard.c

修改内容如下:

#include <linux/fs.h>

编译通过。

到这里rootfs基本上已经制作出来,有些内容需要的,可根据自己rootfs的需要进行自己增加。最后将rootfs目录制作成镜像后,就可以烧写到开发板上了。

后记:

inittab文件格式:

<id>:<runlevels>:<action>:<process>: 在什么时间启动什么进程

当id 和runlevels为空时,就会出现::双冒号的形式
id: 进程所使用的终端名
runlevels:不用填写
action: 是程序执行的时机,包括:sysinit, respawn, askfirst, wait, once, restart, ctrlaltdel, and shutdown.\等
process:将要执行的应用程序或脚本;
sysinit: 系统初始化的时候,放在最前面
respawn,askfirst是一样的,如果process意外终止啦,系统会讲其重启
askfirst 会有提示Please press Enter to activate this console
wait: 该进程一定要执行完,才能执行下一个
once, 进程如果意外终止,那么不会重启

猜你喜欢

转载自blog.csdn.net/guozhongwei1/article/details/79962358