学习嵌入式嘛,就得自己多动手,多实践。入门的话,自己配置开发环境,移植内核这些。开发环境就不说了,移植内核首先就得编译内核。就得有编译器。由于ARM cpu的体系结构与x86不一样。通常的做法就是在 x86 开发平台使用ARM交叉编译器来编译内核,再移植到开发板上。制作交叉工具链是个仔细的活,既繁琐又有难度。网上推荐的做法是新手使用别人制作好的工具链,等以后经验多了,再来仔细研究这个。不知道为什么我就硬着头皮上了,结果花了一个星期还是倒腾出来了,算是有收获。所以这篇博文就简单记录一下,内容不涉及交叉编译器制作的原理还有细节,只是记下制作流程,大部分内容也都是网上的,所以并没有深度。等以后学习FLS的时候再来仔细研究。
我是参考这个文章来制作交叉工具链的,本文的内容大都与其雷同。可以认为本文是一篇转载。 http://www.cnblogs.com/Charles-Zhang-Blog/archive/2013/02/21/2920999.html
另外,本文是来制作 ARM9 —— s3c2440 这款cpu的交叉编译器的。所使用的Linux版本为 2.6.29
Binutils-2.19.tar.bz2
http://ftp.gnu.org/gnu/binutils/
gcc-4.4.4.tar.bz2
http://mirrors.kernel.org/gnu/gcc/gcc-4.4.4/
Glibc-2.11.2.tar.bz2
Glibc-ports-2.11.tar.bz2
http://ftp.gnu.org/gnu/glibc/
Gmp-4.2.tar.bz2
http://ftp.gnu.org/gnu/gmp/
Mpfr-2.4.0.tar.bz2
http://ftp.gnu.org/gnu/mpfr/
Linux-2.6.29.tar.bz2
Patch-2.6.29.bz2
http://www.kernel.org/pub/linux/kernel/v2.6/
在普通用户模式下,先建立 ~/cross/embedded-toolchains/
目录,然后按照下图的关系建立各个子文件夹,这样结构清晰,也利于后面的说明。
目录结构建立好之后,需要修改 setup-dir
文件夹的属性,chmod 777 setup-dir
然后将下载的所有源代码压缩包拷贝到此目录下。最后设置一些环境变量,方便制作流程中的使用。在 doc/srcipt
下建立 envionment-variables
脚本,内容如下,注意修改自己的 home
目录:
然后切换到超级用户,接下来都是在超级用户权限下完成的。执行 source envionment-variables
使环境变量生效。
在制作交叉工具链之前,说明下制作的流程,这样使得制作者有整体上的把握,不至于晕头转向。
建立二进制工具(binutils)
建立内核头文件
建立初始化编译器(bootstarp gcc)
编译 glibc
建立全套编译器(full gcc)
下面就开始制作吧!!
Binutils是GNU工具之一,它包括连接器、汇编器和其他用于目标文件和档案的工具,它是二进制代码的处理维护工具。安装Binutils工具包含的程序有addr2line、ar、as、c++filt、gprof、ld、nm、objcopy、objdump、ranlib、readelf、size、strings、strip、libiberty、libbfd和libopcodes。这些工具的使用就不介绍了,等以后遇到了再去学习。
cd $PRJROOT/src-dir
tar jxvf ../setup-dir/binutils-2.19.tar.bz2
cd $PRJROOT/build-dir/build-binutils
../../src-dir/binutils-2.19/configure --target=$TARGET --prefix=$PREFIX --disable-werror
make
make install
通过查看 ls $PREFIX/bin
下是否生成了 binutils
工具来检查安装是否成功,如下:
这一步使用系统上自带的编译器来编译内核,主要目的是获取一些头文件。无论是交叉编译器还是本地编译器编译内核。都是对 Linux 内核的编译,其基本流程都是一样的。因此在往下制作之前,最好对编译 Linux 内核这一套流程有一定了解。可以在网上找些资料看看。
cd kernel
tar jxvf ../setup-dir/linux-2.6.29.tar.bz2
cd linux-2.6.29
这里我就使用 s3c2410_defconfig
这个默认文件来进行配置:
cp ./arch/arm/configs/s3c2410_defconfig ./.config
make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-
这一步肯定是会出错的, arm-linux-gcc
这个编译器还没有做出来呢。这么做只是为了获得一些跟ARM体系结构相关的头文件,可以查看 /kernel/linux-2.6.29/include/linux/version.h
和autoconf.h
文件是不是生成了,这是编译glibc要用到的。version.h
和 autoconf.h
文件的存在,说明你生成了正确的头文件。
接下来建立工具链需要的include目录,并将内核头文件复制过去。
mkdir -p $TARGET_PREFIX/include
cp –r $PRJROOT/kernel/linux-2.6.29/include/linux $TARGET_PREFIX/include
cp –r $PRJROOT/ kernel /linux-2.6.29/include/asm-arm $TARGET_PREFIX/include/asm
cp –r $PRJROOT/ kernel /linux-2.6.29/include/asm-generic $TARGET_PREFIX/include
cp –r $PRJROOT/ kernel /linux-2.6.29/arch/arm/include/asm $TARGET_PREFIX/include
cp –r $PRJROOT/ kernel /linux-2.6.29/arch/arm/mach-s3c2410/include/mach $TARGET_PREFIX/include/asm
Note: mach-xxx是根据目标板所用的cpu类型来选择的
这一步的目的主要是建立arm-linux-gcc工具,注意这个gcc没有glibc库的支持,所以只能用于编译内核、BootLoader等不需要C库支持的程序,后面创建C库也要用到这个编译器,所以创建它主要是为创建C库做准备,如果只想编译内核和BootLoader,那么安装完这个就可以到此结束。安装过程如下:
cd $PRJROOT/setup-dir
mv gcc-core-4.4.4.tar.bz2 gcc-4.4.4.tar.bz2
cd $PRJROOT/src-dir
tar jxvf ../setup-dir/gcc-4.4.4.tar.bz2
从 GCC-4.3起,安装GCC将依赖于GMP-4.1以上版本和MPFR-2.3.2以上版本。如果将这两个软件包分别解压到GCC源码树的根目录下,并分别命名为"gmp"和"mpfr",那么GCC的编译程序将自动将两者与GCC一起编译。建议尽可能使用最新的GMP和MPFR版本。
tar jxvf ../setup-dir/mpfr-2.4.0.tar.bz2
tar jxvf ../setup-dir/gmp-4.2.tar.bz2
mv mpfr-2.4.0 gcc-4.4.4/mpfr
mv gmp-4.2.0 gcc-4.4.4/gmp
由于第一次安装ARM交叉编译工具,那么支持的libc库的头文件也没有,src-dir/gcc-4.4.4/gcc/config/arm/t-linux
文件,在TARGET_LIBGCC2_CFLAGS
中添加两个定义:-Dinhibit_libc –D__gthr_posix_h
原文:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer –fPIC
改后:
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D_gthr_posix.h
进一步的配置:
cd $PRJROOT/build-dir/build-gcc
../../src-dir/gcc-4.4.4/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-shared --disable-threads --disable-decimal-float --disable-libmudflap --disable-lipssp
make all-gcc
make install-gcc
make all-target-libgcc
make install-target-libgcc
在glibc的编译中,还需要libgcc_eh.a
(否则出现错误:cannot find -lgcc_eh
),使用了--disable-shared
的选项,将不会生成libgcc_eh.a
,可以通过对libgcc.a
的链接来实现。
ln -vs libgcc.a $PRJROOT/tool-chain/lib/gcc/arm-linux/4.4.4/libgcc_eh.a
ls $PREFIX/bin
查看 arm-linux-gcc
工具是否已经生成。
这一步是最为繁琐的过程,目标板必须靠它来执行或者是开发大部分的应用程序。glibc套件常被称为C链接库,但是glibc实际产生很多链接库,其中之一是C链接库libc。因为嵌入式系统的限制,标准GNU C链接库显得太大,不适合应用在目标板上。所以需要寻找C链接库的替代品,在这里现以标准GNU C为例建立工具链。
cd $PRJROOT/src-dir
tar jxvf ../setup-dir/glibc-2.11.2.tar.bz2
tar jxvf ../setup-dir/glibc-ports-2.11.tar.bz2
mv –v glibc-ports-2.11 glibc-2.11.2/ports
cd $PRJROOT/build-dir/build-glibc
CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib
../../src-dir/glibc-2.11.2/configure --host=arm-linux --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
make
make install
../../src-dir/gcc-4.4.4/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --enable-shared
make all
make install
至此,整个交叉编译环境就建立完成了。
下面写个Hello World 程序来测试下我们自己制作的工具链是否确实可以编译。
cd $PRJROOT/program
vim hello.c
#include <stdio.h> int main() { printf("Hello ARM-Linux\n"); return 0; }
然后进行编译:
arm-linux-gcc hello.c -o hello
最后,可以通过 file hello
来查看生成的程序是否是ARM平台的。
这里是我按照上面流程制作自己交叉编译工具链中出现的错误以及排错问题,希望能够帮助到大家。
编译 binutils 出现 [-Werror=unused-but-set-parameter]
这个需要在 配置 configure 文件的时候,使用 --disable-werror 参数
make menuconfig 不出现配置界面:
解决办法: 安装ncurses库 参考: http://blog.chinaunix.net/uid-24782829-id-3211008.html
./configure --without-cxx-binding
abi-versions.h
No rule to make target /home/gru/cross/embedded-toolchains/build-dir/build-glibc/Versions.all', needed by /home/gru/cross/embedded-toolchains/build-dir/build-glibc/abi-versions.h'. Stop.
http://www.linuxquestions.org/questions/linux-from-scratch-13/glibc-2-5-1-make-error-588488/
安装完 gawk 之后需要重新配置再make
制作交叉编译工具时需要尽可能的细致,敲命令的时候只要某个字母不小心错了,就可能编出不来。难免会有几次推到重新开始的过程。只要坚持下去就会成功。