笔者一直以来都对mingw64下动态库和静态库链接的真正区别和用法存疑,于是做了一些测试,这篇文章记录了测试过程和测试结果,如果只想知道结果可以跳转到文章末尾

一、准备工作

首先准备三个测试文件

其中add.c最终会被编译会静态库或动态库,被测试文件main.c调用
使用如下命令构建静态库

gcc -c add.c -o add.o
ar rcs libadd.a add.o

得到静态库如下:

接着使用如下命令构建动态库

gcc -fPIC -shared add.c -o libadd.dll

得到动态库如下:

二、测试过程

1.当一个静态库和一个动态库重名,并且位于同一文件夹下,编译器优先链接哪一个

首先把五个文件放在同一路径下

已知在编译指令中,链接libadd.a 和链接libadd.dll都只需要加上以下参数

-ladd

也即这里静态库和动态库可以看做是重名的,于是我们先来测试当输入-ladd的时候,gcc会默认链接哪个库
输入指令:

gcc main.c -I ./ -L ./ -ladd -o normal_two_implicit

得到文件

文件名是为了对比实验方便而设置的,其中normal意味着正常状态,与后面要进行的反常测试相对应,two表示静态库和动态库同时位于同一文件夹下,与之后将某个库移走单独测试剩下的库相对应,implicit意为在链接命令中隐式指出库名称(即-l格式的指明方法),与之后显示给出库的全称的测试对应。
虽然现在得到了可执行文件,但是现在我们还无法判断默认链接的是哪一个库,于是继续进行测试
先把libadd.dll暂时移到其他文件夹里,只保留libadd.a,再键入同样的命令:

gcc main.c -I ./ -L ./ -ladd -o normal_a_implicit

得到文件

这里的exe一定链接的是静态库,而且和上一个exe大小完全相同,因此合理推测前一个exe也是链接了静态库,也即:当两种同名库同时存在于同一文件夹,并且使用-l格式参数隐式指出链接库名称时,gcc优先链接后缀为.a的库(为什么不说优先链接静态库?后续的测试会说明)
然后把libadd.a暂时移到其他文件夹里,只保留libadd.dll,再键入同样的命令:

gcc main.c -I ./ -L ./ -ladd -o normal_dll_implicit

得到文件

文件大小只有54KB,小于前两个,因此这是个链接了动态库的exe

因此得到结论:当一个静态库和一个动态库重名,并且位于同一文件夹下,编译器优先链接后缀.a的库

2.-static参数有什么用

之前一直以为,加了-static就是静态链接,做出来的exe一定就是那种完全可以移植的,但是经过测试以后我发现我大错特错
首先把libadd.a和libadd.dll放回原位

然后输入以下命令:

gcc -static main.c -I ./ -L ./ -ladd -o normal_two_implicit_static

得到:

文件大小为64KB,这说明不出所料地,编译器优先链接了静态库,这和-static关键字很搭,接下来把libadd.dll暂时移走,只留下libadd.a,输入以下命令

gcc -static main.c -I ./ -L ./ -ladd -o normal_a_implicit_static

得到

64KB,链接了静态库,依然在意料之中
这次移走libadd.a,只留下libadd.dll,然后输入以下命令

gcc -static main.c -I ./ -L ./ -ladd -o normal_dll_implicit_static

错误出现了:

错误信息为并没有找到库文件!这和我们的预设也一致,因为-static禁用了动态库,所以不再能找得到动态库dll
测试至此本可以结束,但是这里仍然存在一个疑问:我们到目前为止还没有通过显式的指出文件名来链接库,因为其结果似乎不用想都可以知道,那就是给出什么文件名就链接哪个文件,不可能出现重名的情况,这当然是对的,但是在-static关键字的加持下,似乎在另一个角度出现了有意思的现象
再一次把文件归位在一起

键入如下命令:

gcc -static main.c -I ./ -L ./ libadd.a -o normal_a_explicit_static

得到文件

没有问题
然后键入如下命令

gcc -static main.c -I ./ -L ./ libadd.dll -o normal_dll_explicit_static

根据之前的经验,我猜测:由于-static禁用了动态库链接的选项,那么这条命令应该也会失败并报错,但是奇怪的事情发生了,命令正常运行并且得到了正常的动态库链接exe(因为它的大小为54KB)

