《3嵌入式操作系统3.ppt》由会员分享,可在线阅读,更多相关《3嵌入式操作系统3.ppt(123页珍藏版)》请在三一办公上搜索。
1、嵌入式操作系统 GNU开发工具链介绍,李春杰,主要内容,.1 前言交叉开发.2 GNU Tools 简介GCCGNU binutilsGdb调试器GNU make软件工程工具GNU ld链接器.3 GNU tools 交叉开发环境的安装.4 小结和作业,1 前言交叉开发.2 GNU Tools 简介GCCGNU binutilsGdb调试器GNU make软件工程工具GNU ld链接器.3 GNU tools 交叉开发环境的安装.4 小结和作业,本地开发 vs 交叉平台开发,本地开发:一般软件的开发属于本地开发,也就是说开发软件的系统与运行软件的系统是相同的。交叉平台开发:本课程所涉及到的嵌入
2、式系统开发属于交叉平台开发,也就是说开发软件的系统与运行软件的系统不同。,交叉开发平台,主机:开发软件的平台,称为主机,往往是通用电脑;目标机:运行软件的平台,称为目标机,在这里是嵌入式系统。,嵌入式交叉开发工具,掌握嵌入式开发工具的使用是进行嵌入式开发的前提条件之一与主流开发工具类似,嵌入式交叉开发工具也包括编译器,即能够把一个源程序编译生成一个可执行程序的软件调试工具,即能够对执行程序进行源码或汇编级调试的软件软件工程工具,用于协助多人开发或大型软件项目的管理的软件,GNU tools,GNU tools和其他一些优秀的开源软件可以完全覆盖上述类型的软件开发工具。为了更好的开发嵌入式系统,
3、需要熟悉如下一些软件GCCGNU 编译器集Binutils辅助 GCC 的主要软件Gdb调试器make软件工程工具di,patch补丁工具CVS版本控制系统,一、GCC,很多人认为GCC只是一个C编译器,其实GCC=GNU Compiler Collection目前,GCC可以支持多种高级语言,如C、C+ADAObject CJAVAFortranPASCAL,GCC下的工具,cpp 预处理器GNU C编译器在编译前自动使用cpp对用户程序进行预处理gcc 符合ISO等标准的C编译器g+基本符合ISO标准的C+编译器gcj GCC的java前端gnat GCC的GNU ADA 95前端,GNU
4、 Toolsgcc,gcc是一个强大的工具集合,它包含了预处理器、编译器、汇编器、链接器等组件。它会在需要的时候调用其他组件。输入文件的类型和传递给gcc的参数决定了gcc调用具体的哪些组件。对于开发者,它提供的足够多的参数,可以让开发者全面控制代码的生成,这对嵌入式系统级的软件开发非常重要作业1:总结Gcc指令的主要参数有哪些?主要用法?,gcc使用举例(1)源程序,gcc使用举例(2)编译和运行,gcc的工作过程(1),如果使用-v选项,则可以看到许多被隐藏的信息,gcc的编译过程,一般情况下,c程序的编译过程为1、预处理2、编译成汇编代码3、汇编成目标代码4、链接,1、预处理,预处理:使
5、用-E参数输出文件的后缀为“.cpp”gcc E o gcctest.cpp gcctest.c使用wc命令比较预处理后的文件与源文件,可以看到两个文件的差异,行数 单词数 字节数,预处理是指在系统对源程序进行编译之前,对程序中某些特殊的命令行的处理,预处理程序将根据源代码中的预处理命令修改程序。使用预处理功能可以改善程序的设计环境,提高程序的通用性、可读性、可修改性、可调试性、可移植性和方便性,易于模块化。预处理命令有三类:宏定义、文件包含和条件编译。下面是常见的预处理命令:#include,文件包含,用于把指定的文件内容包含到所在文件的当前位置处。#define 和#undef,分别用于定
6、义和取消定义条件编译符号。#if、#elif、#else 和#endif,用于按条件跳过源代码中的节。,预处理文件和源文件的区别:从预处理的角度讲:对于一个包含了多个头文件的源文件,只要用头文件的内容替换掉源文件中的对应的include语句,就可以得到预处理后的源文件。这个最终生成的源文件的编译结果就是最终的编译结果。,2、编译成汇编代码,预处理文件汇编代码1)使用-x参数说明根据指定的步骤进行工作,2)cpp-output指明从预处理得到的文件开始编译3)使用-S说明生成汇编代码后停止工作gcc x cpp-output S o gcctest.s gcctest.cpp也可以直接编译到汇编
7、代码gcc S gcctest.c,预处理文件汇编代码,直接编译到汇编代码,s,s,s,3、编译成目标代码,汇编代码目标代码gcc x assembler c gcctest.s-x指定步骤 assembler汇编标志直接编译成目标代码gcc c gcctest.c使用汇编器生成目标代码as o gcctest.o gcctest.s,汇编代码目标代码,直接编译成目标代码,使用汇编器,4、编译成执行代码,目标代码执行代码gcc o gcctest gcctest.o直接生成执行代码gcc o gcctest gcctest.c,目标代码执行代码,直接生成执行代码,gcc的高级选项,-Wall:
8、打开所有的警告信息,根据警告信息检查源程序,Main函数的返回值为int,在函数的末尾应当返回一个值,修改源程序,优化编译,优化编译选项有:-O0缺省情况,不优化-O1-O2-O3等等,gcc的优化编译举例(1)考虑如下的源代码,不同的优化编译选项,gcc的优化编译举例(2)使用time命令统计程序的运行,二、GNU binutils,binutils是一组二进制工具程序集,是辅助GCC的主要软件,它主要包括addr2line 把程序地址转换为文件名和行号。在命令行中给它一个地址和一个可执行文件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。ar 建立、修改、提取归
9、档文件。归档文件是包含多个被包含文件内容的一个大文件,其结构保证了引用文件索引,可以恢复原始文件内容。,as 是GNU汇编器,主要用来编译GNU C编译器gcc输出的汇编文件,他将汇编代码转换成二进制代码,并存放到一个object文件中,该目标文件将由连接器ld连接C+filt解码C+符号名,连接器使用它来过滤 C+和 Java 符号,防止重载函数冲突。gprof 显示程序调用段的各种数据。ld 是连接器,它把一些目标和归档文件结合在一起,重定位数据,并链接符号引用,最终形成一个可执行文件。通常,建立一个新编译程序的最后一步就是调用ld。,nm 列出目标文件中的符号。objcopy把一种目标文
10、件中的内容复制到另一种类型的目标文件中,Objcopy可以使用不同于源目标文件的格式来写目的目标文件(也即是说可以将一种格式的目标文件转换成另一种格式的目标文件)。objdump 显示一个或者更多目标文件的信息。使用选项来控制其显示的信息。它所显示的信息通常只有编写编译工具的人才感兴趣。ranlib 产生归档文件索引,并将其保存到这个归档文件中。在索引中列出了归档文件各成员所定义的可重分配目标文件。readelf 显示elf格式可执行文件的信息。,size 列出目标文件每一段的大小以及总体的大小。默认情况下,对于每个目标文件或者一个归档文件中的每个模块只产生一行输出。strip 丢弃目标文件中
11、的全部或者特定符号,binutils开发工具使用举例,arnmObjcopyreadelf,1、ar,ar用于建立、修改、提取归档文件(archive),一个归档文件,是包含多个被包含文件的单个文件(也可以认为归档文件是一个库文件)。被包含的原始文件的内容、权限、时间戳、所有者等属性都保存在归档文件中,并且在提取之后可以还原文件的相关属性。,使用ar建立库文件(1),源程序add.c和minus.c,Step1:生成 add.o 和 minus.o 两个目标文件step2:生成库文件,并复制到/usr/lib/目录,Ar的rv参数的说明:r:将多个文件组成一个文件v:输出信息,在代码中使用Ad
12、d和Minus函数,在链接时,使用“-l”选项来指明库文件,2、nm,nm的主要功能是列出目标文件中的符号,这样程序员就可以定位和分析执行程序和目标文件中的符号信息和它的属性,nm 显示的符号类型A:符号的值是绝对值,并且不会被将来的链接所改变B:符号位于未初始化数据部分(BSS 段)C:符号是公共的。公共符号是未初始化的数据。在链接时,多个公共符号可能以相同的名字出现。如果符号在其他地方被定义,则该文件中的这个符号会被当作引用来处理D:符号位于已初始化的数据部分T:符号位于代码部分U:符号未被定义?:符号类型未知,或者目标文件格式特殊,nm使用举例,nm使用举例,命令nm test.o的输出
13、说明了test.o定义了main函数,但没有定义Add、Minus和Printf函数符号。命令nm add.o的输出说明了add.o定义了Add函数符号。命令nm minus.o的输出说明了minus.o定义了Minus函数符号。test.o中没有定义但使用了printf函数符号,printf函数实际上定义在libc.a库中。,3 objcopy,可以将一种格式的目标文件内容进行转换,并输出为另一种格式的目标文件。它使用GNU BFD(binary format description)库读/写目标文件,通过这个BFD库,objcopy能以一种不同于源目标文件的格式生成新的目标文件$objco
14、py h命令可以看到objcopy的一般帮助信息在makefile里面用-O binary 选项来生成原始的二进制文件,即通常说的image文件,Objcopy使用举例,使用file命令查看文件类型,生成srec格式的目标文件,4、readelf,readelf:显示一个或多个ELF格式的目标文件信息,Readelf使用举例,5、GNU Toolsld,ld,The GNU LinkerLinux上常用的链接器ld软件的作用是把各种目标文件(.o文件)和库文件链接在一起,并定位数据和函数地址,最终生成可执行程序ld-o hello/lib/crt0.o hello.o lc 该指令把/lib/
15、crt0.o hello.o 和库文件libc.a链接起来生成新的执行程序hello,gcc可以间接的调用ld,使用gcc的-Wl参数可以传递参数给ldgcc-W1,-startgroup foo.o bar.o-W1,-endgroup等同于执行如下ld命令:Ld-startgroup foo.o bar.o-endgroup使用命令:ld-help可以列出ld常用的一些选项,ld使用举例(1),源程序,编译hello.c到hello.o命令:gcc-c hello.c,链接命令:ld dynamic-linker/lib/ld-linux.so.2/usr/lib/crt1.o/usr/l
16、ib/crti.o/usr/lib/crtn.o hello.o lc o hello运行./hello,目标文件,ld通过BFD库可以读取和操作coff、elf、a.out等各种执行文件格式的目标文件BFD(Binary File Descriptor)目标文件(object file)由多个节(section)组成,常见的节有:text节保存了可执行代码,data节保存了有初值的全局标量,bss节保存了无初值的全局变量。,链接描述文件(Linker script),可以使用链接描述文件控制ld的链接过程。链接描述文件,command file又称为链接脚本,Linker script用来控
17、制ld的链接过程描述各输入文件的各节如何映射到输出文件的各节控制输出文件中各个节或者符号的内存布局使用的语言为:The ld command language,链接命令语言,ld命令的-T commandfile选项指定了链接描述文件名如果不指定链接描述文件,ld就会使用一个默认的描述文件来产生执行文件链接描述文件主要由一系列的命令组成,每个命令可以是一个带参数的关键字或赋值语句。,链接描述文件的命令,链接描述文件的命令主要包括如下几类:设置入口点命令处理文件的命令处理文件格式的命令其他,常用的命令,设置入口点格式:ENTRY(symbol)设置symbol的值为执行程序的入口点。ld有多种方
18、法设置执行程序的入口点,确定程序入口点的顺序如下:ld命令的-e选项指定的值Entry(symbol)指定的值.text节的起始地址入口点为0,常用的命令,INCULDE filename包含其他filename的链接描述文件INPUT(file,file,)指定多个输入文件名OUTPUT_FORMAT(bfdname)指定输出文件的格式OUTPUT_ARCH(bfdname)指定目标机器体系结构,例如:OUTPUT_ARCH(arm),常用的命令,MEMORY:这个命令在用于嵌入式系统的链接描述文件中经常出现,它描述了各个内存块的起始地址和大小。格式如下:MEMORYname(attr):O
19、RIGIN=origin,LENGTH=lenName可以理解为描述的内存块名字,len表示这个内存的大小,attr表示内存块的属性,它的值可以是:R:只读W:可读/写X:可执行A:可分配等,例如:,Memory举例,SECTIONS命令,SECTIONS告诉ld如何把输入文件的各个节映射到输出文件的各个节中。在一个链接描述文件中只能有一个SECTIONS命令在SECTIONS命令中可以使用的命令有三种:定义入口点赋值定义输出节,一个简单例子,下面是一个简单的例子:例中,输出文件包含text,data,bss三个节,而输入文件也只包含这3个节:SECTIONS.=0 x01000000;/表示
20、可执行文件的起始加载地址0 x01000000.text:*(.text);/表示把所有输入文件的.text收集起来形成新的输出文件.text.=0 x08000000;/表示.data的起始地址0 x08000000.data:*(.data);.bss:*(.bss);/.bss的起始地址为0 x08000000加上所有输入文件/.data的大小,最后看个简单的输入section相关例子:SECTIONS outputa 0 x10000:all.ofoo.o(.input1)outputb:foo.o(.input2)foo1.o(.input1)outputc:*(.input1)*(
21、.input2)本例中,将all.o文件的所有section和foo.o文件的所有(一个文件内可以有多个同名section).input1 section依次放入输出outputa section内,该section的VMA是0 x10000;将foo.o文件的所有.input2 section和foo1.o文件的所有.input1 section依次放入输出outputb section内,该section的VMA是当前定位器符号的修调值(对齐后);将其他文件(非all.o、foo.o、foo1.o)文件的.input1 section和.input2 section放入输出outputc
22、section内.,运用实例,lds 运用实例展示共5个文件nand.lds Makefile head.s init.c main.c链接描述文件nand.lds1)/nand.ldsSECTIONS firtst 0 x00000000:head.o init.o second0 x30000000:AT(4096)main.o,运用实例,/Makefilenand:head.smain.c init.carm-linux-gcc-c-o head.o head.sarm-linux-gcc-c-o init.o init.carm-linux-gcc-c-o main.o main.ca
23、rm-linux-ld-Tnand.lds head.o init.o main.o-o nand_tmp.oarm-linux-objcopy-O binary-S nand_tmp.o nandarm-linux-objdump-D-b binary-m armnand ttt.sclean:rm-fhead.o init.omain.o tmp.o nand_tmp.onand)执行make语句即可生成所需要的可执行文件objdump D进行反汇编,一个例子u-boot.lds for 2410,=/u-boot.lds for 2410OUTPUT_FORMAT(“elf32-litt
24、learm”,“elf32-littlearm”,“elf32-littlearm”)/*OUTPUT_FORMAT(“elf32-arm”,“elf32-arm”,“elf32-arm”)*/OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS.=0 x00000000;.=ALIGN(4);.text:cpu/arm920t/start.o(.text)*(.text).=ALIGN(4);.rodata:*(.rodata).=ALIGN(4);.data:*(.data).=ALIGN(4);.got:*(.got)_u_boot_cmd_start=.;.u_b
25、oot_cmd:*(.u_boot_cmd)_u_boot_cmd_end=.;armboot_end_data=.;.=ALIGN(4);_bss_start=.;.bss:*(.bss)_end=.;armboot_end=.;,三、其他GNU工具,Gdb调试器GNU make软件工程工具diff,patch补丁工具CVS版本控制系统,1、GNU Toolchaingdb,Gdb=GNU debugerGNU tools中的调试器,功能强大设置断点监视、修改变量单步执行显示/修改寄存器的值堆栈查看远程调试,gdb使用举例,编译:gcc o bug bug.c,由于string是个未确定的字
26、符串地址,程序将出现错误。,gcc g o bug bug.c,编译并运行,?,编译,使用 gdb 调试 bug,加载bug,运行bug,查找错误区域,能不能看到源代码呢?,使用gcc的-g参数,gcc g o bug bug.c重新调试,列出源代码,设置断点,单步执行,察看string的值,发现string指向无效的地址指针,问题答案:在Printf语句和get语句之间加入string=buff,程序正确,2、使用GNU make管理项目,GNU make是一种代码维护工具,在使用GNU编译器开发大型应用时,往往要使用make管理项目。如果不使用make管理项目,就必须重复使用多个复杂的命令
27、行维护项目和生成目标代码。Make通过将命令行保存到makefile中简化了编译工作。Make的主要任务是根据makefile中定义的规则和步骤,根据各个模块的更新情况,自动完成整个软件项目的维护和代码生成工作。,Make可以识别出makefile中哪些文件已经被修改,并且在再次编译的时候只编译这些文件,从而提高编译的效率Make会检查文件的修改和生成时间戳,如果目标文件的修改或者生成时间戳比它的任意一个依赖文件旧,则make就执行makefile文件中描述的相应命令,以便更新目的文件只更新那些需要更新的文件,而不重新处理那些并不过时的文件,特点:适合于支持多文件构成的大中型软件项目的编译,链
28、接,清除中间文件等管理工作提供和识别多种默认规则,方便对大型软件项目的管理支持对多目录的软件项目进行递归管理对软件项目具有很好的可维护性和扩展性,Makefile 介绍,make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。makefile主要定义了1)依赖关系即有关哪些文件的最新版本是依赖于哪些别的文件产生或者组成的2)需要用什么命令来产生目标文件的最新版本3)以及一些其他的功能,Makefile 的规则,target.:mand.target也就是一个目标文件,可以是Object File,也可以是执行文件,还可以是一个标签(Label)。p
29、rerequisites就是,要生成那个target所需要的文件或是目标。command也就是make需要执行的命令。(任意的Shell 命令),这是一个文件的依赖关系,也就是说target这一个或多个的目标文件依赖prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites 中如果有一个以上的文件比target文件要新 command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。,Makefile一个示例,在这个示例中,我们的工程有8 个C 文件,和3个头文件,我们要写一个Makefile来告诉
30、make命令如何编译和链接这几个文件。我们的规则是:如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。,edit:main.o kbd.o command.o display.o insert.o search.o files.o utils.o cc-o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o/目标文件变为可执
31、行文件 main.o:main.c defs.h cc-c main.c kbd.o:kbd.c defs.h command.h cc-c kbd.c command.o:command.c defs.h command.h cc-c command.c display.o:display.c defs.h buffer.h cc-c display.c insert.o:insert.c defs.h buffer.h cc-c insert.c search.o:search.c defs.h buffer.h cc-c search.c files.o:files.c defs.h b
32、uffer.h command.h cc-c files.c utils.o:utils.c defs.h cc-c utils.c clean:rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o,在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号后面的那些.c 文件和.h文件。每一个.o 文件都有一组依赖文件,而这些.o 文件又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些
33、文件生成的,换言之,目标文件是哪些文件更新的。,make 是如何工作的,输入make命令make会在当前目录下找名字叫“Makefile”或“makefile”的文件。如果找到,它会找文件中的第一个目标文(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。如果edit文件不存在,或是edit所依赖的后面的.o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件,然后再用.o 文
34、件生成make的终极任务,也就是执行文件edit。,Makefile 中的变量,使用变量可以降低错误风险简化makefile例:objects变量($(objects))objects=main.o kbd.o command.o display.o insert.o search.o files.o utils.oedit:$(objects)cc-o edit$(objects),make自动推导,make看到一个.o文件,它就会自动的把.c、文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc-c wha
35、tever.c 也会被推导出来。,简化后的makefile文件,objects=main.o kbd.o command.o display.o insert.o search.o files.o utils.oedit:$(objects)cc-o edit$(objects)main.o:defs.h kbd.o:defs.h command.h command.o:defs.h command.h display.o:defs.h buffer.h insert.o:defs.h buffer.h search.o:defs.h buffer.h files.o:defs.h buffe
36、r.h command.h utils.o:defs.h.PHONY:clean clean:rm edit$(objects),这种方法,也就是make的“隐晦规则”。“.PHONY”表示,clean是个伪目标文件,内部变量,$扩展成当前规则的目的文件名$扩展成依赖列表中的第一个依赖文件$扩展成整个依赖列表(除掉了里面所有重复的文件名)等等不需要括号括住例如:CC=gccCFLAGS=-Wall-O-g foo.o:foo.c foo.h bar.h$(CC)$(CFLAGS)-c$-o$(CC)$(CFLAGS)c foo.c-o foo.o,设定目标(Phony Targets),设定目
37、标目标不是一个文件其目的是为了让一些命令得以执行使用PHONY显式声明设定目标.PHONY:clean使用设定目标实现多个目的all:prog1 prog2,典型的设定目标,设定目的也可以用来描述一些其他的动作。例如,想把中间文件和可执行文件删除,可以在 makefile 里设立这样一个规则:clean:$rm*.o exec_file前提是没有其它的规则依靠这个 clean 目的,它将永远不会被执行。但是,如果你明确的使用命令 make clean,make 会把这个目的做为它的主要目标,执行那些 rm 命令,到这里交叉开发的基本工具就讲完了GCCGNU binutilsGdb调试器GNU
38、make软件工程工具GNU ld链接器,GNU tools 交叉开发环境的安装,交叉开发环境源代码配置安装,or直接安装二进制工具第一种方法比较复杂,如果有现成的二进制交叉环境,建议直接使用,使用源代码安装交叉开发环境,GNU tools的各个软件包相对独立,在选择时要注意各个软件包的版本号及其依赖关系如果全部是最新版本,也并不能保证可以配置并安装成功一般下载别人成功的版本组合,或采用从较新版本逐步尝试法进行在安装GNU tools交叉开发环境之前,首先必须建立本地GNU tools环境,一个可行的GNU tools与Linux内核之间关系表,交叉开发环境的安装顺序,需要5个步骤完成整个GNU
39、 Tools的配置/编译/安装:内核头文件配置binutils软件包安装Bootstrap GNU编译器(可完成基本C语言编译工作的编译器)C library的安装,一般是glibc完整的GNU编译器安装,软件包安装步骤,对每个单独的软件包,一般安装过程包括下面4步下载并解压软件包配置软件包编译软件包安装软件包,源代码安装交叉开发环境,这个过程如下1.下载源文件、补丁和建立编译的目录2.建立内核头文件3.建立二进制工具(binutils)4.建立初始编译器(bootstrap gcc)5.建立c库(glibc)6.建立全套编译器(full gcc),1、下载源文件、补丁和建立编译的目录,(1)
40、下载源码选定软件版本号 linux-2.4.21+rmk2binutils-2.10.1gcc-2.95.3glibc-2.2.3glibc-linuxthreads-2.2.3,1、下载源文件、补丁和建立编译的目录,(2)建立工作目录$mkdir embedded 再在这个项目目录 embedded 下建立三个目录 build-tools、kernel 和 tools。build-tools-用来存放你下载的 binutils、gcc 和 glibc 的源代码和用来编译这些源代码的目录。kernel-用来存放你的内核源代码和内核补丁。tools-用来存放编译好的交叉编译工具和库文件$mkdi
41、r build-tools kernel tools$ls embedded build-tools kernel tools,1、下载源文件、补丁和建立编译的目录,(3)建立输出和环境变量我们输出如下的环境变量方便我们编译$export PRJROOT=/home/lichj/embedded$export TARGET=arm-linux$export PREFIX=$PRJROOT/tools$export TARGET_PREFIX=$PREFIX/$TARGET$export PATH=$PREFIX/bin:$PATH,1、下载源文件、补丁和建立编译的目录,环境变量的解释PRJRO
42、OT是建立交叉编译工具链的工作目录TARGET是目标平台的名称PREFIX是一个路径前缀TARGET_PREFIX是目标程序用到的路径前缀$export PATH=$PREFIX/bin:$PATH这句话的目的是把交叉编译环境用到的工具路径加到PATH环境变量的最前面。这样可以在编译工具链的过程中,指定使用交叉编译环境用到的工具,不使用本机的工具,得到一个与本机无关的干净工具链。,1、下载源文件、补丁和建立编译的目录,(4)建立编译目录为了把源码和编译时生成的文件分开,一般的编译工作不在的源码目录中,要另建一个目录来专门用于编译。用以下的命令来建立编译你下载的binutils、gcc和glib
43、c的源代码的目录。$cd$PRJROOT/build-tools$mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patchbuild-binutils-编译binutils的目录build-boot-gcc-编译gcc 启动部分的目录build-glibc-编译glibc的目录build-gcc-编译gcc 全部的目录,1、下载源文件、补丁和建立编译的目录,(4)建立编译目录gcc-patch放gcc的补丁的目录gcc-2.95.3 的补丁有 gcc-2.95.3-2.patch、gcc-2.95.3-no-fixi
44、nc.patch 和gcc-2.95.3-returntype-fix.patch,,2、建立内核头文件,下载的内核源代码放入$PRJROOT/kernel 目录$cd$PRJROOT/kernel$tar-xzvf linux-2.4.21.tar.gz 给 Linux 内核打上你的补丁$cd linux-2.4.21$patch-p1./patch-2.4.21-rmk2 编译内核生成头文件$make ARCH=arm CROSS_COMPILE=arm-linux-menuconfig在System Types中选择正确的硬件类型,2、建立内核头文件,配置完成退出并保存检查一下的内核目录
45、include/linux/version.h 和include/linux/autoconf.h 文件是不是生成。Linux 内核头文件拷贝过来建立连接$mkdir-p$TARGET_PREFIX/include$cp-r$PRJROOT/kernel/linux-2.4.21/include/linux$TARGET_PREFIX/include$cp-r$PRJROOT/kernel/linux-2.4.21/include/asm-arm$TARGET_PREFIX/include,3、建立二进制工具(binutils),解压下载的binutils源文件$cd$PRJROOT/buil
46、d-tools$tar-xvjf binutils-2.10.1.tar.bz2进入build-binutils目录配置和编译binutils$cd build-binutils$./binutils-2.10.1/configure-target=$TARGET-prefix=$PREFIX-target 选项是指出我们生成的是 arm-linux 的工具,-prefix 是指出我们可执行文件安装的位置。,3、建立二进制工具(binutils),$make$make install$PREFIX/bin 下的生成的文件,4.建立初始编译器(bootstrap gcc),首先进入 build-
47、tools 目录,将下载 gcc 源代码解压$cd$PRJROOT/build-tools$tar-xvzf gcc-2.95.3.tar.gz然后进入 gcc-2.95.3 目录给 gcc 打上补丁$cd gcc-2.95.3$patch-p1./gcc-patch/gcc-2.95.3.-2.patch$patch-p1./gcc-patch/gcc-2.95.3.-no-fixinc.patch$patch-p1./gcc-patch/gcc-2.95.3-returntype-fix.patch,4.建立初始编译器(bootstrap gcc),修改gcc配置(/gcc-2.95.3/
48、config/arm/t-linux)TARGET_LIBGCC2-CFLAGS=-fomit-frame-pointer-fPIC这一行改为TARGET_LIBGCC2-CFLAGS=-fomit-frame-pointer-fPIC-Dinhibit_libc-D_gthr_posix_h,4.建立初始编译器(bootstrap gcc),配置boostrap gcc$cd build-boot-gcc$./gcc-2.95.3/configure-target=$TARGET prefix=$PREFIX-without-headers-enable-languages=c-disabl
49、e-threads 这条命令中的-target、-prefix 和配置 binutils 的含义是相同的,-without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。-disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。,4.建立初始编译器(bootstrap gcc),接着我们编译并安装 boot-gcc$make all-gcc$make install-gcc,5、建立 c 库(glibc),首先解压 glibc-2.2.3.
50、tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代码$cd$PRJROOT/build-tools$tar-xvzf glibc-2.2.3.tar.gz$tar-xzvf glibc-linuxthreads-2.2.3.tar.gz-directory=glibc-2.2.3进入 build-glibc 目录配置 glibc$cd build-glibc$CC=arm-linux-gcc./glibc-2.2.3/configure-host=$TARGET-prefix=/usr-enable-add-ons-with-headers=$TARGET_