Linux ARM交叉编译工具链制作过程
源代码文件及其版本与下载地址:
Binutils-2.19.tar.bz2
http://ftp.gnu.org/gnu/binutils/
gcc-4.4.4.tar.bz2
http://mirrors.kernel.org/gnu/gcc/gcc-4.4.4/
Glibc-2.11.2.tar.bz2
Glibc-ports-2.11.tar.bz2
http://ftp.gnu.org/gnu/glibc/
Gmp-4.2.tar.bz2
http://ftp.gnu.org/gnu/gmp/
Mpfr-2.4.0.tar.bz2
http://ftp.gnu.org/gnu/mpfr/
Linux-2.6.29.tar.bz2
Patch-2.6.29.bz2
http://www.kernel.org/pub/linux/kernel/v2.6/
一般一个完整的交叉编译器涉及到多个软件,主要包括binutils、gcc、glibc等。其中,binutils主要生成一些辅助工具;gcc是用来生成交叉编译器,主要生成arm-linux-gcc交叉编译工具,而glibc主要提供用户程序所需要的一些基本函数库。
二、建立工作目录
进入工作目录:
[root@localhost
[root@localhost
/home/karen/cross
创建工具链文件夹:
[root@localhost
在建立了顶层文件夹embedded- toolchains,下面在此文件夹下建立如下几个目录:
Ø
Ø
Ø
Ø
Ø
Ø
Ø
[root@localhost
[root@localhost
[root@localhost
build-dir doc kernel program setup-dir src-dir tool-chain
[root@localhost
这里我们采用直接拷贝源文件的方法,首先应该修改setup-dir的权限
[root@localhost
然后直接拷贝/home/karen目录下的源文件到setup-dir目录中,如下图:

建立编译目录:
[root@localhost
[root@localhost
三、输出环境变量
输出如下的环境变量方便我们编译。
为简化操作过程。下面就建立shell命令脚本environment-variables:
[root@localhost
[root@localhost
[root@localhost
用编辑器vi编辑环境变量脚本envionment-variables:
[root@localhost
export
export
export
export
export
截图如下:

%% Q:为什么用了source ./environment-variables才正常执行,去掉source就没有执行? %%
%%
%%
说明:
TARGET变量用来定义目标板的类型,以后会根据此目标板的类型来建立工具链。参
看表6-1所示。目标板的定义与主机的类型是没有关系的,但是如果更改TARGET的值,
GNU工具链必须重新建立一次。
PREFIX变量提供了指针,指向目标板工具程序将被安装的目录。
TARGET_PREFIX变量指向与目标板相关的头文件和链接库将被安装的目录。
PATH变量指向二进制文件(可执行文件)将被安装的目录。
如果不惯用环境变量的,可以直接用绝对或相对路径。如果不用环境变量,一般都用绝对路径,相对路径有时会失败。环境变量也可以定义在.bashrc文件中,这样就不用老是export这些变量了。
体系结构和TAEGET变量的对应如下表6-1所示:
表6-1 体系结构和TAEGET变量的对应
体系结构 | TARGET变量的值 |
PowerPC | Powerpc-linux |
ARM | arm-linux |
MIPS(big endian) | mips-linux |
MIPS(little endian) | mipsel-linux |
MIPS64 | mips64-linux |
SuperH3 | sh3-linux |
SuperH4 | sh4-linux |
I386 | i386-linux |
Ia64 | ia64-linux |
M68k | m68k-linux |
M88k | m88k-linux |
Alpha | alpha-linux |
Sparc | sparc-linux |
Sparc64 | sparc64-linux |
Binutils是GNU工具之一,它包括连接器、汇编器和其他用于目标文件和档案的工具,它是二进制代码的处理维护工具。安装Binutils工具包含的程序有addr2line、ar、as、c++filt、gprof、ld、nm、objcopy、objdump、ranlib、readelf、size、strings、strip、libiberty、libbfd和libopcodes。对这些程序的简单解释如下。
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Ø
Binutils工具安装依赖于Bash、Coreutils、Diffutils、GCC、Gettext、Glibc、Grep、Make、Perl、Sed、Texinfo等工具
下面将分步介绍安装binutils-2.19.2的过程。
[root@localhost
[root@localhost
[root@localhost
创建Makefile:
[root@localhost
注意:每个工具的文件名的前缀都是前面为TARGET变量设定的值。如果目标板arm-linux,那么这些工具的文件名前缀就会是arm-linux-。这样就可以根据目标板类型找到正确的工具程序。

五、建立内核头文件
在这里我们使用时2.6.29的内核版本,因为交叉工具链工具链是针对特定的处理器和操作系统的,因此在编译之前就需要对linux内核进行配制,可以通过“make config”或“make menuconfig”命令对内核进行配制,配制完成后,在linux源文件的目录下就会生成一个.config文件,这就是我们所需要的文件。
Note: 目标板的内核版本是2.6.29
[root@localhost
[root@localhost
[root@localhost
[root@localhost
给Linux内核打补丁:
[root@localhost
然后就是配置内核,第一步是修改Makefile
修改 Makefile:
ARCH = arm
CROSS_COMPILE = arm-linux- menuconfig
接着使用make menuconfig进入内核配置菜单
或者直接写:
# make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
System Type -à
配置完退出并保存。
配置完须执行make,参数如下:
[root@localhost linux-2.6.29]# make ARCH=arm CROSS_COMPILE=arm-linux- (执行过程中有错误出现也没关系,主要目的是产生头文件version.h和autoconf.h)
执行完检查一下内核目录中的/kernel/linux-2.6.29/include/linux/version.h和autoconf.h文件是不是生成了,这是编译glibc要用到的。version.h 和 autoconf.h 文件的存在,说明你生成了正确的头文件。
接下来建立工具链需要的include目录,并将内核头文件复制过去。
[root@localhost
[root@localhost
可以查看一下,经过编译可以自动生成。如果已经生成链接,则不必重新链接。(2.6.29已自动生成)
[root@localhost
[root@localhost
[root@localhost
可以查看一下,经过编译可以自动生成。如果已经生成链接,则不必重新链接。
复制头文件到交叉编译工具链的安装目录:
[root@localhost
[root@localhost asm] #cp –r $PRJROOT/kernel/linux-2.6.29/include/linux $TARGET_PREFIX/include
[root@localhost
[root@localhost
root@localhost
root@localhost
Note: mach-xxx是根据目标板所用的cpu类型来选择的
六、建立初始编译器 (boot strap gcc)
这一步的目的主要是建立arm-linux-gcc工具,注意这个gcc没有glibc库的支持,所以只能用于编译内核、BootLoader等不需要C库支持的程序,后面创建C库也要用到这个编译器,所以创建它主要是为创建C库做准备,如果只想编译内核和BootLoader,那么安装完这个就可以到此结束。安装过程如下:
重命名:
[root@localhost
[root@localhost
[root@localhost
从 GCC-4.3起,安装GCC将依赖于GMP-4.1以上版本和MPFR-2.3.2以上版本。如果将这两个软件包分别解压到GCC源码树的根目录下,并分别命名为"gmp"和"mpfr",那么GCC的编译程序将自动将两者与GCC一起编译。建议尽可能使用最新的GMP和MPFR版本。
[root@localhost src-dir]# tar jxvf ../setup-dir/mpfr-2.4.0.tar.bz2
[root@localhost src-dir]# tar jxvf ../setup-dir/gmp-4.2.tar.bz2
[root@localhost src-dir]# mv mpfr-2.4.0 gcc-4.4.4/mpfr
[root@localhost src-dir]# mv gmp-4.2.0 gcc-4.4.4/gmp
•因为是交叉编译器,还不需要目标板的系统头文件,所以需要使用 --without-headers这个选项。否则会有很多*.h头文件找不到的报错
•--enable-language=c用来告诉配置脚本,需要产生的编译器支持何种语言,现在只需支持C语言。虽然配置为c,c++也可以的
•--disable-threads 是因为threads需要libc的支持。
•--disable-decimal-float,需要libc的支持,而我们在初步编译的时候尚未生成libc,否则出现以下的报错:
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:52:18: error: fenv.h: No such file or directory
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c: In function __dfp_test_except:
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: FE_INEXACT undeclared (first use in this function)
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: (Each undeclared identifier is reported only once
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: for each function it appears in.)
•--disable-shared,既然是第一次安装ARM交叉编译工具,那么本机的glibc支持的应该是本机的编译工具库,而不是ARM交叉编译工具库。forces GCC to link its internal libraries statically,没有这个选项,会有 crti.o: No such file: No such file or directory collect2: ld returned 1 exit status
注:由于没有arm的glibc,需要使用--disable-libmudflap --disable-libssp,禁止两个边界检查使用的库。
同样,由于第一次安装ARM交叉编译工具,那么支持的libc库的头文件也没有,src-dir/gcc-4.4.4/gcc/config/arm/t-linux文件,在TARGET_LIBGCC2_CFLAGS中添加两个定义:-Dinhibit_libc
原文:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer –fPIC
改后:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D_gthr_posix.h
编译:
[root@localhost
[root@localhost build-gcc]# ../../src-dir/gcc-4.4.4/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-shared --disable-threads --disable-decimal-float –disable-libmudflap –disable-lipssp
注:很多资料中之有前面两项,这只建立了gcc,没有建立libgcc.a,这样会在glibc的编译中出现-lgcc没有找到的错误。报告:
……/build-tools/build-glibc/libc_pic.a
i586-linux-gcc
/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/arm-linux/4.4.4/../../../../ram-linux/bin/ld: cannot find -lgcc
在glibc的编译中,还需要libgcc_eh.a(否则出现错误:-lgcc_eh没有找到……bin/ld: cannot find -lgcc_eh),使用了--disable-shared的选项,将不会生成libgcc_eh.a,可以通过对libgcc.a的链接来实现。
[root@localhost build-gcc]#
“/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/i586-linux/4.3.3/libgcc_eh.a” -> “libgcc.a”
装完成后,查看结果:
[root@localhost

如果arm-linux-gcc等工具已经生成,表示boot trap gcc工具已经安装成功
七、编译glibc
[root@localhost
[root@localhost
[root@localhost
[root@localhost
[root@localhost
[root@localhost
[root@localhost
[root@localhost
[root@localhost build-glibc] # CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib /
../../src-dir/glibc-2.11.2/configure /
--host=arm-linux /
--prefix=$PREFIX/$TARGET /
--with-tls --disable-profile /
--enable-add-ons /
--with-headers=$PREFIX/$TARGET/include /
libc_cv_forced_unwind=yes /
libc_cv_c_cleanup=yes /
libc_cv_arm_tls=yes
这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
对 libc.so 的修正·
vi $PREFIX /${TARGET}/lib/libc.so
去掉绝对路径,修改后的内容如下:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux.so.3 ) )
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
八、建立全套编译器 (full gcc)
[root@localhost
[root@localhost
[root@localhost

我们再来看看 $PREFIX/bin 里面多了哪些东西。你会发现多了 arm-linux-g++ 、和 arm-linux-c++ 几个文件。
G++-gnu的 c++ 编译器。
C++-gnu 的 c++ 编译器。
至此,整个交叉编译环境就建立完成了。
查看文件是否为二进制文件:
[root@localhost
查看缺省的搜寻路径:
[root@localhost
[root@localhost
[root@localhost
#include
int main(void)
{
}
[root@localhost
评论