构建基本的嵌入式Linux根文件系统
来源: ChinaUnix博客 日期: 2010.01.13 15:53 (共有0条评论) 我要评论
制作根文件系统。
编译busybox之前需要弄懂的几个概念。
1、Build BusyBox as a static binary (no shared libs)。也就是busybox 是编译成共享库的形式还是静态的形式,他们有什么区别?
编译成静态(这时我们一般不把工具链里的库拷贝到我们制作的文件系统系统的lib下面):
那么生成的/bin/busybox就可以单独执行,不以来其他的库,原因是在编译时把它运行时需要的库(如libc)也编译到该可执行文件/bin/busybox里了。
由busybox编译处理的命令如mount,ls,cat等也可以单独执行了,原因也是一样,就是在编译时把它运行时需要的库也编译到该各自的可执行文件了。
这样就产生一个问题,由于每个可执行文件读包含了库,这样就导编译出来的可执行文件比较大,而且可能每个可执行文件都包含同一个库(如libc),浪费很大的空间。
另外比如我想运行一个helloword,用arm-linx-gcc -o helloword helloword.c。把helloword放到一个静态编译的busybox里,是执行不了的。因为arm-linx-gcc -o helloword helloword.c没人是编译成动态的,而这时没它运行时需要的库(libc),是执行不行了的。你是在要执行的话,就加-static编译成静态库的形式arm-linx-gcc -o helloword helloword.c -static,让它包含了需要的库。这样编译出来的helloword可以执行了。
编译成共享库的形式:/bin/busybox是不可以单独执行的,必须把它需要的库包含进来,我们需要把工具链里的库拷贝到我们制作的文件系统系统的lib下面。这是就可以通过共享该库了,应用程序(如helloword,cat命令)不必编译到各自的可执行文件了,节省了空间。
在嵌入式中一般编译成共享库的形式。除非你只是进行一些非常简单的形式。
2、启动。
当选择CONFIG_BLK_DEV_INITRD=y。我们把作好的文件系统放在目录myrootfs_shared下(目录下是bin,etc,lib等),再把该文件夹放在内核时的顶层目录,编译时选上。
Initial RAM filesystem and RAM disk (initramfs/initrd) support │ │
│ │ (myrootfs_shared) Initramfs source file(s)
如果这样,就可以认为是ramdisk启动了。
如果没选,就根据CONFIG_CMDLINE决定了,CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/rootfs,rsize=1024,wsize=1024 ip=192.168.1.101:192.168.1.100:192.168.1.100:255.255.255.0::usb0:on console=ttyS1,115200 mem=128M init=/init android uart_dma=1"。
其中root=... , 该参数告诉内核启动时使用哪个设备作为根文件系统。比如可以指定根文件为hda8:root=/dev/hda8。
但不管采用何种方式启动,内核执行的初始化进程名都由init=决定的(内核中启动的起一个用户进程是init).如果该项没有设置,内核会按顺序尝试/etc/init,
/bin/init,/sbin/init, /bin/sh,如果所有的都没找到,内核会抛出 kernel panic:的错误。
如init=/linuxrc,那么执行的第一个进程就是跟目录下的linuxrc。
我们编译好的busybox有bin,sbin目录和linuxrc文件。而linuxrc -> bin/busybox,可见劲儿会执行bin/busybox。而busybox最终会执行/etc/init.d/rcS这个shell脚本。我们一般在rcS完成我们自己想要的工作。
由次可见,在建文件系统时,linuxrc这个名字是无所谓的,只需保证第一个运行我们bin/busybox(这样就可以保证运行rcS这个shell文件了)。这就需要CMDLINE和建文件系统时链向bin/busybox的文件同时配合了。
例如:在CONFIG_CMDLINE里我们指定了init=/test_init,那么我们在建文件系统时,我们这时只需要在文件系统的根目录执行ln -s bin/busybox test_init即可。(之前要把编译busybox生成的bin/busybox拷贝到文件系统的bin目录下)
注意:需要保证test_init,rcS是可以执行的。为了省事,在完成后,我把整个rootfs目录sudo chmod 777 rootfs -R
1、1)创建根文件系统的基本目录结构。
我把这个过程做成了shell脚本(文件名为mkroot)
#! /bin/sh
echo "creatint rootfs dir......"
mkdir rootfs
cd rootfs
echo "making dir : bin dev etc lib proc sbin sys usr"
mkdir bin dev etc lib proc sbin sys usr #必备的8个目录
mkdir usr/bin usr/lib usr/sbin lib/modules
# Don't use mknod ,unless you run this Script as root !
sudo mknod -m 600 dev/console c 5 1 #必须的设备
sudo mknod -m 666 dev/null c 1 3 #必须的设备
echo "making dir : mnt tmp var"
mkdir mnt tmp var
chmod 1777 tmp
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/log var/run var/tmp
chmod 1777 var/tmp
echo "making dir : home root boot"
mkdir home root boot
echo "done"
赋予该shell可执行的权限。sudo chmod 777 mkroot
然后执行./mkroot,中间在生成设备时需要输入密码。这样基本的目录就有了。
(2)配置、编译和安装Busybox
最好去官网下,去别的哪里下可能有时存在编译不过的情况。我用的是官网下的busybox-1.15.2.tar.bz2。然后修改Makefile.
把这部分屏蔽(185行左右)
#SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/
# -e s/arm.*/arm/ -e s/sa110/arm/
# -e s/s390x/s390/ -e s/parisc64/parisc/
# -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
下面的2处
#ARCH ?= $(SUBARCH)
#CROSS_COMPILE ?=
改成
ARCH = arm
CROSS_COMPILE = arm-linux-
注:由于我把工具链的位置添加到了环境变量里,故CROSS_COMPILE = arm-linux-,否则要给出完整的路径。CROSS_COMPILE = /home/mxzh/smartphone/ww21/pxalinux/toolchain/arm-linux-4.1.1/arm-linux-
# make menuconfig
Busybox Settings --->
Build Options --->
[] Build BusyBox as a static binary (no shared libs) //(1)
Installation Options --->
Don't use /usr //(2)
Linux System Utilities --->
mdev //(3)
Support /etc/mdev.conf
Support command execution at device addition/removal
(1) 这个选项是一定要选择的,这样才能把busybox编译成静态链接的可执行文件,运行时才独立于其他函数库.否则必需要其他库文件才能运行,在单一个linux内核不能使他正常工作。如果选中就是静态编译,如果没选中,那么就要拷贝工具链里的库过来,我们这里不选中。
(2) 这个选项也一定要选,否则make install后,busybox将安装在原系统的/usr下,这将覆盖掉系统原有的命令.选择这个选项后,make install后会在busybox目录下生成一个叫_install的目录,里面有busybox和指向他的链接.
(3) 如果没有启动
udev
,造成/dev下没有设备文件。也就是说所有的设备都没有挂接进来。最新的busybox已经包含了udev的简化版本即mdev,且使用非常简单。 要使用mdev还需要在rootfs中做适当配置。
同时还要注意把sh命令选上。
再加一些基本的命令就可以了,其余大可不选,用到时再说。
执行make &&make install。
(3)把工具链里的库拷贝到文件系统的lib下
如果是编译成静态的,这一步可以不做。
[email=mxzh@mxzh:~/work_test/mkrootfs/busybox-1.15.2$]mxzh@mxzh:~/work_test/mkrootfs/busybox-1.15.2$[/email]
/home/mxzh/smartphone/ww21/pxalinux/toolchain/arm-linux-4.1.1/bin/arm-iwmmxt-linux-gnueabi-readelf -d busybox
这样就可以查看busybox需要的库
Dynamic section at offset 0x3700c contains 24 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0xa56c
0x0000000d (FINI) 0x33700
0x00000019 (INIT_ARRAY) 0x47000
0x0000001b (INIT_ARRAYSZ) 4 (bytes)
0x0000001a (FINI_ARRAY) 0x47004
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x00000004 (HASH) 0x80e8
0x00000005 (STRTAB) 0x95e8
0x00000006 (SYMTAB) 0x8798
0x0000000a (STRSZ) 1761 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x470f4
0x00000002 (PLTRELSZ) 1664 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x9eec
0x00000011 (REL) 0x9eb4
0x00000012 (RELSZ) 56 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x9e94
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x9cca
0x00000000 (NULL) 0x0
如上,需要libc库,拷贝库到文件系统的lib目录下。
$ cd ~/work_test/mkrootfs/rootfs/lib
$ cp -d /home/mxzh/smartphone/ww21/pxalinux/toolchain/arm-linux-4.1.1/arm-iwmmxt-linux-gnueabi/lib/ld* ./
$ cp /home/mxzh/smartphone/ww21/pxalinux/toolchain/arm-linux-4.1.1/arm-iwmmxt-linux-gnueabi/lib/libc.so.6 ./
这样就可以了。
(4)添加命令和初始化脚本
把编译busybox的 生成的_install下的bin,sbin目录拷贝到到文件系统的跟目录下。至于linuxrc,可不作拷贝,只是个链接。
添加 /etc/init.d/rcS 文件 添加自动执行部分
#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/lib:
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
#
#Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
/bin/mount -t proc none /proc
/bin/mount -t tmpfs none /root
/bin/mount -t tmpfs none /tmp
/bin/mount -t tmpfs none /var
/bin/mount -t tmpfs none /dev
/bin/mount -t sysfs none /sys
/bin/mkdir -p /var/lib
/bin/mkdir -p /var/run
/bin/mkdir -p /var/log
/bin/mknod -m 660 /dev/console c 5 1
/bin/mknod -m 660 /dev/null c 1 3
/bin/mknod -m 666 /dev/ptmx c 5 2
/bin/mkdir /dev/shm
/bin/mkdir /dev/pts
echo "Starting mdev ..."
/sbin/mdev -s
echo /sbin/mdev > /proc/sys/kernel/hotplug
然后在文件系统的跟目录执行ln -s bin/busybox test_init。
为了保证可执行,sudo chmod 777 rootfs -R
这样,整个文件文件系统rootfs就做成了。
可以把1、rootfs作为nfs目录供小板挂载了,
2、或者是把rootfs整个目录拷贝到内核目录的顶层,配置内核做ramdis文件系统了。具体配置如下 General setup --->
Initial RAM filesystem and RAM disk (initramfs/initrd) support │ │
│ │ (rootfs) Initramfs source file(s)
这是,还需要在CMDLINE里指定init=/test_init,与上面的ln -s bin/busybox test_init对应。
如果是ln -s bin/busybox linxurc,那么CMDLINE里指定init=/linxurc。
如果是ln -s bin/busybox init,那么CMDLINE里指定init=/init。
具体可参考: