GCC编译器总结

GCC简介

1、GCC经过那么多年的发展,已经从最初的C编译器转变成了编译器的集合,官方定义是GNU Complier Collection,现在的GCC不仅支持C还支持C++、Java等语言。
2、GCC是一个编译系统的驱动程序,负责解析输入的参数,依次调用预处理器(cpp)、编译器(ccl/cclplus)、汇编器(as)、链接器(ld)生成可执行文件。
3、GCC 和 G++ 的区别并不是前者用来编译C代码,后者用来编译 C++ 代码。它们的区别是GCC把后缀为c的文件当C代码处理(ccl编译),而 G++ 则当作 C++ 处理(cclplus编译),对于后缀为cpp的文件gcc和 g++ 处理过程没有什么区别。GCC默认是不能编译 C++ 程序的,需要加上-lstdc++选项,G++ 是可以直接编译的,G++相当于是对GCC的封装。

GCC编译过程

在介绍GCC编译步骤之前,首先需要了解GCC支持的后缀文件类型。

后缀名 对应语言
.c C程序
.C/.cc/.cxx C++程序
.i 预处理后的C程序
.ii 预处理后的C++程序
.s/.S 汇编语言程序
.h 头文件
.o 目标文件
.a/.so 编译后的库文件

GCC编译流程分为四个步骤:预处理(生成.i/.ii文件)、编译(生成.s/.S文件)、汇编(生成.o文件)、链接(生成可执行文件)。


gcc指令的一般格式为:
gcc [选项] 要编译的文件 [选项] [目标文件]
其中,目标文件可缺省,gcc默认生成可执行的文件为a.out


#include <stdio.h>
int main()
{
    printf("Hello World\n");
    return 0;
}

1、预处理
对于该阶段,gcc将stdio.h文件中的代码包含进这段程序,我们可以利用gcc -E test.c -o test.i命令来生成预处理过的.i文件。-E选项代表让gcc在预处理阶段后停止编译。test.i文件中的内容如下所示,可以看出stdio.h文件中的内容被展开。

extern int fprintf (FILE *__restrict __stream,
  __const char *__restrict __format, ...);
  ......
  # 8 "test.c" 2
int main()
{
    printf("Hello World\n");
    return 0;
}

2、编译
该阶段主要是对预编译后的.i文件编译,生成汇编代码的.s文件。gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc把代码翻译成汇编语言。我们可以使用-S选项来进行查看,该选项只进行编译而不进行汇编过程,生成汇编代码。
我们可以利用gcc -S test.i -o test.s命令进行编译过程。test.s文件中的内容如下所示。

    .file   "test.c"
    .section    .rodata
.LC0:
    .string "Hello World"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, (%esp)
    call    puts
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
    .section    .note.GNU-stack,"",@progbits

3、汇编
该阶段是将编译后的.s文件转化成二进制文件.o的过程,利用-c选项就可以生成二进制.o文件。我们可以利用gcc -c test.s -o test.o生成二进制代码。
4、链接


该阶段主要将成功编译的二进制文件进行链接操作,生成可执行文件。利用gcc test.o -o test生成可执行文件test,运行./test即可打印出hello world


总结一下:

gcc -E  test.c -o test.i    //把原代码交给cpp预处理器生成经过预处理后的中间文件test.i
gcc -S test.i -o test.s     //把经过预处理之后的test.i文件交给编译器cc1生成test.s文件
gcc -c test.s -o test.o     //把经过编译后汇编文件test.s交给as进行汇编,生成目标test.o文件
gcc test.o -o test          //将as汇编之后的目标文件交给ld链接成一个可执行的文件test

GCC常用编译选项

1、总体编译选项

选项名称 作用
-c 只是编译不链接,生成目标文件.o
-S 只是编译不汇编,生成汇编代码
-E 只进行预编译,不做其他处理
-g 在可执行程序中包含标准调试信息
-o file 把输出文件输出到file里
-v 打印出编译器内部编译各过程的命令行信息和编译器的版本
-I dir 在头文件的搜索路径列表中添加dir目录
-L dir 在库文件的搜索路径列表中添加dir目录
-static 链接静态库
-llibrary 连接名为library的库文件

表中前边几个选项在GCC编译步骤中已经有所了解,主要对表中后四个选项进行介绍。
当我们进行程序开发时,基本都会用到很多函数库,从程序员的角度看,函数库就是封装的一些头文件(.h)和库文件(.a/.so),Linux系统下头文件一般默认放到/usr/include/目录下,库文件放在/usr/lib/目录下,如果我们使用的库不在标准路径下,我们就需要指定头文件和库文件的路径以便让gcc找到它们。
举个例子,假设上一节test.c主要实现C语言连接mysql数据库的功能,我们从官网下载的mysql connectors的头文件在/usr/local/mysq/include/路径下,库函数在/usr/local/mysql/lib/路径下。
我们可以利用

gcc -c -I /usr/local/mysql/include test.c -o test.o

生成test.o二进制文件,再利用

gcc -L /usr/local/mysql/lib -lmysqlclient test.o -o test

进行链接操作产生可执行的test文件。这两步也可以合成一步,直接生成可执行的test文件

gcc -I /usr/local/mysql/include -L /usr/local/mysql/lib -lmysqlclient test.c -o test

Linux下的库文件分为两大类分别是动态链接库(通常以.so结尾)和静态链接库(通常以.a结尾),二者的区别仅在于程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。
默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要使用静态链接库可以在编译时加上-static选项,强制使用静态链接库。
比如在/usr/local/mysql/lib目录下有链接时所需要的库文件libmysqlclient.so和libmysqlclient.a,为了让GCC在链接时只用到静态链接库,可以使用下面的命令:
gcc –L /usr/local/mysql/lib -static –lmysqlclient test.o –o test

需要注意的是:

  • -I dir-L dir都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。
  • 另外值得详细解释一下的是-l选项, 它指示gcc去连接库文件libXXX.so。由于在Linux下的库文件命名时有一个规定:必须以lib三个字母开头。因此在用-l选项指定链接的库文件名时可以省去lib三个字母。也就是说gcc在对”-lXXX”进行处理时,会自动去链接名为libXXX.so的文件。

2、其他常用编译选项

选项名称 作用
-ansi 支持符合ANSI标准的C程序
-pedantic 允许发出ANSI C标准所列的全部警告信息
-pedantic-error 允许发出ANSI C标准所列的全部错误信息
-Wall 允许发出gcc提供的所有有用的报警信息
-Werror 把所有的告警信息转化为错误信息,并在告警发生时终止编译过程
-O 主要进行线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化
-O2 除了完成所有“-O1”级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等
-O3 还包括循环展开和其他一些与处理器特性相关的优化工作
-static 指示链接器构建一个完全链接的可执行程序,即链接静态库而不链接动态库
-fPIC 指示链接器创建一个共享的目标文件,即so文件
-shared 生成动态库,一般和上面的-fPIC一起使用

参考文献:


GCC学习总结

Linux GCC常用命令

GCC 编译详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容