GCC编译过程和Linux的动静态库

GCC编译过程和Linux的动静态库

基于Centos 7

首先我们抛出一个问题:为什么我们可以在我们的Linux或Windows上运行我们的C/C++或者其他类型的开发呢?

因为在Windows下安装了vs这样的集成环境,Linux下安装了gcc这样的编译器,基于这样的环境我们才可以进行编译,但是更重要的是我们也下载了库文件和头文件。

编译型语言:安装开发包一定是下载安装的头文件和库文件。

Windows:

在这里插入图片描述

他会在你安装IDE型软件时下载到你的Windows中。

Linux:

在这里插入图片描述

C/C++程序执行时需要进行四个过程

1.预处理

1.1去注释

很简单就是将注释的内容删除

1.2头文件展开

就是将包含的头文件展开

1.3条件编译

举个例子:

在下载vs等类似软件时,我们可以看到有好几种版本,类似社区版和专业版。

在这里插入图片描述

答案是当然不要,我们是只要添加不同的条件进行控制编译就可以。这就是条件编译。

1.4宏替换

就是将定义的宏进行替换

我们可以使用 命令:gcc -E filename.c -o filename.i 将文件停留在只进行预处理的阶段。

filename.c->filename.i

在这里插入图片描述

我们可以看到就是这样进行上述四个操作。

2.编译

形成汇编代码

使用命令:gcc -S filename.c -o filename.s 将文件停留在进行编译的过程中。

filename.i->filename.s

在这里插入图片描述

3.汇编

将汇编文件形成可重定位二进制文件,简称为目标文件,在vs的环境下生成的后缀为.obj

使用命令为gcc -c filename.c -o filename.o 将文件停留在汇编的过程中。

filename.s->filename.o

在这里插入图片描述

由于是二进制文件,所以是乱码。

但可通过readelf -S 命令查看:

在这里插入图片描述

4.链接

虽然此时文件已经是二进制文件,但是还是不能执行,需要链接库文件才能实现。

如下:

hello程序调用了printf函数,它存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器(ld)就负责处理这种合并。结果就得到了hello文件,它是一个可执行目标文件(或者称为可执行文件),可以被加载到内存中,由系统执行。(链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件)。

**就使用gcc filename.c -o filename **即可

在这里插入图片描述

5.库文件

linux下编程c语言是使用C语言标准库。C语言的标准库定义了诸如printf函数的实现方法。

5.1库的种类

5.1.1动态库

对于默认的机器下,一般只会安装动态库,需要手动安装静态库。

Linux:.so后缀为动态库

Windows:.dll后缀为动态库

如libc.so.xxx lib是标准的意思,c是c语言,xxx是版本号

ldd:ldd用来打印或者查看程序运行所需的共享库(访问共享对象依赖关系)

因为动态库就是共享库,许多的程序都依赖动态库,如果动态库缺失会造成很多程序无法进行。

在这里插入图片描述

5.1.2静态库

编译器在使用静态库的时候,会将实现方法拷贝在目标可执行文件中。该程序以后就不依赖静态库。

Linux:.a后缀为静态库

Windows:.lib后缀为静态库

在编译器进行编译形成可执行文件时,默认先采用动态库链接,所以我们需要加上**-static**进行静态链接

在这里插入图片描述

5.1.3两者对比

a.1如果没有静态库,我们就要进行静态链接,行不行呢?答案是不行

a.2如果没有动态库,只有静态库,而且gcc可以找到,能不能编译成可执行文件呢?答案是可以的

-static本质:是改变优先级

a.3文件编译的时候不一定是纯的动态库或者静态库,而是混合的。

b.动静态库的优缺点:
动态库优点:共享库,节省资源(磁盘空间、内存空间、网络空间)

动态缺点:一旦缺失,会致使多个程序无法运行

静态库优点:不依赖库,程序可以正常运行。

静态库缺点:消费资源(磁盘空间、内存空间、网络空间)

b.动静态库的优缺点:
动态库优点:共享库,节省资源(磁盘空间、内存空间、网络空间)

动态缺点:一旦缺失,会致使多个程序无法运行

静态库优点:不依赖库,程序可以正常运行。

静态库缺点:消费资源(磁盘空间、内存空间、网络空间)

在这里插入图片描述