• 沒有找到結果。

第 2 章 交叉编译工具链的构建

2.2 ARM L INUX 交叉编译工具链的构建

2.2.1 分步构建交叉编译链

分步构建,顾名思义就是一步一步的建立交叉编译链,不同于下一节中讲述的 Crosstool 脚本工具一次编译生成的方法,该方法建议适合那些希望深入学习了解构建交叉编译工具链 的读者。该方法相对来说难度较大,通常情况下困难重重,犹如唐僧西天取经,不过本节尽 可能详细地介绍构建的每一个步骤,读者完全可以根据本节的内容自己独立去实践,构建自 己的交叉工具链。该过程所需的时间较长,希望读者有较强的耐心和毅力去学习和实践它,

通过实践可以使读者更加清楚交叉编译器构建过程以及各个工具包的作用。该方法所需资源 如表 2.1 所示。

表 2.1 所需资源

安装包 下载地址

linux-2.6.10.tar.gz ftp.kernel.org binutils-2.15.tar.bz2 ftp.gnu.org gcc-3.3.6.tar.gz ftp.gnu.org glibc-2.3.2.tar.gz ftp.gnu.org glibc-linuxthreads-2.3.2.tar.gz ftp.gnu.org

以上资源通过相关站点下载后,就可以开始建立交叉编译工具链了。

2.2.1.1 建立工作目录

首先建立工作目录,工作目录就是在什么目录下构建交叉工具链,目录的构建一般没有 特别的要求,根据个人喜好建立。以下所建立的目录是作者自定义的,当前的用户定义为 mike,因此用户目录为:/home/mike,在用户目录下首先建立一个工作目录(armlinux)。建 立工作目录的命令行操作如下:

# cd /home/mike

# mkdir armlinux

再在这个工作目录 armlinux 下建立三个目录 build-tools、kernel 和 tools。具体操 作如下:

# cd armlinux

# mkdir build-tools kernel tools 其中各目录的作用是:

build-tools:用来存放你下载的 binutils、gcc、glibc 等源代码和用来编译这些源代码的 目录。

kernel:用来存放你的内核源代码。

tools:用来存放编译好的交叉编译工具和库文件。

2.2.1.2 建立环境变量

该步骤的目的是为了方便重复输入路径,因为重复操作每件相同的事情总会让人觉得很 麻烦,如果读者不习惯使用环境变量就可以略过该步,直接输入绝对路径就可以。声明以下 环境变量的目的就是在之后编译工具库的时候会用到,并且很方便输入,尤其是可以降低输 错路径的风险。

# export PRJROOT=/home/mike/armlinux

# export TARGET=arm-linux

# export PREFIX=$PRJROOT/tools

# export TARGET_PREFIX=$PREFIX/$TARGET

# export PATH=$PREFIX/bin:$PATH

注意,用 export 声明的变量是临时的变量,也就是当你注销或更换了控制台,这些环 境变量就消失了,如果还需要使用这些环境变量就必须重复 export 操作,所以有时会挺麻 烦。值得庆幸的是,环境变量也可以定义在 bashrc 文件中,这样当注销或更换控制台时,

这些变量就一直有效,就不用老是 export 这些变量了。

2.2.1.3 编译、安装 Binutils

Binutils 是 GNU 工具之一,它包括连接器,汇编器和其他用于目标文件和档案的工具,

它是二进制代码的处理维护工具。安装 Binutils 工具包含的程序有: addr2line, ar, as, c++filt, gprof, ld, nm, objcopy, objdump, ranlib, readelf, size, strings, strip, libiberty, libbfd 和 libopcodes。

对这些程序的简单解释如下:

addr2line:把程序地址转换为文件名和行号。在命令行中给它一个地址和一个可执行文 件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。

ar:建立、修改、提取归档文件。归档文件是包含多个文件内容的一个大文件,其结构 保证了可以恢复原始文件内容。

as:主要用来编译 GNU C 编译器 gcc 输出的汇编文件,产生的目标文件由连接器 ld 连 接。

c++filt:连接器使用它来过滤 C++ 和 Java 符号,防止重载函数冲突。

gprof:显示程序调用段的各种数据。

ld:是连接器,它把一些目标和归档文件结合在一起,重定位数据,并链接符号引用。

通常,建立一个新编译程序的最后一步就是调用 ld。

nm:列出目标文件中的符号。

objcopy:把一种目标文件中的内容复制到另一种类型的目标文件中。

