交叉工具链制作至尊宝典

一些必须知道的基础知识

  • 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 这个环境变量中的原因)
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值