交叉工具链制作至尊宝典

来源:互联网 发布:mac book 和linux 编辑:程序博客网 时间:2024/06/05 02:59

转自:http://blog.csdn.net/turui/article/details/6596093

 

 

一些必须知道的基础知识

  • Debian 操作系统 以及 aptitude 命令
  • autoconf and automake
  • 什么是交叉编译,configure 的几个参数 build host target

    build:
    编译代码的机器,的CPU指令集

    host:
    编译生成的东西,的CPU指令集(目标板上的CPU的指令集)

    target:
    编译生成的东西,他编译生成的的东西,的指令集(所以此选项一般不用,大多只有在做交叉工具链时使用)

    0、以Expert mode 安装Debian

    不要升级,确保环境是一个纯净的环境

     

     

    1、声明环境变量 

     

    export IS_TARGET=arm-linux  export DIR_SRC=/root/cross_toolchains/src  export PREFIX=/opt/cross_toolchains/arm  export CONFIGURE_BASE="../configure --prefix=$PREFIX --with-sysroot=$PREFIX"  


     

    2、下载制作交叉工具链所必须的的代码

     

    binutils  ftp://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.gz  


     

    gcc  ftp://ftp.gnu.org/gnu/gmp/gmp-5.0.2.tar.gz  ftp://ftp.gnu.org/gnu/mpfr/mpfr-3.0.1.tar.gz  http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz  ftp://ftp.gnu.org/gnu/gcc/gcc-4.6.1/gcc-4.6.1.tar.gz  


     

    glibc  ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.gz  ftp://ftp.gnu.org/gnu/glibc/glibc-ports-2.13.tar.gz  


     

    linux kernel  http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.2.tar.bz2  


     

    3、安装(卸载)必要的的软件包

    aptitude install build-essential automake bison flex texinfo gawk g\+\+  aptitude remove mawk  


     

    4、解压、归档软件包

    cd $DIR_SRC  tar -xf binutils-2.21.tar.gz  tar -xf gmp-5.0.2.tar.gz  tar -xf mpc-0.9.tar.gz  tar -xf mpfr-3.0.1.tar.gz  tar -xf gcc-4.6.1.tar.bz2  tar -xf glibc-2.14.tar.gz  tar -xf glibc-ports-2.13.tar.gz  tar -xf linux-2.6.39.2.tar.bz2  


     

    mv gmp-5.0.2 gcc-4.6.1/gmp  mv mpc-0.9 gcc-4.6.1/mpc  mv mpfr-3.0.1 gcc-4.6.1/mpfr  mv glibc-ports-2.13 glibc-2.14/ports  


     

    5、编译 BINUTILS

    cd $DIR_SRC  cd binutils-2.21  mkdir build  cd build  $CONFIGURE_BASE --target=$IS_TARGET --disable-nls --enable-shared --disable-multilib  


     

    make configure-host  make  make install  


     

    export PATH=$PATH:$PREFIX/bin  


    问题:
    编译binutils一般不会遇到什么问题,但是,如果前面步骤3中安装的软件不全会出现问题

     

    6、建立用于编译C库的GCC

    cd $DIR_SRC  cd gcc-4.6.1  mkdir build   cd build  $CONFIGURE_BASE \  --target=$IS_TARGET \  --disable-nls \  --disable-shared \  --without-headers \  --with-newlib \  --enable-languages=c \  --disable-threads \  --disable-multilib \  --disable-decimal-float \  --disable-libgomp \  --disable-libmudflap \  --disable-libssp  


     

    make all-gcc all-target-libgcc  make install-gcc install-target-libgcc  


     

    值得注意的几个configure选项  --target  --disable-shared  --without-headers  --with-newlib  --enable-language-c  --disable-thread  


     

    cd $PREFIX/lib/gcc/$IS_TARGET/4.6.1  ln -s libgcc.a libgcc_eh.a 


     

    有建议修改 gcc/config/t-linux 这个文件  增加 -D__gthr_posix_h -Dinhibit_libc 两个宏,但我这里没这样做,是因为:  在configure后,编译使用的命令并不是 make 或者是 make all 而是 make all-gcc 和 make all-target-libgcc,所以很多问题不会出现  -with-newlib,这个选项不会迫使我们必须使用newlib 


     

    libgcc.mvars: No such file or directory  不能在 GCC 的源代码目录进行configure,必须在另外的目录进行configure make 等工作  所以这里在代码所在目录下 mkdir build 并 cd build 再进行 ../configure 等工作 


     

    configure: error: C compiler cannot create executables  如果使用 make 或 make all 会出现这样的问题,因为我们还未编译出目标指令集的 C 库  所以只能先使用 make all-gcc make all-target-libgcc  


     

    ../../../../arm-linux/bin/ld: cannot find -lgcc  ../../../../arm-linux/bin/ld: cannot find -lgcc_eh  很多资料都只写了 make all-gcc 而没有写 make all-target-libgcc 这样只建立了gcc,没有建立libgcc.a会出现以上第一个错误  如果没手工建立链接文件 libgcc_eh.a 则会出现第二个错误  


     

    7、配置内核生成必要的头文件

    cd $DIR_SRC  cd linux-2.6.39.2  make ARCH=arm CROSS_COMPILE=$IS_TARGET- menuconfig  make ARCH=arm CROSS_COMPILE=$IS_TARGET-


     

    mkdir -p $PREFIX/include  cd $PREFIX/include  ln -s $DIR_SRC/linux-2.6.39.2/arch/arm/include/asm asm  ln -s $DIR_SRC/linux-2.6.39.2/include/linux linux  ln -s $DIR_SRC/linux-2.6.39.2/include/asm-generic asm-generic 


     

    这里并没有将内核的头文件复制到交叉工具链的安装目录  编译C库的时候,需要对应的CPU指令集的汇编代码所以做了链接处理  


     

    编译内核在执行 make ARCH=arm CROSS_COMPILE=$IS_TARGET- 时如果出错,是没有关系的,这里只要生成了对应的 version.h autoconf.h就可以了  


     

    8、编译C库

    cd $DIR_SRC  cd glibc-2.9  mkdir build  cd build  


     

    vi ../configure  vi ../ports/sysdeps/unix/sysv/linux/arm/sigrestorer.S  vi ../sysdeps/unix/syscall-template.S   vi ../nptl/allocatestack.c   vi ../elf/dl-tls.c  vi ../sysdeps/ieee754/dbl-64/s_fma.c  vi ../sysdeps/ieee754/dbl-64/s_fmaf.c    具体的修改,我写在下面(觉得还是要说清楚为什么修改,所以就没用sed命令或是做一些patch文件了,请向下看)  


     

    CC=$IS_TARGET-gcc \  $CONFIGURE_BASE \  --host=$IS_TARGET \  -enable-add-ons \  --with-binutils=$PREFIX/bin \  --with-headers=$PREFIX/include \  libc_cv_forced_unwind=yes \  libc_cv_c_cleanup=yes  


     

    值得注意的几个configure选项  --host  --with-headers  lib_cv_forced_unwind  lib_cv_c_cleanup  


     

    make  make install   


     

    这里编译的时候并有选择TARGET为EABI,所以在制作交叉工具链时会有很多问题需要修改  


     

    *** These critical programs are missing or too old: as ld  *** Check the INSTALL file for required versions.  vi ../configure   查找  "$AS --version" 将 2.1[3-9] 修改为 2.[1-2][0-9]  查询  "$LD --version" 将 2.1[3-9] 修改为 2.[1-2][0-9]  


     

    Error: previous CFI entry not closed (missing .cfi_endproc)  vi ../ports/sysdeps/unix/sysv/linux/arm/sigrestorer.S  ENTRY(__default_sa_restorer) 下增加  END(__default_sa_restorer)  ENTRY(__default_rt_sa_restorer) 下增加  END(__default_rt_sa_restorer)  


     

    syscall-template.S:82: Error: CFI instruction used without previous .cfi_startproc  vi ../sysdeps/unix/syscall-template.S   这个问题的修改我也不是十分确定,我是这样来思考的  看到 syscall-template.S 中 有 #include <sysdep.h>  去查看 ports/sysdeps/unix/sysv/linux/arm/sysdep.h  看到如下代码  #ifdef __ASSEMBLER__  #undef  PSEUDO    #define PSEUDO(name, syscall_name, args)                                      \    .text;                                                                      \    ENTRY (name);                                                               \      DO_CALL (syscall_name, args);                                             \      cmn r0, $4096;    猜测是__ASSEMBLER__宏未打开,以至于未能找到PSEUD0函数的声明,则将    #define PSEUDO(name, syscall_name, args)                                      \    .text;                                                                      \    ENTRY (name);                                                               \      DO_CALL (syscall_name, args);                                             \      cmn r0, $4096;    这段代码 添加至 ../sysdeps/unix/syscall-template.S 中  


     

    LS_DTV_UNALLOCATED  undeclared (first use in this function)  vi ../nptl/allocatestack.c  vi ../elf/dl-tls.c   这个错误会出现在编译以上两个文件的时候,这个宏的定义我grep了整个glibc的所有代码,没找到ARM相关的声明及定义,按照其他指令集的定义猜测着修改如下  在以上两个C文件中增加相应的定义    #define TLS_DTV_UNALLOCATED      ((void *) -1l)  


     

    E_TOWARDZERO undeclared (first use in this function)  E_INEXACT undeclared (first use in this function)  以上两个错误会出现在以下两个文件的的编译过程中  vi ../sysdeps/ieee754/dbl-64/s_fma.c  vi ../sysdeps/ieee754/dbl-64/s_fmaf.c  参考 ports/sysdeps/arm/eabi/bits/fenv.h中的定义  在两个文件中添加  #define FE_TOWARDZERO 0xc00000  #define FE_INEXACT 16  


     

    mawk: scripts/gen-sorted.awk: line 19: regular expression compile failed   所以要 aptitude install gawk 所以也顺带着 aptitude remove mawk  


     

    configure: error: forced unwind support is required   configure 中增加配置参数 libc_cv_forced_unwind=yes   


     

    error: the compiler must support C cleanup handlin  configure 中增加配置参数libc_cv_c_cleanup=yes   


     

    --enable-add-ons 为 C 库 增加 thread 支持,目前默认使用的是 nptl 所以这里没有去下载 glibc-threads 相关的代码  


     

    --with-headers 指定内核头文件所在的目录  


     

    9、编译完整的 gcc 工具链

    mkdir -p $PREFIX/usr  cd $PREFIX/usr  ln -s ../include include  


     

    cd $PREFIX  mkdir -p opt/cross_toolchains  cd opt/cross_toolchains/  ln -s ../../../arm arm  


     

    cd $DIR_SRC  cd gcc-4.6.1  cd build  make clean  make distclean  rm * -rf  


     

    $CONFIGURE_BASE \  --target=arm-linux \  --enable-languages=c,c++ \  --enable-shared \  --disable-nls \  --enable-c99 \  --enable-long-long \  --disable-multilib \  --enable-__cxa_atexit  


     

    几个值得注意的configure 选项  --target  --enable-shared  


     

    make  make install  


     

    The directory that should contain system headers does not exist:  这个问题我没具体的去跟踪了,从表面上看出来是一些路径上的问题,并且经过验证,这个问题是在configure时使用了--with-sysroot选项时产生的  为了尝试不通过建立链接的方式去解决这个问题  在指明了 --includedir --libdir --sysconfdir 等等一系列参数后编译,依然会出现此问题  所以不再跟踪,暂且是当做GCC编译环境上的一个 BUG好了  


     

    opt/cross_toolchains/arm/arm-linux/bin/ld: cannot find /opt/cross_toolchains/arm/lib/libc.so.6 inside /opt/cross_toolchains/arm  这个问题更是有点神经病了,所以这里也不跟踪了,也是由于使用了 --with-sysroot选项产生的问题,建立了第二个链接文件  目的是让 /opt/cross_toolchains/arm 这个被当做是根目录的目录里面能有一个跟 --prefix 指定的 /opt/cross_toolchains/arm 一样的目录结构(说起来真别扭)  


    参考资料
    https://www.ibm.com/developerworks/cn/linux/l-embcmpl/
    http://cross-lfs.org/view/clfs-embedded/arm/cross-tools/introduction.html
    http://www.linuxsir.org/bbs/showthread.php?t=267672(这个文章虽然有点老,也有点神,把一些能看懂的说的让人看不懂,那个图更是让人觉得,汗,但原理还是说的很清楚的,这里强调的--with-sysroot的3次出现的问题,还是值得仔细想想的,这也是我为什么将 --with-sysroot 选项 做到$CONFIGURE_BASE 这个环境变量中的原因)

     

    关于 --with-sysroot 这个参数,真是一个让人觉得可恨的参数,这个参数会引起一系列的问题,前章中,不得已的在 /opt/cross_toolchains/arm 中建立了两个连接文件

    mkdir usr  cd usr  ln -s ../include include  


     

    mkdir -p opt/cross_toolchains  cd opt/cross_toolchains  ln -s ../../../arm arm  


    还记得这两段脚本吗?让我觉得极其不爽,不得已才用这种办法去解决遇到的问题,而这两个问题都是因为使用了 --with-sysroot 这个 configure 参数而导致的,关键是我不知道如何解决!!

    下面的脚本中我们将不再使用 --with-sysroot 这个configure 参数

    下面的脚本将编译 arm eabi 的交叉工具链

    值得注意的地方是,在编译完 glibc 后的一些处理

    cd $PREFIX/arm-none-linux-gnueabi  rm lib include -rf  ln -s ../lib lib  ln -s ../include include 


    上面这段会解决一些看起来很难理解的问题,但我觉得这样做是正确的,因为在最后编译gcc时,需要使用到binutil的一些工具,而binutils的命令安装在bin目录下

    与这个bin 同一层的 lib 和 include 目录并不存在,所以会引起编译gcc 中  pthread.h 头文件找不到,链接需要的 c 库 开工代码 ctri.o ctxxx几个 o文件找不到等问题

    通过这样处理,可以解决这个问题,并且避免了使用 --with-sysroot 这个恶心的参数(autoconf 做的不够好啊,要么就是 gcc 的 autoconf脚本没写好)

    比如这种问题:

    arm-none-linux-gnueabi/bin/ld: cannot find crti.o: No such file or directory  


     

    自动化脚本如下,使用方法:将脚本保存为 makecross.sh,并且设置权限 chmod a+x makecross.sh,然后执行脚本./makecross.sh,可以看到帮助后续我会补充上 targe的选择以及检测方法,cpu指令集的选择,uclibc 编译,等相关内容


     

    #!/bin/sh  # the newer four-part form:  #       CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM        unset CPU  unset MFR  unset KERNEL  unset OS  unset VER_GCC  unset DIR_OPT  unset DIR_SRC  unset PREFIX  unset TARGET    export CPU=arm  export MFR=none  export KERNEL=linux  #export OS=uclibceabi  export OS=gnueabi  export VER_GCC=4.6.1    export DIR_OPT=/opt/cross_toolchains  export DIR_SRC=/root/cross_toolchains/src    export PREFIX=$DIR_OPT/$CPU/$VER_GCC  export CONFIGURE_BASE="../configure --prefix=$PREFIX"  export TARGET=$CPU-$MFR-$KERNEL-$OS  export PATH=$PATH:$PREFIX/bin    function do_unzip_single()  {      cd $DIR_SRC      if [ "$1" = "binutils" ];then          tar -xf binutils-2.21.tar.gz      elif [ "$1" = "gcc" ];then          tar -xf gcc-4.6.1.tar.gz          tar -xf mpfr-3.0.1.tar.gz          tar -xf mpc-0.9.tar.gz          tar -xf gmp-5.0.2.tar.gz                    mv gmp-5.0.2  gcc-4.6.1/gmp          mv mpc-0.9    gcc-4.6.1/mpc          mv mpfr-3.0.1 gcc-4.6.1/mpfr              elif [ "$1" = "glibc" ];then          tar -xf glibc-2.13.tar.gz          tar -xf glibc-ports-2.13.tar.gz            mv glibc-ports-2.13 glibc-2.13/ports      elif [ "$1" = "kernel" ];then          tar -xf linux-2.6.39.2.tar.bz2            fi  }    function do_download_single_do()  {      cd $DIR_SRC      if [ ! -e $DIR_SRC/$1 ];then           wget $2      fi  }    function do_download_single()  {      FILE_NAME=""      URL=""      if [ "$1" = "binutils" ];then          set FILE_NAME=binutils-2.21.tar.gz          set URL=ftp://ftp.gnu.org/gnu/binutils/binutils-2.21.tar.gz                    do_download_single_do $FILE_NAME $URL      elif [ "$1" = "gcc" ];then          set FILE_NAME=gcc-4.6.1.tar.gz          set URL=ftp://ftp.gnu.org/gnu/gcc/gcc-4.6.1/gcc-4.6.1.tar.gz          do_download_single_do $FILE_NAME $URL                    set FILE_NAME=mpfr-3.0.1.tar.gz          set URL=ftp://ftp.gnu.org/gnu/mpfr/mpfr-3.0.1.tar.gz          do_download_single_do $FILE_NAME $URL                    set FILE_NAME=mpc-0.9.tar.gz          set URL=http://www.multiprecision.org/mpc/download/mpc-0.9.tar.gz          do_download_single_do $FILE_NAME $URL                    set FILE_NAME=gmp-5.0.2.tar.gz          set URL=ftp://ftp.gnu.org/gnu/gmp/gmp-5.0.2.tar.gz          do_download_single_do $FILE_NAME $URL      elif [ "$1" = "glibc" ];then          set FILE_NAME=glibc-2.13.tar.gz          set URL=ftp://ftp.gnu.org/gnu/glibc/glibc-2.13.tar.gz          do_download_single_do $FILE_NAME $URL                    set FILE_NAME=glibc-ports-2.13.tar.gz          set URL=ftp://ftp.gnu.org/gnu/glibc/glibc-ports-2.13.tar.gz          do_download_single_do $FILE_NAME $URL      elif [ "$1" = "kernel" ];then          set FILE_NAME=linux-2.6.39.2.tar.bz2          set URL=http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.2.tar.bz2          do_download_single_do $FILE_NAME $URL      fi  }    function do_remove_single()  {      cd $DIR_SRC      # only remove the directory,but not the zip file.      if [ "$1" = "binutils" ];then          rm -rf binutils-2.21      elif [ "$1" = "gcc" ];then          rm -rf gcc-4.6.1           rm -rf mpfr-3.0.1          rm -rf mpc-0.9          rm -rf gmp-5.0.2              elif [ "$1" = "glibc" ];then          rm -rf glibc-2.13          rm -rf glibc-ports-2.13      elif [ "$1" = "kernel" ];then          rm -rf linux-2.6.39.2      fi  }    function do_reconstruction_single()  {      echo "reconstruction single package $1"      cd $DIR_SRC      do_remove_single $1;      do_download_single $1      do_unzip_single $1    }    function do_reconstruction()  {      cd $DIR_SRC       if [ "$1" = "all" ]      then          do_reconstruction_single binutils          do_reconstruction_single gcc          do_reconstruction_single glibc            else          do_reconstruction_single $1           fi    }    function do_build_single_pre()  {      if [ "$1" = "binutils" ];then          cd binutils-2.21          elif [ "$1" = "gcc_first" ];then          # glibc need kernel's .h file          mkdir -p $PREFIX/include          cd $PREFIX/include                    rm -f asm          rm -f linux          rm -f asm-generic               ln -s $DIR_SRC/linux-2.6.39.2/arch/arm/include/asm asm          ln -s $DIR_SRC/linux-2.6.39.2/include/linux linux          ln -s $DIR_SRC/linux-2.6.39.2/include/asm-generic asm-generic                    cd $DIR_SRC            cd gcc-4.6.1          elif [ "$1" = "glibc" ];then          cd glibc-2.13             echo "/* Value used for dtv entries for which the allocation is delayed.  */" >> ports/sysdeps/arm/dl-tls.h          echo "#define TLS_DTV_UNALLOCATED     ((void *) -1l)"  >> ports/sysdeps/arm/dl-tls.h      elif [ "$1" = "gcc" ];then          cd gcc-4.6.1          elif [ "$1" = "kernel" ];then          cd linux-2.6.39.2         fi            # create build directory      rm -rf build      mkdir -p build            if [ "$1" = "kernel" ];then          rm -rf build          fi  }    function do_build_single_config  {      # configure      if [ "$1" = "binutils" ];then          $CONFIGURE_BASE \          --target=$TARGET \          --enable-shared           elif [ "$1" = "gcc_first" ];then          $CONFIGURE_BASE \          --target=$TARGET \          --disable-shared \          --without-headers \          --with-newlib \          --enable-languages=c \          --disable-threads             elif [ "$1" = "glibc" ];then          CC=$PREFIX/bin/$TARGET-gcc \          $CONFIGURE_BASE \          --host=$TARGET \          -enable-add-ons \          --with-headers=$PREFIX/include \          --with-binutils=$PREFIX/bin \          libc_cv_forced_unwind=yes \          libc_cv_c_cleanup=yes             elif [ "$1" = "gcc" ];then          $CONFIGURE_BASE \          --target=$TARGET \          --enable-shared \          --enable-languages=c,c++ \          --enable-c99 \          --enable-long-long \          --enable-__cxa_atexit      elif [ "$1" = "kernel" ];then          make menuconfig       fi  }    function do_build_single_make()  {      # make and make install      if [ "$1" = "gcc_first" ];then          make -j4 all-gcc all-target-libgcc          make -j4 install-gcc install-target-libgcc          cd $PREFIX/lib/gcc/$TARGET/$VER_GCC          rm libgcc_eh.a          ln -s libgcc.a libgcc_eh.a      elif [ "$1" = "glibc" ];then          make -j4          make -j4 install                  cd $PREFIX/arm-none-linux-gnueabi          rm lib include -rf          ln -s ../lib lib          ln -s ../include include      else          make -j4          make -j4 install      fi  }    function do_build_single()  {      cd $DIR_SRC      echo "build single package $1"      if [ "$1" = "kernel" ];then          do_build_single_pre $1          do_build_single_config $1      else          do_build_single_pre $1          cd build          do_build_single_config $1          do_build_single_make $1      fi  }    function do_build()  {      if [ "$1" = "all" ]      then          do_build_single binutils          do_build_single gcc_first          do_build_single glibc             do_build_single gcc      else          do_build_single $1                        fi  }    function do_rebuild()  {      rm -rf $PREFIX/*      do_reconstruction $1      do_build $1  }    function do_help()  {      echo "usage:"      echo "  ./makecross reconstruction binutils"      echo "  ./makecross reconstruction gcc"      echo "  ./makecross reconstruction glibc"      echo "  ./makecross reconstruction all"      echo "  ./makecross build binutils"      echo "  ./makecross build gcc_first"      echo "  ./makecross build glibc"      echo "  ./makecross build gcc"      echo "  ./makecross build all"        echo "  ./makecross rebuild all"  }    # main entery    # to install necessary package  # aptitude install build-essential automake bison flex texinfo gawk g\+\+ zip  # aptitude remove mawk      SOME=`aptitude show build-essential automake bison flex texinfo gawk g\+\+ zip|grep "State: not install"`   #echo $SOME  if [ ! "$SOME" = "" ];then      echo "aptitude install"      aptitude install build-essential automake bison flex texinfo gawk g\+\+ zip  fi    SOME=`aptitude show mawk | grep "State: installed"`  if [ ! "$SOME" = "" ];then      echo "aptitude remove mawk"      aptitude remove mawk  fi    # about kernel  # if there is no kernel headers,then rebuild kernel  # include/linux/version.h and include/generated/autoconf.h  if [ ! -e $DIR_SRC/linux-2.6.39.2/include/linux/version.h ];then      #echo "version"      if [ ! -e $DIR_SRC/linux-2.6.39.2/include/generated/autoconf.h ];then            echo "reconstruction kernel"            do_reconstruction_single $1      fi  fi  echo "check and rebuild env done."    # do command  if [ "$1" = "reconstruction" ];then      do_reconstruction $2  elif [ "$1" = "build" ];then      echo "build"      do_build $2  elif [ "$1" = "rebuild" ];then      do_rebuild $2  else      do_help  fi    


     

  • 原创粉丝点击