• 建立ARM交叉编译环境 (arm-none-linux-gnueabi-gcc with EABI)【转】


    转自:http://lib.csdn.net/article/embeddeddevelopment/60172?knId=886

    建立ARM交叉编译环境 (arm-none-linux-gnueabi-gcc with EABI)
    
    作者:wyjkk
    
    昨天终于把交叉编译环境、移植内核和制作root文件系统在arm开发板上顺利跑通了。期间有的步骤很顺利,但更多的是被诸多问题困扰,比如最后一个不起眼的小问题导致文件系统无法加载,郁闷了我一个星期,最终通过分析慢慢发现了这个bug。还有各源码包版本的问题,而且网上很多介绍都是基于旧版本的。我这里全部用最新或较新的版本,当然,至于新旧版本到底哪个更好更合适,这是个智者见智的论题,不在本文讨论之列。我坚信很多人也遇到过或者即将遇到我曾经历过的错误和问题,因此我觉得把我过去两周做过的相关工作,详细地写下来,希望对大家有所帮助!
     
    
    首先是平台和环境 ,我过去两周都是基于vmware 中ubuntu 10.04的,但是我发现ubuntu这个很火的桌面linux发行版本并不适合进行嵌入式开发,典型的麻烦就是系统缺少很多库、服务等等,需要自己手动安装,增加了不少额外的工作,和我以前用的SuSe 9比麻烦不少。不过所以现在我干脆全新装了一个SUSE 11.2 Enterprise Server 32bit,把过去的工作重复一遍,边编译边纪录,力求不遗漏细节!
     
    
    过程预览:
    1,准备工作,包括下载源码包、补丁、建立文件夹和设置环境变量等
    2,建立内核头文件
    3,建立binutils
    4,建立bootstrap gcc
    5,建立glibc
    6,建立完整版本gcc
    7,测试hello world
     
    
    现在就让我们开始吧!  
     
    
    1 准备工作
    
    我使用的源码包和补丁 如下:
    linux-2.6.34.tar.bz2
    binutils-2.20.tar.gz
    gcc-4.3.5.tar.bz2
    glibc-2.11.tar.gz
    glibc-linuxthreads-2.5.tar.bz2
    glibc-ports-2.11.tar.bz2
    glibc-2.11.2-gcc_fix-1.patch
    至于怎么得到这些源码包,找google吧!
     
    
    建立工作目录
    自己选一个合适的地方,建立一个总文件夹Embedded,并且在其下建立 build-tools、kernel和tools三个子文件夹、我们以后的操作就都在这里进行了。
    
    $ mkdir Embedded
    $ cd Embedded
    $ mkdir build-tools    kernel     tool
    $ ls
    build-tools    kernel     tool
    
     
    
    
    各文件夹作用如下:
    
    build-tools : 保存binutils、gcc 和 glibc的源代码和用来编译这些源代码的目录。
    kernel        : 保存内核源代码和补丁。
    tools          : 保存编译好的交叉编译工具和库文件。
    然后在build-tools文件夹中建立如下子文件夹:
    
     
    
    
    $ cd build-tools
    $ mkdir build-binutils   build-boot-gcc   build-glibc  build-gcc
    
    
    build-binutils    :编译binutils的目录
    build-boot-gcc : 编译gcc 启动部分的目录
    build-glibc        :编译glibc的目录
    build-gcc          :编译完整gcc的目录
    
     
    
    
    
    设置环境变量:
    
    这里设置环境变量只是为了方便,因为每个工具的config都需要输入类似的变量,不如放在环境变量里。
    
    在命令行下打开vi  ~/.bashrc,在文档最后输入下面几行,然后注销当前用户,重新登录
    
    export PRJROOT=/home/jinglelong/MySoftware/Embedded
    export TARGET=arm-none-linux-gnueabi
    export PREFIX=$PRJROOT/tools
    export TARGET_PREFIX=$PREFIX/$TARGET
    export PATH=$PREFIX/bin:$PATH
    
     
    
     
    
    
    各变量的具体意义如下:
    
    PRJROOT                     : 整个工程的根目录,这里当然是Embeded了
    TARGET                       : 目标文件对应的体系结构,arm-linux代表编译出来的target只能在arm体系结构中运行
    PREFIX                        : 设置目标文件夹的路径前缀
    TARGET_PREFIX          : 设置目标文件夹的路径前缀路径
    PATH                           : 添加可执行文件的路径,这里主要是只中间编译工具等
    
     
    
     
    
    
    2 建立内核include文件
    
    $ ln -s  /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/include/linux  $TARGET_PREFIX/include/linux
    $ ln -s  /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/include/asm-generic/      $TARGET_PREFIX/include/asm-generic
    $ ln -s  /home/jinglelong/MySoftware/Embedded/kernel/linux-2.6.34/arch/arm/include/asm/  $TARGET_PREFIX/include/asm 
    
     
    
    
    编译生成version头文件
    
    这个是编译glibc时必须的,使用命令:make include/linux/version.h
    
     
    
     
    
    
    3 建立binutils
    
    解压binutils源码到文件夹: $PRJROOT/build-tools/binutils-2.20
    
     
    
    
    配置:
    
    cd $PRJROOT/build-tools/build-binutils
    $ ../binutils-2.20/configure --target=$TARGET --prefix=$PREFIX
    
    
    编译:make
    出错:
    ../../binutils-2.20/gas/config/tc-arm.c: In function ‘make_mapping_symbol’:
    ../../binutils-2.20/gas/config/tc-arm.c:2489: error: suggest braces around empty body in an ‘if’ statement
    打开文件binutils-2.20/gas/config/tc-arm.c,把2490行的语句,用一对大括号括起来就可以了
    
     
    
    
    安装: make install
    完成后检查一下$PREFIX文件夹,是不是多了三个子文件夹,bin, lib, share? 打开bin,发现里面生成了14个可执行文件:
     
    
    [root@localhost bin]# ls
    arm-none-linux-gnueabi-addr2line  arm-none-linux-gnueabi-as   arm-none-linux-gnueabi-gprof  arm-none-linux-gnueabi-nm       arm-none-linux-gnueabi-objdump  arm-none-linux-gnueabi-readelf  arm-none-linux-gnueabi-strings arm-none-linux-gnueabi-ar         arm-none-linux-gnueabi-c++filt  arm-none-linux-gnueabi-ld     arm-none-linux-gnueabi-objcopy  arm-none-linux-gnueabi-ranlib   arm-none-linux-gnueabi-size     arm-none-linux-gnueabi-strip
    
    
    他们的功能分别是:
    
    add2line         :将你要找的地址转成文件和行号,它要使用 debug 信息。
    ar                  :产生、修改和解开一个存档文件
    as                  :gnu的汇编器
    c++filt            :C++ 和 java 中有一种重载函数,所用的重载函数最后会被编译转化成汇编的标,c++filt 就是实现这种反向的转化,根据标号得到函数名。
    gprof              :gnu 汇编器预编译器。
    ld                   :gnu 的连接器
    nm                 :列出目标文件的符号和对应的地址
    objcopy           :将某种格式的目标文件转化成另外格式的目标文件
    objdump          :显示目标文件的信息
    ranlib              :为一个存档文件产生一个索引,并将这个索引存入存档文件中
    readelf            :显示 elf 格式的目标文件的信息
    size                :显示目标文件各个节的大小和目标文件的大小
    strings            :打印出目标文件中可以打印的字符串,有个默认的长度,为4
    strip                :剥掉目标文件的所有的符号信息
    
     
    
    
    
    4 建立bootstrap gcc
    
    
    首先,我们为什么要建立bootstrap gcc,而不能一次性成功?原因有两点:
    
     
    
    
    一是由于平台本身的gcc编译器和我们要建立的gcc版本不同,第一次用平台本身的编译器去build目标版本的gcc编译器的时候,新生成的目标编译器(相当于初始编译器编译链接生成的可执行文件)必然带有初始编译器的特征。而当我们用新生成的编译器再次编译自身时,便可去掉这种差异性。
    
     
    
    
    二是因为gcc编译器依赖于glibc,而当前我们的glibc是基于本机的,所以我们首先要build基于arm体系结构的glibc,再在glibc的基础上生成基于arm体系结构的gcc。
    
     
    
    
    这一步是最容易出错的,对每一步都必须谨慎,不要犯粗心之类的低级错误。
    
     
    
    
    解压源码
    解压gcc源码到build-tool文件夹下
     
    
    修改源码:
    gcc-4.3.5
    CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC -Dinhibit_libc -D__gthr_posix_h
    
    确保本机已经安装了mpc, mpfr, gmp, 如果没有,则在yast里面安装好再往后走。
    
     
    
    
    配置:
    ../gcc-4.3.5/configure --target=$TARGET --prefix=$PREFIX --without-headers --enable-languages=c --disable-threads --with-newlib --disable-shared --disable-libmudflap --disable-libssp
     
    
    编译:make all-gcc
    安装gcc: make install
    再编译安装libgcc,这个是后面编译glibc必须的。
    编译:make all-target-libgcc
    安装libgcc: make install-target-libgcc
     
    
    我看到网上很多文章在这一步有很多错误,一种是直接用make命令编译gcc下所有内容,这个是没有必要的,而且容易出错。我在ubuntu和suse下都无法完成编译,而在fedora下通过了;第二种情况是没有编译libgcc,这会导致后面编译glibc无法通过。
     
    
    安装完成后,在$PREFIX/bin下又多了几个文件,
    arm-none-linux-gnueabi-cpp         : gnu的 C 的预编译器
    arm-none-linux-gnueabi-gcc         : gnu的 C 语言编译器
    arm-none-linux-gnueabi-gcc-4.3.5 : gnu的 C 语言编译器,其实和arm-linux-gcc是一样的
    arm-none-linux-gnueabi-gccbug    :  一个可执行脚本,具体作用未知。
    arm-none-linux-gnueabi-gcov        : gcc 的辅助测试工具,用来分析和优化程序
    
     
    
     
    
    
    
    5 建立glibc
    解压源码:
    把glibc源码解压到build-tool下,把glibc-linuxthreads-2.5.tar.bz2解压到glibc根目录下,把glibc-ports-2.11.tar.bz2解压到glibc根目录下,并且命名为ports
     
    
    进入文件夹build-glibc,创建config.cache文件,并且在文件中输入以下内容
    
    libc_cv_forced_unwind=yes
    libc_cv_c_cleanup=yes
    libc_cv_arm_tls=yes
    
     
    
    配置:
    
    BUILD_CC="gcc" CC=$TARGET-gcc ../glibc-2.11/configure --host=$TARGET --target=$TARGET --prefix=/usr --enable-add-ons --disable-profile --cache-file=config.cache --with-binutils=$PREFIX/bin/ --with-headers=$TARGET_PREFIX/include/
    
     
    
    
    编译:make
    出错:/arm-linux/bin/ld: cannot find -lgcc_eh
    打开glibc根目录下Makeconfig文件,去掉第541,546行中的-lgcc_eh,重新make
    
     
    
    
    安装:
    
    make install_root=$TARGET_PREFIX prefix="" install
    
     
    
    
    修改libc.so:
    
    用vi或gedit打开libc.so文件,将文件中的:
    GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux.so.2 ) )
    更改为
    GROUP ( libc.so.6 libc_nonshared.a )
    保存后退出
    
     
    
     
    
    
    
    6 建立完整版gcc
    
    有了前面的经验,现在就简单多了,进入目录build-gcc,
    
     
    
    
    配置:
    
    ../gcc-4.3.5/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++ --disable-libgomp
    
     
    
    
    编译:
    make all
     
    
    安装:
    make install
     
    
    安装完成后,在$PREFIX/bin下多了gnu的c++编译器:
    arm-none-linux-gnueabi-gcc
    arm-none-linux-gnueabi-c++  
      
    
     
    
     
    
    7 验证工具链
    创建,编译生成一个hello world程序helloworld, 查看elf文件信息:
    $  arm-none-linux-gnueabi-readelf  -d helloworld
    是不是看到了ARM的信息?更直接的,就是把这个helloworld和相关依赖的动态库拷到开发板上,看它是不是真的能helloworld!
    
     
    
    
    8 总结
    这次在SUSE 11.2上编译安装工具链,整个过程非常顺利,其实我相信只要环境,配置等正确,常见linux发行版上都会比较顺利。不过我还是建议直接下在编译好的工具链,省下了不少麻烦,而且可靠性也能保证。最后,希望本教程对大家有所帮助,如果有什么遗漏或错误之处,希望大家能批评指正!
    
     
    
     
    
    
    
    参考文献:
    
    1, 如何为嵌入式开发建立交叉编译环境: http://www.ibm.com/developerworks/cn/linux/l-embcmpl/
  • 相关阅读:
    php使用redis的有序集合zset实现延迟队列
    php使用redis的几种常见方式和用法
    redis缓存雪崩,缓存穿透,缓存击穿的解决方法
    php操作redis数据库方法总结
    mysql 悲观锁与乐观锁的理解
    OAuth2.0 协议的理解
    windows下的mongodb安装与配置
    node.js中对 redis 的安装和基本操作
    node.js中对 mysql 进行增删改查等操作和async,await处理
    node.js中 koa 框架的基本使用方法
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8628999.html
Copyright © 2020-2023  润新知