制作ARM平台交叉编译工具链

ARM平台交叉编译器的制作

主机环境:

Ubuntu 12.04.1 64bit 

gcc version 4.6.3 

 

 

第1节:下载最新源码包

 官网 :http://www.gnu.org/software/

 官方下载站:http://mirror.bjtu.edu.cn/gnu/glibc/

 

binutils-2.22.tar.gz 

 

gcc-4.7.2.tar.bz2 

gmp-5.0.5.tar.xz 

mpfr-3.1.1.tar.xz 

mpc-1.0.1.tar.gz 

 

glibc-2.16.0.tar.xz 

glibc-linuxthreads-2.5.tar.bz2 

glibc-ports-2.16.0.tar.xz 

 

linux-3.5.4.tar.bz2 

   将以上源码包放入~/src目录中

 

 

2节:配置编译环境

cd ~/src 

vim armenv 

将以下内容写入armenv文件中保存退出 

TARGET=arm-linux-gnueabi 

PREFIX=/opt/cross/gcc-4.7.2/$TARGET 

PATH=$PREFIX/bin:$PATH 

 

export TARGET PREFIX PATH 

 

配置编译环境 

. armenv 

3节:编译binutils

tar -xzf binutils-2.22.tar.gz 

mkdir binutils-build 

cd binutils-build 

../binutils-2.22/configure --target=$TARGET --prefix=$PREFIX 

make -j2 

sudo make install 

cd .. 

4节:第一次编译gcc

tar -xjf gcc-4.7.2.tar.bz2 

mkdir gcc-bootstrap-build 

tar -xf gmp-5.0.5.tar.xz 

tar -xf mpfr-3.1.1.tar.xz 

tar -xf mpc-1.0.1.tar.gz 

cd gcc-4.7.2 

为了支持软浮点运算加入支持库

方法一:直接运行官方给出的下载脚本

./contrib/download_prerequisites 

方法二:将gmp>--host=x86_64-linux-gnu --build=x86_64-linux-gnu \ 

  --enable-targets=all --prefix=$PREFIX \ 

  --enable-languages=c --with-newlib --without-headers --disable-nls \ 

  --disable-threads --disable-shared --disable-libmudflap --disable-libssp \ 

  --disable-libgomp --disable-decimal-float --enable-checking=release \ 

  --disable-bootstrap --disable-libquadmath \ 

  --with-mpfr-include=$(pwd)/../gcc-4.7.2/mpfr/src \ 

  --with-mpfr-lib=$(pwd)/mpfr/src/.libs 

make -j2 all-gcc   

make -j2 all-target-libgcc 

sudo make install-gcc 

sudo make install-target-gcc 

sudo cp -v libiberty/libiberty.a $PREFIX/lib 

以下添加libgcc_eh.a,libgcc_s.alibgcc.a的软链接,防止编译C库时出错 

sudo ln -vs libgcc.a `arm-linux-gnueabi-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'` 

sudo ln -vs libgcc.a `arm-linux-gnueabi-gcc -print-libgcc-file-name | sed 's/libgcc/&_s/'` 

cd .. 

软浮点支持

 

因为要支持软浮点(Soft Float),GCC需要同时编译GMPMPFRGMP是实现任意精度算术运算的软件包,可以完成有符号整数、有理数和浮点数的运算。只要计算机内存的满足

需要,GMP的运算精度没有任何限制。MPFR是一个用于高精度浮点运算的C库。让GCC支持GMPMPFR有两种方法,一是分别编译安装GMPMPFR,把路径通过configure告诉GCC,这

样在编译GCC的时候就会去找到GMPMPFR;另一种更简单的方法是把GMPMPFR源代码拷贝到GCC源代码目录内,两个文件夹分别命名为gmpmpfr,这样在编译GCC的过程中就会

自动去编译GMPMPFR。我们采用第二种方法,下面的命令把GMPMPFR源代码移动到GCC目录内:

  

cd ${SOURCE_DIR}

mv ${PACKAGE_GMP} ${PACKAGE_GCC}/gmp

mv ${PACKAGE_MPFR} ${PACKAGE_GCC}/mpfr

配置选项

 

第一次编译GCC的作用是生成支持C语言的交叉编译器,目的是用它来交叉编译后面的Glibc库。因为生成完整的GCC交叉编译器需要Glibc库的支持,但是现在还没有用于ARM平台

Glibc库,所以我们先生成一个简化的GCC,用它来编译Glibc,有了Glibc后再重新编译GCC生成完整的ARM-GCC。所以第一次编译GCC的配置选项禁止了很多功能,如下所示:

cd ${BUILD_DIR}/${PACKAGE_GCC}

${SOURCE_DIR}/${PACKAGE_GCC}/configure \

   --build=${HOST} \

   --host=${HOST} \

   --target=${TARGET} \

   --prefix=${RESULT_DIR} \

   --without-headers \

   --with-newlib \

   --with-float=soft \

   --with-cpu=arm920t \

   --with-tune=arm9tdmi \

   --with-gnu-as \

   --with-gnu-ld \

   --disable-nls \

   --disable-decimal-float \

   --disable-libgomp \

   --disable-multilib \

   --disable-libmudflap \

   --disable-libssp \

   --disable-shared \

   --disable-threads \

   --disable-libmudflap \

   --disable-libstdcxx-pch \

   --disable-libffi \

   --enable-languages=c

