Linux GCC编译原理

简介

GCC是GNU Compiler Collection也即GNU编译器家族的缩写。

简单编译

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

有上述源文件main.c,在其同目录下执行命令:

gcc main.c -o main

即可在同目录下得到名为main的可执行性文件.(不同的平台有不同的后缀).实际上,上述编译过程是分为四个阶段进行的,即:

  1. 预处理:Preprocessing
  2. 编译:Compilation
  3. 汇编:Assembly
  4. 连接:Linking
预处理
gcc -E main.c -o main.i

可以输出main.i文件,其中存储着main.c经预处理之后的代码.gcc的-E选项,可以让编译器在预处理后停止,并输出预处理的结果.在本例中,预处理结果就是将stdio.h文件中的内容插到main.c中了.

编译为汇编代码

预处理之后,可直接对生成的main.i文件编译,生成汇编代码:

gcc -S main.i -o main.s

gcc的-S选项,表示在程序编译期间,在生成汇编代码后停止,-o输出汇编代码文件.

汇编

对于汇编代码文件main.s,gas汇编器可以将其编译为目标文件:

gcc -c main.s -o main.o

gcc的-c选项,表示将汇编代码编译为目标文件.

连接

gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件.附加的目标文件包括静态连接库和动态连接库.对于上述示例中的main.o,可以将其与C标准库进行连接,最终生成可执行性文件.

gcc main.o -o main

多文件编译

通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用GCC能够很好地管理这边编译单元.假设有一个由test1.c和test2.c两个源文件组成地程序,为了对他们进行编译,并最终生成可执行程序test,可以使用下面这条命令:

gcc test1.c test2.c -o test

如果同时处理的文件不止一个,GCC仍然会按照预处理,编译和连接的过程依次进行.

检错

 gcc -pedantic main.c -o main

-pedantic编译选项能够帮助程序员发现一些不符合ANSI/ISO C标准的代码,但不是全部.

gcc -Wall main.c -o main

-Wall编译选项能够产生警告信息.

gcc -Werror main.c -o main

-Werror也会产生警告信息,并且会在产生警告的地方停止编译.

GCC编译选项

1) -c :指编译,不链接,生成目标文件“.o”。

2) -S :只编译,不汇编,生成汇编代码“.S”。

3) -E :只进行预编译/预处理,不做其他处理。

4) -o file:把输出文件输出到file里。

5) -g :在可执行程序中包含标准调试信息。

6) -v :打印出编译器内部编译各过程的命令行信息和编译器的版本。

7) -I dir :在头文件的搜索路径列表中添加dir目录

8) -L dir :在库文件的搜索路径列表中添加dir目录

9) -static :连接静态库(静态库也可以用动态库链接方式链接)

10) -llibrary :连接名为library的库文件(显示指定需要链接的动态库文件)

11)-On :gcc可以对代码进行优化,它通过编译选项On来控制优化代码的生成,n是一个代表优化级别的整数,比较典型的范围为0变化到2或者3。

1) -ansi :支持符合ANSI标准的C程序

2) -pedantic :允许发出ANSI C标准所列出的全部警告信息

3) -pedantic-error :允许发出ANSI C标准所列出的全部错误信息

4) -w :关闭所有警告

5) -Wall :允许发出gcc提供的所有有用的报警信息

6) -werror :把所有的告警信息转化为错误信息,并在告警发生时终止编译过程

GCC生成动态库和静态库

  • 多个源文件/目标文件生成动态库

动态库在调用的时候,注意设置export LD_LIBRARY_PATH=$(pwd)

gcc -fPIC -shared xxx1.c xxx2.c xxx3.c -o libxxx.so 

gcc -fPIC -shared xxx1.o xxx2.o xxx3.o -o libxxx.so
  • 多个目标文件生成静态库

静态库只能由目标文件打包生成,不能由源文件直接得到。

ar -rc libxxx.a xxx1.o xxx2.o xxx3.o

库文件连接

开发软件时,完全不适用第三方函数库的情况是比较少的,通常来讲都是需要借助许多函数库的支持才能够完成相应的功能.从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(so lib dll)的集合.

Linux下的大多数函数都默认将头文件放到/user/include/目录下,而库文件则放到/user/lib/目录下.Windows所使用的库文件主要放在Visual Stido的目录下的include和lib,以及系统文件夹下.

但有的时候,我们要用的库不在这些目录下,所以GCC在编译的时候必须用自己的办法来查找所需要的头文件和库文件.

例如我们的程序test.c是在linux上使用c连接mysql,这个时候我们需要去mysql官网下载MySQL Connectors的C库,下载下来解压之后,有一个include文件夹,里面包含mysql connectors的头文件,还有一个lib文件夹,里面包含二进制so文件libmysqlclient.so.其中inclulde文件夹的路径是/usr/dev/mysql/include,lib文件夹是/usr/dev/mysql/lib。

静态库和动态库的比较
  • 静态库:静态库是在链接阶段被链接的,所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。
  • 动态库:动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。

链接静态库从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题:

系统空间被浪费:如果多个程序链接了同一个库,则每一个生成的可执行文件都会由一个库的副本,必然会浪费系统空间。

重新编译:一旦发现库中有bug,挽救起来就比较麻烦,必须一一把链接该库的程序找出来,然后重新编译。

动态库嵌入到可执行文件中后,不用担心系统上没有该库。动态库在程序运行时被链接,故程序的运行速度和链接静态库相比打折扣。

编译成可执行文件

首先我们要编译test.c为目标文件,需要执行:

gcc –c –I /usr/dev/mysql/include test.c –o test.o

-I dir  把指定的目录dir加到检索头文件的目录表前面,因此,gcc会优先检索“-I”选项指定的目录,然后再检索标准的系统头文件目录.

连接

最后我们把所有目标文件连接成可执行文件:

gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test

-lname  连接时从“-L”选项指定的目录和标准的库函数目录中检索指定的库函数libname.a

-L dir  把指定的目录dir加到供“-l”选项检索的目录表中。gcc将会优先检索“-L”选项指定的目录,然后再检索标准的系统库函数目录。

强制链接时使用静态链接库

默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static选项,强制使用静态链接库。

在/usr/dev/mysql/lib目录下有链接时所需要的库文件libmysqlclient.so和libmysqlclient.a,为了让GCC在链接时只用到静态链接库,可以使用下面的命令:

gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值