i.MX6ULL开发板源码自制交叉编译器

前言

文章基于HD-IMX6ULL-MB 系列开发板测试验证,该开发板由武汉芯路遥科技有限公司与武汉万象奥科电子有限公司合作推出。此开发板基于 NXP iMX6ULL 系列 Cortex-A7 高性能处理器设计,适用于快速开发一系列具有创新性的产品如人机界面工业 4.0 扫描仪、车载终端以及便携式医疗设备。

i.MX6ULL开发板源码自制交叉编译器_第1张图片

自己制作交叉编译器

早期(2009年以前)我们在做嵌入式系统开发时,第一件事就是自己制作交叉编译器。当时做交叉编译器 需要自己下载gcc、glibc、binutils等相关工具的源码,然后一个一个源码编译安装。制作交叉编译器的 过程中最痛苦的莫过于各个软件之间的版本依赖关系,如gcc 4.6.2 依赖 glibc 2.13,如果你选定 gcc 4.7 则可能编译制作失败,然后再尝试一个新的版本重新编译,直至找到一个合适的版本为止。

后来为了方便交叉编译器的制作,有很多组织或个人开始编写这些制作交叉编译器的脚本或框架,并测 试解决这些软件版本之间的依赖关系。当时最知名的莫过于基于 glibc 的 crosstool 和 基于 uclibc 的

buildroot 了。在开始讲解如何制作交叉编译器之前,我们首先来了解一下 C运行库。

1.嵌入式C运行库

1.1glibc库

glibc是gnu发布的libc库,也即c运行库。glibc是linux 系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了 许多其它一些必要功能服务的实现,主要的如下:

  1. string,字符串处理

  2. signal,信号处理

  3. dlfcn,管理共享库的动态加载

  4. direct,文件目录操作

  5. elf,共享库的动态加载器,也即interpreter

  6. iconv,不同字符集的编码转换

  7. inet,socket接口的实现

  8. intl,国际化,也即gettext的实现

  9. io

  10. linuxthreads

  11. locale,本地化

  12. login,虚拟终端设备的管理,及系统的安全访问

  13. malloc,动态内存的分配与管理

  14. nis

  15. stdlib,其它基本功能

gcc 是编译器,基本上 Linux 下所有的程序(包括内核)都是 gcc 编译的,libc 当然也是。gcc 和 libc 是互相依赖的两个软件,它们合作的方式类似 Linux 系统的 "自举"。先在一个可以运行的带有老 libc 和

gcc 的系统上,用老 gcc 编译出一个新版本的 gcc + 老 libc,再用这个新 gcc 编译出一个新 gcc + 新

libc,再用这套新的组合编译整个新系统。

1.2 uClibc库

PC上常用的标准库glibc是一个非常宠大而完整的库,但早期对于嵌入式系统来说,由于Flash和RAM的 存储空间有线,其体积显得过于大了一些。uClibc的出现就是为了解决这个问题,uClibc尽可能的兼容

Glibc,大多数应用程序可以在很小或完全不修改的情况下就可能使用uClibc替代glibc。通过uClibc来代 替Glibc,可以在不改变应用程序功能的前提下,大大减少发布文件的大小,无论应用程序以静态链接来 编译,还是以动态链接形式编译。

uClibc比一般用于Linux发行版的C库GNU C Library (glibc)要小得多,glibc目标是要支持最大范围的硬件和内核平台的所有C标准,而uClibc专注于嵌入式Linux.很多功能可以根据空间需求进行取舍。现在uClibc更多运行于标准的以及无MMU的Linux系统上,支持i386,x86 64,ARM (big/little endian), AVR32,Blackfin,h8300,m68k,MIPS (big/little endian), PowerPC,SuperH (big/little endian),

SPARC,和v850等处理器。

由于当前嵌入式系统硬件性能的提升,用于存储程序的Flash空间和用于运行程序的RAM空间都有了大幅 提升,为了保证程序更大的兼容性,uClibc也逐步退出了历史的舞台了。

uClibc早期官网: uClibc最新官网:

uClibc h ttps://uclibc-ng.org/

1.3 eglibc库

EGLIBC(Embedded GLIBC,缩写为EGLIBC)是glibc的原创作组织FSF所新推出的glibc的一种变体, 目的在于将glibc用于嵌入式系统。它是GNU C 库(glibc)的一个分支,也采用GNU宽通用公共许可证

(LGPL)发布。它希望能应用于嵌入式系统,但它的源代码与可执行文件仍然保持与glibc一致。它的作 者宣称它不是glibc的一个分支,而是用来容纳glibc核心开发者拒绝采纳的patch。

