cross compiler Toolchain(交叉编译工具链)的建立

要为嵌入式Linux系统建立交叉编译的toolchain。例子使用moblin,涉及的 binutils,gcc,glibc和kernel的版本都是非常新的,碰到了很多问题,网上有很多资料,但是版本大多比较旧,不能解决目前最新版本的 问题。每解决一个问题,后面又出现一个问题,有些沮丧,折腾了一个星期。下面是为目前新的版本建立交叉编译环境的过程,以moblin环境为例。我想,这 将是一篇很长的文章。

Moblin的开发环境应使用MIC2的moblin-chroot或者KVM的环境,我们只是想按传统的方式自己来建立,目的是为了学习交叉编译的构建。推荐资料:http://www.linuxfromscratch.org/lfs/view/development/index.html。

一、下载相关的介质

准备介质:从http://repo.moblin.org/moblin/development/core/source/下载相关的资源:

  • kernel-2.6.29.1-18.1.moblin2.src.rpm
  • binutils-2.19-10.26.moblin2.src.rpm
  • gcc43-4.3.3_20081022-12.6.moblin2.src.rpm
  • glibc-2.9-3.53.moblin2.src.rpm

请注意:在以前的交叉环境的编译中,还需要 glibc-linuxthread……。Linux kernel在2.6的版本支持thread,就是NPTL(New POSIX Threading Libray),在2.6.16的版本后比较稳定。因此不需要linuxthread。如果加载linuxthread,可能会引起头文件定义的冲突。如 果我们选择比较新的版本来构造cross compiler,不要安装linuxtrhead。

为了有一个好组织结构,我在workspace目录下面根据O'Reilly的建议,建立了bootldr  build-tools  debug  doc  images  kernel  project  sysapps  tmp  tools子目录,我们将在build-tools下面编译,将最终工具放置在tools下面。

  在build-tools下面建立环境变量的脚本文件 myenv
$ vi myenv
#使用i586-linux,是因为intel的atom系列芯片的选择,一般的x86可以使用i686-linux
export TARGET=i586-linux 
export PREFIX=/tools
export TARGET_PREFIX=$PREFIX/$TARGET
export PATH=$PATH:$PREFIX/bin
$ chmod 744 myenv
$ . myenv

步骤二、初步建立binutil工具

1、准备源代码:解压缩和打补丁

  在build-tools目录下面设置build-binutil和src-binbuild两个目录,将binutils-2.19-10.26.moblin2.src.rpm放置在src-binutils目录下面将rpm包打开。
$ rpm2cpio binutils-2.19-10.26.moblin2.src.rpm |cpio -idv
  获取source code的tar.bz2和相关的补丁。
$ tar xvfj binutils-2.19.tar.bz2
$ cd binutils-2.19
  打补丁如下。patch的参数有-p0,-p1等,差异只要是打补丁的位置。为了避免补丁误打到我们的操作系统中,在整个交叉编译环境建立的过程中,我们不要使用root的身份
patch -p0 < ../binutils-skip-rpaths.patch
patch -p0 < ../cross-avr-omit_section_dynsym.patch
patch -p0 < ../s390-pic.patch
patch -p0 < ../unit-at-a-time.patch
patch -p0 < ../x86-64-biarch.patch

另外 moblin 还提供cross-avr-nesc-as.patch,但这个补丁所针对的文件没有找到,忽略它。

2、bintuils的编译和安装

  进入build-binutils目录,执行
$ ../src-binutils/binutils-2.19/configure --target=$TARGET --prefix=$PREFIX

  • --target:我们的目标环境是atom的x86设备,还可能是ARM、MIPS,和我们开发机器不一样。这个参数用于高速配置脚本对建立相应cross linker进行适配。
  • --prefix:存放目录
  • --disable-nls:可以增加这个参数,This disables internationalization as i18n is not needed for the temporary tools.
  • --disable-werror:This prevents the build from stopping in the event that there are warnings from the host's compiler.

  在build-binutils目录下面生成Makefile文件,然后执行make , make install。完成,可以在$PREFIX/bin下面看到我们的新的binutil。

