Linux下构建GCC交叉编译器全记录

  • 格式:doc
  • 大小:38.50 KB
  • 文档页数:5

Linux下构建GCC交叉编译器全记录2010-12-15 21:18〇、缘起前不久做了个Damn Small Linux启动U盘,感觉很实用。

美中不足是根文件系统一直是初始RAM盘,不能按需修改;要把DSL安装到U盘又需要200M空间,我的U盘只有128M。

一怒之下,决定自己做一个LFS(Linux From Scratch),开源精神不是支持自己动手么。

计划是构建一个兼容i586(Pentium, Celeron)以上架构的小型系统,完全包含在U盘里。

我所用的机器是x86_64架构,因此LFS的第一步是构建一个到i586的交叉编译器。

Cross-Compile Linux From Scratch是关于交叉编译Linux的详尽文档,开头包括了构建交叉编译器的详细介绍。

但是所用的源代码版本有些已颇旧,而且步骤也略嫌繁琐,我决定用新版本的源代码自己探索一下。

一、准备编译环境构建过程运行在Fedora 14 Linux上,CPU Intel Core 2 Duo,内核版本2.6.35.9 (x86_64)。

要编译交叉编译器首先需要一个编译器,这里就是GCC(4.5.1)。

另外,编译GCC还需要MPFR、GMP、MPC三个库,安装之。

当然一干构建工具如make、autoconf等是不可或缺的,就不赘述了。

为了构建过程清晰,源代码和目标文件尽量分开放置,因此在用户目录下创建目录src放置源代码,cross-build放置目标代码。

mkdir ~/srcmkdir ~/cross-build我准备把交叉编译器安装到/usr/local目录下,为简化配置命令,创建一个脚本~/cross-build/setenv设置环境变量,内容如下:PREFIX=/usr/localPATH=${PREFIX}/bin:/bin:/usr/binTOOLS=`pwd`/toolsHOST=$MACHTYPETARGET=i586-linux如果构建工作中途停止,关机重启,或者其他干扰,继续之前先运行此脚本重设环境。

