1.下载必须的包资源,主要有以下几个:
linux-2.6.10.tar.gz
ftp.kernel.org
glibc-2.3.2.tar.gz
ftp.gnu.org
binutils-2.15.tar.bz2
ftp.gnu.org
glibc-linuxthreads-2.3.2.tar.gz
ftp.gnu.org
gcc-3.3.6.tar.gz
ftp.gnu.org
2.建立工作空间环境
1)创建工作目录树
我们将会在这个工作目录下完成交叉工具链的制作。我是直接把工作目录创建在/opt目录下的:
#cd /opt
#mkdir arm-linux
#cd arm-linux
#mkdir build-tools kernel tools
#mkdir build-tools/sources kernel/sources
# mkdir -p tools/arm-linux/include/linux
# mkdir -p tools/arm-linux/include/asm
arm-linux:是我们的工作主目录。
build-tools:用于编译这些源码包。
build-tools/sources:用于存放我们的源码包。
kernel:用于编译内核源码包(用于生成正确的头文件)。
kernel/sources:用于存放我们的内核源码包。
tools:这个目录用于存放编译后的交叉工具链和库文件。
include/linux :工具的头文件目录,用来存放到时从linux内核提取出来的相应头文件。
include/asm:存放汇编的头文件。
把以下包拷贝到build-tools/sources目录里:
binutils-2.15.tar.bz2,
gcc-core-3.3.6.tar.gz,
glibc-linuxthreads-2.3.2.tar.gz,
gcc-3.3.6.tar.gz,
glibc-2.3.2.tar.gz
把linux-2.6.10.tar.gz拷贝到kernel/sources目录里。
2)设置环境变量
设置了下面这些环境变量可以使编译过程变得方便多了。(这里我是根据自己的实际情况进行设置的)把这些设置写入~/.bashrc或者/etc/profile文件里:
export PROJECT=arm-linux #工程名
export PRJROOT=/opt/${PROJECT} #工程绝对路径
export TARGET=arm-linux #目标平台体系架构
export PREFIX=${PRJROOT}/tools #编译后工具和库文件的路径前缀
export TARGET_PREFIX=${PREFIX}/${TARGET} #目标文件夹的路径前缀路径
export PATH=${PREFIX}/bin:${PATH} #添加可执行文件所在目录到PATH变量
设置好了之后需要执行以下命令使其有效:
#source /etc/profile
3)编译安装binutils工具
①把${PRJROOT}/build-tools/sources目录下的binutils-2.15.tar.bz2包解压到${PRJROOT}/build-tools。命令如下:
#cd $PRJROOT/build-tools/sources
#tar -xjvf binutils-2.15.tar.bz2 -C $PRJROOT/build-tools
②配置binutils并且编译它
#cd $PRJROOT/build-tools/binutils-2.15
# ./configure --target=$TARGET --prefix=#PREFIX(--target指明了生成的是$TARGET的工具,--prefix指明了生成可执行文件所在的目录)
#make
#make install
这样就生成了binutils的可执行文件了,我们可以通过下面的命令来查看这些命令:
#ls $PRJROOT/tools/bin
以下是我编译出来的可执行文件截图:
4)配置编译Linux内核用于生成正确的头文件
①把$PRJROOT/kernel/sources目录下的内核包解压到$PRJROOT/kernel目录里面:
#cd $PRJROOT/kernel/sources
#tar zxvf linux-2.6.10.tar.gz -C $PRJROOT/kernel
②进入$PRJROOT/kernel/linux-2.6.10,配置编译内核:
#cd $PRJROOT/kernel/linux-2.6.10
之后要修改以下Makefiie里面的ARCH和CROSS_COMPILE如下:
ARCH=arm CROSS_COMPILE=arm-linux-
保存之后打开内核配置界面
#make menuconfig
进入配置界面开始配置,配置如下:
SystemType --->ARM system type---> (X)Samsung S3C2410
配置完了之后保存退出,然后在看看include/linux目录下是否生成了文件version.h和autoconf.h,这两个头文件在编译glibc时会用到,如果这两个文件存在,则说明生成了正确的头文件了。
③接下来我们需要把正确的内核头文件拷贝到交叉编译工具链对应的头文件目录里:
#cd $PRJROOT/kernel/linux-2.6.10/include
#cp -r linux $TARGET_PREFIX/include/
#cp -r asm-arm/* $TARGET_PREFIX/incoude/asm
5)编译安装thebootstrap compiler(bootstrap gcc)
这一步主要建立了arm-linux-gcc工具,但是这个gcc并不支持c库,所以只能用于内核和bootloader等不需要用到c库的编译,在后面创建C库的时候会用到这个编译器,所以这里也是为之后创建C库做准备。
下面是编译安装bootstrap gcc的命令:
#cd $PRJROOT/build-tools/
#tar xzvf sources/gcc-3.3.6.tar.gz -C ./
#cd gcc-3.3.6/
开始配置,这里要注意的是默认情况下编译会使用/use/include的头文件的,但是我们这一次编译的gcc是不能支持C库的,所以我们要在gcc/config/arm/t-linux的变量TARGET_LIBGCC2_CFLAGS修改一下,更改如下:
TARGET_LIBGCC2_CFLAGS= -fomit-frame-pointer -fPIC
改成:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -D inhibit_libc -D __gthr_posix_h
保存之后(这里要注意-D后面是有空格的),就可以开始配置操作了:
#./configure --target=$TARGET --prefix=$PREFIX --enable-languages=c--disable-threads --disable-shared
#make
make的时候发现了一个错误,错误信息如下:
这里说在open的第二个参数为O_CREAT时,需要填入第三个参数,这样看应该是程序的bug了,先查看linux API中open函数的用法:
#include <fcntl.h>
int open(constchar *pathname, int oflag, ... );
返回值:成功则返回文件描述符,否则返回 -1
对于open 函数来说,第三个参数(...)仅当创建新文件时才使用,用于指定文件的访问权限位(access permission bits)。pathname是待打开/创建文件的路径名(如C:/cpp/a.cpp);oflag 用于指定文件的打开/创建模式,这个参数可由以下常量(定义于fcntl.h)通过逻辑或构成。
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
O_CREAT 创建模式
如果是创建模式时,第三个参数可以有以下常量通过逻辑或组成:
S_IRUSR
S_IWUSR
S_IRGRP
S_IROTH
这几个是什么意思这里我就不多说了,想要了解的话可以自己去查查。
接下来我就可以来改掉这个错误了:
直接在提示出错的函数把第三个参数改成S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,使用find搜索到collect2.c的路径在./gcc/collect2.c ,修改如下:
改成:
好了,make clean后再重新make一下,真是坑爹阿,有错误,错误信息如下:
*** buffer overflow detected ***: arm-linux-ar terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0x4011cc75]
/lib/i386-linux-gnu/libc.so.6(+0xe7a77)[0x4011ba77]
/lib/i386-linux-gnu/libc.so.6(+0xe70d5)[0x4011b0d5]
/lib/i386-linux-gnu/libc.so.6(_IO_default_xsputn+0x91)[0x400a12f1]
/lib/i386-linux-gnu/libc.so.6(_IO_padn+0xc9)[0x40094fe9]
/lib/i386-linux-gnu/libc.so.6(_IO_vfprintf+0x3322)[0x40077452]
/lib/i386-linux-gnu/libc.so.6(__vsprintf_chk+0xc9)[0x4011b1a9]
/lib/i386-linux-gnu/libc.so.6(__sprintf_chk+0x2f)[0x4011b0bf]
arm-linux-ar[0x804eb70]
arm-linux-ar[0x8050c6c]
arm-linux-ar[0x8054c3a]
arm-linux-ar[0x804c27a]
arm-linux-ar[0x8049e31]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x4004d113]
arm-linux-ar[0x804a4fd]
======= Memory map: ========
08048000-0809e000 r-xp 00000000 08:01 317227 /opt/arm-linux/tools/bin/arm-linux-ar
0809e000-0809f000 r--p 00055000 08:01 317227 /opt/arm-linux/tools/bin/arm-linux-ar
0809f000-080a0000 rw-p 00056000 08:01 317227 /opt/arm-linux/tools/bin/arm-linux-ar
080a0000-080a4000 rw-p 00000000 00:00 0
0908a000-0910e000 rw-p 00000000 00:00 0 [heap]
40000000-4001e000 r-xp 00000000 08:01 932574 /lib/i386-linux-gnu/ld-2.13.so
4001e000-4001f000 r--p 0001d000 08:01 932574 /lib/i386-linux-gnu/ld-2.13.so
4001f000-40020000 rw-p 0001e000 08:01 932574 /lib/i386-linux-gnu/ld-2.13.so
40020000-40021000 r-xp 00000000 00:00 0 [vdso]
40021000-40023000 rw-p 00000000 00:00 0
40023000-4002a000 r--s 00000000 08:01 1967 /usr/lib/i386-linux-gnu/gconv/gconv-modules.cache
40034000-401ac000 r-xp 00000000 08:01 932577 /lib/i386-linux-gnu/libc-2.13.so
401ac000-401ae000 r--p 00178000 08:01 932577 /lib/i386-linux-gnu/libc-2.13.so
401ae000-401af000 rw-p 0017a000 08:01 932577 /lib/i386-linux-gnu/libc-2.13.so
401af000-401b3000 rw-p 00000000 00:00 0
401b3000-403b3000 r--p 00000000 08:01 7090 /usr/lib/locale/locale-archive
403b3000-40557000 r--p 0571f000 08:01 7090 /usr/lib/locale/locale-archive
40568000-40584000 r-xp 00000000 08:01 918459 /lib/i386-linux-gnu/libgcc_s.so.1
40584000-40585000 r--p 0001b000 08:01 918459 /lib/i386-linux-gnu/libgcc_s.so.1
40585000-40586000 rw-p 0001c000 08:01 918459 /lib/i386-linux-gnu/libgcc_s.so.1
bfc89000-bfcac000 rw-p 00000000 00:00 0 [stack]
make[2]: *** [libgcc.a] 已放弃
make[2]: *** 正在删除文件“libgcc.a”
make[2]:正在离开目录 `/opt/arm-linux/build-tools/gcc-3.3.6/gcc'
make[1]: *** [libgcc.a] 错误 2
make[1]:正在离开目录 `/opt/arm-linux/build-tools/gcc-3.3.6/gcc'
make: *** [all-gcc] 错误 2
这个错误是怎么解决一直搞不定。先放下先,出于学习目的,所以也不深究下去了。
6)建立glibc库
glibc是GUN C库,它是编译Linux系统程序很重要的组成部分。安装glibc-2.3.2版本之前推荐先安装以下的工具:
● GNU make 3.79或更新;
● GCC 3.2或更新;
● GNU binutils 2.13或更新。
首先解压glibc-2.2.3.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
然后进行编译配置,glibc-2.2.3配置前必须新建一个编译目录,否则在glibc-2.2.3目录下不允许进行配置操作,此处在$PRJROOT/build-tools目录下建立名为build-glibc的目录,配置操作 如下:
# cd $PRJROOT/build-tools
# mkdir build-glibc
# cd build-glibc
# CC=arm-linux-gcc ../glibc-2.2.3 /configure --host=$TARGET--prefix="/usr"
--enable-add-ons --with-headers=$TARGET_PREFIX/include
选项CC=arm-linux-gcc是把CC(Cross Compiler)变量设成刚编译完的gcc,用它来编译glibc。--prefix="/usr"定义了一个目录用于安装一些与目标机器无关的数据文 件,默认情况下是/usr/local目录。--enable-add-ons是告诉glibc用linuxthreads包,在上面已经将它放入 glibc源代码目录中,这个选项等价于-enable-add-ons=linuxthreads。--with-headers告诉glibclinux内核头文件的目录 位置。
配置完后就可以编译和安装 glibc了,具体操作如下:
# make
# make install
7.编译安装完整的gcc
由于第一次安装的gcc没有交叉glibc的支持,现在已经安装了glibc,所以需要重新编译来支持交叉glibc。并且上面的gcc也只支持C语言,现在可以让它同时支持C语言还要和C++语言。具体操作如下:
# cd $PRJROOT/build-tools/gcc-2.3.6
# ./configure --target=arm-linux --enable-languages=c,c++--prefix=$PREFIX
# make
# make install
安装完成后会发现在$PREFIX/bin目录下又多了arm-linux-g++ 、arm-linux-c++等文件。
# ls $PREFIX/bin
arm-linux-addr2line arm-linux-g77 arm-linux-gnatbind arm-linux-ranlib
arm-linux-ar arm-linux-gcc arm-linux-jcf-dump arm-linux-readelf
arm-linux-as arm-linux-gcc-3.3.6 arm-linux-jv-scan arm-linux-size
arm-linux-c++ arm-linux-gccbug arm-linux-ld arm-linux-strings
arm-linux-c++filt arm-linux-gcj arm-linux-nm arm-linux-strip
arm-linux-cpp arm-linux-gcjh arm-linux-objcopy grepjar
arm-linux-g++ arm-linux-gcov arm-linux-objdump jar
8.测试交叉编译工具链
到此为止,已经介绍完了用分步构建的方法建立交叉编译工具链。下面通过一个简单的程序测试刚刚建立的交叉编译工具链看是否能够正常工作。写一个最简单的hello.c源文件,内容如下:
#include
int main( )
{
printf(“Hello,world!\n”);
return 0;
}
通过以下命令进行编译,编译后生成名为hello的可执行文件,通过file命令可以查看文件的类型。当显示以下信息时表明交叉工具链正常安装了,通过编 译生成了ARM体系可执行的文件。注意,通过该交叉编译链编译的可执行文件只能在ARM体系下执行,不能在基于X86的普通PC上执行。
# arm-linux-gcc –o hello hello.c
# file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (ARM), forGNU/Linux 2.4.3,
dynamically linked (uses shared libs), not stripped
参考自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/74101/showart_1088888.html