make &&>

选项详解

BUILD= 是指在什么平台上编译源代码,这个肯定是主机了,x86

HOST=  是指编译出来的可执行文件在什么平台上运行,这个对binutilsgcc来说是 x86, libc来说是arm

TARGET= 是指用编译出来的交叉编译器编译其它代码生成的可执行文件在什么平台运行, arm


--enable-multilib 

-without-headers

--with-newlib \

   --with-float=soft \

   --with-cpu=arm920t \

   --with-tune=arm9tdmi \

   --with-gnu-as \

   --with-gnu-ld \

--disable-decimal-float \

   --disable-libgomp \

   --disable-multilib \

   --disable-libmudflap \

   --disable-libssp \

   --disable-shared \

   --disable-threads \

   --disable-libmudflap \

   --disable-libstdcxx-pch \

   --disable-libffi \

--disable-shared

Disables the creation of the shared libraries.

--disable-threads

This will prevent GCC from looking for the multi-thread include files, since they haven't been created for this architecture yet. GCC will be able to find 

the multi-thread information after the Glibc headers are created.

--enable-languages=c

This option ensures that only the C compiler is built.

注意: 将这GMPMPFR软件包解压到GCC源码树的根目录下,并分别命名为"gmp""mpfr",那么GCC的编译程序将自动将两者与GCC一起编译。这样做了后,不需要加 --with-gmp 

with-mpfr 选项,加了反而会出错:configure: error: in `/home/hongwang/mktoolchain/build/gcc-4.4.0/mpfr':

configure: error: Do not use --with-gmp-build and other --with-gmp options simultaneously.

See `config.log' for more details.

make: *** [configure-mpfr] 错误 1

 

 

 编译过程组遇到问题参阅:http://blog.csdn.net/dragon101788/article/details/17557343

 

5节:安装内核头文件

tar -xjf linux-3.5.4.tar.bz2 

cd linux-3.5.4 

make ARCH=arm headers_check 

make ARCH=arm INSTALL_HDR_PATH=dest headers_install 

