4. ARM-GCC和开发板的HelloWorld

为了加深对GCC编译工具链的了解,本章尝试在ARM64开发板上运行x86_64平台、Ubuntu系统用各种不同方法编译的HelloWorld。

由于需要在Ubuntu主机及开发板之间共享文件,请按《挂载NFS网络文件系统》章节搭建好NFS网络文件系统环境。

本章的示例代码目录为:base_code/linux_app/hello_crosscompile。

4.1. 在ARM板上运行x86_64平台的程序

上一章Ubantu编译生成了X86_64平台的Hello World程序,我们尝试ARM64开发板上直接运行它。

在开发板的终端上,切换至主机共享目录下的hello_c文件夹,可以直接执行如下命令测试:

#将上一章节主机编译的x86架构程序传输板卡并运行

./hello

如下图:

未找到图片2|

如图所示,程序无法正常运行,终端提示ARM开发板在执行x86架构(Intel或AMD)的hello程序时提示格式错误,原因是x86_64和ARM64架构的程序不兼容,本质是由于这些CPU使用的指令集不同。这就是为什么需要针对芯片架构定制文件系统、软件工具,apt使用的源也针对不同架构提供不同的软件包。前 面说Debian系统有支持多种架构的优势,本质上就是说它的文件系统针对不同芯片架构提供了适配的软件包。

当然,对于由Python等跨平台语言编写的源程序,它们不需要编译,只需要使用匹配的解释器即可运行,与芯片架构甚至操作系统无关。

4.2. 安装并使用交叉编译工具链

在前面《GCC和Hello World》章节中,我们编译了两个程序,分别是:

  • 编译器运行在X86_64架构平台上,编译生成X86_64架构的可执行程序

  • 编译器运行在ARM64架构平台上,编译生成ARM64架构的可执行程序

这种编译器和目标程序都是相同架构的编译过程,被称为 本地编译

而当前我们希望的是编译器运行在x86架构平台上,编译生成ARM64架构的可执行程序,这种编译器和目标程序运行在不同架构的编译过程,被称为 交叉编译

既然已经有本地编译,为什么需要交叉编译?这是因为通常编译工具链对编译环境有较高的要求,编译复杂的程序时,可能需要巨大的存储空间以及强大的CPU运算能力加快编译速度。常见的ARM64 架构平台资源有限,无论是存储空间还是CPU运算能力,都与X86平台相去甚远,特别是对于MCU平台,安装编译器根本无从谈起。有了交叉编译,我们就可以在PC上快速编译出针对其他架构的可执行程序。

相对的,能进行架构“交叉”编译过程的编译器,就被称为 交叉编译器(Cross compiler)。 交叉编译器听起来是个新概念,但在MCU开发中一直使用的就是交叉编译器, 例如开发STM32、RT1052所使用的IDE软件Keil(MDK)或IAR,就是在Windows x86架构编译,生成MCU平台的应用程序,最后下载到板子执行。

4.2.1. 使用APT安装ARM-GCC

安装交叉编译工具链有如下三种方式:

  • 直接在Ubuntu下使用APT包管理工具下载安装,操作简单,在本章节我们直接使用该方式安装即可。

  • 自行下载第三方制作好的工具链,如Linaro,好处是选择丰富,能找到很多不同的版本。

  • 使用crosstool-ng根据需要自己制作,过程复杂,不推荐。

本书使用的编译器主要有一种类型:

  • gcc-arm-xxx-x86_64-aarch64-none-linux-gnu:

(1)gcc-arm-xxx: 这部分表示ARM 架构工具链。

(2)x86_64: 这部分表示目标架构,即工具链的目标平台是 x86_64 架构。

(3)aarch64: 这部分表示生成的可执行文件或目标代码的目标架构是 AArch64(ARM 64 位)架构,且默认采用小端字节序。

(4)none: 这部分表示没有特定的操作系统相关组件,该工具链是为嵌入式系统或特定目标架构而构建的,而不是针对特定的操作系统。

(5)linux-gnu: 这部分表示生成的可执行文件或目标代码适用于 Linux 系统,并使用 GNU C 库(glibc)作为默认的 C 库。

本章节示例代码只需要使用aarch64-linux-gnu-gcc编译器,可通过APT包管理工具可直接执行以下命令安装:

#在主机上执行如下命令

sudo apt install gcc-aarch64-linux-gnu

#安装完成后使用如下命令查看版本

aarch64-linux-gnu-gcc -v

可以看到下图的内容,它表明交叉编译工具链安装成功了,输出信息表明了它是7.5.0版本的编译器,其中的 “Target: aarch64-linux-gnu”也表明了它的目标架构。

未找到图片3|

arm-linux-gnueabi-gcc版本信息

安装完成后输入“aarch64-linux-gnu-”,再按两下TAB键,终端会提示可用的相关命令,如下图包含了ARM-GCC工具链Binutils的各种工具。

未找到图片4|

安装后包含的Binutils工具集

4.2.2. arm官网下载安装ARM-GCC

有些时候apt并不能安装合适的版本或者希望使用特定的版本,可以到arm官网下载编译链压缩包。

官网为:https://developer.arm.com/downloads/-/gnu-a

以10.2版本为例:

../../_images/arm10_2_1.png

然后选择gcc-arm-xxx-x86_64-aarch64-none-linux-gnu的编译器:

../../_images/arm10_2_2.png

下载完成后解压到虚拟机,编译链工具包bin目录下就是我们需要的编译工具,需要导出到环境变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#解压编译链工具包
tar xvf gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/

#查看工具包里面的编译工具
ls gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin/

#导出环境变量,需要根据实际指定编译工具链的 绝对路径
export PATH=/home/hyw/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu/bin:$PATH

#查看编译器信息,注意名字
aarch64-none-linux-gnu-gcc -v
../../_images/arm10_2_3.png

注意以上编译器的名字和apt下载的有区别,apt下载的名字为aarch64-linux-gnu-gcc,压缩包工具链的为aarch64-none-linux-gnu-gcc 。

后续程序均以apt下载的工具链为主,请读者自行区分。

4.2.3. 交叉编译Hello World程序

安装好交叉编译器后,直接使用它对Hello World程序进行交叉编译即可。

交叉编译器与本地编译器使用起来并没有多大区别。对于源文件的编译过程,都是四个阶段:预处理,编译,汇编以及链接,区别只在于编译工具。因此,我们可以依葫芦画瓢,修改一下前面GCC编译章节的命令,就可以完成这个过程。

在主机上执行如下命令对Hello World程序进行交叉编译:

#以下命令在主机上运行

#在hello.c程序所在的目录执行如下命令

aarch64-linux-gnu-gcc hello.c –o hello

同样的C代码文件,使用交叉编译器编译后,生成的hello已经变成了ARM64平台的可执行文件,可以通过readelf工具来查看具体的程序信息。

readelf工具在系统安装GCC编译工具链时一起被安装了,我们可以直接使用。在主机上执行以下命令:

#以下命令在主机上运行

readelf -a hello
未找到图片5|

可看到hello程序的系统架构为ARM64平台。

编译好后,可以通过前面文件传输章节介绍的方法将执行文件传输到板卡,执行结果如下图所示。

#执行主机编译的arm64平台程序

./hello
未找到图片6|