2009年5月6日,因为与glibc核心开发者之间对程序发展方向的争议,Debian开发者宣布将要采用EGLIBC来取代glibc。Ubuntu自9.10后也采用了EGLIBC,Ark Linux也使用它。2014年初,官网上宣布,eglibc已经停止开发,因为现在的目标是在glibc上直接解决问题(goals are now being addressed directly in GLIBC),Debian开发者也恢复到使用glibc了。

1.4 newlib库

在做一些单片机的裸机程序开发时,有时候最想要的是实现一个printf打印函数,以便及时输出各种信 息。除去底层的设备驱动不说,printf本身的实现就有够麻烦,如果平时有保存相关的代码还好,不然就 很浪费时间。除此之外,还有一些诸如strlen、strcpy之类的函数,我们不愿意自己写,既麻烦而且效率 不高,如果能借助已有的代码或库就好了。

Newlib 就满足了这点需求,它是一个面向嵌入式系统的C运行库。最初是由Cygnus Solutions收集组装的一个源代码集合,取名为newlib,现在由Red Hat维护。对于与GNU兼容的嵌入式C运行库,Newlib 并不是唯一的选择,但是从成熟度来讲,newlib是最优秀的。newlib具有独特的体系结构,具有可移植 性强,具有可重入特性、功能完备等特点,使得它能够非常好地满足深度嵌入式系统的要求。

Newlib 库是一个开源的c函数库,包括libc和libm两部分。它支持ANSI C库标准,针对不同处理器架构进行优化,轻量级,适用于嵌入式系统。其特点如下:

  1. 支持printf和优化的字符串操作

  2. 支持malloc和free等内存操作

  3. 支持函数可重入功能(不过这种支持对内存有压力,总之是感觉弊大于利)

  4. 支持libm数学库(不过一般嵌入式用不到浮点数,而且用模拟的开销略大)

  5. newlib的函数是分文件实现的,如果用不到,绝不加入链接,一般不会造成目标文件猛增的情况。

  6. newlib C库一般在制作单片机裸机开发的交叉编译器时,使用得比较多。

2 Crosstool-ng制作交叉编译器

Crosstool早期是个很不错的交叉编译器制作工具,但是后来完善得不够好,于是有人弄出了个更好的

—— crosstool-ng(crosstool Next Generation)。其特点如下:

支持menuconfig(类似于Linux内核配置) 支持众多的架构

可选多种不同的C库等模块提供示例配置

支持多种主机编译环境:各种Linux发行版,Cygwin等。

接下来,我们学习了解一下如何使用 crosstool-ng 来制作一个ARM交叉编译器。

2.1 Crosstool-NG 编译与安装

首先我们到 Crosstool-NG 的官方站点(crosstool-NG)下载其软件源码压缩包,并解压缩源码。

i.MX6ULL开发板源码自制交叉编译器_第2张图片

接下来进入到源码路径下,开始Linux系统下源码安装的三部曲: ./configure、make、 make install

。 这里在configure 时通过 --prefix 选项指定将编译生成的文件安装到当前路径下即可。在进行

./configure 时可能会提示 help2man、 libtool 找不到,这可能是系统没有安装或者安装的版本过低导致的,直接使用 sudo apt install 命令安装相关系统命令即可。

i.MX6ULL开发板源码自制交叉编译器_第3张图片

上面命令成功编译安装之后,可执行程序将会放到 install 文件夹下,接下来我们可以测试 ct-ng 命令是否能够成功执行。接下来我们将会使用该程序来制作交叉编译器。

i.MX6ULL开发板源码自制交叉编译器_第4张图片

2.2 交叉编译器配置

在Crosstool-NG的安装路径下,有很多参考的交叉编译器示例配置,我们没有必要所有的选项都自己从

0开始配置,可以在某个示例配置的基础上来修改。

i.MX6ULL开发板源码自制交叉编译器_第5张图片

因为i.MX6ULL是ARM CortexA7核的处理器,但在上面的示例配置中并没有该架构的相关配置,这样我们在 A8的基础上来进行修改,这两种架构大致都差不多。我们将ARM CortexA8的示例配置拷贝一份并命名为 .config, 接下来的 ct-ng menuconfig 将会默认读取该配置文件。

接下来使用 export 命令导出 ct-ng 命令所在的路径,如果是使用 SecureCRT 远程登录到Linux服务器上操作的话,还需要 export TERM=vt100 命令配置TERM环境变量,否则接下来的配置可能不能输入。接下来再执行 ct-ng menuconfig 对交叉编译器制作进行配置。

下面是Crosstool-NG的配置界面,我们接下来需要在这里进行修改。在配置的过程中,上、下方向键 用来选择相应选项,TAB键 用来选择底下的