gcc编译流程

发布时间 2023-03-29 17:25:04作者: Rxin

gcc编译流程

一、GUN工具

  • 编译工具:把一个源程序编译为一个可执行程序
  • 调试工具:能对执行程序进行源码或者汇编级调试
  • 软件工程工具:用于协助多人开发或者大型软件项目的管理。如make、CVS、Subvision
  • 其它工具:用于把多个人件链接成可执行文件的连接器,或者用作格式转换的工具

二、GCC介绍

  • 全称为GUN CC,GUN项目中符合ANSI C标准编译系统
  • 编译如C、C++、Object C、JAVA、Fortran、Pascal、Modula-3和Ada等多种语言
  • GCC是可以在多种硬件平台上编译出可执行程序的超级编译器,其执行效率与一般编辑器相比平均效率高出20%~30%
  • 一个交叉平台编译器,适合在嵌入式平台领域的开发编译
  • gcc所支持后缀名解释
后缀名 解释程序类型
.c C源程序
.C/.cc/.cxx C++源程序
.m Objective-C源程序
.i 已经预处理的C源程序
.ii 已经预处理的C++源程序
.s/.S 汇编语言源程序
.h 预处理文件(头文件)
.o 目标文件
.a/.so 编译后的库文件

三、编译器的主要组件

  • 分析器:将源语言程序代码转换为汇编语言(C到汇编),所以分析器需要知道目标机器的汇编语言。
  • 汇编器:汇编器将汇编语言代码转换为CPU可执行的字节码
  • 链接器:将汇编器生成的单独的目标文件组合成可执行的应用程序。链接器需要知道这种目标格式以便于工作。
  • 标准C库:核心的C语言库都有一个主要的C库来提供,如果在应用程序中用到了C库中的函数,这个库就会通过链接器和源代码连接来生成最终的可执行程序。

四、GCC的基本用法和选项

GCC的基本用法是:

gcc [options] [filenames]

选项:

  • -c:只汇编,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o的后缀的目标文件,通常用于编译不包含主程序的子程序文件;
  • -o output filename:确定输出文件名称为output filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out
  • -g:产生符号调试工具(GUN的gdb)所必要的符号资讯,想要对源代码进行调试,我们必须加这个选项。
  • -O:对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、链接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是编译、链接的速度会相对变慢一些。
  • -O2:比-O更好的优化编译、链接,当然整个编译、链接过程会很慢。
  • -I dirname:将dirname所指出的目录加入到程序头文件目录列表,是在预编译过程中使用的参数
  • -L dirname:将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数
  • -wall:显示警告
  • -E:仅执行编译预处理
  • -S:将C代码转换为汇编代码

五、gcc的错误类型及对策

  • 第一类:C语法错误
    • 错误信息:文件source.c中第n行语法错误(systex error)。有些情况下,一个简单的语法错误,gcc会出现一大堆报错信息,我们要保持头脑清醒,不要被吓到。
  • 第二类:头文件错误
    • 错误信息:找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、制定的头文件所在目录名错误等,也有可能是错误的使用双引号和尖引号。
  • 第三类:档案库错误
    • 错误信息:链接程序找不到所需的函数库(Id:-Im:No such file or dirctory)。这类错误是与目标文件相连接的函数库有错误,有可能是函数库名错误、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。
  • 第四类:未定义符号
    • 错误信息:有未定义的符号(Undefined symbo1)。这类错误实在连接过程中出现的,可能有两种原因:一、是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译链接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二、未定义的额符号是一个标准的库函数,在源程序中使用了该库函数而连接过程中还没有给定相应的函数库名称,或者该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改gcc链接选项中的-I和-L项。

六、GCC编译过程

gcc编译分为4个步骤:

  • 预处理(Pre-Processing)
  • 编译(Compiling)
  • 汇编(Assembliang)
  • 链接(Linking)


1、预处理

预处理是读取C源程序,对其中的伪指令(以#开头的指令,也就是宏)和特殊符号进行”替代“处理;经过此处理生成一个没有宏定义,没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,仍然是C文件,但是内容有所不同。

预处理的过程主要处理包含以下过程:

  • 将所有的#define删除,并且展开所有的宏定义
  • 处理所有的条件编译指令,比如#if #ifdef #elif #else #endif等
  • 处理#include预编译指令,将包含的文件插入到该预编译指令的位置
  • 删除所有注释“//”和"/* */"
  • 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号
  • 保留所有的#pragma编译器指令,因为编译器需要使用它们

如:gcc -E hello.c -o hello.i (-E只对其预处理)

2、编译

编译程序所要做的工作就是通过词法分析和语法分析,再确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码

如:gcc -S hello.i -o hello.s(-S将.i文件生成.s汇编文件)

不同的编译器交叉编译同一个hello.i文件生成的汇编文件也不同,这也是C语言可移植性的一种体现。

3、汇编

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标机器语言代码。目标文件由段组成。通常一个目标文件中至少有两个段:

  • 代码段(文本段):该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般不可写;
  • 数据段:主要存放程序中用到的各种常量、全局变量、静态的数据。一般数据段都是可读、可写、可执行的;

如:gcc -c hello.s -o hello.o (-c汇编文件,不链接)

4、链接

汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中 定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经过连接程序的处理方能的已解决。链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号桶盖符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,也就是可执行程序。根据开发人员指定的库函数的连接方式的不同链接处理可分为两种:

  • 静态链接
  • 动态链接

对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一下内存,因为在内存中只需要保存一份共享对象的代码。但是并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接节能带来一些性能上的损害。

如:gcc hello.o -o hello -static(静态链接编译)

​ gcc hello.o -o hello (动态链接编译)

可见两种编译生成的可执行文件大小的差距,静态连接编译将静态库包含在了生成的可执行文件中,增加了其独立性,但是也使其文件大小更大。

七、调试器

  • 首先使用gcc对test.c进行编译,注意一定要加上选项“-g”
  • gcc -g hello.c -o hello
  • gdb hello

gdb是调试运行错误的,对于语法错误不能进行调试

GDB调试流程

作用 参数
查看文件 (gdb) l
设置断点 (gdb) b 6
查看断点情况 (gdb) info b
运行代码 (gdb) r
查看变量值 (gdb) p n
单步运行 (gdb) n/(gdb) s
恢复程序运行 (gdb) c
帮助 (gdb) help [command]

八、GDB调试

  • 运行被调试程序,设置所有的能影响该程序的参数和变量
  • 保证被调试的程序在指定情况下停止运行
  • 当被调用程序停止运行时,让开发工程师检查发生了什么
  • 根据每次调试器的提示信息来做响应的改变,以便修正某个错误引起的问题。

转载说明:

1、https://blog.csdn.net/weixin_44895651/article/details/106260030?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168008133316800217265389%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168008133316800217265389&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2

2、https://blog.csdn.net/DRAXY/article/details/123972550?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168008133316800217265389%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168008133316800217265389&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2