objdump:显示一个或者更多目标文件的信息。使用选项来控制其显示的信息。它所显 示的信息通常只有编写编译工具的人才感兴趣。

ranlib:产生归档文件索引,并将其保存到这个归档文件中。在索引中列出了归档文件 各成员所定义的可重分配目标文件。

readelf:显示 elf 格式可执行文件的信息。

size:列出目标文件每一段的大小以及总体的大小。默认情况下,对于每个目标文件或 者一个归档文件中的每个模块只产生一行输出。

strings:打印某个文件的可打印字符串,这些字符串最少 4 个字符长,也可以使用选项 -n 设置字符串的最小长度。默认情况下,它只打印目标文件初始化和可加载段中的可打印

字符;对于其它类型的文件它打印整个文件的可打印字符,这个程序对于了解非文本文件的 内容很有帮助。

strip:丢弃目标文件中的全部或者特定符号。

libiberty: 包含许多 GNU 程序都会用到的函数,这些程序有:getopt, obstack, strerror, strtol 和 strtoul。

libbfd:二进制文件描述库.

libopcode:用来处理 opcodes 的库, 在生成一些应用程序的时候也会用到它。

Binutils 工具安装依赖于:Bash, Coreutils, Diffutils, GCC, Gettext, Glibc, Grep, Make, Perl, Sed, Texinfo 等工具。

介绍完 Binutils 工具后,下面将分步介绍安装 binutils-2.15 的过程。

首先解压 binutils-2.15.tar.bz2 包,命令如下:

# cd $PRJROOT/build-tools

# tar –xjvf binutils-2.15.tar.bz2

接着配置 Binutils 工具,建议建立一个新的目录用来存放配置和编译文件,这样可以使 源文件和编译文件独立开,具体操作如下:

# cd $PRJROOT/build-tools

# mkdir build-binutils

# cd build-binutils

# ../ binutils-2.15/configure --target=$TARGET --prefix=$PREFIX

其中选项 –target 的意思是制定生成的是 arm-linux 的工具,--prefix 是指出可执行文件 安装的位置。执行上述操作会出现很多 check 信息,最后产生 Makefile 文件。接下来执行 make 和安装操作,命令如下:

# make

# make install

该编译过程较慢,需要数十分钟,安装完成后察看/home/mike/armlinux/tools/bin 目录下 文件,察看结果如下,表明此时 Binutils 工具已经安装结束。

# ls $PREFIX/bin

arm-linux-addr2line arm-linux-ld arm-linux-ranlib arm-linux-strip arm-linux-ar arm-linux-nm arm-linux-readelf

arm-linux-as arm-linux-objcopy arm-linux-size arm-linux-c++filt arm-linux-objdump arm-linux-strings

2.2.1.4 获得内核头文件

编译器需要通过系统内核的头文件来获得目标平台所支持的系统函数调用所需要的信 息。对于 Linux 内核,最好的方法是下载一个的合适的内核,然后拷贝获得头文件。需要对 内核做一个基本的配置来生成正确的头文件;不过,不需要编译内核。对于本例中的目标,

arm-linux,需要以下步骤:

在 kernel 目录下解压 linux-2.6.10.tar.gz 内核包,执行命令如下:

# cd $PRJROOT/kernel

# tar –xvzf linux-2.6.10.tar.gz

接下来配置编译内核使其生成正确的头文件,执行命令如下:

# cd linux-2.6.10

# make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

其中 ARCH=arm 表示是以 arm 为体系结构,CROSS_COMPILE=arm-linux-表示以 arm-linux-为前缀的交叉编译器。也可以用 config 和 xconfig 来代替 menuconfig,推荐大 家用 make menuconfig,这也是内核开发人员用的最多的配置方法。注意在配置时一定要选 择处理器的类型,这里选择三星的 S3C2410(System Type->ARM System Type->/Samsung S3C2410 ), 如 图 2.1 所 示 。 配 置 完 退 出 并 保 存 , 检 查 一 下 的 内 核 目 录 中 的 include/linux/version.h 和 include/linux/autoconf.h 文件是不是生成了,这是编译 glibc 是要 用到的,如果 version.h 和 autoconf.h 文件存在,这说明生成了正确的头文件。

图 2.1 Linux 2.6.10 内核配置界面

拷贝头文件到交叉工具链的目录,首先需要在/home/mike/armlinux/tools/arm-linux 目录 下建立工具的头文件目录 inlcude,然后拷贝内核头文件到此目录下,具体操作如下:

# mkdir –p $TARGET_PREFIX/include

# cp –r $PRJROOT/kernel/linux-2.6.10/include/linux $TARGET_PREFIX/include

# cp –r $PRJROOT/kernel/linux-2.6.10/include/asm-arm $TARGET_PREFIX/include/asm

2.2.1.5 编译安装 boot-trap gcc

这一步的目的主要是建立 arm-linux-gcc 工具,注意这个 gcc 没有 glibc 库的支持,所以 只能用于编译内核,bootloader 等不需要 C 库支持的程序,后面创建 C 库也要用到这个编译 器,所以创建它主要是为创建 C 库做准备,如果只想编译内核和 Bootloader,那么安装完这 个就可以到此结束。安装命令如下:

# cd $PRJROOT/build-tools

# tar –xvzf gcc-3.3.6.tar.gz

# mkdir build-gcc

# cd gcc-3.3.6

# vi gcc/config/arm/t-linux

由于第一次安装 ARM 交叉编译工具,那么支持的 libc 库的头文件也没有,所以在 gcc/config/arm/t-linux 文 件 中 给 变 量 TARGET_LIBGCC2_CFLAGS 增 加 操 作 参 数 选 项 -Dinhibit_libc -D__gthr_posix_h 来屏蔽使用头文件,否则一般默认会使用/usr/inlcude 头文

件。

将 TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer –fPIC 改为以下:

TARGET_LIBGCC2-CFLAGS=-fomit-frame-pointer–fPIC -Dinhibit_libc -D__gthr_posix_h 修改完 t-linux 文件后保存,接紧着执行配置操作,如下命令:

# cd build-gcc

# ../ build-gcc /configure --target=$TARGET --prefix=$PREFIX --enable-languages=c --disable-threads --disable-shared

其中选项--enable-languages=c 表示只支持 C 语言,--disable-threads 表示去掉 thread 功 能,这个功能需要 glibc 的支持。--disable-shared 表示只进行静态库编译,不支持共享库编 译。

接下来执行编译和安装操作,命令如下:

# make

# make install

安装完成后,在/home/mike/armlinux/tools/bin 下查看,arm-linux-gcc 等工具已经生成,

boot-trap gcc 工具已经安装成功。

2.2.1.6 建立 glibc 库

glibc 是 GUN C 库,它是编译 Linux 系统程序很重要的组成部分。安装 glibc-2.3.2 版本 之前推荐先安装以下的工具:

l GNU make 3.79 或更新 l GCC 3.2 或更新

l GNU binutils 2.13 或更新

首先解压 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代码,操作如下:

# cd $PRJROOT/build-tools

# tar -xvzf glibc-2.2.3.tar.gz

# tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3

然后进行编译配置,glibc-2.2.3 配置前必须新建一个编译目录,否则在 glibc-2.2.3 目录 下不允许进行配置操作,此处在$PRJROOT/build-tools 目录下建立名为 build-glibc 的目录,

配置操作如下:

# cd $PRJROOT/build-tools

# mkdir build-glibc

# cd build-glibc

# CC=arm-linux-gcc ../glibc-2.2.3 /configure --host=$TARGET --prefix="/usr"

--enable-add-ons --with-headers=$TARGET_PREFIX/include

选项 CC=arm-linux-gcc 是把 CC(Cross Compiler)变量设成刚编译完的 gcc,用它来 编译 glibc。--prefix="/usr"定义一个目录用于安装一些与机器无关的数据文件,默认情况下 是/usr/local 目录。--enable-add-ons 是告诉 glibc 用 linuxthreads 包,在上面已经将它放入了 glibc 源码目录中,这个选项等价于 -enable-add-ons=linuxthreads。--with-headers 告诉 glibc linux 内核头文件的目录位置。

配置完后就可以编译和安装 glibc 了,具体操作如下:

# make

# make install

2.2.1.7 编译安装完整的 gcc

由于第一次安装的 gcc 没有交叉 glibc 的支持,现在已经安装了 glibc,所以需要重新编 译来支持交叉 glibc。并且上面的 gcc 也只支持 C 语言,现在可以让它不仅支持 C 语言还要 让它支持 C++语言。具体操作如下:

# cd $PRJROOT/build-tools/gcc-2.3.6

# cd $PRJROOT/build-tools/gcc-2.3.6