文章基于HD-IMX6ULL-MB 系列开发板测试验证,该开发板由武汉芯路遥科技有限公司与武汉万象奥科电子有限公司合作推出。此开发板基于 NXP iMX6ULL 系列 Cortex-A7 高性能处理器设计,适用于快速开发一系列具有创新性的产品如人机界面工业 4.0 扫描仪、车载终端以及便携式医疗设备。
早期(2009年以前)我们在做嵌入式系统开发时,第一件事就是自己制作交叉编译器。当时做交叉编译器 需要自己下载gcc、glibc、binutils等相关工具的源码,然后一个一个源码编译安装。制作交叉编译器的 过程中最痛苦的莫过于各个软件之间的版本依赖关系,如gcc 4.6.2 依赖 glibc 2.13,如果你选定 gcc 4.7 则可能编译制作失败,然后再尝试一个新的版本重新编译,直至找到一个合适的版本为止。
后来为了方便交叉编译器的制作,有很多组织或个人开始编写这些制作交叉编译器的脚本或框架,并测 试解决这些软件版本之间的依赖关系。当时最知名的莫过于基于glibc的crosstool和 基于uclibc的buildroot了。在开始讲解如何制作交叉编译器之前,我们首先来了解一下C运行库。
glibc是gnu发布的libc库,也即c运行库。glibc是linux 系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了 许多其它一些必要功能服务的实现,主要的如下:
gcc 是编译器,基本上 Linux 下所有的程序(包括内核)都是 gcc 编译的,libc 当然也是。gcc 和 libc 是互相依赖的两个软件,它们合作的方式类似 Linux 系统的 自举。先在一个可以运行的带有老 libc 和
PC上常用的标准库glibc是一个非常宠大而完整的库,但早期对于嵌入式系统来说,由于Flash和RAM的 存储空间有线,其体积显得过于大了一些。uClibc的出现就是为了解决这个问题,uClibc尽可能的兼容
Glibc,大多数应用程序可以在很小或完全不修改的情况下就可能使用uClibc替代glibc。通过uClibc来代 替Glibc,可以在不改变应用程序功能的前提下,大大减少发布文件的大小,无论应用程序以静态链接来 编译,还是以动态链接形式编译。
由于当前嵌入式系统硬件性能的提升,用于存储程序的Flash空间和用于运行程序的RAM空间都有了大幅 提升,为了保证程序更大的兼容性,uClibc也逐步退出了历史的舞台了。
(LGPL)发布。它希望能应用于嵌入式系统,但它的源代码与可执行文件仍然保持与glibc一致。它的作 者宣称它不是glibc的一个分支,而是用来容纳glibc核心开发者拒绝采纳的patch。
在做一些单片机的裸机程序开发时,有时候最想要的是实现一个printf打印函数,以便及时输出各种信 息。除去底层的设备驱动不说,printf本身的实现就有够麻烦,如果平时有保存相关的代码还好,不然就 很浪费时间。除此之外,还有一些诸如strlen、strcpy之类的函数,我们不愿意自己写,既麻烦而且效率 不高,如果能借助已有的代码或库就好了。
Newlib就满足了这点需求,它是一个面向嵌入式系统的C运行库。最初是由Cygnus Solutions收集组装的一个源代码集合,取名为newlib,现在由Red Hat维护。对于与GNU兼容的嵌入式C运行库,Newlib 并不是唯一的选择,但是从成熟度来讲,newlib是最优秀的。newlib具有独特的体系结构,具有可移植 性强,具有可重入特性、功能完备等特点,使得它能够非常好地满足深度嵌入式系统的要求。
Newlib 库是一个开源的c函数库,包括libc和libm两部分。它支持ANSI C库标准,针对不同处理器架构进行优化,轻量级,适用于嵌入式系统。其特点如下:
Crosstool早期是个很不错的交叉编译器制作工具,但是后来完善得不够好,于是有人弄出了个更好的
。 这里在configure 时通过--prefix选项指定将编译生成的文件安装到当前路径下即可。在进行
./configure 时可能会提示 help2man、 libtool 找不到,这可能是系统没有安装或者安装的版本过低导致的,直接使用sudo apt install命令安装相关系统命令即可。
上面命令成功编译安装之后,可执行程序将会放到install文件夹下,接下来我们可以测试ct-ng命令是否能够成功执行。接下来我们将会使用该程序来制作交叉编译器。
在Crosstool-NG的安装路径下,有很多参考的交叉编译器示例配置,我们没有必要所有的选项都自己从
因为i.MX6ULL是ARM CortexA7核的处理器,但在上面的示例配置中并没有该架构的相关配置,这样我们在 A8的基础上来进行修改,这两种架构大致都差不多。我们将ARM CortexA8的示例配置拷贝一份并命名为, 接下来的ct-ng menuconfig将会默认读取该配置文件。
接下来使用export命令导出ct-ng命令所在的路径,如果是使用SecureCRT远程登录到Linux服务器上操作的话,还需要export TERM=vt100命令配置TERM环境变量,否则接下来的配置可能不能输入。接下来再执行ct-ng menuconfig对交叉编译器制作进行配置。
下面是Crosstool-NG的配置界面,我们接下来需要在这里进行修改。在配置的过程中,上、下方向键用来选择相应选项,TAB键用来选择底下的Select或Exit:
在Paths and misc options选项中,我们主要要修改如下几个选项,修改指定下载的软件包存放路径
在Operating System选项中,因为我们移植的Linux内核目标版本为 5.10.x, 所以这里内核的版本选择要跟开发板上移植的版本保持一致,否则今后编译Linux内核时可能会出现兼容性问题。在这里, crosstool-NG的默认内核版本较低,这里需要修改配置为我们想要的版本。下面的这些选项配置,依赖Paths and misc options菜单中的[*] Try features marked as EXPERIMENTAL选项。
剩余的其它选项,我们就不作任何修改采用默认配置。关于C compiler编译器里的相关选项,大家也可以了解一下。
配置完成后回到主菜单,使用Tab键切换到 Exit ,然后选择保存退出即可。交叉编译器配置完成之后,接下来我们就准备开始交叉编译器的编译过程。
在前面的配置中,我们计划将交叉编译器安装到系统的/opt/xtools路径下,这里我们首先需要使用
CrossTool-NG在编译过程中,会下载制作交叉编译器所需要的软件源码包,但有些软件包的下载地址可 能已经失效,这时我们可以自己找到相关软件的相应版本软件包,然后手动下载到指定的压缩包存放路 径下,如前面配置中指定的${PWD}/tarballs。下面是一些已知的失效文件,我们提前手动下载好,其它所需要的软件包将会在开始编译后自动下载。
接下来我们就开始交叉编译的编译制作过程,这个过程的时间依赖PC的性能。我的Linux服务器处理器 是Intel(R) Xeon(R) CPU E31235 @ 3.20GHz,4核8线程,所以我这里使用ct-ng build.8命令用8个进程同时编译。
接下来我们使用制作好的交叉编译器,交叉编译之前写好的hello.c测试程序,并放到 ARM 开发板上运行测试。需要注意的是因为新制作的交叉编译器跟开发板上运行的C运行库版本不一致,这里必须加上 -

