1. 直接下载已经编译好的文件。例如:http://arm.linux.org.uk,这里提供已经编译好的cross,如cross-3.3.2.tar.bz2,cross-3.0.tar.bz2。直接下载某个包后解压,然后创建合适的链接或者输出环境变量即可调用。
这种做法操作很简单,但是不能根据自己的需求去定义,只能选择已经编译好的东西。
2. 自己动手利用crosstool来制作。
A. 在CROSSTOOL官方网站下载源码包,解压,进入解压后的目录。
$sudo wget http://kegel.com/crosstool/crosstool-0.42.tar.gz
$sudo tar -xzvf crosstool-0.42.tar.gz
$cd crosstool-0.42
B. 以ROOT建立目录,存放生成的交叉编译链
改变该目录的 所有者为普通用户
例如,存放生成的交叉编译链目录为/opt/crosstool,如下所示:
sudo mkdir /opt/crosstool
sudo chown $USER /opt/crosstool
C. 修改针对目标板的脚本文件。
$sudo vi demo-arm.sh
(1)这几个环境变量可以根据实际情况修改
TARBALLS_DIR=$HOME/downloads
RESULT_TOP=/opt/crosstool
export TARBALLS_DIR RESULT_TOP
GCC_LANGUAGES="c,c++"
export GCC_LANGUAGES
(2)在若干行eval语句中选择要建立的交叉编译链的组合,去掉该行eval的#号。例如要做gcc为3.3.3,glibc为2.3.2的工具链
eval `cat arm.dat gcc-3.4.5-glibc-2.3.6.dat` sh all.sh --notest
D. 修改目标板脚本文件demo-arm.sh中eval那一行出现的体系结构的配置文件
$sudo vi arm.dat
KERNELCONFIG=`pwd`/arm.config
TARGET=arm-unknown-linux-gnu
TARGET_CFLAGS="-O"
可以修改TARGET变量为
TARGET=arm-S3C2410-linux-gnu(你的arm型号)
E.修改目标板脚本文件demo-arm.sh中eval那一行出现的工具链的匹配文件
$sudo vi gcc-3.4.5-glibc-2.3.6.dat
BINUTILS_DIR=binutils-2.15
GCC_DIR=gcc-3.3.3
GLIBC_DIR=glibc-2.3.2
LINUX_DIR=linux-2.4.26
GLIBCTHREADS_FILENAME=glibc-linuxthreads-2.3.2
以上变量要根据实际情况修改。不过
例如想下载linux2.6的版本,并且下载gdb最新的版本。内核具体的版本要参照http://kernel.org/和ftp://ftp.gnu.org/pub/gnu/gdb。例如。
LINUX_DIR=linux-2.6.12.1
GDB_DIR=gdb-6.0
F.以普通用户运行脚本
$sudo sh demo-arm.sh
进入漫长的等待过程中……
3. 安装完成后路径设置和测试。
编辑~/.bash_profile,在其中export PATH前加入这样一行, PATH=/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-S3C2410-linux-gnu/bin:$PATH
,改完后我的是这样的
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
PATH=/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-S3C2410-linux-gnu/bin:$PATH
export PATH
unset USERNAME
然后就好了。可以开始测试使用了。测试的方法很简单,随便找个程序源码编译一下就好了。这里用的这些编译器生成的是二进制文件,和平时的gcc生成的可执行文件并不相同。例如我测试时的文件是test.c,
#include int main() { printf("Hello!"); return 0; } 调用新的arm-linux-gcc来编译:arm-S3C2410-linux-gnu-gcc -o test test.c,这时生成的test文件是一个二进制的可执行文件,并不是我们平时常用的,所以在PC上执行这个文件的话是不行的,系统会提示:bash: ./test: cannot execute binary file。所以不能用这种方法来测试交叉编译是否成功。而应改采用file命令,例如我的是这样的: file test 结果如下: test: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.4.3, dynamically linked (uses shared libs), for GNU/Linux 2.4.3, not stripped 如果出现这样的结果说明交叉编译环境已经安装成功。否则…………重新想办法吧…… 第二种方法中,gcc,gdb等文件的下载方法有两种,一是设置好网络后让shell程序自己去下载,这种方法简单,但是下载速度不敢恭维。另外一种是自己使用下载工具去下载,然后将存放路径告诉demo-arm.sh,即 2.C里面的内容。这种方法速度让人满意。推荐使用。 建立ARM交叉编译环境 (arm-none-linux-gnueabi-gcc with EABI)2011-03-24 11:00昨天终于把交叉编译环境、移植内核和制作root文件系统在arm开发板上顺利跑通了。期间有的步骤很顺利,但更多的是被诸多问题困扰,比如最后一个不起眼的小问题导致文件系统无法加载,郁闷了我一个星期,最终通过分析慢慢发现了这个bug。还有各源码包版本的问题,而且网上很多介绍都是基于旧版本的。我这里全部用最新或较新的版本,当然,至于新旧版本到底哪个更好更合适,这是个智者见智的论题,不在本文讨论之列。我坚信很多人也遇到过或者即将遇到我曾经历过的错误和问题,因此我觉得把我过去两周做过的相关工作,详细地写下来,希望对大家有所帮助! 首先是平台和环境 ,我过去两周都是基于vmware 中ubuntu 10.04的,但是我发现ubuntu这个很火的桌面linux发行版本并不适合进行嵌入式开发,典型的麻烦就是系统缺少很多库、服务等等,需要自己手动安装,增加了不少额外的工作,和我以前用的SuSe 9比麻烦不少。不过所以现在我干脆全新装了一个SUSE 11.2 Enterprise Server 32bit,把过去的工作重复一遍,边编译边纪录,力求不遗漏细节! 过程预览: 1,准备工作,包括下载源码包、补丁、建立文件夹和设置环境变量等 2,建立内核头文件 3,建立binutils 4,建立bootstrap gcc 5,建立glibc 6,建立完整版本gcc 7,测试hello world 现在就让我们开始吧! 1 准备工作 我使用的源码包和补丁 如下: linux-2.6.34.tar.bz2 binutils-2.20.tar.gz gcc-4.3.5.tar.bz2 glibc-2.11.tar.gz glibc-linuxthreads-2.5.tar.bz2 glibc-ports-2.11.tar.bz2 glibc-2.11.2-gcc_fix-1.patch 至于怎么得到这些源码包,找google吧! 建立工作目录 自己选一个合适的地方,建立一个总文件夹Embedded,并且在其下建立 build-tools、kernel和tools三个子文件夹、我们以后的操作就都在这里进行了。 $ mkdir Embedded $ cd Embedded $ mkdir build-tools kernel tool $ ls build-tools kernel tool 各文件夹作用如下: build-tools : 保存binutils、gcc 和 glibc的源代码和用来编译这些源代码的目录。 kernel : 保存内核源代码和补丁。 tools : 保存编译好的交叉编译工具和库文件。 然后在build-tools文件夹中建立如下子文件夹: $ cd build-tools $ mkdir build-binutils build-boot-gcc build-glibc build-gcc build-binutils :编译binutils的目录 build-boot-gcc : 编译gcc 启动部分的目录 build-glibc :编译glibc的目录 build-gcc :编译完整gcc的目录 设置环境变量: 这里设置环境变量只是为了方便,因为每个工具的config都需要输入类似的变量,不如放在环境变量里。 在命令行下打开vi ~/.bashrc,在文档最后输入下面几行,然后注销当前用户,重新登录 export PRJROOT=/home/jinglelong/MySoftware/Embedded export TARGET=arm-none-linux-gnueabi export PREFIX=$PRJROOT/tools export TARGET_PREFIX=$PREFIX/$TARGET export PATH=$PREFIX/bin:$PATH 各变量的具体意义如下: PRJROOT : 整个工程的根目录,这里当然是Embeded了 TARGET : 目标文件对应的体系结构,arm-linux代表编译出来的target只能在arm体系结构中运行 PREFIX : 设置目标文件夹的路径前缀 TARGET_PREFIX : 设置目标文件夹的路径前缀路径 PATH : 添加可执行文件的路径,这里主要是只中间编译工具等 2 建立内核include文件 $ ln -s /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/include/linux $TARGET_PREFIX/include/linux $ ln -s /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/include/asm-generic/ $TARGET_PREFIX/include/asm-generic $ ln -s /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/arch/arm/include/asm/ $TARGET_PREFIX/include/asm 编译生成version头文件 这个是编译glibc时必须的,使用命令:make include/linux/version.h 3 建立binutils 解压binutils源码到文件夹: $PRJROOT/build-tools/binutils-2.20 配置: cd $PRJROOT/build-tools/build-binutils $ ../binutils-2.20/configure --target=$TARGET --prefix=$PREFIX 编译:make 出错: ../../binutils-2.20/gas/config/tc-arm.c: In function ‘make_mapping_symbol’: ../../binutils-2.20/gas/config/tc-arm.c:24: error: suggest braces around empty body in an ‘if’ statement 打开文件binutils-2.20/gas/config/tc-arm.c,把2490行的语句,用一对大括号括起来就可以了 安装: make install 完成后检查一下$PREFIX文件夹,是不是多了三个子文件夹,bin, lib, share? 打开bin,发现里面生成了14个可执行文件: [root@localhost bin]# ls arm-none-linux-gnueabi-addr2line arm-none-linux-gnueabi-as arm-none-linux-gnueabi-gprof arm-none-linux-gnueabi-nm arm-none-linux-gnueabi-objdump arm-none-linux-gnueabi-readelf arm-none-linux-gnueabi-strings arm-none-linux-gnueabi-ar arm-none-linux-gnueabi-c++filt arm-none-linux-gnueabi-ld arm-none-linux-gnueabi-objcopy arm-none-linux-gnueabi-ranlib arm-none-linux-gnueabi-size arm-none-linux-gnueabi-strip 他们的功能分别是: add2line :将你要找的地址转成文件和行号,它要使用 debug 信息。 ar :产生、修改和解开一个存档文件 as :gnu的汇编器 c++filt :C++ 和 java 中有一种重载函数,所用的重载函数最后会被编译转化成汇编的标,c++filt 就是实现这种反向的转化,根据标号得到函数名。 gprof :gnu 汇编器预编译器。 ld :gnu 的连接器 nm :列出目标文件的符号和对应的地址 objcopy :将某种格式的目标文件转化成另外格式的目标文件 objdump :显示目标文件的信息 ranlib :为一个存档文件产生一个索引,并将这个索引存入存档文件中 readelf :显示 elf 格式的目标文件的信息 size :显示目标文件各个节的大小和目标文件的大小 strings :打印出目标文件中可以打印的字符串,有个默认的长度,为4 strip :剥掉目标文件的所有的符号信息 4 建立bootstrap gcc 首先,我们为什么要建立bootstrap gcc,而不能一次性成功?原因有两点: 一是由于平台本身的gcc编译器和我们要建立的gcc版本不同,第一次用平台本身的编译器去build目标版本的gcc编译器的时候,新生成的目标编译器(相当于初始编译器编译链接生成的可执行文件)必然带有初始编译器的特征。而当我们用新生成的编译器再次编译自身时,便可去掉这种差异性。 二是因为gcc编译器依赖于glibc,而当前我们的glibc是基于本机的,所以我们首先要build基于arm体系结构的glibc,再在glibc的基础上生成基于arm体系结构的gcc。 这一步是最容易出错的,对每一步都必须谨慎,不要犯粗心之类的低级错误。 解压源码 解压gcc源码到build-tool文件夹下 修改源码: gcc-4.3.5 CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC -Dinhibit_libc -D__gthr_posix_h 确保本机已经安装了mpc, mpfr, gmp, 如果没有,则在yast里面安装好再往后走。 配置: ../gcc-4.3.5/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-threads --with-newlib --disable-shared --disable-libmudflap --disable-libssp 编译:make all-gcc 安装gcc: make install 再编译安装libgcc,这个是后面编译glibc必须的。 编译:make all-target-libgcc 安装libgcc: make install-target-libgcc 我看到网上很多文章在这一步有很多错误,一种是直接用make命令编译gcc下所有内容,这个是没有必要的,而且容易出错。我在ubuntu和suse下都无法完成编译,而在fedora下通过了;第二种情况是没有编译libgcc,这会导致后面编译glibc无法通过。 安装完成后,在$PREFIX/bin下又多了几个文件, arm-none-linux-gnueabi-cpp : gnu的 C 的预编译器 arm-none-linux-gnueabi-gcc : gnu的 C 语言编译器 arm-none-linux-gnueabi-gcc-4.3.5 : gnu的 C 语言编译器,其实和arm-linux-gcc是一样的 arm-none-linux-gnueabi-gccbug : 一个可执行脚本,具体作用未知。 arm-none-linux-gnueabi-gcov : gcc 的辅助测试工具,用来分析和优化程序 5 建立glibc 解压源码: 把glibc源码解压到build-tool下,把glibc-linuxthreads-2.5.tar.bz2解压到glibc根目录下,把glibc-ports-2.11.tar.bz2解压到glibc根目录下,并且命名为ports 进入文件夹build-glibc,创建config.cache文件,并且在文件中输入以下内容 libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes libc_cv_arm_tls=yes 配置: BUILD_CC="gcc" CC=$TARGET-gcc ../glibc-2.11/configure --host=$TARGET --target=$TARGET --prefix=/usr --enable-add-ons --disable-profile --cache-file=config.cache --with-binutils=$PREFIX/bin/ --with-headers=$TARGET_PREFIX/include/ 编译:make 出错:/arm-linux/bin/ld: cannot find -lgcc_eh 打开glibc根目录下Makeconfig文件,去掉第541,546行中的-lgcc_eh,重新make 安装: make install_root=$TARGET_PREFIX prefix="" install 修改libc.so: 用vi或gedit打开libc.so文件,将文件中的: GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) ) 更改为 GROUP ( libc.so.6 libc_nonshared.a ) 保存后退出 6 建立完整版gcc 有了前面的经验,现在就简单多了,进入目录build-gcc, 配置: ../gcc-4.3.5/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --disable-libgomp 编译: make all 安装: make install 安装完成后,在$PREFIX/bin下多了gnu的c++编译器: arm-none-linux-gnueabi-gcc arm-none-linux-gnueabi-c++ 7 验证工具链 创建,编译生成一个hello world程序helloworld, 查看elf文件信息: $ arm-none-linux-gnueabi-readelf -d helloworld 是不是看到了ARM的信息?更直接的,就是把这个helloworld和相关依赖的动态库拷到开发板上,看它是不是真的能helloworld! 8 总结 这次在SUSE 11.2上编译安装工具链,整个过程非常顺利,其实我相信只要环境,配置等正确,常见linux发行版上都会比较顺利。不过我还是建议直接下在编译好的工具链,省下了不少麻烦,而且可靠性也能保证。最后,希望本教程对大家有所帮助,如果有什么遗漏或错误之处,希望大家能批评指正!