11.静态链接和动态链接

上一篇我们一笔带过了 静态链接 动态链接 ,这篇就主要讲讲这两个。

上篇我们讲到随着软件项目的复杂度越来越大,单兵作战已经越来越捉襟见肘了,大项目它不是一个人就能搞定的,更不可能把所有代码集成到一个文件里,所以 把项目分模块拆分是常见的做法 。有些公共的函数就放在一些公共的模块里,以便其他模块进行调用。最后代码写完后需要进行编译才能得到一个完整的项目,如果一个项目只有一个文件的话,直接 gcc 这个文件就搞定了,但是如果拆分了众多模块,模块之间又有相互调用,这得如何编译呀?

这可难不倒软件工程师们,即便项目再大,模块再多,都逃不过猿的手掌心。整个编译的过程是: 先将每个模块进行编译,那每个模块就会得到一个目标文件(*.o)。一般来说目标文件里面包含了这个模块的功能。然后将所有的目标文件都链接到一个文件中成为最终的可执行文件 。这也是目前所有大型项目的编译方式。

有同学可能发现在 linux 系统里面会有很多 *.a 或者 *.so 文件?为什么呢?这就引入了这篇文章的两个概念:静态链接和动态链接。

静态链接 指的是在编译时把这个程序所有依赖的库或者文件统统打入最后形成的可执行文件中,当这个程序运行起来后就不需要从其他地方加载各种功能库。

动态链接 指的是在编译时对于依赖的库根据自身的需要打入形成的可执行文件中,有些库不必打入最终的可执行文件中,因为这些没有进入可执行文件中的库可以在程序运行时从操作系统里面进行加载。

从历史的时间线来看, 先有静态链接,然后才有动态链接 。也就是说很久之前的编译都是静态链接,所有的东西都在一个可执行文件内,那为什么后来有了动态链接呢?这得继续说说静态链接和动态链接两者的特点。

静态链接

执行速度较快 :因为所需要的东西都在一个文件内,不需要再去寻找其他类库进行加载,所以速度相对动态链接而言较快。

浪费空间 :也因为所有的东西都在一个文件内,它所占的体积就增大不少。

更新困难 :每次更新代码都需要把所依赖的库进行重新链接。

动态编译

执行速度较慢 :因为把链接推迟到了程序运行时,所以每次执行程序都需要进行动态链接,速度相对静态链接较慢,大概慢上 5% 左右。

节省空间 :只需要编译自己的工程文件,体积相对小了不少。

更新方便 :每次更新代码只需要更新自己的工程文件,无需管依赖的库。

回到上面那个问题,*.a 文件是静态库,*.so 是动态库。linux 系统中存在这些静态库和动态库的原因就是为了让程序的编译更加便捷,直接从本地查找对应的库就行,同时也是为了让一些动态链接的程序能够运行起来,毕竟现在的程序所依赖的库是比较多的,而且很多都是底层的基础库,比如 glibc 等。

接下来我们来看看如何制作静态库和动态库。

制作静态库

先生成目标文件。假设现在有个 test.c 的文件需要制作成静态库,test.c 里面的代码是什么不重要。可以先用如下命令制作成目标文件:

gcc -c test.c -o test.o

然后根据目标文件创建静态库。使用 ar 命令根据目标文件创建出静态库 test.a

ar crv test.a test.o

如果有多个目标文件需要打包成一个静态库,可以参考如下命令:

ar crv test.a test1.o test2.o test3.o

命令格式为: ar crv [静态库名称] [目标文件1] [目标文件2]…

制作动态库

同样的,需要先生成目标文件。还是以 test.c 为例:

gcc -c test.c -o test.o

然后根据目标文件创建动态库:

gcc -shared -fPIC -o test.so test.o

欢迎关注公众号:哈扣。

哈扣
我还没有学会写个人说明!
上一篇

粉丝投稿:pipenv 让你的虚拟环境更加funny一点

你也可能喜欢

评论已经被关闭。

插入图片