GCC,是指GNU C compiler,是不是仅仅是C编译器,不是,它最早是C,现在可以支持很多语言。它的创建者是Richard Stallman,这位大牛就是GNU项目的开山者。1984年建立GNU 项目,并且为这个项目建立一个组织叫FSF(Free Software Foundation)。第一个版本的GCC于1987年发布,是第一个免费编译器软件支持portable ANSI C。现在GCC的版本经过二十多年的发展还在4.6版本,而且目前GCC已经发展出一个非常的架构,可以支持新型语言。了解GCC的最好方式就是登陆GCC官方网站。http://gcc.gnu.org

GCC基本概念及实践(1)_第1张图片

GCC作为一个成功的编译器,它具有一些非常特别的特点:

【1】GCC是一个可移植的编译器。它可以运行在绝大部分操作平台,也支持绝大部分CPU架构,特别是一些专用的如DSP等。

【2】GCC不仅仅是一个本地编译器,它同时支持交叉编译,这个就牛了。可以在一个不同架构的平台和CPU上产生出适合另一个平台另一种架构的执行文件。因此GCC大量用于嵌入式软件开发。

【3】GCC本身是C开发,当然现在在其源代码中也有很多C++,从先有鸡后有蛋这个角度,是很让人费脑子的,但实际上它是一个逐渐开发的过程。最开始肯定是汇编,然后有C,再然后慢慢演进去了。GCC可以用前一版本的GCC来编译下一个版本的GCC。

【4】GCC是模块化设计,非常容易支持新语言和新架构。

【5】GCC是免费的,GNU GPL的授权,

知道了GCC的一些基本历史之后,因为GCC从根本上来说同VISUAL Studio的CL一样,它是一个工具,它是用来编译一段C源程序的。如下所示:

GCC基本概念及实践(1)_第2张图片

从上图中可以看出,GCC编译一个源文件,直接跟上源文件,产生文件用-O指示,如果没有指定,缺省是a.out。同其它工具一样,gcc也具有丰富的选项功能,其中-Wall是代码检查。后面还会学过更多的编译选项。GCC基本概念及实践(1)_第3张图片

通常源程序不止一个文件,编译时可先顺序依次编译。从编译的角度,我们知道一个源代码绎预处理过程生成一个中间文件,然后这个中间文件进行汇编生成汇编代码,汇编经过编译生成的是对象文件,然后对象文件进行连接就成了可执行文件。GCC支持这个过程是通过不同的选项来实现的。如下图:

如果想要查看详细过程,可以通过-v选项进行查看。

GCC基本概念及实践(1)_第4张图片

正如前面所说,现代软件都是非常复杂,不可能一个功能在一个文件中实现,都是由多个源文件实现的。因此使用GCC进行多个文件编译时,需要处理相关的include文件的搜索路径问题。这是一个经典问题,其实也非常简单,就是一个查找路径。所谓路径也就是你这个头文件所在目录。

GCC基本概念及实践(1)_第5张图片

源程序分成多个文件,一方面不仅是在编写时更清晰,另一方面在编译时也会带来性能提高,GCC在编译时,当然包括任何一种C编译器,它都要经过预处理、汇编、编译及连接等过程,在这些过程,通常连接比编译要快得多,因为编译它需要进行预处理,这个过程需要进行路径搜索和宏定义替换,耗时较多。GNU提供了GNU Make工具,这个工具它进行调用GCC编译时,它有一个基本判断就是源码的修改时间与对象文件时间的先后,如果源码时间在对象时间之后,它通常是不在对源码进行连接之前的工作。当多个源码一起编译或者多个源码一起连接时,通常需要考虑顺序问题,这个问题在现代编译器中不再重要,但是还是要遵循调用在前,实现在后的。

GCC基本概念及实践(1)_第6张图片

我们知道开发一个C语言程序或者一个C++语言程序,它需要依赖于两个外在条件,第一个在编译阶段,对单个源文件来说,它需要知道它所include进来的头文件的路径,知道了这些头文件才能进行预处理。第二在连接阶段,连接的外在库在哪。首先我们要了解一个库,库在C语言中就是一个预先编译好的特定平台的对象文件,它可以直接跟程序进行连接。比喻我们学习C语言时最常用的数学函数库和标准输入输出函数库。这些对象文件通常随便操作系统或者编译器默认安装在指定目录下,如LINUX的/usr/local/lib或/usr/lib或/lib下。对象库文件形式前面我们学习了一种.o结尾的文件,还有以.a结尾的表态压缩库(一个.a中通常包含多个.o),最后是以.so结尾的动态链接库。通常外在库不在系统指定的目录下就需要在编译时进行指定,在命令行中指定的方式有两种,一种是文件库的全路径名,另一种是简单写-lm,这时连接器将在标准目录下进行搜索。如下所示:

GCC基本概念及实践(1)_第7张图片

特别需要提到一点,就是通过指定连接库文件可以避免同样函数在不同库中的重复定义。

GCC基本概念及实践(1)_第8张图片

这里也存在一个多个外在库问题,其排放顺序同前面一样,也是源码在前,调用在前,实现在后这个顺序。这里所有编译器共用的顺序。但现代编译器可以不是很重要,接下来我们了解第二个问题,就是这些库,通常其中的函数都是有声明文件,这些声明文件通常是以.h结尾存在一些特定目录中。GCC在预处理时是需要查找这些文件,并将这些内容拷贝进去。缺省情况GCC查找头文件的路径是/usr/local/include 和/usr/include。当然这还取决于系统架构如64bitOS通常是lib64。前面两个都是讲的系统指定的,如果这些库和头文件放在其它目录时,可以通过-I和-L来指定特定目录。从程序移植性角度来说,通常不要在头文件include时写死文件路径名称。

GCC基本概念及实践(1)_第9张图片

我们前面讲了两种关于外在头文件和外在库的指定方式,还有一种是通过修改系统环境变量来指定系统缺省路径。这里有两个环境是头文件:C_INCLUDE_PATH(用于C),CPLUS_INCLUDE_PATH(用于C++),库 LIBRAY_PATH用于静态,LD_LIBRAY_PAT用于动态。