《Linux基础-gcc编译器课件》由会员分享,可在线阅读,更多相关《Linux基础-gcc编译器课件(36页珍藏版)》请在金锄头文库上搜索。
1、Linux基础 gcc编译器,gcc内容大纳,gcc的简介 如何使用gcc编译一个简单的C程序 gcc的编译流程 gcc的常用编译选项 使用gcc实现多文件编译 使用gcc编译静态库、动态库,学习目标,掌握gcc,掌握gcc的编译过程 知道一些常见的编译错误 多文件编译的方法 了解动态库与静态库的区别 掌握静、动态库的编译方法,gcc的简介,gcc是一个用于linux系统下编程的编译器。 gcc原名为 GNU C compile(语言编译器),因为它原本只能处理 C语言。 gcc 很快地扩展,变得可处理 C+,之后也变得可处理 Pascal、Object-C、Java以及其他语言。 GNU是一
2、个开源项目组,是一个递归的缩写。 GNU : GNU is NOT UNIX,gcc的格式,gcc指令的一般格式为: gcc 选项 要编译的文件 选项 目标文件 其中目标文件可以缺省,缺省情况,生成的可执行文件名为a.out,使用gcc编译一个简单的C程序,使用vi编写一个简单的hello world程序, 并使用gcc编译,缺省情况下编译成功后,会生成可执行文件a.out 我们可以通过gcc的-o选项指定生成的可执行文件名 以上两条命令,实际隐含了四个步骤。,gcc编译流程,使用gcc编译程序的时候 ,实际包含了四个步骤: 预处理(Pre-processing) 读取C语言源文件,对以“#”
3、开头的语句进行处理 编译(Compilation) 对预处理之后输出的文件进行词法分析,试图找出所有不符合语法规则的部份,打印错误或警告。若没有任何语法问题,则将其翻译为功能等价的汇编代码 汇编(Assembly) 把汇编代码翻译成目标机器代码(二进制文件) 链接(Linking) 将一个文件中引用的符号(函数、外部变量等)与该符号在另文件中的定义和实现连接起来,从而使有关的目标文件连成一个整体,最终生成可以被操作系统执行的可执行文件,写一个简单的测试程序,写一个简单的程序gcc-test.c便于我们接下来探讨用,写完之后仔细阅读该代码,了解代码功能,并判断是否有问题:,gcc编译流程 第一步
4、:预处理,在该阶段,gcc将对以“#“起始的语句进行处理: 将头文件展开: 将头文件的内容展开至C文件 做宏的替换: 将源文件中出现的宏做宏值替换。 条件编译的判断 : 根据条件编译选项,加载指定代码 (注:该阶段会删除注释代码) 可以通过gcc的选项-E来单独执行预处理,而不处理其它三个步骤,并生成gcc-test.i的文件:,gcc编译流程 第一步:预处理,预处理成功后,使用cat 指令查看gcc-test.i的文件信息,并对源文件比较:,以上省略n行,gcc编译流程 第一步:预处理,预处理总结: 在预处理时,gcc编译器仅仅做的只是对头文件的展开、宏的替换、条件编译选项的判断,注释删除操
5、作(注:不做语法检测)。 因此,在预处理时,gcc编译器不会出现任何错误提示。即便是非C源代码的普通文本文档,我们也可以使用预处理执行。,gcc编译流程 第二步:编译,在这个阶段中,gcc将对所有正文内容进行处理: 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作。 在检查无误后,gcc把代码翻译成汇编语言。 可以通过gcc的选项-S来执行编译,而不处理其它二个步骤,并生成gcc-test.s的文件:,编译时出现错误,修改该错误,重新使用-S选项编译。,gcc编译流程 第二步:编译,编译成功后,使用cat 指令查看gcc-test.s的文件信息:,gcc编译流程 第二步:编
6、译,编译总结: 找出源文件中的语法的错误,没有错误生成汇编文件 因此基本上的错误显示都是在该步骤出现,gcc编译流程 第三步:汇编,在这个阶段中,gcc将对汇编文件进行处理: 将编译阶段生成的.s汇编文件翻译成二进制机器代码。 可以通过gcc的选项-c来执行汇编,并生成gcc-test.o的文件:,gcc编译流程 第三步:汇编,汇编成功后,使用cat -n指令查看gcc-test.o的文件信息:,此时的.o文件已经为二进制的机器代码,不再是文本的ASCII代码,所以不能使用cat指令查看 汇编总结: 将高级的语言代码翻译成机器语言代码,gcc编译流程 第四步:链接,在这个阶段中,若之前三个步骤
7、没有任何错误的情况下,gcc将最后生成我们的可执行程序: 链接没有任何的选项。,在链接环节有一个重要的概念,即函数库: 在这个程序中并没有定义”printf”的函数实现,且在预编译中包含进的中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现”printf”函数的呢? 最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,gcc会到系统默认的搜索路径”/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数”printf” 了,而这也就是链接的作用。,gcc编译流程 第四步:链接,链接总结: 链接生成最后可执行程序 链接做符号(函数)的
8、引用和链接。 若函数找不到实现,将会有链接错误提示。 通过ldd命令可以查看某个可执行文件的库链接状态,gcc编译流程 图示,gcc文件扩展名规范,gcc的基本选项,在使用gcc编译器的时候,我们必要给出一系列的必要参数和文件名称。 gcc的参数大约有100多个,已知-o、-E、-S、-c。 但是其中多数是我们用不到的,所以接下来只介绍最基本的。,gcc基本编译选项-g,-g: 在可执行文件中加入调试信息,方便进行程序的调试,方便使用gdb来进行调试 比较加选项g和不加g的可执行程序大小区别:,gcc基本编译选项-O,-O0、1、2、3 :对生成的代码使用优化,中括号中的部分为优化级别,缺省的
9、情况为2级优化,0为不进行优化。 注意,采用更高级的优化并不一定得到效率更高的代码。 对比每种优化选项生成的可执行文件大小:,gcc基本编译选项-D,-D :宏定义 一般格式-Dname=value,若vlaue为空缺省为1 在C程序源文件中,可以使用#define来定义一个宏 在编译时,我们也可以使用gcc来定义一个宏,与用#define定义的效果是一样的,gcc基本编译选项-W,-Wall :表示产生所有警告。 未使用的变量 有类型的函数,无返回值 不同类型变量的赋值,-Werror:含义是将警告作为错误(error),即出现警告就停止编译。,gcc基本编译选项 总结,-g -O -D -
10、I(大写的i) -L -l -Wall -Werror,利用gcc编译多个文件,一次性编译 gcc file1.c file2.c o hello 先编译中间机器代码文件,链接所有的机器代码文件 gcc c file1.c gcc c file2.c gcc file1.o file2.o o hello,gcc编译常见错误,语法错误 例如:语句少分号,使用未定义的变量,括号未匹配等等 头文件错误 例如:头文件包含错误,找不到该头文件 链接库错误 例如:在用-l连接库的时候,连接了一个不存在的库 未定义符号 符号没有实现的地方,可能是库连接错误,或符号输入错误,函数库,在windows平台和l
11、inux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二者库的二进制是不兼容的。 linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。“空间换时间” 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。 “时间换空间”,库存在的意义,库是别人写好的现有的,成熟的,可以复用的。 现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常
12、。 共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。 你可以使用但要记得遵守许可协议。,库示例,写三个文件fun1.c fun2.c fun3.c 这三个文件中分别对应有函数fun1(), fun2(), fun3(),现在希望将这三个文件分别编译成静态库与动态库。 写一个文件main.c 在main.c中有main函数,并调用fun1(), fun2(), fun3()函数。,静态库编译与加载,生成源文件的目标机器文件,对目标机器文件进行归档,编译可执行程序并加载静态库,执行main程序,看其效果静态库加载到可执行程序中,只需在编译的时候,跟上需要加载
13、的库名即可,执行结果,动态库 (共享库)编译与加载,生成源文件的目标机器文件,对目标机器文件进行处理,编译出动态库,编译可执行程序并加动态库,执行main程序,看其效果,执行结果:,动态库 (共享库)编译与加载,编译与运行加载的情况不同,我们已经在编译的时候指定过需要加载的库,但是运行的时候为何提示找不到? LINUX下:默认的库加载路径为/lib/ 、 /usr/lib/ 有多种办法解决问题: 将libfun.so拷贝到默认的库目录中(/lib/或/usr/lib/); 设置新的环境变量: export LD_LIBRARY_PATH=./ echo $LD_LIBRARY_PATH,总结,我们使用gcc编译了一个简单的程序,通过该程序引申gcc的四个编译步骤,再对四个编译步骤进行逐一解释。 学习了gcc的一些常用编译选项,有涉及到优化、头文件、连接库、警告、调试等等。 了解了动态库与静态库,用示例演示如何生成动、静态库,并在可执行程序中分别加载它们。,练习,完成本章PPT中所有的代码练习,对 gcc的每一个选都了解。 简述gcc编译流程,并说明编程中每一个步骤产生的中间文件的类型。,