本文章的基础来自于http://www.cnblogs.com/geekard/archive/2012/05/06/powerpc-toolchain.html
目录:
1. 基本概念
2.准备工作
3.制作过程
3.1 安装内核头文件
3.2 交叉编译Binutils软件包
3.3 交叉编译临时的GCC
3.4 交叉编译Glibc
3.5 交叉编译GCC
4. 总结
1.基本概念
什么是交叉编译工具链,这是许多第一次接触嵌入式开发的童鞋需要理解的首要问题。通常我们已经习惯在X86平台上运行gcc,对源程序进行编译,编译得到的目标程序,仍然是在X86平台上跑的。而交叉编译工具链就是,需要在某个平台上,对源程序进行编译,但是得到的目标程序却是在另外一个平台上运行的。
我们已经知道,在某个平台对程序进行编译后,得到的目标程序,默认也是在该平台运行的(例如X86)。所以我们通常需要在现有平台(通常我们把这个平台称为 Host)的基础上,制作出一个交叉编译工具链(包括gcc、binutils、glibc),得到新的gcc仍然是在该平台(通常我们把该平台称为Host)上运行的,但是当利用新的gcc去对某个源程序进行编译时,得到的目标程序是在目标平台上运行的(通常我们把该平台称为Target)。
现在我们知道,制作交叉编译工具链少不了要先编译一个gcc和 binutils(包括链接器ld strip等工具),但是仅仅是这两个还不够的。我们知道,在对源程序进行编译时,少不了要依赖一些库,例如C运行时库(glibc),而你的Host中的库,它是针对Host体系结构的。例如你的X86中的库,其机器指令一定是X86的。这样,你的交叉编译工具链中,必须有目标平台的库。你肯定已经想到了,先编译好gcc和binutils,然后用这个gcc编译目标平台的库,然后就可以在这个库的基础上,编译目标平台的程序了。
现在你已经可以想到制作一个交叉编译工具链的步骤了,但是很快你会看到,在gcc的编译过程中,我们需要编译2遍,这是为什么呢? 一个全面的gcc(支持各种语言的),需要目标平台的C库(glibc)的一些头文件,但是这个新的gcc编译出来之前,我们又没有安装目标平台的库 (glibc)。所以我们先编译一个基本的gcc(仅仅支持C语言),然后用这个gcc编译目标平台的glibc,注意此时得到的glibc是目标平台的。最后,再在这个库的基础上,重新编译一个全面的gcc。除此之外,我们还要准备好内核头文件,这样我们就可以直接使用内核的一些宏,数据结构定义,数据类型,等等。
在有了这些概念的基础上,下面的操作就相对比较简单了。这里需要提醒的是,同样的编译参数,不同的编译环境,或者不同的gcc binutilsglibc版本,都可能编译不成功。根据我的经验,制作交叉编译工具链,一帆风顺就成功是很少见的。因此在编译过程中,如果遇到失败,耐心+细心的分析config.log,Makefile,可以帮助你定位问题。尤其对于新手来说,千万不要急于求成,妄想直接复制一下命令行,一步步编译就成功。我建议只是先看完一遍,对自己要做什么,和每一步的目的有个大概的了解,然后再开始。欲速则不达,这个道理很简单,恐怕只有多品位几次才能体会。另外,千万不要以超级用户(root)的身份来制作交叉编译工具链,否则一不小心用target平台的库,把Host平台上的库给覆盖了,后果可是很严重哦!
2. 准备工作
cd $HOME
mkdir ppc #工具链的顶层目录,你也可以命名为ARM
cd ppc
mkdir sources
cd sources
wget http://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2
wget http://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2
wget http://ftp.gnu.org/gnu/glibc/glibc-linuxthreads-2.5.tar.bz2
wget http://ftp.gnu.org/gnu/gcc/gcc-4.6.2/gcc-4.6.2.tar.bz2
wget ftp://ftp.kernel.org/pub/linux/kernel/v3.x/linux-3.1.5.tar.bz2
wget ftp://ftp.gnu.org/gnu/gmp/gmp-5.0.2.tar.bz2
wget http://www.mpfr.org/mpfr-current/mpfr-3.1.0.tar.bz2
mkdir ../tools
export TARGET=powerpc-linux #如果是ARM平台,则为arm-linux
export TOOLS=~/ppc/tools
export SOURCES=~/ppc/sources
export PATH=$TOOLS/bin:$PATH #这一步是必需的,只有将带target alias 即powerpc-linux-前缀的工具放到PATH中,才能使用整个交叉编译环境。
export LANGUAGE=C #下面两个参数编译glibc时默认使用的locale
export LC_ALL=C
以上工作主要是安装需要的工具,值得一提的是直接从网站上下载似乎要比wget速度快。还需要MPC的c库工具(http://www.multiprecision.org/index.php?prog=mpc&page=home,它的安装过程和mpfr相似)
3.制作过程
3.1 安装内核头文件(编译glibc时用到)
3.2 交叉编译Binutils软件包
配置源码:
编译并安装:
make
make install
mkdir $TOOLS/include
复制相关的头文件,以后如果要交叉编译gdb时会用到。
安装完成后,$TOOLS目录如下:
此处需要注意的是:$TOOLS/bin/ 和 $TOOLS/$TARGET/bin(TARGET就是powerpc-linux)的内容
这些文件虽然在不同的目录,有不同的名字,但其实是一个文件:
除此之外,binutils把用于生成目标平台的代码的链接脚本安装到$TOOLS/$TARGET/ldscripts目录下。
3.3 交叉编译临时的GCC
由于编译gcc依赖 gmpmpfr这两个库,因此在编译gcc之前,首先安装这两个库到系统中(如果你的系统已经安装了这两个库,则下面的安装步骤可省略。).
如果没有指定--prefix=/usr,那么gmp默认安装到/usr/local目录下,而mpfr默认到/usr目录下搜索这个库。因此这里通过--prefix=/usr,把他们都安装到/usr下。见mpfr的FAQ:http://www.mpfr.org/faq.html
现在第一次编译GCC:
cd $SOURCES
tar jvxf gcc-4.6.2.tar.bz2
mkdir gcc-bootstrap-build
cd gcc-bootstrap-build
../gcc-4.6.2/configure\
--target=$TARGET \ #编译后生成的gcc可以生成的目标代码的执行平台(即编译生成的gcc可以生成target对应的平台的代码)。
--prefix=$TOOLS --disable-nls --disable-shared \
--disable-multilib --disable-decimal-float --disable-threads --disable-libmudflap \
--disable-libssp --disable-libgomp --without-headers --with-newlib \
--enable-languages=c
这一步编译的是一个bootstarp类型的gcc(一个在当前主机上运行的、使用自带的newlib库的gcc,其实是为了解决gcc和glibc间的 “鸡、蛋问题”,:) 。),因此不会使用上一步生成的binutils工具使用的当前系统的binutils,但是当我们编译glibc 最后一次编译gcc时,需要使用上面生成的binutils。
这里的--with-package 的含义是drop newlib into the tree and do a combined build of both at once which breaks the circular dependency. 所以我们编译的gcc被成为bootstrap 即编译的是一个能引导整个编译环境的基本功能编译器。
编译安装gcc库:
3.4 交叉编译Glibc
下面用刚才编译出的临时gcc交叉编译glibc,这个glibc可运行在目标平台的(由host参数指定)。
编译之前,修改glibc-2.9的Makeconfig,否则会出错。
把下面两行:
改成:
配置glibc:
编译并安装:
用这种方法(--prefix=/usr 然后用install_root指定安装位置)编译安装的glibc可以直接拷贝到目标机上运行。
首先,CC=...,binutils=... 指定了用我们新编译好的gcc和binutils,因此得到的glibc是目标平台的。(CC在下一步应该unset)
最后,打开$TOOLS/$TARGET/lib/libc.so
把 GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a ) 改为:
GROUP ( libc.so.6 libc_nonshared.a )
3.5 交叉编译GCC
现在,库已经准备好了,编译一个全面的gcc
这里没有指定--with-newlib,所以使用的是$TOOL/$TARGET下的glibc库,以及$TOOL/$TARGET/bin中的binutils工具。这里使用的是系统的gcc,而不是第一遍生成的powerpc-linux-gcc(因为最终的gcc是运行在本机上的。) 第一遍生成的gcc只用于编译glibc。
交叉编译gcc(powerpc-linux-gcc)被安装在$TOOL目录下,所以不能直接使用$TOOL/$TARGET/bin/gcc,因为交叉编译gcc所调用的一些辅助程序如cc1是放在$TOOL/libexec目录下的。
现在整个交叉编译环境就建立起来了,可以将$TOOL/bin目录放到PATH变量中,这样就可以使用powerpc-linux-gcc即目录中的其它工具为目标板编译任何程序了。
4. 总结
上面的几个步骤中只有编译glibc时是交叉编译过程,需要用到交叉编译器powerpc-linux-gcc和相应的带target alias的binutils。
交叉编译是指在本机上本次编译生成的代码运行在目标主机上,这个过程才叫交叉编译过程。上面的编译bintuils和gcc的过程都不是交叉编译过程,因为它们生成的程序是在当前主机上运行。非交叉编译过程使用的都是本机上的gcc和binutils。但是上面编译后获得的binutils和gcc是交叉编译环境中必不可少的组件(当然,还包括glibc)。一旦使用交叉编译环境中的gcc,则它会自动使用相应的binutils和glibc(因为它们都放在交叉编译环境的目录中$TOOL/$TARGET)。
现在,你就可以在X86平台上运行powerpc-linux-gcc,编译一个C程序,注意得到的目标程序是在 PowerPC平台上执行的。