gcc编译器简单使用
gcc的全称:GNU CCompiler,是Linux平台下最常用的编译器,是GNU的一款编译器,通过后缀名来区别输入文件的类型。
①常用文件类型如下表:
后缀名 |
说明 |
c |
C语言源代码文件 |
.C/.cc |
C++源代码文件 |
.h |
文件(head也即include) |
.i |
已经预处理过(完成头文件和宏定义的展开)的C源代码文件 |
.ii |
已经预处理过的C++源代码文件 |
.s |
汇编语言的源代码 |
.S |
预编译的汇编语言源代码文件 |
.o |
编译后的目标文件object |
②命令选项
gcc命令选项分基本选项和优化选项:
基本选项如下表:
类型 |
说明 |
-E |
预处理后即停止,生成预处理文件(*.i),不进行编译、汇编及连接。 语法:gcc -E xxx.c -o xxx.i |
-S |
编译后即停止,生成汇编语言文件(.s),不进行汇编及连接。 语法:gcc -S xxx.i -o xxx.s |
-c |
编译或汇编源文件,生成目标文件(.o),不进行连接 语法:gcc -c xxx.s -o xxx.o |
-o |
指定输出文件file |
file |
指定命令后的文件,可以直接对file进行编译连接 语法:gcc xxx.c -o xxx //xxx为执行程序 gcc xxx.i -o xxx gcc xxx.s -o xxx gcc xxx.o -o xxx |
-l |
指定连接时引用xxx库(LIB),一般库文件名为libxxx.so或libxxx.a,要连接这个库只需要-lxxx,而不用加lib。 语法:gcc –lLIB file |
-L |
指定连接时引用库的PATH,除了默认的库搜索路径,还可去PATH路径搜索库文件 |
-g |
使编译器进行debug编译 |
备注:库文件*.so是动态库,*.a是静态库。
优化选项如下表:
类型 |
说明 |
-O0 |
不进行优化处理。 |
-O或-O1 |
进行基本的优化 |
-O2 |
除了完成-O1级别的优化外,还要一些额外的调整工作,如处理器指令调度等,这是GNU发布软件的默认优化级别。 |
-O3 |
除了完成-O2级别的优化外,还进行循环的展开以及其他一些与处理器特性相关的优化工作。 |
-Os |
生成最小的可执行文件,主要用于在嵌入式领域。 |
注意:优化级别越高,生成可执行文件的运行速度也越快,但消耗在编译上的时间就越长,因此在开发的时候最好不使用优化选项,只有到软件发行或开发结束的时候才考虑对最终生成的执行代码进行优化。
③范例演示
合成执行程序要经历预处理、编译、汇编以及连接4个阶段,现在我们使用具体范例来演示每个阶段:
新建测试目录protest,编辑源码文件hello.c
[root@localhost ~]# mkdir protest
[root@localhost ~]# cd protest/
[root@localhost protest]# vi hello.c
源码文件清单:
/*hello.c*/
#include "stdio.h"
int main()
{
printf("This is gcc complie testing\n");
return 0;
}
[root@localhost protest]# ll hello*
-rw-r--r-- 1 root root 73 Nov 21 17:32 hello.c
I预处理pre-processing
生成预处理文件,如hello.i
[root@localhost protest]# gcc -E hello.c-o hello.i
[root@localhost protest]# ll hello*
-rw-r--r-- 1 root root 73Nov 21 17:32 hello.c
-rw-r--r-- 1 root root 138 Nov 21 17:34 hello.i
II编译 compling
生成汇编代码的汇编文件,如hello.s
[root@localhost protest]# gcc -S hello.i-o hello.s
III汇编 assembling
生成二进制的目标文件,如hello.o
[root@localhost protest]# gcc -c hello.s -o hello.o
IV链接 linking
生成可执行文件(暂不链接库文件),如hello
[root@localhost protest]# gcc hello.o -ohello
[root@localhost protest]#./hello
[root@localhost protest]#rmmain
//由源代码直接生成
[root@localhost protest]# gcc hello.c -o hello
④加强点训练难度:单个库文件的链接
编译源文件f1.c、f2.c,编译它们后加入库文件libtest.a中,hello程序调用其中的函数func1(),func2()。
f1.c源码清单
/*f1.c*/
#include "stdio.h"
void func1()
{
printf("This is testing,itis func1() in f1.c\n");
}
f2.c源码清单
/*f2.c*/
#include "stdio.h"
void func2()
{
printf("This is testing,itis func2() in f2.c\n");
}
hello.c源码清单
/*hello.c*/
#include "stdio.h"
extern void func1();
extern void func2();
int main()
{
printf("This is gcc complietesting\n");
func1();
func2();
return 0;
}
//编译f1.c、f2.c
[root@localhost protest]# gcc -c f1.c -o f1.o
[root@localhost protest]# gcc -c f2.c -o f2.o
//加入库文件libtest.a中
[root@localhost protest]# ar -rcs libtest.a f1.o f2.o
//可以查看库文件中包含哪些目标文件
[root@localhost protest]# ar -tv libtest.a
rw-r--r-- 0/0 876 Nov 23 15:02 2015 f1.o
rw-r--r-- 0/0 876 Nov 23 14:22 2015 f2.o
//关键一步,编译hello.c,把库文件libtest.a中的函数(func1/func2)链接入可执行程序hello。
[root@localhost protest]# gcc hello.c -ohello -L./ -ltest
//查看运行结果
[root@localhost protest]#./hello
This is gcc complie testing
This is testing,it is func1() in f1.c
This is testing,it is func2() in f2.c
显示,运行结果符合我们的要求!
⑤测试程序执行速度
[root@localhost protest]# time ./hello
This is gcc complie testing
This is testing,it is func1() in f1.c
This is testing,it is func2() in f2.c
real 0m0.002s
user 0m0.000s
sys 0m0.002s
关于多库文件(库之间有函数调用的)链接时要注意库文件的链接顺序就可避免undefined reference的错误!如libxx1.a调用libxxx2.a中的实现函数,则libxx1.a 放在libxx2.a前面。如下:
[root@localhost protest]# gcc hello.c -o hello -L./ -lxx1 -lxx2
编译器(gcc)了解上面这些简单使用,日常开发基本够用。