cd ~/cross-build. setenv二、下载源代码需要下载Binutils、GCC、Glibc的源代码,源代码包位于GNU的FTP(ftp:///)上。

这里下载的是Binutils 2.21、GCC 4.5.1和Glibc 2.11.3。

因为我的目标平台是Linux,编译Glibc还需要Linux的源代码,可以从/获取。

wget ftp:///gnu/binutils/binutils-2.21.tar.bz2wget ftp:///gnu/gcc/gcc-4.5.1/gcc-4.5.1.tar.bz2wget ftp:///gnu/glibc/glibc-2.11.3.tar.bz2wget /pub/linux/kernel/v2.6/linux-2.6.36.2.tar.bz2三、编译Binutils整个构建过程分四大步,依次为Binutils,静态GCC,Glibc,最终(带Glibc的)GCC,后面的工作依赖于前面的结果。

Binutils包含交叉编译器必需的汇编器、链接器、archiver (打包器?)和其他各种工具。

首先解压源代码到~/src。

tar xjf binutils-2.21.tar.bz2 -C ~/src在~/cross-build目录下为Binutils目标文件创建一个目录,然后切换到该目录。

mkdir ~/cross-build/binutilscd ~/cross-build/binutils配置为交叉编译,--target指明编译出来的工具可以处理的体系结构,而不是它们将要运行在的体系结构。

这里构建的是交叉编译器,编译器的运行环境(宿主host)和目标程序的运行环境(目标机target)是不同的,但是编译交叉编译器的工具的运行环境(build)和宿主是一样的(至少这里是)。

~/src/binutils-2.21/configure --prefix=$PREFIX --target=$TARGET --disable-nls make -j 2 2>&1 | tee make.out-j 2 选项使GNU make并行编译,2>&1 把错误输出重定向到标准输出,然后用tee存入文件make.out。

sudo make -j 2 install四、编译静态GCC一个完整的交叉编译器必须带有标准C库,这里选择Glibc,而为了编译Glibc,又必须先有一个交叉编译器。

解决的办法是先编译一个受限的、不带C库的交叉编译器,然后用它来编译Glibc,最后再携同Glibc一齐编译完整的交叉编译器。

这一步就是编译一个受限的GCC,称为静态,是因为它用到的所有库(是交叉编译器用到的库,不是目标程序需要的库,不是将要编译的Glibc)都是静态链接入可执行文件的,不然下面编译libgcc的时候会遇到链接找不到crti.o和crtn.o的问题,原因未分析。

tar xjf gcc-4.5.1.tar.bz2 -C ~/src这个临时的交叉编译器只用于编译Glibc,为它创建一个临时的安装目录:mkdir ~/toolsmkdir ~/cross-build/gcc-staticcd ~/cross-build/gcc-static~/src/gcc-4.5.1/configure --prefix=$TOOLS --target=$TARGET --disable-multilib --disable-nls --disable-shared --without-headers --disable-threads--enable-visibility --disable-decimal-float --enable-languages=c--disable-shared禁止动态链接,使用静态链接;--enable-visibility使能visibility 属性,编译Glibc时需要;--disable-decimal-float禁止十进制浮点数库,此库需要fenv.h 头文件,无法编译通过。

另外,编译Glibc依赖libgcc,编译GCC的同时编译之。

make -j 2 all-gcc all-target-libgcc 2>&1 | tee make.outmake -j 2 install-gcc install-target-libgcc五、安装Linux头文件我编译的交叉编译器的目标平台是Linux(i586-linux),所以在编译Glibc之前必须安装Linux头文件,Glibc使用到这些头文件。

tar xjf glibc-2.11.3.tar.bz2 -C ~/srccd ~/src/linux-2.6.36.2make -j 2 mrpropermake -j 2 ARCH=i386 headers_checksudo make -j 2 ARCH=i386 INSTALL_HDR_PATH=${PREFIX}/${TARGET} headers_install 完成之后Linux头文件就安装在${PREFIX}/${TARGET}/include下了。

六、编译Glibc编译Glibc可能是最繁杂也最易出错的工作,为了交叉编译,必须对源代码目录树的文件做一点修改,而且要手动设置几个configure变量。

首先,编译期间会链接GCC的库文件libgcc_eh.a,但是上一步编译的GCC实际不产生这个库,为了顺利通过链接器,可以创建一个到libgcc.a的符号链接。

cd ${PREFIX}/lib/gcc/${TARGET}/4.5.1sudo ln -s libgcc.a libgcc_eh.a其次,configure Glibc时检测forced unwind会失败,查看config.log似乎是因为GCC 的库还没有准备好。

解决办法是在编译目录下创建config.cache来欺骗configure。

tar xjf linux-2.6.36.2.tar.bz2 -C ~/srcmkdir ~/cross-build/glibccd ~/cross-build/glibc创建config.cache加入如下两行:libc_cv_forced_unwind=yeslibc_cv_c_cleanup=yes使用Glibc编译的程序运行时使用ld-linux.so.2载入共享库,为了以后这些程序能正确找到共享库,配置Glibc的前缀为/usr。

这是共享库在目标机的前缀,宿主机的前缀则安装时使用install_root来指定。

之所以这样,是为了将此前缀硬编码进ld-linux.so.2,否则该程序将目标机用宿主机的前缀查找共享库。

PATH=${TOOLS}/bin:$PATH BUILD_CC=gcc CC=${TARGET}-gcc AR=${TARGET}-arRANLIB=${TARGET}-ranlib CFLAGS="-march=$(cut -d- -f1 <<< $TARGET) -mtune=generic -g -O2" ~/src/glibc-2.11.3/configure --prefix=/usr --build=$HOST --host=$TARGET --disable-profile --enable-add-ons --with-tls --enable-kernel=2.6.0--with-__thread --with-headers=${PREFIX}/${TARGET}/include--cache-file=config.cache环境变量CC指定目标机器的编译器,即上一步构建的交叉编译器;而BUILD_CC指定本次编译Glibc用到的编译器。

编译Glibc要用到Linux的头文件,用--with-headers选项指明刚安装的头文件的位置。

PATH=${TOOLS}/bin:$PATH make -j 2 2>&1 | tee make.outsudo sh -c "PATH=${TOOLS}/bin:$PATH make -j 2 install_root=${PREFIX}/${TARGET} prefix= install"如上述,install_root指定安装到宿主机的前缀。

安装Glibc还有最后一步,由于配置和安装指定了不同的前缀,链接某些库文件事会使用目标机的绝对路径搜索宿主机,导致找不到库文件。