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.a到libgcc.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需要同时编译GMP和MPFR。GMP是实现任意精度算术运算的软件包,可以完成有符号整数、有理数和浮点数的运算。只要计算机内存的满足
需要,GMP的运算精度没有任何限制。MPFR是一个用于高精度浮点运算的C库。让GCC支持GMP和MPFR有两种方法,一是分别编译安装GMP和MPFR,把路径通过configure告诉GCC,这
样在编译GCC的时候就会去找到GMP和MPFR;另一种更简单的方法是把GMP和MPFR源代码拷贝到GCC源代码目录内,两个文件夹分别命名为gmp和mpfr,这样在编译GCC的过程中就会
自动去编译GMP和MPFR。我们采用第二种方法,下面的命令把GMP和MPFR源代码移动到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= 是指编译出来的可执行文件在什么平台上运行,这个对binutils个gcc来说是 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.
注意: 将这GMP和MPFR软件包解压到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
第一遍只编译一个支持c的gcc,原因是要编译出一个支持交叉的c++,必须有一个编译好的用于目标体系平台的glibc,而不是只有glibc的头文件就可以的,好在编译glibc有c支持就够了,所以编译glibc也成了第一遍的gcc唯一的理由和作用。工具链中gcc的第一次和第二次编译都是由主系统的gcc和binutils来完成的(之前没有提及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
实际还未放入开发板中进行测试,待开发板环境搭好,测试过再做更新。