Skip to content

编译器

想成为记事本编程大师吗?

前言:工具链是什么

编写一个(C语言)程序不过光需要编写源文件,在编写完成之后还需要考虑,如何将文件转化成为计算机可以执行的二进制程序,这个过程需要经历预处理,编译,汇编,链接这四个过程才能得到可执行程序,这时就需要一套专门的程序来进行这个过程,而这一套过程所需要的全部程序就是我们这里讲工具链。也许在初学C语言的时候我们没有注意过这些过程都需要哪些程序(那是因为IDE为我们做好了大部分的事情),但是如果想要进一步深入就需要掌握工具链搭建的过程。

编译过程

C语言的源文件要转换成可执行文件需要经历以下四步:

  • 预处理:将源文件中的宏展开,对条件编译部分进行处理,头文件插入源文件
  • 编译:将预处理过的源文件转换成为汇编文件
  • 汇编:将汇编文件转换成为由二进制组成的目标文件
  • 链接:将所有目标文件和库链接在一起生成可执行程序

编译器概念

在上面所说的编译过程中,大部分任务是由编译器完成的,常见的C语言编译器如下

PC编译器:

  • GCC:

    GCC(GNU Compiler Collection)是一个由GNU组织编写的开源的编译器,在最开始的时候它仅作为C语言编译器(所以它的原名是“GNU C Compiler”),后来逐渐支持多种语言(如C++、Go等)便改为现在的名字。它能支持多种操作系统,如Linux,Windows,Mac等。

    1.在Linux平台上获取GCC仅需要执行下面的命令:

    sudo apt install build-essential
    

    2.在Windows平台上使用GCC需要下载MinGW(Minimalist GNU for Windows),然后将所下载文件夹中的/bin目录添加到环境变量当中,就可以在终端中使用gcc命令了。

    下载地址:MinGW - Minimalist GNU for Windows - Browse Files at SourceForge.net

  • Clang:

    Clang编译器是由苹果公司开发的,最开始的时候苹果公司也是使用GCC的,据说是苹果想要实现一些C语言的特性但是GNU的人不给苹果添加,于是苹果公司便开始研发自家的编译器,这才有了Clang(Only Apple can do),但是Clang也是开源的。

    Clang编译器的前端是Clang,后端是LLVM(Low Level Virtual Machine)。这里解释一下编译器的前端和后端,可以理解为编译器的两个功能不同的组成部分。

    • 前端主要负责源码的语法检查,分析源文件生成抽象语法树,中间代码的生成(将抽象语法树转换为中间表示(IR),一种与机器无关的中间代码用于后端优化和目标代码的生成)
    • 后端主要负责优化,目标文件生成,链接生成可执行程序。

    Clang编译器在Github上开源:Clang编译器获取

    如何配置: 在Windows下配置Clang编译器

  • MSVC:

    MSVC(Microsoft Visual C++)是微软公司的C/C++开发工具,Windows原生环境不提供类似gccClang的C/C++语言源程序编译运行工具链,它的编译器都是包含在集成开发环境里的(当然这不是开源的),可以通过下载Microsoft Visual Studio来获取。

    MSVC编译器工具链主要由cl.exe与link.exe构成。其中:

    1. cl.exe用于控制在 Microsoft C/C++的编译器和链接器
    2. link.exe 将通用对象文件格式 (COFF) 对象文件和库链接起来,以创建可执行 (.exe) 文件或动态链接库 (DLL)
    3. 用户只需要调用cl.exe,即可完成编译-链接全过程。

    如何使用:MSVC 编译器命令行语法 | Microsoft Learn

嵌入式编译器:

因为编译器是要将源码转换成为机器码的,由于不同的处理器使用不同的指令集,因此相同的源码对于不同的处理器转换成的机器码也不相同。主流的PC计算机都是X86的处理器架构,而嵌入式设备则是arm架构,因此嵌入式开发使用的编译器和和上面介绍的编译器不同,主要由下面三种:

  • armcc(AC5):基于GCC开发的arm平台编译器,并不开源
  • armclang (AC6):基于Clang开发的arm平台编译器,并不开源
  • Arm GNU 工具链:开源的arm开发工具链,不止支持arm开发。

官网下载:用于嵌入式的 AC6编译器 GNU Arm 嵌入式工具链下载

GCC的使用

编译过程:

预处理:

执行下面的命令编译器就只会进行预处理,然后将处理后的文件输出到test.i这个文件中(选项大小写敏感)

$ gcc -E -o test.i test.c #-C选项可以阻止删除注释,

编译:

执行下面的命令编译器执行完编译部分就会停止,并将翻译得到的汇编结果存放在.s文件之中。

$ gcc -S test.c #加上-fverbose-asm选项可以将C语言中变量名作为注释

汇编

由于不同的机器机构有着不同的汇编语言,因此GCC通过调用宿主系统的汇编器来生成对象文件(object file,包含描述所有外部链接的符号表和源文件汇编生成的二进制机器码),执行下面命令生成对象文件:

$ gcc -c test.c #小写的c

链接

将对象文件中所需要的外部链接与对象文件链接成可执行文件文件,如下例中,将两个对象文件链接

$ gcc -o circle circle.o circulararea.o —lncurses

共享链接库是一个特殊的对象文件,在运行时才被链接到程序,这样能使可执行文件更小,同时便于共享模块更新。通过下面的方法创建共享链接库:

$ gcc -shared -o libcirculararea.so circulararea.o

常用的选项:

  • -v 显示版本信息
  • -w 取消所有警告
  • -Wall 对所有问题输出警告
  • -std=<语言标准 > 支持的语言的标准-std=c11表示支持c11标准
  • -c 只预处理,编译,汇编,不链接
  • -C 预处理保留注释
  • -E 只执行预处理,不结合-o使用会将结果输出到stdour
  • -s 删除可执行文件的符号表
  • -S 只执行预处理和编译
  • -save-tems 保留中间输出文件
  • -shared 创建共享对象文件
  • -ename 指定程序从name处开始执行
  • -g 生成GDB调试所需要的符号表

文件类型:

  • .c C语言源文件
  • .i C程序预处理后的文件,可以被编译。
  • .h C程序头文件。
  • .s 汇编文件
  • .S 有C语言的汇编文件,进行汇编前需要预处理
  • .o 对象文件
  • .exe 可执行文件

优化等级:

  • -O0:

    关闭所有优化选项

  • -O/-O1:

    让可执行文件更小、执行得更快,但是不会因此增加过多的编译时间。所采用的技术包括:合并一致的常量、优化基本循环,以及在连续函数调用后对栈操作分组。

  • -O2:

    应用几乎所有支持的优化技术,只要这些优化技术不涉及程序大小与执行速度之间的相互取舍。使用该选项通常情况下会增加编译时间。

  • -O3:

    生成 inline 函数,并且让变量在 CPU 寄存器中更加灵活地分配空间。同时也包括了2 所有的优化技术。

  • -Os:

    优化程序大小。这个选项类似-O2 ,但没有包括任何可能导致代码大小增加的优化技术。而且,禁用块重新排序、函数对齐,以及其他以 2 为指数字节边界目的地的跳转操作。如果希望获得更小的可执行文件,可以使用 GCC 选项-s来编译,该选项指示链接器在所有必须的函数和对象被链接后,把所有符号表从执行的输出文件中删除。