[编译器] GCC编译器简介
一,GCC编译器简介
GCC是Linux平台下常用的编译链接器。编译链接的过程分为:
源代码-->预处理文件(.i)-->编译后的汇编代码(.s)-->汇编后的二进制文件(.o)-->链接后的二进制物件(无后缀)。
处理程序分别是 :cpp、ccl、as、ld。
使用 -v选项,可以看到各个阶段关联的处理程序。
使用gcc -E 指示gcc对源代码进行预处理,结果直接输出到终端。
使用gcc -S 指示gcc编译成为汇编语言
使用gcc -c 指示gcc直至形成二进制文件(不进行链接)
使用gcc 指示gcc链接形成二进制物件(多个二进制模块链接形成大的模块或者可执行程序)
因此你需要的目标文件的种类是 -E、-S、-c或者不带这些参数确定的,
源文件可以是中间文件的一种。-o参数控制的仅仅是输出文件的名称。
但是gcc默认会根据源文件的后缀去判断应该调用处理程序的那些。例如源文件的后缀是.c,则gcc -E使用的是cpp,gcc -c则使用cpp、ccl、as。如果源文件的后缀是.o,则gcc -E 是无法进行的,会报错:linker input file unused because linking not done。这是gcc发现这个应该进行链接,但是选项指示不使用linker程序,因而报这种错误信息。如果源文件是二进制的文件,但是保存的源文件后缀却是.c,则gcc会当作这是.c文件,如果采用gcc不带参数,则gcc会很多错,因为它把这个文件当作源代码处理的。
注意:这里,源文件指的是gcc的输入文件,源代码指的是程序源代码文件。
以下是使用gcc 不带-E、-S、-c这些参数时,将会进行的处理与输入文件后缀(类型)的对应关系。
使用-save-temps可以保存编译各个阶段的临时文件。
<!-- [if !mso]> <mce:style><! v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} p\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} v\:textbox {display:none;} --><![endif]--><!-- [if !ppt]--><!-- [endif]-->
后缀 名
|
种类说明
|
源文件相应的后续处理
|
|||
预处理
|
编译
|
汇编
|
链接
|
||
.c
|
C 语言 源 程序 |
○
|
○
|
○
|
○
|
.C/.cc/.cxx
|
C++ 语言 源程序 |
○
|
○
|
○
|
○
|
.h
|
源程序所包含的头文件 |
--
|
--
|
--
|
--
|
.i
|
经过预处理的 C 源程序 |
○
|
○
|
○
|
|
.ii
|
经过预处理的 C++ 源程序 |
○
|
○
|
○
|
|
.s
|
汇编语言源程序 |
○
|
○
|
||
.S
|
汇编语言源程序 |
○
|
○
|
○
|
|
.o
|
目标文件 |
○
|
|||
.a
|
由目标文件构成的档案文件 |
○
|
<!-- [if !mso]> <mce:style><! v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} p\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} v\:textbox {display:none;} --><!-- [endif]--><!-- [if !ppt]--><!-- [endif]-->
二,GCC常用编译选项
格式为:
gcc [option | filename] .......
gcc的命令可以分为如下几类:
1,全局选项 -c,-S,-E ,-o
2,目录选项 -Ipath,-Lpath
3,链接选项 -shared,-llibrary -Wl option
4,警告选项 -Wall, -Wextra,-Wconversion,-Wshardow,-Wcast-qual
5,调试选项 -g ,-ggdb
6,优化选项 -O, -O0,-O1,-O2,-O3
7,其它选项 -fPIC
a)目录选项
目录选项是为编译器指定搜索头文件和库文件所在目录的,
编译时,头文件的搜索顺序为:
-Ipath指定--------->环境变量C_INCLUDE_PATH或者CPLUS_INCLUDE_PATH--------->/usr/local/include和/usr/include
库文件搜索顺序:
-Lpath指定-------->环境变量LIBRARY_PATH----------->/usr/local/lib和/usr/lib。
<!-- [if !mso]> <mce:style><! v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} p\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} v\:textbox {display:none;} --><!-- [endif]--><!-- [if !ppt]--><!-- [endif]-->
ln -s ` g++ -print-file-name = libstdc++.a` (注意是反引号,不是单引号,意义是运行反引号里边的命令)
这样便建立了一个到g++使用的静态库libstdc++.a的符号链接。
g++ -o hello -L. hello.cpp 该命令会使得g++搜索当前目录的链接库,搜索到了libstdc++.a,因而采用静态链接。
使用ldd查看编译结果,可以看到没有对c++动态链接库的依赖:
方案
|
对目标文件的影响
|
对编译过程的影响
|
优化级别选用的方案
( ○: 使用; △: 部分使用; ×:不使用)
|
|||||
执行速度
|
代码大小
|
编译速度
|
内存 使用
|
-O0 或者默认(default)
|
-O1 或者 -O
|
-O2
|
-O3
|
|
合并公共表达式(源代码级别优化) |
加快
|
减少
|
减慢
|
增加
|
×
|
○
|
○
|
○
|
函数内联(源代码级别优化) |
加快
|
增加
|
减慢
|
增加
|
×
|
△
|
△
|
○
|
循环展开
(空间换时间优 化)
|
加快
|
增加
|
减慢
|
增加
|
×
|
×
|
×
|
○
|
度优化 |
加快
|
不增加
|
减慢
|
增加
|
×
|
×
|
○
|
○
|
e)编译链接、创建库文件的过程:
使用源代码文件test.c、main.c作为说明例子,其中main.c用到了test.c中的函数:
test.c:
int max(int a,int b) {
return a>b?a:b;
}
main.c:
int main(){
printf("max(1,2)=%d\n",max(1,2));
return 0;
}
1,创建动态库 :
1)gcc -fPIC -c -o test.o test.c
-fPIC表示产生位置无关代码(position independence code),
-c表示产生的是二进制文件,不进行链接,
-o表示产生的文件名。
2)gcc -shared -o libtest.so test.o
使用1)中编译的二进制文件,产生动态库
2,使用动态库
gcc -o main mian.c -L. -ltest
使用链接的库文件在前目录,名字为test。
3,创建静态库
1)gcc -c -o test.o test.c
-c表示产生的是二进制文件,不进行链接,
-o表示产生的文件名。
2)ar rcs libtest.a test.o
使用1)的二进制文件,产生静态库(文档文件)
4,使用静态库
gcc -o main main.c -L. -ltest
使用链接的库文件在当前目录,名字为test。