ubuntu上制作 (arm+linux) toolchain的详细过程(二)

  建立二进制工具( binutils

 

binutils是一些二进制工具的集合,其中包含了我们常用到的asld

 

首先,我们解压我们下载的binutils源文件。

$cd $PRJROOT/build-tools

$tar -xvjf binutils-2.10.1.tar.bz2

然后进入build-binutils目录配置和编译binutils(should make sure that you have ‘lex’ (or ‘flex’) installed, or you can’t pass the ‘configure’, I used UBUNTU and it’s not installed beforehand) labels behind configure are necessary, or you can’t pass ‘make’

$cd build-binutils

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

--target 选项是指出我们生成的是 arm-linux 的工具,--prefix 是指出我们可执行文件安装的位置。

会出现很多 check,最后产生 Makefile 文件。

有了 Makefile 后,我们来编译并安装 binutils,命令很简单。

$make

$make install

看一下我们 $PREFIX/bin 下的生成的文件

$ls $PREFIX/bin

arm-linux-addr2line    arm-linux-gasp arm-linux-objdump              arm-linux-strings

arm-linux-ar                   arm-linux-ld           arm-linux-ranlib               arm-linux-strip

arm-linux-as                   arm-linux-nm           arm-linux-readelf     

arm-linux-c++filt              arm-linux-objcopy      arm-linux-size

 

我们来解释一下上面生成的可执行文件都是用来干什么的

add2line - 将你要找的地址转成文件和行号,它要使用 debug 信息。

Ar-产生、修改和解开一个存档文件

As-gnu 的汇编器

C++filt-C++ java 中有一种重载函数,所用的重载函数最后会被编译转化成汇编的标号,c++filt 就是实现这种反向的转化,根据标号得到函数名。

Gasp-gnu 汇编器预编译器。

Ld-gnu 的连接器

Nm-列出目标文件的符号和对应的地址

Objcopy-将某种格式的目标文件转化成另外格式的目标文件

Objdump-显示目标文件的信息

Ranlib-为一个存档文件产生一个索引,并将这个索引存入存档文件中

Readelf-显示 elf 格式的目标文件的信息

Size-显示目标文件各个节的大小和目标文件的大小

Strings-打印出目标文件中可以打印的字符串,有个默认的长度,为4

Strip-剥掉目标文件的所有的符号信息

 

建立初始编译器(bootstrap gcc)

首先进入 build-tools 目录,将下载 gcc 源代码解压

$cd $PRJROOT/build-tools

$tar -xvzf  gcc-2.95.3.tar.gz

然后进入 gcc-2.95.3 目录给 gcc 打上补丁

$cd gcc-2.95.3

$patch -p1< ../gcc-patch/gcc-2.95.3.-2.patch

$patch -p1< ../gcc-patch/gcc-2.95.3.-no-fixinc.patch

$patch -p1< ../gcc-patch/gcc-2.95.3-returntype-fix.patch

echo timestamp > gcc/cstamp-h.in

在我们编译并安装 gcc 前,我们先要改一个文件 $PREFIX/build-tools/gcc-2.95.3/gcc/config/arm/t-linux,把
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC
这一行改为
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h

接着就是配置boostrap gcc 后面要用bootstrap gcc 来编译 glibc 库。

$cd ..; cd build-boot-gcc

$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX /

>--without-headers  --enable-languages=c --disable-threads(not needed when you modify the file mentioned above)

这条命令中的 -target--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。

接着我们编译并安装 boot-gcc

$make all-gcc

$make install-gcc

An error like ‘~~/arm.c:530: error: invalid lvalue in assignment’ will occur if you compile it on a 64-bit machine.        The contant of this line is:

(arm_prog_mode =TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;)

Open file gcc-2.95.3/gcc/config/arm/arm.h and find the line:

#define arm_prog_mode ((enum attr_prog_mode) arm_prgmode)

Modify it as:

#define arm_prog_mode (arm_prgmode)

 

我们来看看 $PREFIX/bin 里面多了哪些东西

$ls $PREFIX/bin

你会发现多了 arm-linux-gcc arm-linux-unprotoizecpp gcov 几个文件。

Gcc-gnu C 语言编译器

Unprotoize- ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。

Cpp-gnu C 的预编译器

Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。

使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。

 

Accordding to method of book ‘building embedded linux system’ to build gcc, an error like below will occur,we should add a parameter ‘—disable-thread’

{

In file included from gthr-default.h:1,

                 from ../../gcc-2.95.3/gcc/gthr.h:98,

                 from ../../gcc-2.95.3/gcc/libgcc2.c:3034:

../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory

make[3]: *** [libgcc2.a] Error 1

make[3]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make[2]: *** [stmp-multilib-sub] Error 2

make[2]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make[1]: *** [stmp-multilib] Error 1

make[1]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make: *** [all-gcc] Error 2

}

Add ‘—disable-thread’, error as below:

{

In file included from gthr-default.h:1,

                 from ../../gcc-2.95.3/gcc/gthr.h:98,

                 from ../../gcc-2.95.3/gcc/libgcc2.c:3034:

../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory

make[3]: *** [libgcc2.a] Error 1

make[3]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make[2]: *** [stmp-multilib-sub] Error 2

make[2]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make[1]: *** [stmp-multilib] Error 1

make[1]: Leaving directory `/workdir/embedded/build-tools/build-boot-gcc/gcc'

make: *** [all-gcc] Error 2

}

No errors if you modify the file $PREFIX/build-tools/gcc-2.95.3/gcc/config/arm/t-linux as the method above

 

建立 c (glibc)

 

首先解压 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

 

然后进入 build-glibc 目录配置 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 变量设成你刚编译完的boostrap gcc,用它来编译你的glibc--enable-add-ons是告诉glibc linuxthreads 包,在上面我们已经将它放入了 glibc 源码目录中,这个选项等价于 -enable-add-ons=linuxthreads--with-headers 告诉 glibc 我们的linux 内核头文件的目录位置。

配置完后就可以编译和安装 glibc

$make

$make install_root=$TARGET_PREFIX prefix="" install

An error like below occurs when install glibc:

{

./stdio.texi:3269: First argument to cross-reference may not be empty.
./stdio.texi:3270: First argument to cross-reference may not be empty.
makeinfo: Removing output file `/home/dank/downloads/crosstool-0.24/build/mipsel-unknown-linux-gnu/gcc-3.2.3-glibc-2.2.3/glibc-2.2.3/manual/libc.info' due to errors; use --force to preserve.
make[2]: *** [libc.info] Error 2
make[2]: Leaving directory `/home/dank/downloads/crosstool-0.24/build/mipsel-unknown-linux-gnu/gcc-3.2.3-glibc-2.2.3/glibc-2.2.3/manual'

}

Should patch the glibc (glibc-2.2.3)

The patch file is below:

{

===================================================================
RCS file: /cvs/glibc/libc/manual/stdio.texi,v
retrieving revision 1.126
retrieving revision 1.127
diff -u -r1.126 -r1.127
--- libc/manual/stdio.texi        2001/06/06 07:11:31        1.126
+++ libc/manual/stdio.texi        2001/07/31 18:57:16        1.127
@@ -3265,8 +3265,8 @@
If you are trying to read input that doesn't match a single, fixed
pattern, you may be better off using a tool such as Flex to generate a
lexical scanner, or Bison to generate a parser, rather than using
-@code{scanf}.  For more information about these tools, see @ref{, , ,
-flex.info, Flex: The Lexical Scanner Generator}, and @ref{, , ,
+@code{scanf}.  For more information about these tools, see @ref{Top, , ,
+flex.info, Flex: The Lexical Scanner Generator}, and @ref{Top, , ,
bison.info, The Bison Reference Manual}.

@node Input Conversion Syntax

}

copy the content between the parentheses to a file(*.patch) as a patch file.

Should enter the directory (~~ /glibc-2.2.3/manual/) where the file stdio.texi located. And patch this file, then redo the install command.

 

然后你还要修改 libc.so 文件(vi $TARGET_PREFIX/lib/libc.so)

line:
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)

改为line:
GROUP ( libc.so.6 libc_nonshared.a)

 

这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。

 

建立全套编译器(full gcc)

 

在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持CC++

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

$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++

--enable-languages=c,c++ 告诉 full gcc 支持 c c++ 语言。

然后编译和安装你的 full gcc

$make all

$make install

When make all, an error occurs:

Actually, no error. Maybe because I make a mistake when modifying the file $TARGET_PREFIX/lib/libc.so

I modified it as: GROUP ( /libc.so.6 /libc_nonshared.a). maybe! I’m not sure.

 

我们再来看看 $PREFIX/bin 里面多了哪些东西

$ls $PREFIX/bin

 

你会发现多了 arm-linux-g++ arm-linux-protoize arm-linux-c++ 几个文件。

G++-gnu c++ 编译器。

Protoize-Unprotoize相反,将K&R C的源码转化为ANSI C的形式,函数原型中加入参数类型。

C++-gnu c++ 编译器。

到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。

 

用它来编译一个很简单的程序 test.c

#include

int main(void)

{

        printf("hello arm-linux!/n");

        return 0;

}

$arm-linux-gcc test.c -o test

$file test

test: ELF 32-bit LSB executable, ARM, version 1, for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped

 

No output? L

then i copy it to the platform board, which is used to run our workproject now, by NFS, and it can run normally. 

 

上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。Yes, I got it.

But how to use it? It’s task of the next step.

 

参考资料

1. Wookey ,Chris Rutter, Jeff Sutherland, Paul Webb ,The GNU Toolchain for ARM Target HOWTO

2. Karim Yaghmour,《Building Embedded Linux Systems》,USAO'Reilly2003

3. www.google.com

4. http://forum.ubuntu.org.cn/

你可能感兴趣的:(embedded,toolchain)