GNU/GCC编译器及其编译流程详解

GNU介绍

GNU是一个由理查德·斯托曼发起的自由软件项目,其全称是“GNU’s Not Unix!”。GNU项目的目标是创建一个完全自由的操作系统,包括一整套完全自由的软件工具,以取代Unix系统。这里的“自由”指的是自由软件(Free Software)的概念,即用户有使用、复制、修改和分发软件的自由。

GNU关键组件

  1. GNU操作系统:包括内核、shell、编程语言编译器、文本编辑器、文件系统等组件。
  2. 软件自由性:用户有权自由地运行、学习、分享和改进软件。
  3. GNU通用公共许可证(GPL):GNU项目开发了一种许可证,即GNU通用公共许可证,它允许软件以自由软件的形式分发和使用。

GNU重要软件

  • Bash:Bourne Again Shell,一个Unix shell和命令语言。
  • GCC:GNU编译器集合(GNU Compiler Collection),支持多种编程语言的编译器。
  • GDB:GNU调试器(GNU Debugger),用于调试程序。
  • GNU Hurd:GNU项目开发了自己的内核,称为Hurd,它是GNU系统的一部分,但Hurd的开发进度较慢,并没有广泛部署。
  • GNU/Linux:虽然GNU Hurd的开发没有达到预期,但GNU项目开发的许多组件被用于Linux操作系统中。Linux内核与GNU工具集合合,形成了广泛使用的操作系统,通常被称为GNU/Linux。

编译器介绍

编译器是一种将高级语言编写的源代码转换为计算机可执行的机器语言或低级语言的程序,其本质是一种翻译程序,核心功能包括词法分析、语法分析、代码优化及目标代码生成等。

编译器的一般构成

传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd)。在编译过程中,前端主要负责词法和语法分析,将源代码转化为抽象语法树;优化器则是在前端的基础上,对得到的中间代码进行优化,使代码更加高效;后端则是将已经优化的中间代码转化为针对各自平台的机器代码。

几种常见的编译器

GCC

GCC(GNU Compiler Collection,GNU编译器套装),是一套由 GNU 开发的跨平台编程语言编译器。GCC 原名为 GNU C 语言编译器,因为它原本只能处理 C语言。GCC 快速演进,变得可处理 C++、Fortran、Pascal、Objective-C、Java, 以及 Ada、Go 等他语言。常用于嵌入式系统和高性能计算领域。

LLVM

LLVM(Low Level Virtual Machine,底层虚拟机)提供了与编译器相关的支持,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成等。可以作为多种编译器的后端使用。在LLVM项目开发的初期,主要使用GCC作为前端;后期由Apple主导开发的Clang作为前端将源代码翻译成LLVM IR这一中间代码,然后由LLVM将这一中间代码转换成机器语言。

Clang

Clang是LLVM项目的前端编译器,专注于C、C++和Objective-C等语言的编译。Clang由Apple公司主导编写,并逐渐成为了业界知名的编译器之一。Clang以其快速编译速度、较小内存占用和清晰的诊断信息,赢得了广大开发者的喜爱。此外,Clang还提供了静态分析功能,有助于开发者在编译阶段就发现潜在的问题,如内存泄漏、未初始化变量等。

MSVC

MSVC,全称Microsoft Visual C++,是微软开发的编译器工具链。它主要用于Windows平台应用程序的开发,并通常与Visual Studio IDE集成在一起。MSVC提供了从编写代码到调试、部署的完整开发环境,是Windows应用开发者的首选编译器之一。MSVC主要用于Windows平台的应用程序开发。它是Visual Studio IDE的默认编译器之一,支持C++、C#等多种编程语言。此外,MSVC还被用于游戏开发、桌面应用开发等领域。

从源代码到可执行程序

编译流程

1
2
3

(源代码) --预处理器--> (调整之后的代码) --编译器--> (汇编语言代码) --汇编器--> 
(可调整的机器语言代码) --连接器或加载器--> (可执行程序)

可以看到从源代码到可执行程序要经过预处理器(preprocessor)、编译器(compiler)、汇编器(assembler)和连接器(linker)或加载器(loader),而编译器只是负责将源代码转换成对应的汇编代码的功能。

gcc的各种处理转换程序

在gcc的编译过程中,除了调用其本身包含的编译器和预处理器cpp,还会调用外部程序提供的汇编器as和连接器ld

预处理阶段

1
gcc -E 源代码 -o XXX.i

注意:如果需要在预处理之后停止需要使用选项-E,-o用于指定输出文件的名称。(gcc调用的预处理器cpp会将源文件处理后直接输出到标准输出,而不是生成某个文件!)

编译阶段

1
gcc -S XXX.i

如果你想编译但不进行汇编,那么使用-S选项,编译后会生成一个新的.s汇编文件

汇编阶段

1
gcc -c XXX.s

汇编阶段使用选项-c来进行编译和汇编,但是不进行连接。刚才是进行了编译,但是没有汇编,所以这里使用-c相当于只使用了汇编器。汇编阶段完成后,会自动生成新的对象文件(object file),文件后缀为.o。

连接阶段

1
gcc -o XXX XXX.o

最后的连接阶段,使用-o直接输出可执行文件即可,因为从汇编之后的对象文件到可执行程序和从源代码到可执行程序这个结果是一样的,gcc这些选项只是限定“终点”。注意:绝大多数编译器的使用几乎等价gcc+选项,除了一些小细节。唯一大不同的是连接器。

gcc与g++的区别

  • gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别。gcc 指令也为用户提供了“手动指定代表编译方式”的接口,即使用 -x 选项
    • xxx.c:默认以编译 C 语言程序的方式编译此文件;
    • xxx.cpp:默认以编译 C++ 程序的方式编译此文件。
    • xxx.m:默认以编译 Objective-C 程序的方式编译此文件;
    • xxx.go:默认以编译 Go 语言程序的方式编译此文件;
  • g++ 指令,则无论目标文件的后缀名是什么,该指令都一律按照编译 C++ 代码的方式编译该文件。
Licensed under CC BY-NC-SA 4.0
热爱可抵岁月漫长,温柔可挡艰难时光。
Nothing but enthusiasm brightens up the endless years.
转载请注明主页网址哦~