至此我们得到了第二个十分有用的结论:-static并不禁用动态链接,它只是禁用了采用隐式指明库名法(即以-l格式指明库名)时动态链接的选项,如果你愿意的话完全可以在有-static的情况下输入完整的动态库dll的全称来进行动态链接

3.编译器靠什么识别一个库时静态库还是动态库(后缀还是二进制内容)

这个疑问乍看起来有些多次一举:后缀为.a的就是静态库,后缀为.dll的就是动态库呀。
但是事实真的如此吗?我们完全可以通过修改后缀名而保持它们的二进制数据并不变化,修改以后真正的静态库后缀为.dll,而真正的动态库后缀为.a,。在这种情况下如果将.a链接进去,编译器会辨别出它实际上是个披着静态库外皮的动态库呢,还是会傻傻地将其当做静态库打包进exe?于是有了下面的测试:
修改后缀名的过程略去

经过修改后缀名,现在这里的.a才是真正的动态库,而.dll才是真正的静态库
键入以下命令:

gcc main.c -I ./ -L ./ -ladd -o unnormal_two_implicit

得到文件

文件只有54KB,这说明它实际上链接了动态库,也即现在的.a库,这与我们测试1中的结论也相同,即:当同名库同时存在时,隐式指明库名会默认优先链接.a库(这也是为什么前面不说优先链接静态库的原因,因为.a不一定是静态库,在本例中它是一个披着静态库后缀的动态库)
于是得到有用的第三条结论:编译器靠二进制内容识别静态库和动态库,而不会被其后缀名所迷惑

三、结论

1.当一个静态库和一个动态库重名,并且位于同一文件夹下,编译器优先链接后缀.a的库
2.-static并不禁用动态链接,它只是禁用了采用隐式指明库名法(即以-l格式指明库名)时动态链接的选项,如果你愿意的话完全可以在有-static的情况下输入完整的动态库dll的全称来进行动态链接
3.编译器靠二进制内容识别静态库和动态库,而不会被其后缀名所迷惑

下面以编程人员的角度,根据以上三条结论再导出出几条实用结论:

Q:当需要把一个dll链接进程序的时候该怎么做?
A:在不确定是否有重名库的情况下,建议直接在编译参数中显式给出库名的全称,如果确定没有重名静态库的话,可以考虑使用-l的参数指出dll的名称

Q:当需要进行静态编译,即把所有库打包放进exe以保证其良好的不受环境依赖性的时候该怎么做?
A:只加一条-static并不会完事大吉,建议仔细检查给出的库中不包含动态库,然后加上-static参数作为最终检查

Q:我要开发一个程序,程序运行时需要调用一些第三方动态库如opencvworld455.dll,但是我又希望我编译出的exe可以单独发布出去让其他人运行,可以做到把opencvworld455.dll静态链接到exe中吗?
A:不能这么做,动态库无法静态链接,这是库的二进制内容差异决定的,要发布依赖第三方dll的可执行文件exe,必须同时打包发布其依赖的第三方dll(有些商业软件为了保证在一些连基本dll环境如msvcr.dll都没有的机器上运行,甚至会将全部dll和exe一起打包发布)

四、注

1.本文省略了一些与主题相关性不高的测试过程,比如测试第一个问题,重名问题时,并没有给出显式指明库名的结果,以及第三个问题,编译器靠什么识别一个库时静态库还是动态库问题中,也没有给出加上-static之后的测试结果,另外仅凭文件大小就判断链接了静态库和动态库未免有些草率,这些问题都从某种程度上显得测试的逻辑性不够严密。但实际上笔者几乎做了一切可以想到的测试,并且通过移走dll再运行exe发现不能运行才判断其为动态链接产物,发现能运行才判断其为静态链接产物,这些测试结果由于结果显而易见和篇幅限制(懒)的缘故在文章中没有给出,感兴趣的读者可以自己试试
2.本文测试的平台为mingw64+windows10,结论并不一定适用于其他平台
3.如有错误,欢迎指正

