交叉编译

来源:互联网 发布:淘宝店铺公告图片素材 编辑:程序博客网 时间:2024/06/09 21:53

一、什么是交叉编译

  什么是交叉编译呢,简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓

  平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。

  一个经常会被问到的问题就是,“既然我们已经有了主机编译器,那为什么还要交叉编译呢?”其实答案很简单,没办法啊!有时是因为目的平台上不允许或不能够安装我们所需要的编译器,而我们又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行我们所需要编译器;有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。

  另一个经常会被问到的问题就是:“既然可以交叉编译,那还要主机编译干吗?”其实答案也很简单,交叉编译是不得已而为之!与主机编译相比,交叉编译受的限制更多,虽然在理论上我们可以做任何形式的交叉编译,但事实上,由于受到专利、版权、技术的限制,并不总是能够进行交叉编译,尤其是在业余条件下!举例来说,我们至今无法生成惠普公司专有的som格式的可执行文件,因此我们根本无法做目的平台为HPPA-HPUX的交叉编译。

  就我们这个项目而言,需要交叉编译的原因有两个:首先,在项目的起始阶段,目的平台尚未建立,因此需要做交叉编译,以生成我们所需要的bootloader(启动引导代码)以及操作系统核心;其次,当目的平台能启动之后,由于目的平台上资源的限制,当我们编译大型程序时,依然可能需要用到交叉编译。

二、交叉编译的基础知识

  在做实际工作之前,我想我们应该先掌握一些关于交叉编译的基本知识,其实说白了也就是理解一些我们经常会碰到的英文单词:

  host 主机平台。

  target 目的平台。

  perfix 交叉编译器的安装位置。

  xxx-xxxx-xxxxx 平台描述。

  我们在主机平台上开发程序,并在这个平台上运行交叉编译器,编译我们的程序;而由交叉编译器生成的程序将在目的平台上运行。这里值得说明得是平台描述,象arm-linux、i386-pc-linux2.4.3这样的字符串我们经常会看到,其实它是用来描述平台的,它有完整格式、缩减格式和别名之分。完整格式是:CPU-制造厂商-操作系统,如sparc-sun-sunos4.1.4,说明平台所使用的CPU是sparc,制造厂商是sun,上面运行的操作系统是SunOS,版本是4.1.4。当然,我们都不愿记这么长的东西,因此可以使用短格式,短格式中有选择地去处了制造厂商、软件版本等信息,因此我们同样可以用sparc-sunos或sparc-sunos-sunos4来描述这个平台。如果觉得这个还是太麻烦,那就可以使用别名,sun4m就可以很简单地描述这个平台。需要注意的是,并不是所有的平台都有别名,也不是所有的短格式都可以正确地描述平台。

三、我需要准备些什么

  怎么说呢,你先得准备好主机平台,对我们这个项目来说,我们建议采用x86 Linux做主机平台,因为这样需要的设置工作最少。当然你也可以使用你所喜欢的平台或你所能得到的平台,其中的区别在于你可能必须做更多的设置工作,当然也有这种可能,就是你所选择的主机平台根本不能生成适用于目标平台的正确的交叉编译器。

  对于交叉编译器,可以自己生成,也可以从网上下载。区别在于从网上下载非常简单方便,但也许你找不到适合你所选择的平台的。而自己生成交叉编译器,有时会遇到很多挫折,但这的确是个有趣的值得怀念的经历。

  如果你想自己生成交叉编译器,那你必须先准备下面这些东西

  1、磁盘空间。至少要500M左右的空间,如果想一气呵成的话,那就要900M-1G的空间。

  2、各种源代码。你至少要准备binutils-2.11.2、gcc-2.95.3、linux-2.4.6、newlib-1.8.2或glibc-2.2.2的源代码。

  如果你所使用的主机平台不是运行的linux,那你还必须注意以下这些问题

  1、GNU bash必须是默认shell,所以你也许得把/bin/sh改成bash。

  2、你要确认已经安装了GNU bison,因为这些软经同样使用了bison扩展。

  3、GNU gmake最好是系统默认得make,因为这些软件都使用了gmake扩展,如果不是,在需要make时,记得使用gmake。

  4、如果你想生成交叉glibc,则GNU gsed必须是默认sed,因为glibc会用到gsed的扩展。

  5、如果你想生成交叉glibc,那还必须准备glibc-linuxthreads-2.2.2的源代码。

  6、确认正确的路径搜索顺序,最好让GNU软件首先被执行。

