交叉编译的概念在第4章中已经详细讲述过,搭建交叉编译环境是嵌入式开发的第一步,也是必备的一步。搭建交叉编译环境的方法很多,不同的体系结构、不同的操作内容甚至是不同版本的内核,都会用到不同的交叉编译器,而且,有些交叉编译器经常会有部分的bug,这都会导致最后的代码无法正常地运行。因此,选择合适的交叉编译器对于嵌入式开发是非常重要的。
交叉编译器完整的安装一般涉及多个软件的安装(读者可以从ftp://gcc.gnu.org/pub/下载),包括binutils、gcc、glibc等软件。其中,binutils主要用于生成一些辅助工具,如objdump、as、ld等;gcc是用来生成交叉编译器的,主要生成arm-linux-gcc交叉编译工具(应该说,生成此工具后已经搭建起了交叉编译环境,可以编译Linux内核了,但由于没有提供标准用户函数库,用户程序还无法编译);glibc主要是提供用户程序所使用的一些基本的函数库。这样,交叉编译环境就完全搭建起来了。
上面所述的搭建交叉编译环境比较复杂,很多步骤都涉及对硬件平台的选择。因此,现在嵌入式平台提供厂商一般会提供在该平台上测试通过的交叉编译器,而且很多公司把以上安装步骤全部写入脚本文件或者以发行包的形式提供,这样就大大方便了用户的使用。如优龙的FS2410开发光盘里就附带了2.95.3和3.3.2两个版本的交叉编译器,其中前一个版本是用于编译Linux 2.4内核的,而后一个版本是用于编译Linux 2.6版本内核的。由于这是厂商测试通过的编译器,因此可靠性会比较高,而且与开发板能够很好地吻合。所以推荐初学者直接使用厂商提供的编译器。当然,由于时间滞后的原因,这个编译器往往不是最新的版本,若需要更新时希望读者另外查找相关资料学习。本书就以优龙自带的cross-3.3.2为例进行讲解(具体的名称不同厂商可能会有区别)。
安装交叉编译器的具体步骤在第2章的实验二中已经进行了详细地讲解了,在此仅回忆关键步骤,对于细节请读者参见第2章的实验二。
在/usr/local/arm下解压cross-3.3.2.bar.bz2。
[root@localhost arm]# tar –jxvf cross-3.3.2.bar.bz2
[root@localhost arm]# ls
3.3.2 cross-3.3.2.tar.bz2
[root@localhost arm]# cd ./3.3.2
[root@localhost arm]# ls
arm-linux bin etc include info lib libexec man sbin share VERSIONS
[root@localhost bin]# which arm-linux*
/usr/local/arm/3.3.2/bin/arm-linux-addr2line
/usr/local/arm/3.3.2/bin/arm-linux-ar
/usr/local/arm/3.3.2/bin/arm-linux-as
/usr/local/arm/3.3.2/bin/arm-linux-c++
/usr/local/arm/3.3.2/bin/arm-linux-c++filt
/usr/local/arm/3.3.2/bin/arm-linux-cpp
/usr/local/arm/3.3.2/bin/arm-linux-g++
/usr/local/arm/3.3.2/bin/arm-linux-gcc
/usr/local/arm/3.3.2/bin/arm-linux-gcc-3.3.2
/usr/local/arm/3.3.2/bin/arm-linux-gccbug
/usr/local/arm/3.3.2/bin/arm-linux-gcov
/usr/local/arm/3.3.2/bin/arm-linux-ld
/usr/local/arm/3.3.2/bin/arm-linux-nm
/usr/local/arm/3.3.2/bin/arm-linux-objcopy
/usr/local/arm/3.3.2/bin/arm-linux-objdump
/usr/local/arm/3.3.2/bin/arm-linux-ranlib
/usr/local/arm/3.3.2/bin/arm-linux-readelf
/usr/local/arm/3.3.2/bin/arm-linux-size
/usr/local/arm/3.3.2/bin/arm-linux-strings
/usr/local/arm/3.3.2/bin/arm-linux-strip
可以看到,在/usr/local/arm/3.3.2/bin/下已经安装了很多交叉编译工具。用户可以查看arm文件夹下的VERSIONS文件,显示如下:
Versions
gcc-3.3.2
glibc-2.3.2
binutils-head
Tool chain binutils configuration:
../binutils-head/configure …
Tool chain glibc configuration:
../glibc-2.3.2/configure …
Tool chain gcc configuration
../gcc-3.3.2/configure …
可以看到,这个交叉编译工具确实集成了binutils、gcc、glibc这几个软件,而每个软件也都有比较复杂的配置信息,读者可以查看VERSIONS文件了解相关信息。
5.1.2 超级终端和minicom配置及使用
前文已知,嵌入式系统开发的程序只能在对应的嵌入式硬件平台上运行,那么如何把开发板上的信息显示给开发人员呢?最常用的就是通过串口线输出到宿主机的显示器上,这样,开发人员就可以看到系统的运行情况了。在Windows和Linux中都有不少串口通信软件,可以很方便地对串口进行配置,其中最主要的配置参数是波特率、数据位、停止位、奇偶校验位和数据流控制位等,但是它们一定要根据实际情况进行相应配置。下面介绍Windows中典型的串口通信软件“超级终端”和在Linux下的“minicom”。
1.超级终端
首先,打开Windows下的“开始”→“附件”→“通讯”→“超级终端”,这时会出现如图5.1所示的新建超级终端界面,在“名称”处可随意输入该连接的名称。
图5.1 新建超级终端界面
接下来,将“连接时使用”的方式改为“COM1”,即通过串口1,如图5.2所示。
接下来就到了最关键的一步——设置串口连接参数。要注意,每块开发板的连接参数有可能会有差异,其中的具体数据在开发商提供的用户手册中会有说明。如优龙的这款FS2410采用的是波特率为115200,数据位数为8,无奇偶校验位,停止位数为1,无硬件流控,其对应配置如图5.3所示。
图5.2 选择连接时使用方式 图5.3 配置串口相关参数
这样,就基本完成了配置,最后一步单击“确定”按钮就可以了。这时,读者可以把开发板的串口线和PC机相连,若配置正确,在开发板上电后,在超级终端的窗口里应能显示类似于图5.4的串口信息。
图5.4 在超级终端上显示信息
注意
要分清开发板上的串口1、串口2,如在优龙的开发板上标有“UART1”、“UATR2”,否则串口无法打印出信息。
2.minicom
minicom是Linux下串口通信的软件,它的使用完全依靠键盘的操作,虽然没有“超级终端”那么易用,但是使用习惯之后读者将会体会到它的高效与便利。下面主要讲解如何对minicom进行串口参数的配置。
首先在命令行中键入“minicom”,这就启动了minicom软件。minicom在启动时默认会进行初始化配置,如图5.5所示。可以通过“minicom -s”命令进行minicom的配置。
图5.5 minicom启动
注意
在minicom的使用中,经常会遇到3个键的操作,如“CTRL-A Z”,这表示先同时按下CTRL和“A”,然后松开这两个键再按下“Z”。
正如图5.5中的提示,接下来可键入CTRL-A Z,来查看minicom的帮助,如图5.6所示。按照帮助所示,可键入“O”(代表Configure minicom)来配置minicom的串口参数,当然也可以直接键入“CTRL-A O”来进行配置。如图5.7所示。
图5.6 minicom帮助
图5.7 minicom配置界面
在这个配置框中选择“Serial port setup”子项,进入如图5.8所示的配置界面。
图5.8 minicom串口属性配置界面
上面列出的配置是minicom启动时的默认配置,用户可以通过键入每一项前的大写字母,分别对每一项进行更改。图5.9所示为在“Change which setting” 中键入了“A”,此时光标转移到第A项的对应处。
图5.9 minicom串口号配置
注意
在minicom中“ttyS0”对应“COM1”,“ttyS1”对应“COM2”。
接下来,要对波特率、数据位和停止位进行配置,键入“E”,进入如图5.10所示的配置界面。
图5.10 minicom波特率等配置界面
在该配置界面中,可以键入相应波特率、停止位等对应的字母,即可实现配置,配置完成后按回车键就退出了该配置界面,在上层界面中显示如图5.11所示配置信息,要注意与图5.8进行对比,确定相应参数是否已被重新配置。
图5.11 minicom配置完成后界面
在确认配置正确后,可键入回车返回上级配置界面,并将其保存为默认配置,如图5.12所示。之后,可重新启动minicom使刚才配置生效,在用串口线将宿主机和开发板连接之后,就可在minicom中打印出正确的串口信息,如图5.13所示。
图5.12 minicom保存配置信息
图5.13 minicom显示串口信息
到此为止,读者已经能将开发板的系统情况通过串口打印到宿主机上了,这样,就能很好地了解硬件的运行状况。
小知识
通过串口打印信息是一个很常见的手段,很多其他情况如路由器等也是通过配置串口的波特率这些参数来显示对应信息的。
5.1.3 下载映像到开发板
正如第4章中所述,嵌入式开发的运行环境是目标板,而开发环境是宿主机。因此,需要把宿主机中经过编译之后的可执行文件下载到目标板上。要注意的是,这里所说的下载是下载到目标机中的SDRAM。然后,用户可以选择直接从SDRAM中运行或写入到Flash中再运行。运行常见的下载方式有网络下载(如tftp、ftp等方式)、串口下载、USB下载等,本书主要讲解网络下载中的tftp方式和串口下载方式。
1.tftp
tftp是简单文件传输协议,它可以看作是一个FTP协议的简化版本,与FTP协议相比,它的最大区别在于没有用户管理的功能。它的传输速度快,可以通过防火墙,使用方便快捷,因此在嵌入式的文件传输中广泛使用。
同FTP一样,tftp分为客户端和服务器端两种。通常,首先在宿主机上开启tftp服务器端服务,设置好tftp的根目录内容(也就是供客户端访问的根目录),接着,在目标板上开启tftp的客户端程序(现在很多Bootloader几乎都提供该服务)。这样,把目标板和宿主机用直连线相连之后,就可以通过tftp协议传输可执行文件了。
下面分别讲述在Linux下和Windows下的配置方法。
(1)Linux下tftp服务配置。
Linux下tftp的服务器服务是由xinetd所设定的,默认情况下是处于关闭状态。
首先,要修改tftp的配置文件,开启tftp服务,如下所示:
[root@localhost tftpboot]# vim /etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer
# protocol. The tftp protocol is often used to boot diskless
# workstations, download configuration files to network-aware printers,
# and to start the installation process for some operating systems.
service tftp
{
socket_type = dgram /* 使用数据报套接字*/
protocol = udp /* 使用UDP协议 */
wait = yes /* 允许等待 */
user = root /* 用户 */
server = /usr/sbin/in.tftpd /* 服务程序*/
server_args = -s /tftpboot /* 服务器端的根目录*/
disable = no /* 使能 */
per_source = 11
cps = 100 2
flags = IPv4
}
在这里,主要要将“disable=yes”改为“no”,另外,从“server_args”可以看出,tftp服务器端的默认根目录为“/tftpboot”,用户如果需要则可以更改为其他目录。
接下来,重启xinetd服务,使刚才的更改生效,如下所示:
[root@localhost tftpboot]# service xinetd restart
(或者使用/etc/init.d/xinetd restart,而且因发行版的不同具体路径会有所不同)
关闭 xinetd: [ 确定 ]
启动 xinetd: [ 确定 ]
接着,使用命令“netstat -au”以确认tftp服务是否已经开启,如下所示:
[root@localhost tftpboot]# netstat –au | grep tftp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 *:tftp *:*
这时,用户就可以把所需要的传输文件放到“/tftpboot”目录下,这样,主机上的tftp服务就可以建立起来了(注意:需要在服务端关闭防火墙)。
接下来,用直连线把目标板和宿主机连起来,并且将其配置成一个网段的地址(例如两个IP都可以设置为192.168.1.XXX格式),再在目标板上启动tftp客户端程序(注意:不同的Bootloader所使用的命令可能会不同,例如:在RedBoot中使用load命令下载文件是基于tftp协议的。读者可以查看帮助来获得确切的命令名及格式),如下所示:
=>tftpboot 0x30200000 zImage
TFTP from server 192.168.1.1; our IP address is 192.168.1.100
Filename 'zImage'.
Load address: 0x30200000
Loading: #################################################################
###############################################################
#############################################
done
Bytes transferred = 881988 (d7544 hex)
可以看到,此处目标板使用的IP为“192.168.1.100”,宿主机使用的IP为“192.168.1.1”,下载到目标板的地址为0x30200000,文件名为“zImage”。
(2)Windows下tftp服务配置。
在Windows下配置tftp服务器端需要下载tftp服务器软件,常见的为tftpd32。
首先,单击tftpd32下方的设置按钮,进入设置界面,如图5.14所示,在这里,主要配置tftp服务器端地址,也就是宿主机的地址。
接下来,重新启动tftpd32软件使刚才的配置生效,这样服务器端的配置就完成了,这时,就可以用直连线连接目标机和宿主机,且在目标机上开启tftp服务进行文件传输,这时,tftp服务器端如图5.15和图5.16所示。
图5.14 tftp文件传输 图5.15 tftpd32配置界面 图5.16 tftp服务器端显示情况
小知识
tftp是一个很好的文件传输协议,它的简单易用吸引了广大用户。但它同时也存在着较大的安全隐患。由于tftp不需要用户的身份认证,因此给了黑客的可乘之机。2003年8月12日爆发的全球冲击波(Worm.Blaster)病毒就是interwetten与威廉的赔率体系 一个tftp服务器,并启动一个攻击传播线程,不断地随机生成攻击地址进行入侵。因此在使用tftp时一定要设置一个单独的目录作为tftp服务的根目录,如上文所述的“/tftpboot”等。
2.串口下载
使用串口下载需要配合特定的下载软件,如优龙公司提供的DNW软件等,一般在Windows下进行操作。虽然串口下载的速度没有网络下载快,但由于它很方便,不需要额外的连线和设置IP等操作,因此也广受用户的青睐。下面就以DNW软件为例,介绍串口下载的方式。
与其他串口通信的软件一样,在DNW中也要设置“波特率”、“端口号”等。打开“Configuration”下的“Options”界面,如图5.17所示。
图5.17 DNW配置界面
在配置完之后,单击“Serial Port”下的“Connect”,再将开发板上电,选择“串口下载”,接着再在“Serial Port”下选择“Transmit”,这时,就可以进行文件传输了,如图5.18和图5.19所示。这里DNW默认串口下载的地址为0x30200000。
图5.18 DNW串口下载图
图5.19 DNW串口下载情形图
5.1.4 编译嵌入式Linux内核
在做完了前期的准备工作之后,在这一步,读者就可以编译嵌入式Linux的内核了。在这里,本书主要介绍嵌入式Linux内核的编译过程,在下一节会进一步介绍嵌入式Linux中体系结构相关的内核代码,读者在此之后就可以尝试嵌入式Linux操作系统的移植。
编译嵌入式Linux内核都是通过make的不同命令来实现的,它的执行配置文件就是在第3章中讲述的makefile。Linux内核中不同的目录结构里都有相应的makefile,而不同的makefile又通过彼此之间的依赖关系构成统一的整体,共同完成建立依赖关系、建立内核等功能。
内核的编译根据不同的情况会有不同的步骤,但其中最主要分别为3个步骤:内核配置、建立依赖关系、创建内核映像,除此之外还有一些辅助功能,如清除文件和依赖关系等。读者在实际编译时若出现错误等情况,可以考虑采用其他辅助功能。下面分别讲述这3步主要的步骤。
(1)内核配置。
第一步内核配置中的选项主要是用户用来为目标板选择处理器架构的选项,不同的处理器架构会有不同的处理器选项,比如ARM就有其专用的选项如“Multimedia capabilities port drivers”等。因此,在此之前,必须确保在根目录中makefile里“ARCH”的值已设定了目标板的类型,如:
ARCH := arm
接下来就可以进行内核配置了,内核支持4种不同的配置方法,这几种方法只是与用户交互的界面不同,其实现的功能是一样的。每种方法都会通过读入一个默认的配置文件—根目录下“.config”隐藏文件(用户也可以手动修改该文件,但不推荐使用)。当然,用户也可以自己加载其他配置文件,也可以将当前的配置保存为其他名字的配置文件。这4种方式如下。
n make config:基于文本的最为传统的配置界面,不推荐使用。
n make menuconfig:基于文本选单的配置界面,字符终端下推荐使用。
n make xconfig:基于图形窗口模式的配置界面,Xwindow下推荐使用。
n make oldconfig:自动读入“.config”配置文件,并且只要求用户设定前次没有设定过的选项。
在这4种模式中,make menuconfig使用最为广泛,下面就以make menuconfig为例进行讲解,如图5.20所示。
图5.20 make menuconfig配置界面
从该图中可以看出,Linux内核允许用户对其各类功能逐项配置,一共有18类配置选项,这里就不对这18类配置选项进行一一讲解了,需要的时候读者可以参见相关选项的help。在menuconfig的配置界面中是纯键盘的操作,用户可使用上下键和“Tab”键移动光标以进入相关子项,图5.21所示为进入了“System Type”子项的界面,该子项是一个重要的选项,主要用来选择处理器的类型。
图5.21 System Type子项
可以看到,每个选项前都有个括号,可以通过按空格键或“Y”键表示包含该选项,按“N”表示不包含该选项。
另外,读者可以注意到,这里的括号有3种,即中括号、尖括号或圆括号。读者可以用空格键选择相应的选项时可以发现中括号里要么是空,要么是“*”;尖括号里可以是空,“*”和“M”,分别表示包含选项、不包含选项和编译成模块;圆括号的内容是要求用户在所提供的几个选项中选择一项。
此外,要注意2.4和2.6内核在串口命名上的一个重要区别,在2.4内核中“COM1”对应的是“ttyS0”,而在2.6内核中“COM1”对应“ttySAC0”,因此在启动参数的子项要格外注意,如图5.22所示,否则串口打印不出信息。
图5.22 启动参数配置子项
一般情况下,使用厂商提供的默认配置文件都能正常运行,所以用户初次使用时可以不用对其进行额外的配置,在以后需要使用其他功能时再另行添加,这样可以大大减少出错的几率,有利于错误定位。在完成配置之后,就可以保存退出,如图5.23所示。
图5.23 保存退出
(2)建立依赖关系。
由于内核源码树中的大多数文件都与一些头文件有依赖关系,因此要顺利建立内核,内核源码树中的每个Makefile都必须知道这些依赖关系。建立依赖关系通常在第一次编译内核的时候(或者源码目录树的结构发生变化的时候)进行,它会在内核源码树中每个子目录产生一个“.depend”文件。运行“make dep”即可。在编译2.6版本的内核通常不需要这个过程,直接输入“make”即可。
(3)建立内核
建立内核可以使用“make”、“make zImage”或“make bzImage”,这里建立的为压缩的内核映像。通常在Linux中,内核映像分为压缩的内核映像和未压缩的内核映像。其中,压缩的内核映像通常名为zImage,位于“arch/$(ARCH)/boot”目录中。而未压缩的内核映像通常名为vmlinux,位于源码树的根目录中。
到这一步就完成了内核源代码的编译,之后,读者可以使用上一小节所讲述的方法把内核压缩文件下载到开发板上运行。
小知识
在嵌入式Linux的源码树中通常有以下几个配置文件,“.config”、“autoconf.h”、“config.h”,其中“.config”文件是make menuconfig默认的配置文件,位于源码树的根目录中。“autoconf.h”和“config.h”是以宏的形式表示了内核的配置,当用户使用make menuconfig做了一定的更改之后,系统自动会在“autoconf.h”和“config.h”中做出相应的更改。它们位于源码树的“/include/linux/”下。
5.1.5 Linux内核源码目录结构
Linux内核源码的目录结构如图5.24所示。
n /include子目录包含了建立内核代码时所需的大部分包含文件,这个模块利用其他模块重建内核。
n /init子目录包含了内核的初始化代码,这里的代码是内核工作的起始入口。
n /arch子目录包含了所有处理器体系结构特定的内核代码。如:arm、i386、alpha。
n /drivers子目录包含了内核中所有的设备驱动程序,如块设备和SCSI设备。
n /fs子目录包含了所有的文件系统的代码,如:ext2、vfat等。
n /net子目录包含了内核的网络相关代码。
n /mm子目录包含了所有内存管理代码。
n /ipc子目录包含了进程间通信代码。
n /kernel子目录包含了内核核心代码。
5.1.6 制作文件系统
读者把上一节中所编译的内核压缩映像下载到开发板后会发现,系统在进行了一些初始化的工作之后,并不能正常启动,如图5.25所示。
可以看到,系统启动时发生了加载文件系统的错误。要记住,上一节所编译的仅仅是内核,文件系统和内核是完全独立的两个部分。读者可以回忆一下第2章讲解的Linux启动过程的分析(嵌入式Linux是Linux裁减后的版本,其精髓部分是一样的),其中在head.S中就加载了根文件系统。因此,加载根文件系统是Linux启动中不可缺少的一部分。本节将讲解嵌入式Linux中文件系统的制作方法。
图5.25 系统启动错误
制作文件系统的方法有很多,可以从零开始手工制作,也可以在现有的基础上添加部分内容并加载到目标板上去。由于完全手工制作工作量比较大,而且也很容易出错,因此,本节将主要介绍把现有的文件系统加载到目标板上的方法,主要包括制作文件系统映像和用NFS加载文件系统的方法。
1.制作文件系统映像
读者已经知道,Linux支持多种文件系统,同样,嵌入式Linux也支持多种文件系统。虽然在嵌入式系统中,由于资源受限的原因,它的文件系统和PC机Linux的文件系统有较大的区别,但是,它们的总体架构是一样的,都是采用目录树的结构。在嵌入式系统中常见的文件系统有cramfs、romfs、jffs、yaffs等,这里就以制作cramfs文件系统为例进行讲解。cramfs文件系统是一种经过压缩的、极为简单的只读文件系统,因此非常适合嵌入式系统。要注意的是,不同的文件系统都有相应的制作工具,但是其主要的原理和制作方法是类似的。
在嵌入式Linux中,busybox是构造文件系统最常用的软件工具包,它被非常形象地称为嵌入式Linux系统中的“瑞士军刀”,因为它将许多常用的Linux命令和工具结合到了一个单独的可执行程序(busybox)中。虽然与相应的GNU工具比较起来,busybox所提供的功能和参数略少,但在比较小的系统(例如启动盘)或者嵌入式系统中已经足够了。busybox在设计上就充分考虑了硬件资源受限的特殊工作环境。它采用一种很巧妙的办法减少自己的体积:所有的命令都通过“插件”的方式集中到一个可执行文件中,在实际应用过程中通过不同的符号链接来确定到底要执行哪个操作。例如最终生成的可执行文件为busybox,当为它建立一个符号链接ls的时候,就可以通过执行这个新命令实现列出目录的功能。采用单一执行文件的方式最大限度地共享了程序代码,甚至连文件头、内存中的程序控制块等其他系统资源都共享了,对于资源比较紧张的系统来说,真是最合适不过了。在busybox的编译过程中,可以非常方便地加减它的“插件”,最后的符号链接也可以由编译系统自动生成。
下面用busybox构建FS2410开发板的cramfs文件系统。
首先从busybox网站下载busybox源码(本实例采用的busybox-1.0.0)并解压,接下来,根据实际需要进行busybox的配置。
[root@localhost fs2410]# tar jxvf busybox-1.00.tar.bz2
[root@localhost fs2410]# cd busybox-1.00
[root@localhost busybox-1.00]# make defconfig /* 首先进行默认配置 */
[root@localhost busybox-1.00]# make menuconfig
此时需要设置平台相关的交叉编译选项,操作步骤为:先选中“Build Options”项的“Do you want to build Busybox with a Cross Complier?”选项,然后将“Cross Compiler prefix”设置为“/usr/local/arm/3.3.2/bin/arm-linux-”(这是在实验主机中的交叉编译器的安装路径)。
图5.26 busybox配置画面
下一步编译并安装busybox。
[root@localhost busybox-1.00]# make
[root@localhost busybox-1.00]# make install PREFIX=/home/david/fs2410/cramfs
其中,PREFIX用于指定安装目录,如果不设置该选项,则默认在当前目录下创建_install目录。创建的安装目录的内容如下所示:
[root@localhost cramfs]# ls
bin linuxrc sbin usr
从此可知,使用busybox软件包所创建的文件系统还缺少很多东西。下面我们通过创建系统所需要的目录和文件来完善一下文件系统的内容。
[root@localhost cramfs]# mkdir mnt root var tmp proc boot etc lib
[root@localhost cramfs]# mkdir /var/{lock,log,mail,run,spool}
如果busybox是动态编译的(即在配置busybox时没选中静态编译),则把所需的交叉编译的动态链接库文件复制到lib目录中。
接下来,需要创建一些重要文件。首先要创建/etc/inittab和/etc/fstab文件。inittab是Linux启动之后第一个被访问的脚本文件,而fstab文件是定义了文件系统的各个“挂接点”,需要与实际的系统相配合。接下来要创建用户和用户组文件。
以上用busybox构造了文件系统的内容,下面要创建cramfs文件系统映像文件。制作cramfs映像文件需要用到的工具是mkcramfs。此时可以采用两种方法,一种方法是使用我们所构建的文件系统(在目录“/home/david/fs2410/cramfs”中),另一种方法是在已经做好的cramfs映像文件的基础上进行适当的改动。下面的示例使用第二种方法,因为这个方法包含了第一种方法的所有步骤(假设已经做好的映像文件名为“fs2410.cramfs”)。
首先用mount命令将映像文件挂载到一个目录下,打开该目录并查看其内容。
[root@localhost fs2410]# mkdir cramfs
[root@localhost fs2410]# mount fs2410.cramgs cramfs –o loop
[root@localhost fs2410]# ls cramfs
bin dev etc home lib linuxrc proc Qtopia ramdisk sbin testshell tmp usr var
因为cramfs文件系统是只读的,所以不能在这个挂载目录下直接进行修改,因此需要将文件系统中的内容复制到另一个目录中,具体操作如下所示:
[root@localhost fs2410]# mkdir backup_cramfs
[root@localhost fs2410]# tar cvf backup.cramfs.tar cramfs/
[root@localhost fs2410]# mv backup.cramfs.tar backup_cramfs/
[root@localhost fs2410]# umount cramfs
[root@localhost fs2410]# cd backup_cramfs
[root@localhost backup_cramfs]# tar zvf backup.cramfs.tar
[root@localhost backup_cramfs]# rm backup.cramfs.tar
此时我们就像用busybox所构建的文件系统一样,可以在backup_cramfs的cramfs子目录中任意进行修改。例如可以添加用户自己的程序:
[root@localhost fs2410]# cp ~/hello backup_cramfs/cramfs/
在用户的修改工作结束之后,用下面的命令可以创建cramfs映像文件:
[root@localhost fs2410]# mkcramfs backup_cramfs/cramfs/ new.cramfs
接下来,就可以将新创建的new.cramfs映像文件烧入到开发板的相应位置了。
2.NFS文件系统
NFS为Network File System的简称,最早是由Sun公司提出发展起来的,其目的就是让不同的机器、不同的操作系统之间通过网络可以彼此共享文件。NFS可以让不同的主机通过网络将远端的NFS服务器共享出来的文件安装到自己的系统中,从客户端看来,使用NFS的远端文件就像是使用本地文件一样。在嵌入式中使用NFS会使应用程序的开发变得十分方便,并且不用反复地烧写映像文件。
NFS的使用分为服务端和客户端,其中服务端是提供要共享的文件,而客户端则通过挂载(“mount”)这一动作来实现对共享文件的访问操作。下面主要介绍NFS服务端的使用。在嵌入式开发中,通常NFS服务端在宿主机上运行,而客户端在目标板上运行。
NFS服务端是通过读入它的配置文件“/etc/exports”来决定所共享的文件目录的。下面首先讲解这个配置文件的书写规范。
在这个配置文件中,每一行都代表一项要共享的文件目录以及所指定的客户端对它的操作权限。客户端可以根据相应的权限,对该目录下的所有目录文件进行访问。配置文件中每一行的格式如下:
[共享的目录] [客户端主机名称或IP] [参数1,参数2…]
在这里,主机名或IP是可供共享的客户端主机名或IP,若对所有的IP都可以访问,则可用“*”表示。这里的参数有很多种组合方式,常见的参数如表5.1所示。
表5.1 常见参数
选 项
参 数 含 义
rw
可读写的权限
ro
只读的权限
no_root_squash
NFS客户端分享目录使用者的权限,即如果客户端使用的是root用户,那么对于这个共享的目录而言,该客户端就具有root的权限
sync
资料同步写入到内存与硬盘当中
async
资料会先暂存于内存当中,而非直接写入硬盘
如在本例中,配置文件“/etc/exports”的代码如下:
[root@localhost fs]# cat /etc/exports
/root/workplace 192.168.1.*(rw,no_root_squash)
在设定完配置文件之后,需要启动nfs服务和portmap服务,这里的portmap服务是允许NFS客户端查看NFS服务在用的端口,在它被激活之后,就会出现一个端口号为111的sun RPC(远端过程调用)的服务。这是NFS服务中必须实现的一项,因此,也必须把它开启。如下所示:
[root@localhost fs]# service portmap start
启动 portmap: [确定]
[root@localhost fs]# service nfs start
启动 NFS 服务: [确定]
关掉 NFS 配额: [确定]
启动 NFS 守护进程: [确定]
启动 NFS mountd: [确定]
可以看到,在启动NFS服务的时候启动了mountd进程。这是NFS挂载服务,用于处理NFS递交过来的客户端请求。另外还会激活至少两个以上的系统守护进程,然后就开始监听客户端的请求,用“cat /var/log/messages”命令可以查看操作是否成功。这样,就启动了NFS的服务,另外还有两个命令,可以便于使用NFS。
其中一个是exportfs,它可以重新扫描“/etc/exports”,使用户在修改了“/etc/exports”配置文件之后不需要每次重启NFS服务。其格式为:
exportfs [选项]
exportfs的常见选项如表5.2所示。
表5.2 常见选项
选 项
参 数 含 义
-a
全部挂载(或卸载)/etc/exports中的设定文件目录
-r
重新挂载/etc/exports中的设定文件目录
-u
卸载某一目录
-v
在export的时候,将共享的目录显示到屏幕上
另外一个是showmount命令,它用于当前的挂载情况。其格式为:
showmount [选项] hostname
showmount的常见选项如表5.3所示。
表5.3 常见选项
选 项
参 数 含 义
-a
在屏幕上显示目前主机与客户端所连上来的使用目录状态
-e
显示hostname中/etc/exports里设定的共享目录
评论
查看更多