sudo cp -rv dest/include/* $PREFIX/$TARGET/include 

注意:内核头文件的安装位置是$PREFIX/$TARGET/include,而不是$PREFIX 

cd .. 

内核头文件其实是在第四步编译Glibc时才用到的,所以这一步也可以放在编译GCC(第一次)之后。这一步并没有编译内核,只是把内核头文件拷贝到了安装目录而已。

 

cd ${SOURCE_DIR}/${PACKAGE_KERNEL}

make \

   ARCH=arm \

   CROSS_COMPILE=${TARGET}- \

   INSTALL_HDR_PATH=${TARGET_PREFIX} \

  >

 

 

6节: 编译C

tar -xf glibc-2.16.0.tar.xz 

tar -xjf glibc-linuxthreads-2.5.tar.bz2 -C glibc-2.16.0 

tar -xf glibc-ports-2.16.0.tar.xz 

mv glibc-ports-2.16.0 glibc-2.16.0/ports 

mkdir glibc-build 

cd glibc-build 

 

CC=$TARGET-gcc \ 

AR=$TARGET-ar \ 

RANLIB=$TARGET-ranlib \ 

../glibc-2.16.0/configure \ 

  --host=$TARGET \ 

  --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 

注意:C库的安装位置是$PREFIX/$TARGET,编译完整的gcc时链接使用 

sudo make -j2 

sudo -s 

. ../armenv 

make install 

exit 

cd .. 

Glibc也就是C库函数,包括分配内存、搜索目录、打开和关闭文件、读和写文件、字符串操作、模式匹配、代数运算等。 libc-ports软件包的作用是移植,把Glibc库移植到ARM

平台时需要它,解压后拷贝到glibc目录,并命名为 ports,就可以了:

mv ${PACKAGE_GLIBCPORTS} ${PACKAGE_GLIBC}/ports

编译完成需要时间大概为:1.5小时

配置选项

 

为了使Glibc支持NPTL,需要在Glibc编译目录下建立config.cache文件并写入:

cat >>

libc_cv_c_cleanup=yes

libc_cv_arm_tls=yes

libc_cv_gnu99_inline=yes

EOF

其中 libc_cv_arm_tls=yes 可以省略,因为交叉编译环境已经完全了解你要编译的目标体系,所以可以自行检测出来。

BUILD_CC=gcc \

CC=${TARGET}-gcc \

AR=${TARGET}-ar \

RANLIB=${TARGET}-ranlib \

${SOURCE_DIR}/${PACKAGE_GLIBC}/configure \

   --build=${HOST} \

   --host=${TARGET} \

   --target=${TARGET} \

   --prefix="/usr" \

   --with-headers=${TARGET_PREFIX}/include \

   --with-binutils=${RESULT_DIR}/bin \

   --with-tls \

   --with-__thread \

   --enable-sim \

   --enable-nptl \

   --enable-add-ons \

   --enable-kernel=2.6.29 \

   --disable-profile \

   --without-gd \

   --without-cvs \

   --cache-file=config.cache

make

make>

选项详解

 

BUILD_CC="gcc"

Glibc在编译过程中需要先创建一些工具,这些工具需要用主机上的GCC来编译。

CC=${TARGET}-gcc

告诉Glibc使用我们在上一步为ARM目标平台创建的交叉编译器GCC来编译C库。

AR=${TARGET}-ar \

告诉Glibc使用我们在上一步为ARM目标平台创建的ar来汇编C库。

RANLIB=${TARGET}-ranlib

告诉Glibc使用我们在上一步为ARM目标平台创建的ranlib

-with-headers=${TARGET_PREFIX}/include \

   --with-binutils=${RESULT_DIR}/bin

This>

   --disable-profile

This>

This>

 

 

7节:编译完整的gcc

tar -xf gmp-5.0.5.tar.xz 

cd gmp-5.0.5 

./configure --prefix=/usr 

make -j2 

sudo make install 

cd .. 

 

tar -xf mpfr-3.1.1.tar.xz 

cd mpfr-3.1.1 

./configure --prefix=/usr 

make -j2 

sudo make install 

cd .. 

 

tar -xf mpc-1.0.1.tar.gz 

cd mpc-1.0.1 

./configure --prefix=/usr 

make -j2 

sudo make install 

cd .. 

若系统中安装gmp,mpfr,mpc且版本满足要求,可不用编译安装。 

构建期间,将三者安装到其他位置,并添加了链接搜索路径,试了几次都没有成功。 

有时间再做尝试,估计是哪里配置不正确。 

 

../gcc-4.7.2/configure --target=$TARGET \ 

  --host=x86_64-linux-gnu --build=x86_64-linux-gnu \ 

  --prefix=$PREFIX \ 

  --enable-languages=c,c++ --enable-shared 

make -j2 

sudo make install 

cd .. 

 

配置选项

这次是编译完整的GCC,因此第一次disable的一些选项这次可以enable了。

${SOURCE_DIR}/${PACKAGE_GCC}/configure \

   --build=${HOST} \

   --host=${HOST} \

   --target=${TARGET} \

   --prefix=${RESULT_DIR} \

   --with-float=soft \

   --with-cpu=arm920t \

   --with-tune=arm9tdmi \

   --enable-languages=c,c++ \

   --enable-threads=posix \

   --enable-c99 \

   --enable-long-long \

   --enable-shared \

   --enable-__cxa_atexit \

   --enable-nls \

   --disable-libgomp \   

    --with-sysroot='${exec_prefix}/xxx' #将xxx替换成prefix的路径,参照http://blog.csdn.net/dragon101788/article/details/17509987sysroot与specs

make && make install

选项详解

-enable-languages=c,c++

This option ensures that only the C and C++ compilers are built.

--enable-__cxa_atexit

This option allows use of __cxa_atexit, rather than atexit, to register C++ destructors for local statics and global objects and is essential for fully standards-compliant handling of destructors. It also affects the C++ ABI and therefore results in C++ shared libraries and C++ programs that are interoperable with other Linux distributions.

--enable-c99

Enable C99 support for C programs.

--enable-long-long

Enables long long support in the compiler.

--enable-threads=posix

This enables C++ exception handling for multi-threaded code.

--enable-nls \

--disable-libgomp

如果不加这一项会出现如下错误:

configure: error: Pthreads are required to build libgomp
make[1]: *** [configure-target-libgomp] 错误 1
make[1]:
正在离开目录
 `/home/hongwang/mktoolchain/build/gcc-4.4.0-2'
make: *** [all] 
错误
 2
没有找到好的解决办法,只能在configure里增加
 --disable-libgomp

为什么要编译两次GCC

第一遍只编译一个支持cgcc,原因是要编译出一个支持交叉的c++,必须有一个编译好的用于目标体系平台的glibc,而不是只有glibc的头文件就可以的,好在编译glibcc支持就够了,所以编译glibc也成了第一遍的gcc唯一的理由和作用。工具链中gcc的第一次和第二次编译都是由主系统的gccbinutils来完成的(之前没有提及binutils,只是为了理解方便,但实际上编译后是少不了链接过程的,这个过程是要binutils来完成的)。到目前为止只有在编译glibc的时候用到了交叉版本的binutils,其它部分的链接都是由主系统的binutils来完成的。 

 

 可能出现的错误:

error: '_N' was not declared in this scope

请检查参数中是否含有--without-headers --disable-shared --disable-threads --with-newlib如果没有请尝试添加删除参数,修改参数的排序

 

 

8节: 测试

(1) 动态编译

arm-linux-gnueabi-gcc -o hello hello.c 

arm-linux-gnu-eabi-strip hello 

file hello 

hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, stripped 

(2) 静态编译

arm-linux-gnueabi-gcc -o hello hello.c -static 

arm-linux-gnu-eabi-strip hello 

hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, stripped 

实际还未放入开发板中进行测试,待开发板环境搭好,测试过再做更新。

 


你可能感兴趣的:(制作ARM平台交叉编译工具链)