三、导入kernel头文件

1、将kernel源码解开,并打补丁

打补丁的脚本如下:
$ patch -p1 < ../patch-2.6.29.1
patch -p1 < ../0001-drm-Split-out-the-mm-declarations-in-a-separate-hea.patch
patch -p1 < ../0002-drm-Add-a-tracker-for-global-objects.patch
patch -p1 < ../0003-drm-Export-hash-table-functionality.patch
patch -p1 < ../0007-drm-Add-unlocked-IOCTL-functionality-from-the-drm-r.patch
patch -p1 < ../linux-2.6.19-modesetting-by-default.patch
patch -p1 < ../linux-2.6.29-dont-wait-for-mouse.patch
patch -p1 < ../linux-2.6.29-drm-i915-Fix-LVDS-dither-setting.patch
patch -p1 < ../linux-2.6.29-drm-revert.patch
patch -p1 < ../linux-2.6.29-e100-add-support-for-82552-10-100-adapter.patch
patch -p1 < ../linux-2.6.29-enable-async-by-default.patch
patch -p1 < ../linux-2.6.29-even-faster-kms.patch
patch -p1 < ../linux-2.6.29-fast-initrd.patch
patch -p1 < ../linux-2.6.29-fast-kms.patch
patch -p1 < ../linux-2.6.29-flip-ide-net.patch
patch -p1 < ../linux-2.6.29-input-introduce-a-tougher-i8042.reset.patch
patch -p1 < ../linux-2.6.29-jbd-longer-commit-interval.patch
patch -p1 < ../linux-2.6.29-kms-after-sata.patch
patch -p1 < ../linux-2.6.29-msiwind.patch
patch -p1 < ../linux-2.6.29-pnv-agp.patch
patch -p1 < ../linux-2.6.29-pnv-drm.patch
patch -p1 < ../linux-2.6.29-pnv-fix-gtt-size.patch
patch -p1 < ../linux-2.6.29-pnv-fix-i2c.patch
patch -p1 < ../linux-2.6.29-psb-driver.patch
patch -p1 < ../linux-2.6.29-psb-S0i1_and_S0i3_OSPM_support.patch
patch -p1 < ../linux-2.6.29-retry-root-mount.patch
patch -p1 < ../linux-2.6.29-silence-acer-message.patch
patch -p1 < ../linux-2.6.29-sreadahead.patch
patch -p1 < ../linux-2.6.29-timberdale.patch
patch -p1 < ../linux-2.6.29-touchkit.patch
patch -p1 < ../linux-2.6.30-fix-async.patch
patch -p1 < ../linux-2.6.30-fix-suspend.patch
patch -p1 < ../linux-2.6-build-nonintconfig.patch


2、导入头文件

[wei@wei linux-2.6.29]$ make ARCH=x86 INSTALL_HDR_PATH=$TARGET_PREFIX headers_install

四、初始编译器GCC的建立

开始只能建立支持C语言的引导编译器,因为缺少C链接库(glibc)的支持。等到glibc编译好之后,可以重新编译gcc并提供完整的C++支持,同样我们建立src-gcc和build-gcc两个目录。


1、介质准备


