`
uro494zq
  • 浏览: 16032 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

【转】如何为嵌入式开发建立交叉编译环境

 
阅读更多

【转】如何为嵌入式开发建立交叉编译环境
2009年10月26日
  如何为嵌入式开发建立交叉编译环境
  级别: 初级
  恩 梁元 (www.kernel.org 下载的内核源代码放入 $PRJROOT /kernel 目录
  进入你的 kernel 目录:
  $cd $PRJROOT /kernel
  解开内核源代码
  $tar -xzvf linux-2.4.21.tar.gz
  或
  $tar -xjvf linux-2.4.21.tar.bz2
  小于 2.4.19 的内核版本解开会生成一个 linux 目录,没带版本号,就将其改名。
  $mv linux linux-2.4.x
  给 Linux 内核打上你的补丁
  $cd linux-2.4.21$patch -p1
  
  
  
  
  
  
  
  建立二进制工具(binutils)
  binutils是一些二进制工具的集合,其中包含了我们常用到的as和ld。
  首先,我们解压我们下载的binutils源文件。
  $cd $PRJROOT/build-tools
  $tar -xvjf binutils-2.10.1.tar.bz2
  然后进入build-binutils目录配置和编译binutils。
  $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-stringsarm-linux-ar arm-linux-ld arm-linux-ranlib arm-linux-striparm-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/cstamp-h.in
  在我们编译并安装 gcc 前,我们先要改一个文件 $PRJROOT/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
  你如果没定义 -Dinhibit,编译时将会报如下的错误
  ../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
  ../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
  make[3]: *** [libgcc2.a] Error 1
  make[2]: *** [stmp-multilib-sub] Error 2
  make[1]: *** [stmp-multilib] Error 1
  make: *** [all-gcc] Error 2
  如果没有定义 -D__gthr_posix_h,编译时会报如下的错误
  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[2]: *** [stmp-multilib-sub] Error 2
  make[1]: *** [stmp-multilib] Error 1
  make: *** [all-gcc] Error 2
  还有一种与-Dinhibit同等效果的方法,那就是在你配置configure时多加一个参数-with-newlib,这个选项不会迫使我们必须使用newlib。我们编译了bootstrap-gcc后,仍然可以选择任何c库。
  接着就是配置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
  这条命令中的 -target、--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。
  接着我们编译并安装 boot-gcc
  $make all-gcc
  $make install-gcc
  我们来看看 $PREFIX/bin 里面多了哪些东西
  $ls $PREFIX/bin
  你会发现多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 几个文件。
  Gcc-gnu 的 C 语言编译器
  Unprotoize-将 ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。
  Cpp-gnu的 C 的预编译器
  Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。
  使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。
  建立 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
  然后你还要修改 libc.so 文件
  将
  GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
  改为
  GROUP ( libc.so.6 libc_nonshared.a)
  这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
  
  
  
  
  
  
  
  
  建立全套编译器(full gcc)
  在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持C和C++。
  $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
  我们再来看看 $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++ 编译器。
  到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。
  用它来编译一个很简单的程序 helloworld.c
  #include 
  int main(void)
  {
  printf("hello world");
  return 0;
  }
  $arm-linux-gcc helloworld.c -o helloworld
  $file helloworld
  helloworld: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped
  上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。
  参考资料
  Wookey ,Chris Rutter, Jeff Sutherland, Paul Webb ,《The GNU Toolchain for ARM Target HOWTO》
  Karim Yaghmour,《Building Embedded Linux Systems》,USA:O'Reilly,2003  
  d-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/cstamp-h.in
  在我们编译并安装 gcc 前,我们先要改一个文件 $PRJROOT/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
  你如果没定义 -Dinhibit,编译时将会报如下的错误
  ../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
  ../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
  make[3]: *** [libgcc2.a] Error 1
  make[2]: *** [stmp-multilib-sub] Error 2
  make[1]: *** [stmp-multilib] Error 1
  make: *** [all-gcc] Error 2
  如果没有定义 -D__gthr_posix_h,编译时会报如下的错误
  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[2]: *** [stmp-multilib-sub] Error 2
  make[1]: *** [stmp-multilib] Error 1
  make: *** [all-gcc] Error 2
  还有一种与-Dinhibit同等效果的方法,那就是在你配置configure时多加一个参数-with-newlib,这个选项不会迫使我们必须使用newlib。我们编译了bootstrap-gcc后,仍然可以选择任何c库。
  接着就是配置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
  这条命令中的 -target、--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。
  接着我们编译并安装 boot-gcc
  $make all-gcc
  $make install-gcc
  我们来看看 $PREFIX/bin 里面多了哪些东西
  $ls $PREFIX/bin
  你会发现多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 几个文件。
  Gcc-gnu 的 C 语言编译器
  Unprotoize-将 ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。
  Cpp-gnu的 C 的预编译器
  Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。
  使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。
  建立 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
  然后你还要修改 libc.so 文件
  将
  GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
  改为
  GROUP ( libc.so.6 libc_nonshared.a)
  这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
  
  
  
  
  
  
  
  
  建立全套编译器(full gcc)
  在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持C和C++。
  $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
  我们再来看看 $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++ 编译器。
  到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。
  用它来编译一个很简单的程序 helloworld.c
  #include 
  int main(void)
  {
  printf("hello world");
  return 0;
  }
  $arm-linux-gcc helloworld.c -o helloworld
  $file helloworld
  helloworld: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), not stripped
  上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。
  参考资料
  Wookey ,Chris Rutter, Jeff Sutherland, Paul Webb ,《The GNU Toolchain for ARM Target HOWTO》
  Karim Yaghmour,《Building Embedded Linux Systems》,USA:O'Reilly,2003  
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics