GNU(GNU 是 GNU’s Not Unix 的递归首字母缩写词)是一个自由软件工程项目,目标在于创建一个完全兼容UNIX的自由软件环境(因为Unix属于商业版,收费不开源)。GNU已经开发出了大部分UNIX系统的程序库和工具,如:功能强大的文字编辑器Emacs, GUN开发编译器GCC等。尤其是Linux与其它的GNU软件结合,诞生了GNU下完全自由免费的操作系统。GNU软件功能完善而强大,丝毫不输商业软件,其开源免费的特性也得到了世界各地程序员的积极响应,让GNU软件尤其是Linux得到了相当广泛的应用。

笔者此处就搭建Arm交叉编译环境作一个简单的介绍。

1、交叉编译工具链概述

代码编译主要分为预处理、编译、汇编、链接这四个步骤。

SofTool.CN Notes:
编译过程的四个阶段,可以参考:https://www.softool.cn/read/gcc_base/20051801.html

这个流程需要多个开发工具配合使用:

例如:
gcc : 预处理和编译需要使用 gcc 工具,gcc 产生汇编代码
as : 汇编代码需要使用 as 工具把汇编指令对照翻译成机器指令
ld: 最后通过链接器 ld 将各个目标文件组装一起,解决符号依赖、库依赖,生成可执行文件

除此之外,项目开发往往还需要使用其它的工具:

例如:
objcopy : 通过 objcopy 将某种格式的目标文件转换成另外格式的文件(elf转hex、bin等);
size : 用 size 显示目标文件各个节的大小和目标文件的大小;
ar : 用 ar 生成库文件,生成反汇编调试等等。

因此,整个开发过程需要的是一套编译工具链。

2、交叉编译工具链命名方式

由于 GNU 工具链支持众多不同架构、不同厂商、运行不同系统的 CPU ,为了便于区分,交叉编译工具链有相应的命名规则:

[arch]-[vendor]-[os]-[(gnu)eabi]
各参数含义:
arch:可选项 体系结构(架构) 如: ARMMIPS
vendor:可选项(如果不使用该选项,则可以不填或none) 工具链提供商(厂商)
os:可选项(如果不使用该选项,则可以不填或none) 目标操作系统 如: Linux表用于Linux操作系统,none表没有操作系统的裸机
eabi:可选项 嵌入式应用二进制接口 如: 对于ARM架构,ARM公司规范了其调用标准AAPCS

关于eabi的扩展知识:eabi表示软浮点二进制接口,e指embeded;
armel 是arm eabi little endian的缩写;
armhf 是arm hard float 硬件浮点的缩写,通常暗指32位;
arm64 因为64位的arm默认就是hf的,因此不需要hf的后缀;

根据对操作系统的支持与否,ARM交叉编译工具链可分为支持和不支持操作系统。

命名举例:

  • arm-none-eabi
    命名规则注解:
    [arch] - arm
    [vendor] - none
    [os] - none
    [(gnu)eabi] - eabi
    none在此处可以理解为表示没有[vendor],也可以理解为表示没有[os]选项;
    此处的命名没有Linux,所以不支持Linux操作系统,通常用于裸机编程,使用面向嵌入式的小型c标准库(如uclibc、newlib等);

  • arm-linux-gnueabi
    命名规则注解:
    [arch] - arm
    [vendor] - none 此处只是没写,直接省略了而已。
    [os] - linux
    [(gnu)eabi] - gnueabi
    none在此处可以理解为表示没有[vendor]选项;
    支持linux操作系统,通常使用glibc;

  • arm-none-linux-gnueabi
    命名规则注解:
    [arch] - arm
    [vendor] - none
    [os] - linux
    [(gnu)eabi] - gnueabi
    none在此处可以理解为表示没有[vendor]选项;
    支持linux操作系统,通常使用glibc;

3、库选择

不管是裸机交叉编译工具链arm-none-eabi,还是Linux交叉编译工具链arm-linux-gnueabi,其实没有本质的区别,工具链都能编译成相应架构的指令、链接生成可执行代码。只不过arm-none-eabi默认使用的是非Linux接口的C库,适合于裸机开发,无法开发基于Linux的应用程序。而arm-linux-gnueabi默认使用的是Linux接口的C库,适合于Linux应用程序开发。

通常情况下,我们如果用C语言开发,如果重新实现C库往往不现实,需要交叉编译工具链支持标准C库。

对于arm交叉编译工具链,一般会支持三个最基本的库(静态库为例):libgcc.a、 libc.a、 libm.a

SofTool.CN Notes:
libgcc.a : 在编译gcc时产生,提供平台相关的底层运行库,大多数用于目标处理器的算术运算。如对于arm9,不支持硬件除法,硬件浮点,代码中任何除法、浮点相关操作都应该去链接libgcc.a,由libgcc.a提供除法、浮点操作的软件模拟实现。但对于支持硬件除法、硬件浮点的cortex-a架构cpu,无需libgcc.a提供软实现,编译器直接生成除法或浮点指令,处理速度是软实现远远不及的。
libc.a : C语言标准函数库
libm.a : 数学处理库

任何C编译器均应支持 libc.a 和 libm.a。

用于裸机开发以及用于Linux应用开发的Arm交叉编译工具链实质是一样的,只不过采用库的策略差异。理论上只要用裸机开发的交叉编译工具链编译一个基于某个Linux内核头的C库(如: glibc),那么就可以实现Linux应用程序的编程。同样,Linux应用开发的交叉编译工具链只要再编译一个基于裸机开发的C库(如: newlib),即可实现标准的裸机编程,与windows下mdk、iar等裸机开发无异。

arm交叉工具链支持各个arm架构版本,工具链版本越高,所能支持的arm版本也越高。

  • 对于arm7/arm9,支持生成armv4指令集;
  • 对于cortex-m,可以支持armv6-m/armv7-m指令集;
  • 对于cortex-a,可以支持armv7-a指令集等等。

通常对于版本跨度不大的arm交叉编译工具链,无需改动或简单的版本差异改动,就能够很好地实现bootloader、Linux内核、Linux应用程序、裸机的编译。因此,往往无需绑定使用不同芯片厂商、不同架构cpu、不同应用目标所附带的Arm交叉编译工具,避免多余的交叉编译工具链。

4、制作交叉编译工具链

制作arm交叉编译工具链一般有几种方法。

4.1 分步架构

分步编译和安装交叉编译工具链所需要的库和源码。由于各个GNU工具相互之间对版本依赖较大、补丁依赖、命令工具依赖等,一旦编译失败,解决完需再重新编译,如此往复,非常浪费精力以及时间,采用这种方法,只能自寻烦恼。

4.2 脚本工具架构

使用如crosstool-ng脚本可以解决各个GUN工具的版本依赖以及补丁。多次编译后,总能架构成功。但采用通用的GNU源码编译工具,而不是针对arm架构,往往代码优化,性能等不能达到最佳,同时脚本工具所能支持的Arm交叉编译工具链版本往往也不高。采用这种方法,相对吃力不讨好。

4.3 开源项目工具链

显然一些公司、开源组织已经意识到需要单独维护Arm交叉编译工具链了。这些工具链可以直接解压使用(已经是二进制可执行代码),可以基本兼容各个Linux发行版,如ubuntu、centos等。这些工具链往往针对arm架构使用了特定的优化,也经过一定的测试,可使用到较高版本的交叉编译工具链。非常省时省事,可以直接采用这种方法构架Arm交叉编译工具链。

GNU 推出的裸机开发Arm交叉编译工具链:
https://launchpad.net/gcc-arm-embedded

Linaro(ARM、Samsung、Freescale等联合非营利开源公司):
http://www.linaro.org/

CodeSourcery公司:★★★
https://www.mentor.com/embedded-software/codesourcery/

笔者使用 CodeSourcery 的 arm-none-linux-gnueabi 交叉编译工具链,工具包为 arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2,可以直接开发Linux应用程序。

5、使用交叉工具链

解压 arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 ,打开当前Linux电脑端的 etc/profile 文件,增加交叉工具链的环境变量即可。

Eastar Notes:
1、一般对于Linux应用程序arm交叉编译工具链,往往约定用 arm-linux- 作为linux开发交叉编译工具链的前缀,可以创建 arm-linux- 工具链的软链接。
2、同时,也可以使用这个交叉编译工具链编译裸机程序,可以采用约定的 arm-none-eabi- 作为裸机开发交叉编译工具链的前缀,可以创建 arm-none-eabi- 工具链的软链接。
3、上面的1和2,实际上两者使用的都是同一个编译程序,只是通过软链接制作了两种不同的前缀,以便符合我们的习惯而已。
4、.profile文件简介,可参考: https://www.softool.cn/read/linux_getting_started/20120104.html

创建的链接脚本 link.sh 如下,在工具链目录下执行即可。

SofTool.CN Notes:
通过实践,我把该脚本放在了 /home/arm/src/arm-2014.05/bin 目录下去执行。 为了顺利执行,需要将其属性设置为可执行。

link.sh 脚本内容如下:

#!/bin/bash
for file in $(ls arm-none-linux-gnueabi*)
do
ln -s $file arm-linux${file#arm-none-linux-gnueabi}
ln -s $file arm-none-eabi${file#arm-none-linux-gnueabi}
done

SofTool.CN Notes:
${file#arm-none-linux-gnueabi} 表示从file变量表示的字符串中,裁掉#号右边字符部分取剩余的部分
了解 Shell脚本,请参考: https://www.softool.cn/books/shell
了解 Linux命令,请参考: https://www.softool.cn/books/linux_command
因为我使用的是 arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 压缩包格式,所以需要把该脚本文件解压后的放到 arm-2014.05/bin 目录下,然后运行该脚本,即可产生两种软件链接:一种以 arm-linux- 开头,一种以 arm-none-eabi- 开头;
如下图所示,其中左侧和右侧开头的淡蓝色字体就是我刚刚生成的对应的软连接:

01_ARM交叉编译环境 - 图1

6、结语

笔者直接用CodeSourcery已编译好的Arm交叉编译工具链arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2去编译newlib,来支持完整的裸机开发。

有了完整的C库支持,以及Linux下集成开发环境Eclipse,可以解决依赖关系,可视化选项设置等,避免写makefile脚本,裸机开发与windows下mdk、iar开发并没有太大的差异。

同时,不同版本交叉编译工具链只是简单的编译选项、语法严格等方面的差异,采用这个交叉工具链无需或只需简单地改动即可编译s3c2416以及s5pv210的uboot、Linux内核。实现一个交叉编译工具链即可支持裸机、bootloader、Linux内核、Linux应用程序的开发。

SofTool.CN Notes:
1、介绍CodeSourcery工具链的文章和下载地址
http://blog.csdn.net/aiqing0119/article/details/46887581
2、将解压的工具链路径添加到etc/environment的PATH的方法:
PATH=”/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/arm/src/arm-2014.05/bin