构建嵌入式linux详细步骤.docx
《构建嵌入式linux详细步骤.docx》由会员分享,可在线阅读,更多相关《构建嵌入式linux详细步骤.docx(27页珍藏版)》请在冰豆网上搜索。
构建嵌入式linux详细步骤
如何构建嵌入式linux操作系统
第一章前言
目的
本文的目的,是讲述嵌入式Linux系统的建立、开发的一般过程。
制作一个小型的Linux
的系统,可以移植至其它硬盘、软盘、优盘、flashrom……
做一个嵌入式Linux系统究竟要做哪些工作
做一个嵌入式Linux系统究竟需要做哪些工作?
也就是本文究竟要讲述哪些容?
我
先介绍一个脉络,可以做为我们后面工作的一个总的提纲:
第一步、建立交叉编译环境
没有交叉开发经验的读者,可能一时很难接受这个概念。
首先,要明白两个概念:
一般
我们工作的机器,称为开发机、主机;我们制作好的系统将要放到某台机器,如手机或另一
台PC机,这台机我们称为目标主机。
我们一般开发机上已经有一套开发工具,我们称之为原生开发套件,我们一般就是用它
们来写程序,那么,那什么又是交叉编译环境呢?
其实一点也不神秘,也就是在开发机上再
安装一套开发工具,这套开发工具编译出来的程序,如核、系统工作或者我们自己的程序,
是放在目标主机上运行的。
那么或许有初学者会问,直接用原生开发工具为目标主机编译程序不就完了?
至少我当
初是这么想的。
一般来说,我们的开发机都是X86平台,原生开发套件开发的工具,也针
对X86平台,而我们的目标主机可能是PowerPC、IXP、MIPS……所以,我们的交叉编译
环境是针对某一类具体平台的。
一般来讲,交叉开发环境需要二进制工具程序、编译器、C库,嵌入式开发常用的
这三类软件是:
Binutils
Gcc
uClibc
当然,GNU包含的工具套件不仅于此,你还要以根据实际需要,进行选择
第二步、编译核
开发工具是针对某一类硬件平台,核同样也是。
这一步,我们需要用第一步中建立的
工具,对核进行编译,对于有核编译经验的人来说,这是非常简单的;
第三步、建立根文件系统
也就是建立我们平常看到的bin、dev、proc……这一大堆目录,以及一些必备的文件;
另外,我们还需要为我们的目标系统安装一些常用的工具软件,如ls、ifconfig……当然,
一个办法是找到这些工具的源代码,用第一步建立的交叉编译工具来编译,但是这些软件一
是数量多,二是某些体积较大,不适合嵌入式系统,这一步,我们一般都是用busybox来完
成的,包括系统引导软件init;
最后,我们为系统还需要建立初始化的引导文件,如inittab……
第四步、启动系统
在这一步,我们把建立好的目标、文件、程序、核及模块全部拷贝到目标机存储器上,
如硬盘。
然后为系统安装bootloader,对于嵌入式系统,有许多引导程序可供我们使用。
不
过它们许多都有硬件平台的限制。
当然,如果你是工作在X86,可以直接用lilo来引导,事
实上,本文就是采用的lilo。
做到这一步,将目标存储设备挂上目标机,如果顺利,就可以启动系统了。
当然,针对某些特别的平台,不能像硬盘这样拷贝了,需要读卡器、烧录……但是基本
的方法是相通的!
第五步、优化和个性化系统
通过前四步,我们已经得到了一个可以正常工作的系统。
在这一步里,就是发挥你想像
的时候了……
本文的工作环境
项目根目录/home/kendo/project------>我将它指定至PATH:
$PRJROOT
子目录及说明
目录容
bootloader目标板的引导加载程序,如lilo等
build-tools建立交叉编译平台的工具源码
debug调试工具及所有相关包
doc项目中用到的所有文档
images编译好的核映像,以及根文件系统
kernel各个版本的Linux核源码
rootfs制作好的根文件系统
sysapps目标板将要用到的系统应用系统,比如thttpd,udhcpd等
tmp存放临时文件
tools编译好的跨平台开发工具链以及C库
工作的脚本
#!
/usr/bin
exportPROJECT=skynet
exportPRJROOT=/home/${PROJECT}
exportTARGET=i386-linux
exportPREFIX=${PRJROOT}/tools
exportTARGET_PREFIX=${PREFIX}/${TARGET}
exportPATH=${PREFIX}/bin:
/bin:
/sbin:
/usr/bin:
/usr/sbin
cd$PRJROOT
第二章建立交叉编译环境
在CU中发表的另一篇同名的贴子里,我讲述了一个全手工创建交叉编译环境的方法。
目前,创建交叉编译环境,包括建立根文件,一般来讲,有两种方法:
手功创建
可以得到最大程序的个性化定制,缺点是过程繁杂,特别是极易出错,注意这个“极”
字,包括有经验的开发人员;
自动创建
无它,方便而。
因为前一篇文章中,已经讲述了全手工创建交叉编译环境的一般性方法,本文就不打算
再重复这个步骤了,感兴趣的朋友,可以再去搜索那篇贴子,提醒一点的就是,在准备工具
链的时候,要注意各个工具版本之间的搭配、每个工具需要哪些补丁,我建议你在google
上针对这两项搜索一下,准备一个清单,否则……
本章要讲述的是自动创建交叉编译环境的方法。
目标,针对商业硬件平台,厂家都会为
你提供一个开发包,我用过XX厂家的IXP425和MIPS的,非常地方便,记得我第一次接
触嵌入式开发,拿着这个开发包自动化创建交叉编译环境、编译核、建立根文件系统、创
建RamDisk,我反复做了三四次,结果还不知道自己究竟做了些什么,呵呵,够傻吧……
所以,建议没有这方面经验的读者,还是首先尝试一下手工创建的方法吧,而本章接下来的
容,是送给曾经被它深深伤害而不想再次去亲历这项工作而又想提高交率而又在通用平台
上工作没有商业开发包的朋友。
建立交叉开发工具链
准备工具:
buildroot-0.9.27.tar.tar
只需要一个软件?
对,其它的不用准备了,buildroot事实上是一个脚本与补丁的集合,其它
需要用到的软件,如gcc、uClibc,你只需在buildroot中指明相应的版本,它会自动去给你
下载。
事实上,buildroot到网上去下载所需的所有工作是需要时间的,除非你的带宽足够,否
则下载软件时间或许会占去80%,而我在做这项工作之间,所需的工作链全部都在我本地
硬盘上,我解压开buildroot后,新建dl文件夹,将所有工具源码的压缩包拷贝进去,呵呵,
buildroot就不用去网上下载了。
我的软件清单:
Linux-libc-headers-2.4.27.tar.bz2
Gcc-3.3.4.tar.bz2
binutils2.15.91.0.2.tar.bz2
uClibc0.9.27.tar.bz2
genext2fs_1.3.orig.tar.gz
ccache-2.3.tar.gz
将它拷贝到${PRJROOT}/build-tools下,解压
[rootskynetbuild-tools]#tarjxvfbuildroot-0.9.27.tar.tar
[rootskynetbuild-tools]#cdbuildroot
配置它:
[rootskynetbuild-tools]#makemenuconfig
TargetArchitecture(i386)--->选择硬件平台,我的是i386
Buildoptions--->编译选项
这个选项下重要的是(${PRJROOT}/tools)Toolchainandheaderfilelocation?
编译好的工
具链放在哪儿?
如果你像我一样,所有工具包都在本地,不需它到网上自动下载,可以把wgetcommand
选项清空;
ToolchainOptions--->工具链选项
---KernelHeaderOptions头文件它会自动去下载,不过应该保证与你将要用的核是
同一个版本;
[]UsethedailysnapshotofuClibc?
使用最近的uClibc的snapshot
BinutilsVersion(binutils2.15.91.0.2)--->Binutils的版本
GCCcompilerVersion(gcc3.4.2)--->gcc版本
[*]Build/installc++compilerandlibstdc++?
[]Build/installjavacompilerandlibgcj?
支持的语言,我没有选择java
[]Enableccachesupport?
启用ccache的支持,它用于编译时头文件的缓存处理,
用它来编译程序,第一次会有点慢,但是以后的速度可就很理想了,呵呵……
---GdbOptions根据你的需要,选择gdb的支持
PackageSelectionforthetarget--->
这一项我没有选择任意一项,因为我打算根文件系统及busybox等工具链创建成工,
手工来做。
TargetOptions--->文件系统类型,根据实际需要选,我用的ext2;
配置完成后,编译它:
[rootskynetbuild-tools]#make
这一项工作是非常花时间的,我的工具包全部在本地,也花去我一小时十三分的时间,如果
全要下载,我估计网速正常也要多花一两个钟头。
经过漫长的等待(事实上并不漫长,去打了几把游戏,很快过去了):
……
make[1]:
Leavingdirectory`/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3'
touch-c/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs
#-find/home/skynet/build-tools/buildroot/build_i386/root/lib-typef-name\*.so\*|xargs
/home/skynet/tools/bin/i386-linux-uclibc-strip--remove-section=.comment
--remove-section=.note--strip-unneeded2>/dev/null||true;
/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs-i503-b1056\
-d/home/skynet/build-tools/buildroot/build_i386/root-q-D
target/default/device_table.txt/home/skynet/build-tools/buildroot/root_fs_i386.ext2
大功告成!
!
!
清点战利品
让我来看看它究竟做了哪些事情吧:
[rootskynetskynet]#cdtools
[rootskynettools]#ls
binbin-ccachei386-linuxi386-linux-uclibcincludeinfoliblibexecmanusr
bin:
所有的编译工具,如gcc,都在这儿了,只是加了些指定的前缀;
bin-ccache:
如果在Toolchainoptaion中没有选择对ccache的支持,就没有这一项了;
i386-linux:
文件;实际指向include
i386-linux-uclibc:
uclibc的相关工具;
include:
供交叉开发工具使用的头文件;
info:
gcc的info文件;
lib:
供交叉开发工具使用的库文件;
……
现在可以把编译工具所在目录XXX/bin添加至PATH了
测试工具链
如果你现在写一个程序,用i386-linux-gcc来编译,运行的程序会告诉你:
./test:
linkedagainstGNUlibc
因为程序运行库会寻到默认的/lib:
/usr/lib上面去,而我们目前的uclibc的库并不在那里(虽
然对于目标机来讲,这是没有错的),所以,也只能暂时静态编译,试试它能否工作了。
当
然,你也可以在建好根文件系统后,试试用chroot……
第三章编译核
本章的工作,是为目标机建立一个合适的核,对于建立核,我想有两点值得考虑的:
1、功能上的选择,应该能够满足需要的情况下,尽量地小;
2、小不是最终目的,稳定才是;
所以,最好编译核前有一份目标机硬件平台清单以及所需功能清单,这样,才能更合理地
裁减核。
准备工具
Linux核源码,我选用的是Linux-2.4.27.tar.bz2
编译核
将Linux-2.4.27.tar.bz2拷贝至${PRJROOT}/kernel,解压
#cdlinux-2.4.27
//配置
#makeARCH=i386CROSS_COMPILE=i386-linux-menuconfig
//建立源码的依存关系
#makeARCH=i386CROSS_COMPILE=i386-linux-cleandep
//建立核映像
#makeARCH=i386CROSS_COMPILE=i386-linux-bzImage
ARCH指明了硬件平台,CROSS_COMPILE指明了这是交叉编译,且编译器的名称为
i386-linux-XXX,这里没有为编译器指明路径,是因为我前面已将其加入至环境变量PATH。
又是一个漫长的等待……
OK,编译完成,673K,稍微大了点,要移到其它平台,或许得想办法做到512以下才好,
回头来想办法做这个工作。
安装核
核编译好后,将核及配置文件拷贝至${PRJROOT}/images下。
#cparch/i386/boot/bzImage${PRJROOT}/images/bzImage-2.4.27-rmk5
#cpvmlinux${PRJROOT}/images/vmlinux-2.4.27-rmk5
#cpSystem.map${PRJROOT}/images/System-2.4.27-rmk5
#cp.config${PRJROOT}/images/2.4.27-rmk5
我采用了后缀名的方式重命名,以便管理多个不同版本的核,当然,你也可以不用这样,
单独为每个版本的核在images下新建对应文件夹也是可行的。
安装核模块
完整核的编译后,剩下的工作就是建立及安装模块了,因为我的核并没有选择模块的支
持(这样扩展性差了一点,但是对于我的系统来说,功能基本上定死了,这样影响也不太大),
所以,剩下的步骤也省去了,如果你还需要模块的支持,应该:
//建立模块
#makeARCH=i386CROSS_COMPILE=i386-linux-modules
//安装核模块至${PRJROOT}/images
#makeARCH=i386CROSS_COMPILE=i386-linux-\
>INSTALL_MOD_PATH=${PRJROOT}/images/modules-2.4.18-rmk5\
>modules_install
最后一步是为模块建立依存关系,不能使用原生的depmod来建立,而需要使用交叉编译工
具。
需要用到busybox中的depmod.pl脚本,很可惜,我在busybox1.0.0中,并没有找到这
个脚本,所以,还是借用了busybox0.63中scripts中的depmod.pl。
将depmod.pl拷贝至${PREFIX}/bin目录中,也就是交叉编译工具链的bin目录。
#depmod.pl\
>-k./vmlinux–F./System.map\
>-b${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules>\
>${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules/2.4.27-rmk5/modules.dep
注:
后面讨论移植核和模块容时,我只会提到核的拷贝,因为我的系统并没有模块的
支持。
如果你需要使用模块,只需按相同方法将其拷贝至相应目录即可。
附,核编译清单
附,核选择:
核编译记录:
Codematurityleveloptions不选
Loadablemodulesupport不选
Processortypeandfeatures根据实际,选择处理器类型
Generalsetup--->
[*]Networkingsupport
[*]PCIsupport
(Any)PCIaccessmode
[*]PCIdevicenamedatabase
[*]SystemVIPC
[*]Sysctlsupport
(ELF)Kernelcore(/proc/kcore)format
[*]KernelsupportforELFbinaries
[*]PowerManagementsupport
MemoryTechnologyDevices(MTD)--->MTD设备,我用CF卡,不选
Parallelportsupport--->不选
PlugandPlayconfiguration--->我的系统用不着即插即用,不选
Blockdevices--->
[*]Loopbackdevicesupport
[*]RAMdisksupport
(4096)DefaultRAMdisksize(NEW)
[*]InitialRAMdisk(initrd)support
Multi-devicesupport(RAIDandLVM)--->不选
Networkingoptions--->基本上都选了
ATA/IDE/MFM/RLLsupport--->用了默认的
TelephonySupport--->不选
SCSIsupport--->不选
FusionMPTdevicesupport--->不选
I2Odevicesupport--->不选
Networkdevicesupport--->根据实际情况选择
AmateurRadiosupport--->不选
IrDA(infrared)support--->不选
ISDNsubsystem--->不选
OldCD-ROMdrivers(notSCSI,notIDE)--->不选
Inputcoresupport--->不选
Characterdevices--->
[*]Virtualterminal
[*]Supportforconsoleonvirtualterminal
[*]Standard/generic(8250/16550andcompatibleUARTs)serialsupport
[*]Supportforconsoleonserialport
Multimediadevices--->不选
Filesystems--->
[*]Kernelautomounterversion4support(alsosupportsv3)
[*]Virtualmemoryfilesystemsupport(formershmfs)
[*]/procfilesystemsupport
[*]Secondextendedfssupport
Consoledrivers--->
[*]VGAtextconsole调试时接显示器用
剩下三个都不要
Sound--->
USBsupport--->
Kernelhacking--->
第四章建立根文件系统
1、建立目录
构建工作空间时,rootfs文件夹用来存放根文件系统,
#cdrootfs
根据根文件系统的基本结构,建立各个对应的目录:
#mkdirbindevetclibprocsbintmpusrvarroothome
#chmod1777tmp
#mkdirusr/binusr/libusr/sbin
#ls
devetclibprocsbintmpusrvar
#mkdirvar/libvar/lockvar/logvar/runvar/tmp
#chmod1777var/tmp
对于单用户系统来说,root和home并不是必须的。
准备好根文件系统的骨架后,把前面建立的文件安装到对应的目录中去。
2、拷贝库
把uclibc的库文件拷贝到刚才建立的lib文件夹中:
#cd${PREFIX}/lib
[rootskynetlib]#cp*-*.so${PRJROOT}/rootfs/lib
[rootskynetlib]#cp-d*.so.[*0-9]${PRJROOT}/rootfs/lib
3、拷贝核映像和核模块
因为没有模块,所以拷贝模块就省了,
新建boot目录,把刚才建立好的核拷贝过来
#cd/home/kendo/control-project/daq-module/rootfs/
#mkdirboot
#cd${PRJROOT}/images
#cpbzImages-2.4.18-rmk5/home/kendo/control-project/daq-module/rootfs/boot
4、建立/dev下边的设备文件
在linux中,所有的的设备文件都存放在/dev中,使用mknod命令创建基本的设备文件。
mknod命令需要root权限,不过偶本身就是用的root用户,本来是新建了一个用户专门用
于嵌入式制作的,不过后来忘记用了……
#mknod-m600memc11
#mknod-m666nullc13
#mknod-m666zeroc15
#mknod-m644randomc18
#mknod-m600tty0c40
#mknod-m600tty1c41
#mknod-m600ttyS0c464
#mknod-m666ttyc50
#mknod-m600consolec51
基本的设备文件建立好后,再创建必要的符号:
#ln-s/proc/self/fdfd
#ln-sfd/0stdin
#ln-sfd/1stdout
#ln-sfd/2stderr