<UG.NX二次开发> 之 非科班的编译基础原理补课

4 阅读3分钟

动态/静态链接库详解

VS调用链接库常见问题及解决

头文件:编译时使用

Error C3861:找不到标识符

  • C/C++ >> 附加包含目录 >> 写上头文件路径

.lib文件:链接时使用

Error LINK2019:无法解析的外部符号

  • 链接器 >> 常规 >> 附加库目录 >> lib文件所在路径
  • 链接器 >> 输入 >> 附加依赖项 >> lib文件的名字 (注意配置属性时 debug/release x86/x64 和项目相匹配)

.dll文件:运行时使用

缺失仍然可以编译通过

程序执行时弹窗报错:由于找不到.dll,无法继续执行代码,重新安装程序可能会解决此问题

  • 将dll文件复制到exe文件同一目录下

  • 或者:项目 >> 属性 >> 配置属性 >> 环境 PATH=%PATH%;E:\Qt\5.15.2\msvc2019_64\bin; 不同路径用分号隔开,记得加%PATH%不然无法调用系统SDK

动态/静态链接原理

静态连接

编译时需要:头文件.h + 链接库.lib

运行时不依赖外部文件

编译链接阶段,编译器会把你用到的静态库.lib文件中的代码完整复制到最终生成的可执行文件.exe里。.lib文件和最终生产的.exe文件都包含了函数的具体实现。

这种 .lib文件是完整的静态库,包含了库的所有二进制代码、数据、符号表等。比如你用 Visual Studio 链接 libcmt.lib(C 标准库的静态版本),链接器会把标准库中 printfmalloc 等函数的代码直接拷贝到你的 .exe 中。

动态链接

编译时需要:头文件.h + 链接库.lib

运行时依赖库对应的.dll文件

编译链接阶段,编译器不复制库代码,只在可执行文件中记录 “依赖的动态库.dll名称 + 函数入口地址”;程序运行时才加载对应的.dll文件,调用其中的代码。

这种 .lib`是**导入库,也叫 “链接库”,它不包含函数的具体实现,只包含:

  • 动态库.dll的名称;
  • 库中导出函数 / 变量的名称和地址偏移;

作用是告诉链接器:“我的代码在 XXX.dll 里,你只需要记录这个依赖,运行时再找它”。比如你链接 msvcrt.lib(C 标准库的动态导入库),最终 .exe 会依赖 msvcrt.dll,运行时系统会加载这个 DLL 并执行其中的函数。

那和直接给出函数定义的文件(如.cpp文件)有什么区别,链接库有什么用? .cpp文件是源代码文本文件,库文件是编译后的二进制代码,比如你可以调用Windows的API,但是不能看到其源代码一样。

链接库中的lib文件只要用到,则整个lib文件的内容都放进了.exe文件中,那它是被编译进去还是链接的时候连接进去的呢? 是在链接的时候将lib链接到目标代码中。

库代码分发方式

  • 源代码:头文件.h + 源文件.cpp
  • 动态链接库:头文件.h + lib文件 + dll文件
  • 静态链接库:头文件 .h + lib文件

综合对比

维度静态链接动态链接
核心文件静态库 .lib(含完整代码)导入库 .lib + 动态库 .dll
代码整合时机编译链接阶段程序运行阶段
可执行文件体积大(包含库代码)小(仅记录依赖)
运行依赖无(独立运行)依赖.dll(缺失则报错)
库更新方式重新编译链接整个程序直接替换.dll即可
内存 / 磁盘占用多个程序重复占用多个程序共享.dll,节省资源