1. 为什么要交叉编译?
交叉编译其实是相对于本地编译(native build)来说的,相信大家最开始学习 C/C++ 这些语言的时候,都是在电脑上写程序,然后在电脑上编译生成可执行文件,最后在电脑上运行。程序的编辑—>编译—>运行,整个过程都是在一台 X86 电脑上。
当我们开始接触嵌入式开发后,事情变的不一样了,你在电脑上写程序,在电脑上编译出可执行文件,最后这个可执行文件需要下载到你的开发板上运行。程序最后运行的环境变了,比如你的开发板是基于 Arm 的——程序在 X86 上编辑,编译,最终运行在另一个和 X86 完全不同的架构的 Arm 芯片上。
之所以整个流程变成了这个样子,这是由嵌入式系统的特性决定的:一般嵌入式系统里面使用的芯片性能都比较弱,而且绝大部分都不能像 X86 一样运行 Windows/Ubuntu 桌面系统,即使能运行,性能也很弱,无法给你提供一个在开发板上写代码、编译代码的环境。所以我们还是离不开 X86 电脑强大高效的桌面环境进行软件开发。
但是这样有一个问题,X86、Arm、MIPS、RISC-V 这些芯片,它们的指令集是由不同的组织或者公司设计的,彼此并不兼容——Arm 和 MIPS 的 CPU 无法运行以 X86 的指令集编码的程序,反之亦然。所以我们要在 X86 的电脑上编译出能够在 Arm 上运行的程序,我们必须明确告诉编译器,编译生成的可执行文件需要以 Arm 指令集的标准编码。为了让这个流程变得简单,开发者们为不同的芯片开发了不同的编译器,比如针对 Arm 平台的 arm-linux-gcc,针对 mips 平台的 mips-linux-gnu-gcc,这些编译器都是基于 GCC 针对具体的架构指令集进行对应配置,所以它们在运行的时候就就会生成和该目标平台对应的可执行文件。
这篇文章主要讲 Arm 的交叉编译,所以这里后面都以 Linux 开发环境下的 Arm gcc 为例。
2. 工具链的种类
GCC 的命名规则为: arch [-vendor] [-os] [-(gnu)eabi]-gcc
比如 arm-linux-gnueabi-gcc
,arm-none-eabi-gcc
, aarch64-linux-gnu-gcc
- 带 [] 的是可选部分。
- arch: 芯片架构,比如 32 位的 Arm 架构对应的 arch 为 arm,64 位的 Arm 架构对应的 arch 为 aarch64。
- vendor :工具链提供商,大部分工具链名字里面都没有包含这部分。
- os :编译出来的可执行文件(目标文件)针对的操作系统,比如 Linux。
arm-none-eabi-gcc 一般适用用于 Arm Cortex-M/Cortex-R 平台,它使用的是 newlib 库。
arm-linux-gnueabi-gcc 和 aarch64-linux-gnu-gcc 适用于 Arm Cortex-A 系列芯片,前者针对 32 位芯片,后者针对 64 位芯片,它使用的是 glibc 库。可以用来编译 u-boot、linux kernel 以及应用程序。
另外, 需要补充一点的是,32 位的 Arm 和 64 位的 Arm,它们的指令集是不同的,所以需要使用不同的工具链。当然,Arm64 为了保证前向兼容,提供了一个 32 位的兼容模式,所以我们用 arm-linux-gnueabi-gcc 编译的应用程序也是可以直接在Arm64 的系统上运行的,但是 Linux Kernel 和 U-Boot 就不行,除非你提前把 CPU 切换到 32 位模式。曾经有个项目使用了一颗四核的 Arm64 芯片,但是内存只有64M,为了节省空间,在 CPU 运行到 U-Boot 之前,我们就把它切到了 32 位模式,后面的 U-Boot、Linux Kernel,应用全部都用 32 位编译,加上 Thumb 指令集,节省了不少空间。
3. 工具链的下载安装
现在 Arm 平台上用的最广泛的工具链是 Linaro 发布的,大家可以到 Linaro 官网下载,地址如下:
Linaro 申明称后续新版本的工具链会通过 Arm 官方发布。
最新版本的 U-Boot 已经强制必须使用 6.0 以上版本的 GCC 进行编译。
这两个网站下载可能会比较慢,可以考虑使用国内的镜像下载:
https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/
可以直接点击下载,也可以通过命令行用 wget 命令下载:
wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz wget https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchains/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
arm 针对是是 32 位的, aarch64 针对 Arm64.
解压:
xz -d gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz xz -d gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
安装到
/usr/local/toolchain/
目录下,当然也可以放在其他任何你喜欢的地方:
sudo mkdir -p /usr/local/toolchain tar -xvf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar -C /usr/local/toolchain/ sudo tar -xvf gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar -C /usr/local/toolchain/
成功后执行
ls
命令,就可以看到两个 toolchain 都被安装到 /usr/local/toolchain/
目录下了。
4. 添加环境变量
4. 添加环境变量
只有把可执行文件对应的路径加入到
PATH
环境变量里,系统才可以认到这些命令。
这里的路径就是上面截图中
pwd
命令显示的路径,可以添加到 ~/.bashrc
文件的最后:
PATH=$PATH:/usr/local/toolchain/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin:/usr/local/toolchain/gcc-linaro-6.4. 1-2017.11-x86_64_aarch64-linux-gnu/bin
注意: 两个独立的路径之间用 冒号
:
隔开。
执行
source ~/.bashrc
命令让配置生效,然后我们就可以在命令行里执行这些命令了:
比如
arm-linux-gnueabihf-gcc -v
和aarch64-linux-gnu-gcc -v
查看编译器版本,能够看到版本号就大功告成了。
5. 编译示例
5. 编译示例
1)
这里下载 imx 的官方内核:
git clone https://source.codeaurora.org/external/imx/linux-imx
切换到 4.19 版本:
git checkout -b imx_v2019.04_4.19.35_1.0.0 origin/imx_v2019.04_4.19.35_1.0.0
编译:
make ARCH=arm imx_v7_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
如果你电脑上其他的依赖库都安装的完整,就能顺利编译成功。
2)
arm-linu-gcc应用实例
实例:如何使用交叉编译器编译源码包boa-0.94.13.tar.tar
1. 启动SMB服务器,将源码包放在共享文件夹/home/lishuai下
2. 输入命令: tar xzvf boa-0.94.13.tar.tar
// 解压该源码包
// 一般的源码包内有Makefile文件,执行make就可以编译,但该源码包内没有,此时执行make是无效的
// 虽然没有Makefile,但找到了configure文件,通过执行configure文件可以生成Makefile
[root@localhost]# ./configure
// 运行configure文件,生成了Makefile文件
// 由于要编译出在ARM平台上的程序,就需要使用交叉编译器.在Makefile文件内的绿色大写字母都是Makefile变量,可以看到变量CFLAGS = -g -o2 -pipe -Wall -l,该变量是设置编译选项;变量CC = gcc,该变量是设置需要使用的编译器.由于要使用交叉编译器arm-linux-gcc,所以该变量应设置为CC = arm-linux-gcc,CPP = arm-linux-gcc -E,保存并退出.
[root@localhost]#make
// 执行make进行编译
// 生成名为boa的可执行程序,该程序可下载到ARM内来执行
3)使用cmake进行交叉编译
请参考:
使用CMake交叉编译Arm Linux程序_爱就是恒久忍耐的博客-CSDN博客
在LINUX X86上cmake交叉编译arm遇到的问题_雪回的博客-CSDN博客
其实,这个过程也叫做移植。移植就是将一个源码包经过修改、配置、交叉编译,然后下载到一个平台上运行.比如经常移植的有Bootloader、内核、QT等.