四、怎样生成交叉编译器

  我们建议使用现成的脚本来生成交叉编译器,因为在配置交叉编译器时,会经常使用一些难以理解的开关项。

linux下的交叉编译环境重要包括以下几个部分: 

针对目标系统的编译器gcc 

针对目标系统的二进制工具binutils 

目标系统的标准c库glibc 

目标系统的linux内核头文件 

交叉编译环境的建立步骤 

下载源代码 

下载包括binutils、gcc、glibc及linux内核的源代码(需要注意的是,glibc和内核源代码的版本必须与目标机上实际使用的版本保持一致),并设定shell变量PREFIX指定可执行程序的安装路径。 

编译binutils 

首先运行configure文件,并使用--prefix=$PREFIX参数指定安装路径,使用--target=arm-linux参数指定目标机类型,然后执行make install。 

配置linux内核头文件 

首先执行make mrproper进行清理工作,然后执行make config ARCH=arm(或make menuconfig/xconfig ARCH=arm)进行配置(注意,一定要在命令行中使用ARCH=arm指定cpu架构,因为缺省架构为主机的cpu架构),这一步需要根据目标机的实际情况进行详细的配置,笔者进行的实验中目标机为HP的ipaq-hp3630 PDA,因而设置system type为SA11X0,SA11X0 Implementations中选择Compaq iPAQ H3600/H3700。 

配置完成之后,需要将内核头文件拷贝到安装目录: cp -dR include/asm-arm $PREFIX/arm-linux/include/asm cp -dR include/linux $PREFIX/arm-linux/include/linux 

第一次编译gcc 

首先运行configure文件,使用--prefix=$PREFIX参数指定安装路径,使用--target=arm-linux参数指定目标机类型,并使用--disable-threads、--disable-shared、--enable-languages=c参数,然后执行make install。这一步将生成一个最简的gcc。由于编译整个gcc是需要目标机的glibc库的,它现在还不存在,因此需要首先生成一个最简的gcc,它只需要具备编译目标机glibc库的能力即可。 

交叉编译glibc 

这一步骤生成的代码是针对目标机cpu的,因此它属于一个交叉编译过程。该过程要用到linux内核头文件,默认路径为$PREFIX/arm-linux/sys-linux,因而需要在$PREFIX/arm-linux中建立一个名为sys-linux的软连接,使其内核头文件所在的include目录;或者,也可以在接下来要执行的configure命令中使用--with-headers参数指定linux内核头文件的实际路径。 

configure的运行参数设置如下(因为是交叉编译,所以要将编译器变量CC设为arm-linux-gcc): 

CC=arm-linux-gcc ./configure --prefix=$PREFIX/arm-linux --host=arm-linux --enable-add-ons 

最后,按以上配置执行configure和make install,glibc的交叉编译过程就算完成了,这里需要指出的是,glibc的安装路径设置为$PREFIXARCH=arm/arm-linux,如果此处设置不当,第二次编译gcc时可能找不到glibc的头文件和库。 

第二次编译gcc 

运行configure,参数设置为--prefix=$PREFIX --target=arm-linux --enable-languages=c,c++。 

运行make install。 

到此为止整个交叉编译环境就完全生成了。 

几点注意事项 

第一点、在第一次编译gcc的时候可能会出现找不到stdio.h的错误,解决办法是修改gcc/config/arm/t-linux文件,在TARGET_LIBGCC2_CFLAGS变量的设定中增加-Dinhibit_libc和-D__gthr_posix_h。 

第二点、对与2.3.2版本的glibc库,编译linuxthread/sysdeps/pthread/sigaction.c时可能出错,需要通过补丁glibc-2.3.2-arm.patch解决:执行patch -p1 < glibc-2.3.2-arm.patch 

第三点、第二次编译gcc时可能会出现libc.so的错误,这是需要利用文本编辑器手动修改libc.so。 

原创粉丝点击