【Linux】Linux编译器(gcc,g++)与动静态链接库

发布于:2024-06-28 ⋅ 阅读:(23) ⋅ 点赞:(0)

对于一个 C 程序,从源文件到形成可执行程序一共要进行四步:预处理、编译、汇编、链接 。

接下来,我们用 gcc 分别演示这四个过程。

一、预处理(进行宏替换)

预处理中,需要完成头文件的展开、宏替换、去注释、条件编译等工作。

gcc -E file.c -o file.i

-E 选项:让 gcc 进行程序的预处理,预处理之后就停下来。
-o 选项:-o 选项紧跟目标生成文件的名称。gcc -o file.i file.c 或者上方的指令都是可以的。

可以发现 头文件 #include <stdio.h> 被展开,宏被替换,注释被删除 

二、编译 

当程序在编译时,gcc 会检查代码是否有语法错误,了解代码基本内容,检查无误就会把代码翻译为汇编语言

gcc -S file.i -o file.s

 -S 选项:让 gcc 进行程序的编译,编译之后就停下来。

我们也可以接着从上次预编译后的文件继续执行。

 三、汇编

汇编之后会把汇编语言转换为二进制文件。

由于机器只认识二进制文件,所以这一步就是把人能看懂的文件,翻译成机器能看懂的,就是 生成机器可识别代码

gcc -c file.s -o test.o

 -c 选项:让 gcc 进行程序的汇编,汇编之后就停下来。

注意: 二进制文件不可执行

四、链接 

链接过程就是将程序和对应的库链接起来,编译器会自动识别语言。

gcc file.o -o myfile

生成可执行文件,完成链接

五、动静态链接库

1.什么是库

首先清楚一点,我们写的代码里面经常会用库函数,这些调用接口的方式是我们写的,但是这些库函数的底层实现不是我们写的,而这中间就有一个调用库的过程。

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而 没有定义函数的实现,那么,是在哪里实“printf”函数的呢?

最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到 系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函 数“printf”了,而这也就是链接的作用

在上面我们写的my代码就用到了库,我们可以用ldd指令来查看,该程序都用了哪些库

在 /usr/include/ 中我们就能看到系统的内置的头文件,我们通过头文件就可以根据库函数,找到对应的方法,从而链接到正确的库:

静态库:lib....a....

动态库:   lib....so.... 

我们的可执行程序,包括指令,都依赖于库。

2.库的链接方式

库的连接方式一共有两种:动态链接(默认)和静态链接

用 file 指令查看 test 文件的类型:

3.动态库与静态库  

动态库:

动态库也可以说是共享库。动态库在链接的时候,并没有把相应的库文件加载到可执行程序中,而是在运行的时候,拷贝库中所需代码的地址到可执行程序中相关的位置。
通过这种链接方式,使用动态库就大大节省了内存损耗。
但是这也带来一个缺点,由于动态库链接时,是通过地址链接的。所以只要我们的动态库缺失,程序便无法运行

静态库:

静态库则是在编译链接时,把库文件的代码全部加载到可执行程序中。
这种链接方式导致生成文件体积庞大。若文件数目一多,到时候内存就会被占用很多。
但是这也有一个优点,这样就使得程序不依赖于库了。即使库出了问题,也没事,因为我们已经将代码加载到程序中了。 

抽象一点的比喻就是,我是一个学生想使用电脑,动态库是网吧,我们可以去网吧使用电脑但电脑是公共的不能带走,静态库就是自己买了一台电脑自己随意使用。

一般只默认装了动态库,我们需要自己装静态库

 C语言:

yum install -y glibc-static

C++:

yum install -y libstdc++-static

 可以看到使用了静态库的程序非常大

 文件类型也变成静态链接

4.debug和release

1、debug版本:程序本身会被加入更多的调试信息,以便于进行调试。
2、release版本:不会添加任何调试信息,是不可调试的。

在我们平时生成的默认程序是 release版本是不可调试的,生成debug版本需要加上-g选项

debug版本包含了更多的调试信息

5.gcc/g++ 选项汇总

-E :只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S :编译到汇编语言不进行汇编和链接
-c :编译到目标代码
-o :文件输出到文件
-static :此选项对生成的文件采用静态链接
-g :生成调试信息。GNU 调试器可利用该信息
-shared :此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库
-O0 :不做任何优化,这是默认的编译选项。
-O1 : 对程序做部分编译优化
-O2 :是比O1更高级的选项,进行更多的优化
-O3 :比O2更进一步的进行优化
-w :不生成任何警告信息
-Wall: 生成所有警告信息

g++安装 

yum install gcc-c++

c++的代码需要用g++编译