打补丁如下:
patch -p0 < ../acats-timeout.patch
patch -p0 < ../boehm-gc-strict-aliasing.patch
patch -p0 < ../fpreserve-function-arguments43.patch
patch -p0 < ../gcc41-ia64-stack-protector.patch
patch -p0 < ../gcc41-java-slow_pthread_self.patch
patch -p0 < ../gcc41-ppc32-retaddr.patch
patch -p0 < ../gcc43-c++-builtin-redecl.patch
patch -p0 < ../gcc43-ecj-link.patch
patch -p0 < ../gcc43-java-debug-iface-type.patch
patch -p0 < ../gcc43-libgomp-omp_h-multilib.patch
patch -p0 < ../gcc43-pr34037.patch
patch -p0 < ../gcc43-pr36741-revert.patch
patch -p0 < ../gcc43-pr37189.patch
patch -p0 < ../gcc43-rename-info-files.patch
patch -p0 < ../gcc43-textdomain.patch
patch -p0 < ../gcc43-x86_64-va_start.patch
patch -p0 < ../gcc4-ppc64-m32-m64-multilib-only.patch
#patch -p0 < ../gcc-dir-version.patch 这个补丁打之后,version.o的编译出现问题,忽略它
patch -p0 < ../gcc-sles-version.patch
patch -p0 < ../nvl423594.patch
patch -p0 < ../nvl425783.patch
patch -p0 < ../nvl425784.patch
patch -p0 < ../nvl425788.patch
patch -p0 < ../nvl425789.patch
patch -p0 < ../nvl425791.patch
patch -p0 < ../nvl425794.patch
patch -p0 < ../nvl425798-1.patch
patch -p0 < ../nvl425798-2.patch
patch -p0 < ../nvl425799.patch
patch -p0 < ../nvl425806.patch
patch -p0 < ../nvl426087.patch
patch -p0 < ../nvl428413.patch
patch -p0 < ../nvl434500.patch
patch -p0 < ../nvl436041.patch
patch -p0 < ../nvl440482.patch
cd ..
patch -p0 < nvl441016.patch  将里面的20081002改为20081022,修订目录
cd gcc-4.3.3-20081022
patch -p0 < ../nvl464739.patch


2、编译GCC

  这个过程出现了很多问题。很多和后面glibc编译相关
$ ../src-gcc/gcc-4.3.3-20081022/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-threads --disable-shared 
-disable-decimal-float

因为是交叉编译器,还不需要目标板的系统头文件,所以需要使用 --without-headers这个选项。否则会有很多*.h头文件找不到的报错 --enable-language=c用来告诉配置脚本,需要产生的编译器支持何种语言,现在只需支持C语言。虽然配置为c,c++也可以的 --disable-threads 是因为threads需要libc的支持。 --disable-decimal-float,需要libc的支持,而我们在初步编译的时候尚未生成libc,否则出现以下的报错:
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:52:18: error: fenv.h: No such file or directory
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c: In function '__dfp_test_except':
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: 'FE_INEXACT' undeclared (first use in this function)
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: (Each undeclared identifier is reported only once
../../../gcc-4.3.1/libgcc/config/libbid/bid_decimal_globals.c:64: error: for each function it appears in.)
--disable-shared,forces GCC to link its internal libraries statically,没有这个选项,会有 crti.o: No such file: No such file or directory collect2: ld returned 1 exit status --disable-multilib,用于x86_64,在这里也可以使用。

  然后执行:
make all-gcc
make install-gcc
make all-target-libgcc
make install-target-libgcc
  
  很多资料中之有前面两项,这只建立了gcc,没有建立libgcc.a,这样会在glibc的编译中出现-lgcc没有找到的错误。报告:
……/build-tools/build-glibc/libc_pic.a
i586-linux-gcc   -nostdlib -nostartfiles -r -o /home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/librtld.map.o '-Wl,-(' /home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/dl-allobjs.os /home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.a -lgcc '-Wl,-)' -Wl,-Map,/home/wei/workspace/mywork/moblin/build-tools/build-glibc/elf/librtld.mapT
/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/i586-linux/4.3.3/../../../../i586-linux/bin/ld: cannot find -lgcc

在glibc的编译中,还需要libgcc_eh.a(否则出现错误:-lgcc_eh没有找到……bin/ld: cannot find -lgcc_eh),使用了--disable-shared的选项,将不会生成
libgcc_eh.a,可以通过对libgcc.a的链接来实现。
[wei@wei build-gcc]$  ln -vs libgcc.a `i586-linux-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`
   运行报告:
“/workspace/wei/mywork/moblin/tools/bin/../lib/gcc/i586-linux/4.3.3/libgcc_eh.a” -> “libgcc.a”

五、建立C库(glibc)

1、准备介质


  还是老方法,解压和打补丁。
[wei@wei src-glibc]$ rpm2cpio glibc-2.9-3.53.moblin2.src.rpm | cpio -idv
[wei@wei src-glibc]$ tar xvfj glibc-20081113T2206.tar.bz2
[wei@wei src-glibc]$ tar xvfj glibc-fedora-20081113T2206.tar.bz2 -C glibc-20081113T2206

