一次搞定 Arm Linux 交叉编译

交叉编译

为什么要交叉编译

交叉编译其实是相对于本地编译(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 为例。

工具链的种类

GCC 的命名规则为: arch [-vendor] [-os] [-(gnu)eabi]-gcc

比如 arm-linux-gnueabi-gccarm-none-eabi-gccaarch64-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 指令集,节省了不少空间。

工具链的下载安装

下载地址

现在 Arm 平台上用的最广泛的工具链是 Linaro 发布的,大家可以到 Linaro 官网下载,地址如下:

http://releases.linaro.org/components/toolchain/binaries/

同时我发现 Linaro 申明称后续新版本的工具链会通过 Arm 官方发布。

https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain

4.9、6.3、7.4 这些是工具链的版本号,理论上越新的版本,性能越好。

在一次优化 u-boot 大小的时候我发现 6.3 版本的工具链生成的二进制文件要比 4.9 版本生成的小几百个字节,进一步对比分析后发现是因为 6.3 版本的工具链把代码中没用到的一些字符串全部过滤掉了,虽然 4.9 的版本也有过滤,但是没有 6.3 做的干净。

目前用的多的版本应该是 6.x,当然我也看到有些开发组织在使用 7.x 的工具链,比如 Armbian 目前在用 7.4 编译内核。

另外目前最新版本的 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/ 目录下了。

添加环境变量

只有把可执行文件对应的路径加入到 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 -vaarch64-linux-gnu-gcc -v 查看编译器版本:

能看到如图的信息,说明已经大功告成了。

编译内核

这里下载 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-

如果你电脑上其他的依赖库都安装的完整,就能顺利编译成功。

更多原创请扫码关注微信公众号:HackforFun

7 声望
2 粉丝
0 条评论
推荐阅读
Linux Kernel 和 U-Boot 编译的那些事
Linux Kernel 和 U-Boot 编译的那些事 之前的文章:《一次搞定交叉编译》 给大家讲了如何安装交叉编译工具链,搭建交叉编译环境。 这篇文章主要教大家如何正确的去编译 Linux Kernel、U-Boot 这些著名的开源软件...

andyshrk阅读 3k

Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节6阅读 1.5k

封面图
C 程序眼中的 Unicode
去年写了一篇文章「在 C 程序中处理 UTF-8 字符串」,介绍了如何使用 GLib 提供的 UTF-8 字符串处理函数来实现基本的 UTF-8 文本处理。不过,GLib 是一个功能比较全面的 C 程序库,C 字符串处理仅仅是它的一个很...

garfileo3阅读 5.7k评论 5

工具篇:iTerm与Zsh
iTerm2支持许多的主题配色,可以自己定义,也可以参考网上现成的主题配色。我个人比较喜欢draculatheme配色。支持item,vim,phpstorm , 下方存在主题官网路径,按照教程安装即可。

super白4阅读 4.7k

深入剖析容器网络和 iptables
Docker 能为我们提供很强大和灵活的网络能力,很大程度上要归功于与 iptables 的结合。在使用时,你可能没有太关注到 iptables 的作用,这是因为 Docker 已经帮我们自动完成了相关的配置。

张晋涛3阅读 1.3k

封面图
麒麟操作系统 (kylinos) 从入门到精通 - 常用软件安装 - 第三篇 常用软件安装(windows下的习惯)
本篇内容大部分从应用商店进行安装,部分通过官网下载,少部分通过命令行安装。1.原生应用1.1钉钉1.2飞书1.3 蓝信1.4 腾讯文档1.5 金山文档1.6 搜狗输入法(拼音)1.7 五笔输入法1.8 libreoffice官方也带了WPS,...

码上世界3阅读 7.5k评论 17

封面图
Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4k评论 1

7 声望
2 粉丝
宣传栏