mingw64下动态库和静态库链接的真正区别和用法(详细)相关推荐

  1. Linux下制作和使用静态库和动态库

    写在前面: ldd + 可执行文件 可以查看可执行文件所依赖的库 概述: Linux操作系统支持的函数库分为静态库和动态库,动态库又称共享库.linux系统有几个重要的目录存放相应的函数库,如/lib ...

  2. 关于VS2013下制作和使用静态库和动态库

    关于VS2013下制作和使用静态库和动态库 引言 什么是库:库是写好的现有的,成熟的,可以复用的代码. 所谓静态.动态是指链接.将一个程序编译成可执行程序的步骤: 静态库在链接阶段,会将汇编生成的目标 ...

  3. 关于VS环境下制作和使用静态库和动态库

    转载理由:虽然操作什么的很基础,不过作为初学还是很好的文章,手把手教学 关于VS2013下制作和使用静态库和动态库 引言 什么是库:库是写好的现有的,成熟的,可以复用的代码. 所谓静态.动态是指链接. ...

  4. Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库

    文件描述符 重定向 文件系统 软链接和硬链接 动态库和静态库 文件描述符 上面两个接口分别是c语言的fread接口和linux的read接口,当我们在使用的时,可能会有疑问,为什么linux的io接口 ...

  5. 结合CmakeList来更好地理解windows下的动态库和静态库

    动态库和静态库的输出 window下输出的静态库为.lib文件,用于包含所有的函数,以及函数的实现,以及其他的一些东西,所以文件较大:输出的动态库包含.lib文件和.dll文件,.lib文件主要包含接 ...

  6. Linux下的动态库和静态库

    什么是库? 在 Linux 开发时,我们经常会看到一些形如 xxx.so 的名称出现,其中 so 是 Shared Object 的缩写,即可以共享的目标文件,也就是我们所称为的动态链接库,和在 Wi ...

  7. Linux下用gcc生成静态库和动态库及练习使用OpenCV

    我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为 静态库和动态库两种.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而 ...

  8. Linux下动态库和静态库制作与调用

    Linux下动态库和静态库制作与调用 1.动态库和静态库简介   静态库是指在应用中,有一些公共代码需要反复使用,就把这些代码编译为"库"文件:在链接步骤中,连接器将从库文件取得所 ...

  9. Linux-动态链接与静态链接对比(动态库和静态库)

    博客转载自:Linux-动态链接与静态链接对比 一.库的基础概念: 在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于wi ...

最新文章

  1. 网站自动登录功能的设计[转]
  2. TensorFlow从1到2(十三)图片风格迁移
  3. mac下在eclipse中怎样清除/切换svn
  4. JAVAWEB 一一 SpringMVC(注解)
  5. Micronaut for Spring支持Spring Boot应用以Micronaut形式运行
  6. mvc的视图中显示DataTable的方法
  7. 数据可视化及其重要性:Python
  8. 前端学习(1963)vue之电商管理系统电商系统之控制级联选择框的选择范围
  9. lstm中look_back的大小选择_LSTM 扫盲:长短期记忆网络解读及其 PyTorch 应用实现
  10. lintcode 中等题:Divide Two Integers 两个数的除法
  11. html table 向上滚动,决策报表的表格自动向上滚动问题
  12. html5 tooltips,纯js轻量级tooltips工具提示插件
  13. Unity官方中文网站
  14. Python~FTP文件下载
  15. 图像拼接算法(zz)
  16. 八进制数转十进制计算机计算器,八进制转十进制计算器
  17. 命令行LOGO在线生成网站
  18. 台式计算机的打印机端口,打印机端口设置,高手教你如何搞定电脑打印机端口设置...
  19. 【181029】FreeEIM 飞鸽传书仿QQ即时通讯软件VC++源代码
  20. fedora 25 安装字体

热门文章

  1. 肾囊肿如何有效预防?
  2. python 项目结构规范
  3. [财务][数据化分析][帆软]报表设计-第一张报表
  4. 绝地求生pubg崩溃,无法开始游戏怎么办
  5. curl发送post请求带Json参数、发送get请求
  6. View.inflate 和 inflater.inflate 区别
  7. 使用AI修复高压缩失真的老视频~~以“机修钳工”教育片为例
  8. 网络驱动->PHY驱动调试
  9. IDEA——开发工具快捷键
  10. html单元格颜色填充颜色,PPT表格中的单元格怎么填充颜色