GCC是GNU项目的编译器,是GNU最具代表性的作品。GCC设计之初是专门用于C程序的编译器,展开叫做GNU C Compiler。经过数十年的发展,如今的GCC现在已经支持编译多种语言,像C、C++、Objective-C、JAVA、Fortran等等,是GNU  Compiler Collection。当我们用gcc命令编译的时候,它会根据文件的后缀名自动的选择相应的编译器。GCC种包含以下常见命令:

  • C编译器:cc、gcc
  • C++编译器:c++、g++
  • 源代码预处理器:cpp

注意:1.cc是Unix下的编译器,gcc是Linux下的编译器。用Unix编写的程序都用cc编译,故其Makefile文件中的编译命令为cc。Linux为了兼容Unix的命令,在linux下用cc其实并不是用的Unix下的编译器,而是gcc编译器的链接,故用gcc和cc都是一样的。

           2.g++和gcc两个命令,当源文件后缀是.c,gcc按C语言来编译,g++按c++程序编译,当后缀是.cpp时,gcc和g++都将其作为c++程序编译。除此之外,gcc不能链接C++程序的库,故当链接时C++程序必须要用g++来链接。而用g++编译的时候,实际上用的还是gcc编译。

一、程序的编译过程

当我们用编译命令将一个源程序文件编写成可执行文件的时候,实际上分为下面4步:

  • 预处理     将源文件中包含的头文件插入进来,进行宏替换等等,最终生成预处理后的文件。
  • 编译     将上一步生成的预处理后的文件,编译生成汇编代码。
  • 汇编     根据汇编代码,调用as程序,将相应的汇编代码生成机器代码,即计算机能够直接运行的二进制.o文件。
  • 链接     将多个.o文件和程序中用到的库文件通过连接器进行连接,生成最终的可执行文件。

二、GCC编译命令

格式为gcc [option] [filename] ...,假设源文件为test.c。

1. 直接编译

  • 无编译选项
gcc test.c

直接生成二进制可执行文件a.out。

  • 用-o指定输出文件名
gcc test.c -o test

生成指定名为test的二进制可执行文件。

2. 分步编译

  • -E选项:将test.c生成预处理后的文件
gcc -E test.c -o test.i

这里要加上-o指定输出文件名,否则会直接在终端输出。

  • -S选项:将test.c或test.i文件生成汇编文件
gcc -S test.i [-o filename]

此处不指定输出文件名,会自动生成test.s文件,当然也可以用-o来指定输出文件名。

gcc -S test.c [-o filename]

同样也可以用-S选项直接对test.c文件生成汇编文件,若不输出文件名,默认为test.s。

注意:对于test.c->test.i->test.s->test.o->test的文件生成过程,能够作用于当前文件的选项都能作用于其前面的文件,后面不在赘述。

  • -c选项:将test.s文件生成二进制文件
gcc -c test.s [-o filename]

未指定文件名时,生成test.o文件。

注意:gcc 命令直接作用于test.c、test.i、test.s、test.o都会生成a.out可执行文件,同样可用-o指定输出文件名。

3. 编译优化

  • -O选项:对源程序test.c或是test.i进行编译优化
gcc -O1 test.c -o test

优化有1~3个等级,等级越高优化越彻底,编译越慢,汇编代码与源代码的匹配率越低,故要生成调试信息时不应该编译优化,否则不方便调试。

4. 多文件编译

假设有两个文件test.c和func.c。

  • 直接编译
gcc test.c func.c -o test

将两个文件分别编译,然后链接成二进制可执行文件test。

  • 分步编译
gcc -c test.c func.c
gcc test.o func.o -o test

先编译成test.o和func.o,在将他们链接成二进制文test。

直接编译中每次编译时,所有文件都要重新编译,即使源文件没有改变。分步编译时,只编译发生改变了的源文件,最后链接成二进制文件。这样当文件比较多时,非常节省编译的时间。

5. 链接库文件

软件开发过程中,经常会用到库,要么是自己写的库,要么就是第三方库。Linux中的库文件分为两种:

  • 静态链接库(libname.a)
  • 动态链接库(libname.so)

静态库在链接时静态加载到最终的可执行文件,而动态库在运行时动态的加载。故对于静态链接库,一旦编译链接完成,最终的程序就可以独立的运行;但对于使用了动态链接库的程序,即使编辑链接完成,最终运行时还是要依赖所用到的动态链接库。

一般情况下用到的库会给出头文件和相信的库文件,我们可以用-I(大写的i)、-L和-l(L的小写)三个参数来实现使用库的程序的编译与链接。假设有个libtest库,头文件和库文件分别在/usr/test/include,/usr/test/lib,其中lib目录下既有静态链接库libtest.a也有动态链接库libtest.so。

  • 编译:-I(大写的i)选项

不管是动态链接库还是静态链接库,在编译的时候只需要知道其头文件就可, 即只需要知道相关方法的声明。

gcc -c -I /usr/test/include test.c [-o test.o]
  • 链接:-L选项,-l(L的小写)选项
gcc -L /usr/test/lib  -ltest test.o -o test

默认情况下,在/usr/test/lib 目录下寻找libtest.so动态链接库,若没有动态链接库,则寻找libtest.a静态链接库。若想链接时只用静态链接库,可用-static选项指定:

gcc -L /usr/test/lib -static -ltest test.o -o test

注意:-L是指定库文件的搜索路径,-l(L的小写)用来指定库名,库文件通常为libxxxx.a或libxxxx.so,去掉前面的lib和后缀即为库名。

头文件的编译时寻找顺序:

  • -I(i的大写)指定的路径
  • /usr/include

静态库的链接时寻找顺序:

  • -L指定的路径
  • 环境变量LIBRARY_PATH指定的静态库搜索路径
  •  /lib 、 /usr/lib 

动态库的链接时寻找顺序:

  • -L指定路径
  • 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  • 配置文件/etc/ld.so.conf中指定的动态库搜索路径
  • 默认的动态库搜索路径/lib 、/usr/lib

动态库运行时的搜索的顺序:

  • 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
  • 配置文件/etc/ld.so.conf中指定的动态库搜索路径
  • 默认的动态库搜索路径/lib 、/usr/lib

有关环境变量:
LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

6. 编写自己的库

假设有若干3源程序文件:test1.c,test2.c,test3.c和3个头文件:test1.h,test2.h,test3.h。[详细]

  • 建立静态库
gcc -c test1.c test2.c test3.c
ar c libtest.a tes1.o test2.o test3.o

先将各个源文件编译成二进制文件,再用ar命令生成静态库文件。[linux命令大全]

  • 建立动态库
gcc test1.c test2.c -fPIC -shared -o libtest.so

 [linux教程]

Posted on 2017-06-30 22:33  小小旅行商  阅读(319)  评论(0编辑  收藏  举报