gcc编译流程、参数实例详细(总结)

一、简介

本文主要讲解gcc命令的参数以及动态库和静态库的制作,通过程序的编译过程运行具体的实例进行阐述。

二、编译过程

GCC即GNU Compiler Collection,编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和链接(Linking),gcc可以理解为编译管理工具,它会具体调用相关的工具进行执行,具体如下图:
在这里插入图片描述

2.1预处理

[root@localhost /]# gcc -E test.c -o test.i 或 gcc -E test.c

可以输出到test.i文件中存放着test.c经预处理之后的代码。打开test.i文件,看一看,就明白了。后面那条指令,是直接在命令行窗口中输出预处理后的代码.
gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将stdio.h 文件中的内容插入到test.c中了。
2.2编译为汇编代码(Compilation)
预处理之后,可直接对生成的test.i文件编译,生成汇编代码:

[root@localhost /]# gcc -S test.i -o test.s

gcc的-S选项,表示在程序编译期间,在生成汇编代码后,停止,-o输出汇编代码文件。
2.3汇编(Assembly)
对于上一小节中生成的汇编代码文件test.s,as汇编器负责将其编译为目标文件,如下:

[root@localhost /]# gcc -c test.s -o test.o

2.4链接(Linking)
gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
对于上一小节中生成的test.o,将其与C标准输入输出库进行连接,最终生成程序test

[root@localhost /]# gcc test.o -o test

gcc参数详解

编译参数详细说明
-o指定编译的⽬标,否则会⽣成的⽬标⽂件名是a.out; gcc main.c -o main
-S把源文件编译成汇编代码
-E只执行预处理
-include包含头文件,功能如同在源码的语句#include <xxx.h>
-I(大写i)指定程序包含头文件的路径,一般用于指定第三方库的头文件。
-L编译时,用于指定程序第三方库的查找路径。
-l链接时,指定程序需要进行链接的库。注:一般库文件名是libxxx.so,-I指定xxx即可。如-Ixxx
-rpath程序执⾏需要指定动态库的路径,但是可以⽤-rpath参数在编译时指定程序运⾏时需要加载的库的路径。
-D程序编译阶段可以定义一些宏,该方法可以让程序有选择性的运行代码。
-0n这是程序的优化等级。n的范围是0-3。n越大优化等级越高,程序运行的越快。否则越慢,n==0时是关闭优化。利于程序的调试,一般程序调试阶段会关闭优化等级,发布程序会把优化等级设为-O2。-O0:不进行优化处理。-O 或 -O1:优化生成代码。-O2:进一步优化。-O3 比 -O2 更进一步优化,包括 inline 函数。
-g打印程序的调试信息,如果需要使⽤gdb⼯具进⾏调试程序,程序编译的时候,需要加上该参数。
-share编译的时候尽量使用动态库。(除非只有静态库,没有动态库)
-static禁止使用动态库,编译的时候只加载静态库,这会导致执行件很大。
-w不生成任何的警告信息。
-Wall生成所有的警告信息。
-fpic使输出的对象模块可重定位地址方式行成的。
-shared把对应的源文件形成对应的动态链接库。

四、实例讲解

动态库和静态库
静态库
当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被copy到最终的可执行文件中。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了,优点是这样运行起来相对就快些。
不过会有个缺点:占用磁盘和内存空间。静态库会被添加到和它连接的每个程序中,而且这些程序运行时,都会被加载到内存中。无形中又多消耗了更多的内存空间。
动态库
与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。

**优点:**这样就使可执行文件比较小,节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。
**缺点:不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些,总的来说静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。
另外,一个程序编好后,有时需要做一些修改和优化,如果我们要修改的刚好是库函数的话,在接口不变的前提下,使用共享库的程序只需要将共享库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一遍。这也是使用过程当中的差别,以现在的项目举例,在远程更新的时候,如果只是
.so动态库封装内容变化了,那么只需要更新
.so即可。
动态库生成:

#同静态库一样编译成目标文件:
[root@localhost /]# gcc –c a.c b.c
#生成共享库:
[root@localhost /]# gcc –fPIC –shared –o libshared.so a.o b.o

静态库的生成:

#在程序编译时,会全部代码加载到可执行程序中。
[root@localhost /]# ar rcs libstatic.a fun.o

静态库的链接方法:

[root@localhost /]# gcc –o staticcode –L. –lstatic main.c –static(默认库在当前文件夹)

动态库的链接方法:

[root@localhost /]# gcc –o sharedcode -L. –lshared main.c(默认库在当前文件夹)
  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值