修改glibc-ia64-lib64.patch ,将libc/sysdeps改为sysdeps
[wei@wei glibc-20081113T2206]$ patch -p0 < ../glibc-ia64-lib64.patch

2、编译协助文件

   如果我们在编译的过程中出现下面的问题:
....../build-tools/build-glibc/elf/librtld.os: In function `_dl_tlsdesc_dynamic':
....../build-tools/src-glibc/glibc-20081113T2206/elf/../sysdeps/i386/dl-tlsdesc.S:131: undefined reference to `__i686.get_pc_thunk.bx'

   增加一个补丁:glibc-dl-tlsedsc.patch,内容如下:
--- sysdeps/i386/dl-tlsdesc.S.org    2008-11-17 18:17:04.004203199 +0100
+++ sysdeps/i386/dl-tlsdesc.S    2008-11-17 18:18:28.029877701 +0100
@@ -128,8 +128,7 @@
 .Lslow:
     cfi_adjust_cfa_offset (28)
     movl    %ebx, 16(%esp)
-    call    __i686.get_pc_thunk.bx
-    addl    $_GLOBAL_OFFSET_TABLE_, %ebx
+    LOAD_PIC_REG(bx)
     call    ___tls_get_addr@PLT
     movl    16(%esp), %ebx
     jmp    .Lret

   我们还需要准备两个文件:
[wei@wei build-glibc]$  echo "libc_cv_forced_unwind=yes" > config.cache
[wei@wei build-glibc]$  echo "libc_cv_c_cleanup=yes" >> config.cache
[wei@wei build-glibc]$  echo "libc_cv_gnu89_inline=yes" >> config.cache
  
  当然这些参数也可以做为configure的参数加上。头两个是为了顺利使用configure脚本生成Makefile文件,而
libc_cv_gnu89_inline=yes是为了解决编译中重复定义的出现,例如:
stat.c:50: 错误:‘__stat’重定义
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/elf/../nptl/sysdeps/pthread/allocalim.h:27: multiple definition of `__libc_use_alloca'include/alloca.h:extern int __libc_use_alloca (size_t size) __attribute__ ((const));
我记得是即使加上这个配置,在第一编译的也会出现什么__stat __mknod的重复定义的问题,不要使同make clean之类,直接删除build-glibc,重现再来一次就可以解决。

第二个文件:
$ echo "CFLAGS += -march=i486 -mtune=native" > configparms
也可以使用i686,否则会出现
/home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.os: In function `__libc_fork':
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/posix/../nptl/sysdeps/unix/sysv/linux/i386/../fork.c:79: undefined reference to `__sync_bool_compare_and_swap_4'
/home/wei/workspace/mywork/moblin/build-tools/build-glibc/libc_pic.os: In function `nscd_getpw_r':
/workspace/wei/mywork/moblin/build-tools/src-glibc/glibc-20081113T2206/nscd/nscd_getpw_r.c:232: undefined reference to `__sync_fetch_and_add_4'

这是因为Glibc已经不再支持i386,需要定义一个i486以上的版本。

3、编译和安装

$../src-glibc/glibc-20081113T2206/configure --host=$TARGET --prefix=$PREFIX --enable-add-ons --with-headers=$TARGET_PREFIX/include --cache-file=config.cache --disable-profile --build=i686-pc-linux-gnu

  • --enable-add-ons,允许增加NPTL的线程库

$ make
$ make install

六、进行完整的编译

有了Glibc后,可以进行完整编译

1、重新建立binutils

$ confiure --prefix=$PREFIX --target=$TARGET --disable-nls --with-lib-path=$TARGET/lib --with-sysroot=$TARGET
如果没有--with-sysroot来重新重新编译binutils,那么在gcc的完整编译中,会引导到系统的lib中,很多了路径会出现问题。

2、重新建立gcc

$ configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --enable-shared
$ make
$ make install

不容易啊,终于搞定了。

你可能感兴趣的:(嵌入式Linux)