目录
【基础】动态链接库/静态链接库的区别_叫我东方小巴黎的博客-CSDN博客_动态链接库和静态链接库的区别
Linux动静态库详解_GSX_MI的博客-CSDN博客_linux动态库后缀
动态链接库的显示加载和隐式加载的区别_y13156556538的博客-CSDN博客
VS生成自己的DLL并调用_aspiretop的博客-CSDN博客_vs生成dll
通过gcc编译,将一个.c源文件到可执行文件,要经过
预处理(.c->.i)
$ gcc -E main.c -o main.i
编译(.i->.s) (.s文件为一堆汇编指令)
$ gcc -S main.i
汇编(.s->.o) (汇编得到的.o为可重定位目标文件,包含二进制代码和数据)
$ gcc -c main.s
链接(.o->可执行)
$ gcc -o main.o
这四个步骤。
对于频繁用到的目标文件(.o),我们可以将其进行打包,打包后就成为一个库。在之后要使用这些目标文件时,只要链接库里面的目标文件即可。一个库就是一堆目标文件(.o)的集合,但其中不包含main函数。
其中,链接分为静态链接和动态链接两种。
(linux中静态链接库后缀通常为.a,动态链接库后缀通常为.so,这两种库通常存放在/usr/bin或/bin目录下;win中静态链接库后缀通常为.lib,动态链接库后缀通常为.dll)
静态链接
静态链接以一组可重定位目标文件和命令行参数作为输入,经过符号解析和重定位,输出一个完全链接的可加载和运行的可执行目标文件。
(静态库在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。调用静态库函数多少次,就复制多少次代码过去。)
优点:可移植性强;可独立运行,与库函数无关,可在任何环境中运行。
缺点:代码冗余,可执行文件体积大;如果所有使用的静态库发生改变,程序需要重新编译。
动态链接
动态链接方式下,函数定义在动态链接库(也称共享对象目标文件、共享库)中。在链接阶段,动态链接库只提供符号表和其他少量信息用于保证所有符号引用都有定义,使得编译能顺利通过;在运行过程中,动态链接库链接程序根据记录的共享对象的符号定义来加载动态链接库,以完成重定位。
(采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。在运行采用动态链接库生成的可执行文件时,GCC 编译器会将对应的动态链接库一同加载在内存中,由于可执行文件中事先记录了所需功能模块的位置信息,所以在现有动态链接库的支持下,也可以成功运行。)
优点:可执行文件体积小;动态库改动更方便,改动后对程序不用重新编译。
缺点:无法独立运行;可移植性差。
linux下使用动静态库编译成可执行程序
- $ gcc test.c -o test_d //动态库编译,test_d为生成的可执行文件名
- $ gcc test.c -o test_s -static //静态库编译,test_s为生成的可执行文件名
-
- // 通过ldd命令查看一个可执行程序所需依赖的库文件
- $ ldd test_d
- $ ldd test_s //静态库编译的是查看到不到依赖的库文件的,因为它已经编到可执行文件中了,不需要再依赖其他库文件了。
-
- // 通过file命令可以查看一个可执行文件是静态链接还是动态链接的
- $ file test_d
- $ file test_s
win中
.h文件包含了库函数声明
.dll文件为.o文件的集合。
.lib文件(这里的lib文件指导入库文件,而不是静态库文件,大小比静态库文件小很多。两者只是恰好使用了相同的后缀)提供地址符号表等信息,可以理解为用来存放.dll文件中各功能模块的位置信息,在加载时先从.lib文件中找到.dll文件中各个功能模块在机器代码中的位置。
win中动态库加载方式
可以通过两种方式加载,隐式链接(隐式加载、静态调用)和显示链接(显示加载、动态调用)。
隐式链接(静态调用)
隐式链接在程序开始执行时,将dll加载到内存中,需要用到.h、.lib、.dll文件。
默认加载到内存中,并始终占用内存。
显示链接(动态调用)
显示链接调用比较麻烦,但可以没有lib库,只需要用到.h、.dll文件。
只在加载时载入内存,用完时(即对该库引用计数为0时)立即释放。
显式和隐式只是对于代码编写时来说的,最后产生的可执行程序,不管是显式和隐式,都是用loadlibrary载入的。
我们大多数情况使用隐式链接比较方便。
可完全参考下面文献,进行动态库的生成和调用