# GCC 简述
The GNU Compiler Collection,通常简称 GCC ,是一套由 GNU 开发的编译器集合。
为什么是编辑器集合而不是编译器呢?
那是因为 GNU 编译器集合包括 C、C++、Objective-C,Fortran,Ada、Go 和 D 等,以及这些语言的库 (libstdc++,...)。 GCC 最初是作为 GNU 操作系统的编译器编写的。 GNU 系统被开发为 100% 的自由软件 ,即从某种意义上说它是自由的,尊重用户的自由。另外 GCC 对硬件平台的支持,可以说无所不在,它不仅支持 x86 处理器架构,还支持 ARM, Motorola 68000, Motorola 8800,AtmelAVR,MIPS 等处理器架构。
# GCC 主要构成
- gcc-core:顾明之意是 GCC 的核心部分,这部分是只包含 c 的编译器及公共部分,而对其他语言(C++、Ada 等)的支持包需要另外安装,这也是 GCC 为何如此强大的重要原因 。gcc-core 依赖于 Binutils。
- Binutils:它是一组开发工具,包括连接器,汇编器和其他用于目标文件和档案的工具。关于 Binutils 的介绍可以参考官方的 Binutils 介绍。这个软件包依赖于不同的目标机平台,因为不同目标机的指令集是不一样的,比如 arm 跟 x86 就不一样。
常用的工具有:- as:汇编器,把汇编语言代码转换为机器码(目标文件)。
- ld:链接器,把编译生成的多个目标文件组织成最终的可执行程序文件。
- readelf:可用于查看目标文件或可执行程序文件的信息。
- objcopy: 可用于目标文件格式转换,如
.elf
转换成.bin
。 - objdump:可用于查看目标文件的信息,最主要的作用是反汇编。
- addr2line:可用于将程序指令地址转换为所对应的函数名、以及函数所在的源文件名和行号。
- Glibc:包含了主要的 c 库,这个库提供了基本的例程,用于分配内存,搜索目录,读写文件,字符串处理等等。
# ARM 编译工具链
编译器主要用来编译源文件,而在编译一个源文件时需要经过以下 4 步:
- 预处理:为把头文件的代码、宏之类的内容转换成生成的
.i
文件,还是 C 代码。 - 编译:把预处理后的
.i
文件通过编译成.s
文件,汇编语言。 - 汇编:将汇编语言文件生成目标文件
.o
文件,机器码。 - 链接:将每个源文件对应的
.o
文件链接起来,就生成一个可执行程序文件。
交叉编译器:如果我们希望编译器运行在 x86 架构平台上,然后编译生成 ARM 架构的可执行程序,这种编译器和目标程序运行在不同架构的编译过程,被称为 “交叉编译”,而对应使用的编译工具就成为交叉编译器。
GNU 交叉编译器的命名规则:
arch [-vendor] [-os] [-(gnu)abi] [-language]
- arch:体系架构,如
arm
、aarch64
或者mips
等; - vendor:工具链提供商,没有 vendor 时,用
none
代替; - os:目标操作系统,没有 os 支持时,用
none
代替; - abi:应用二进制接口(Application Binary Interface),对于嵌入式平台命名为
eabi
,e
表示 Embedded; - language:编译器支持的语言,如:
gcc
、g++
。
note:如果同时没有 vendor 和 os 支持,则只用一个 none 代替。例如 arm-none-eabi 中的 none 表示既没有 vendor 也没有 os 支持。
关于 ABI 和 EABI 的区别
ABI:应用二进制接口(Application Binary Interface)。在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口。
EABI:嵌入式应用二进制接口(Embedded Application Binary Interface)。嵌入式应用二进制接口指定了文件格式、数据类型、寄存器使用、堆积组织优化和在一个嵌入式软件中的参数的标准约定。开发者使用自己的汇编语言也可以使用 EABI 作为与兼容的编译器生成的汇编语言的接口。
两者主要区别是:ABI 是计算机上的,EABI 是嵌入式平台上(如 ARM,MIPS 等)的;EABI 去掉了用户代码和系统内核之间的抽象,可以让用户代码直接访问硬件,提高了性能。
关于 gcc 和 g++ 的区别
实际上,只要是 gcc 编译器支持的语言都可以使用 gcc 编译器完成编译,而 g++ 编译器只会按照 C++ 的风格编译代码。虽然很多情况下我们都认为 C++ 是对 C 语言兼容的,但是实际上在一些具体的语法规则上,C++ 在编译过程中的语法检查会更加严格。此外,C++ 语言本身在编译 过程中也会引入 C++ 的标准库,如果使用 gcc 编译器直接编译 C++ 语言会在编译过程中添加额外的参数,这样会显得编译过程较为繁琐(因为大部分情况下我们希望标准库可以直接引入,而不是再需要手动指定,否则对于初级使用者会带来额外的学习负担)。为了更方便使用编译器,我们选择 g++ 来编译 C++ 代码。总结一下,gcc 可以完成 C++ 语言的编译,但是使用过程会较为繁琐,而 g++ 就是简化后的编译指令。
与 gnueabi 相关的 gnueabi 和 gnueabihf 的区别
gcc-arm-linux-gnueabi – The GNU C compiler for armel architecture
AND
gcc-arm-linux-gnueabihf – The GNU C compiler for armhf architecture
这两个交叉编译器分别适用于 armel 和 armhf 两个不同的架构,armel 和 armhf 这两种架构在对待浮点运算采取了不同的策略(有 fpu 的 ARM 才能支持这两种浮点运算策略)。
这两个交叉编译器是 gcc 的选项 -mfloat-abi
的默认值不同;该选项有三种值 soft、softfp、hard(其中后两者都要求 ARM 里有 fpu 浮点运算单元,soft 与后两者是兼容的,但 softfp 和 hard 两种模式互不兼容):
soft: 不用 fpu 进行浮点计算,即使有 fpu 浮点运算单元也不用,而是使用软件模式。
softfp: armel 架构(对应的编译器为 arm-linux-gnueabi-gcc )采用的默认值,用 fpu 计算,但是传参数用普通寄存器传,这样中断的时候,只需要保存普通寄存器,中断负荷小,但是参数需要转换成浮点的再计算。
hard: armhf 架构(对应的编译器 arm-linux-gnueabihf-gcc )采用的默认值,用 fpu 计算,传参数也用 fpu 中的浮点寄存器传,省去了转换,性能最好,但是中断负荷高。
几种常见的编译 ARM 的交叉编译器:
arm-none-eabi:用于编译裸机程序或系统,这个是没有操作系统的,不支持那些系统调用等系列接口,可调用 newlib
库,适用于 ARM7/Cortex-M/Cortex-R。
arm-none-linux-gnueabi:用于编译 ARM 架构的 u-boot、Linux 内核、Linux 应用等,使用 glibc
库,适用于 ARM9/ARM11/Cortex-A。
arm-eabi: 用于安卓程序编译。
armcc:早期 Keil 软件公司(现已被 ARM 公司收购)出品的支持相应器件的编译工具,可以编译裸机程序,一般和 ARM 开发工具一起,Keil MDK 内置。
# 基于 GCC 的 ARM 编译工具链提供商
目前,为 ARM 平台提供交叉编译工具链的提供商,本人所找到的只有两家:ARM 官方和 Linaro 公司。
# Arm GNU Toolchain
ARM 除了有自己的专用编译器之外,还维护了一套基于 GCC 的交叉编译工具链,被称为 Arm GNU Toolchain。截至于 2022 年,Arm GNU Toolchain 被分为了 A family(GNU Toolchain for the Cortex-A Family) 和 R & M family(GNU Arm Embedded Toolchain)两大类,但是自 2022 年开始,ARM 对其进行了统一。
编译器的目标平台:
- AArch32 bare-metal target:32 位纯裸机平台
- AArch64 ELF bare-metal target:64 位纯裸机平台
- AArch64 ELF bare-metal, big-endian target:64 位纯裸机平台(大端模式)
- AArch64 GNU/Linux target:64 位 Linux 平台
- AArch64 GNU/Linux big-endian target:64 位 Linux 平台(大端模式)
- AArch32 target with soft float:32 位带软件模式浮点运算
- AArch32 target with hard float:32 位带硬件模式浮点运算
# Linaro Toolchain
Linaro 是一间非营利性质的开放源代码软件工程公司,主要的目标在于开发不同半导体公司系统单片机(SoC)平台的共通软件。其维护的工具链下载地址为:https://snapshots.linaro.org/gnu-toolchain/ 。另外,从 https://www.linaro.org/downloads/ 的描述上看,目前 Linaro 仅针对于 Cortex-A 内核的编译工具链进行维护,而对用于 ARM 嵌入式处理器的 Cortex-R 和 Cortex-M 的最新裸机编译工具链,则需要去 ARM 官网下载!旧版可以在 http://releases.linaro.org/components/toolchain/binaries/ 中下载。
# Yocto Toolchain
Yocto 为构建定制化的嵌入式 Linux 发行版提供一系列模板、工具和方法来简化定制 Linux 开发,允许更换软件配置和构建,避免重复工作 以及不必要的维护。Yocto 鼓励跨各种应用程序和设备类型的创新,支持多种硬件架构,包括 X86 (32 bit 和 64 bit)、ARM (32 bit 和 64 bit) 、RISC-V、PPC 和 MIPS 等。
Yocto 构建的交叉编译工具,蕴含了众多的第三方组件,因此在构建完整的系统的中,不需要花太多的时间去编译添加第三方组件;像 NXP 的 i.MX 系列的 SDK 固件包,就推荐使用 Yocto 搭建,同时给出基于 Yocto 定制的 i.MX 搭建环境。除此如果想用 Yocto 原生 Toolchain 可以到 http://downloads.yoctoproject.org/releases/yocto/?C=M&O=D 进行下载,先选择需要版本,在 ./toolchain/
路径下选择相应的平台,一般后缀 .sh
文件为 Yocto Toolchain 的安装脚本。
# Reference
https://www.cnblogs.com/xiaotlili/p/3306100.html
https://blog.csdn.net/ZCShouCSDN/article/details/89553323
https://community.arm.com/arm-community-blogs/b/embedded-blog/posts/shrink-your-mcu-code-size-with-gcc-arm-embedded-4-7
https://stackoverflow.com/questions/14737104/what-is-the-default-c-std-standard-version-for-the-current-gcc-especially-on-u
https://ubuntuqa.com/article/10432.html
https://www.amobbs.com/forum.php?mod=viewthread&tid=5709400
# 附
GNU win:https://gnuwin32.sourceforge.net/
GNU software:https://www.gnu.org/software/software.zh-cn.html