动态库dll、静态库

这篇博客详细介绍了C++中的动态库(.dll)和静态库的区别和使用方法,包括.o文件、.exe文件、.a静态库文件、.dll动态库文件的查看与创建。动态库分为隐式链接和显式链接,并通过g++示例说明了两者区别。此外,还探讨了Qt框架中动态库的创建和使用,以及动态库的加载和链接过程。
摘要由CSDN通过智能技术生成

.dll动态库

dll必须和exe一个目录

---------------------------------------------------------------------

.o文件 (windows)

file a.o 使用file命令, 可以查看 一个文件的格式

g++ 32bit 生成的.o文件: Intel 80386 COFF object file, no line number info, not stripped, 7 sections, symbol offset=0x3d2, 36 symbols

g++ 32bit 生成的.o文件: Intel amd64 COFF object file, no line number info, not stripped, 11 sections, symbol offset=0x4d0, 47 symbols


.o文件, 都是COFF格式

查看.o文件内容

$GCC32/nm.exe -C main.o

.exe文件 (windows)

file a.exe

32bit的.exe文件: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows

64bit的.exe文件: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows


nm -C xx.exe 可以查看这个exe的内容

.a静态库文件

windows的静态库文件, 是以.a后缀的; (也称为 .lib文件)
使用file xx.a, 会得到: current ar archive 存档文件

你有a.h b.ha.cpp b.cpp; (当然, 他们里面是没有main函数的)

然后你编译得到了: a.ob.o

ar -rcs external_lib.a a.o b.o 表示: 将a.o 和 b.o 打包成一个 .a的静态库文件


这个.a静态库文件, 他是对 很多的.o文件的 整合/合成!!!
即, .a 并不依赖于.o文件!!! 他是完全独立的, 他里面 有所有.o文件的内容!!!

故, 上面的: (external_lib.a文件大小) 肯定是大于> (a.o的文件大小 + b.o的文件大小)

使用

$GCC32 main.o external_lib.a -o main.exe: 将main.o 和 external_lib.a静态库文件, 一起链接生成一个main.exe

查看静态库文件

ar -t xx.a: 查看 这个静态库文件里, 有哪些.o文件 (即当初, 它是由哪些.o合成的) (他会列出来: a.o b.o)


ar -x xx.a 还原出来 所有的.o (即此时文件夹里, 多了a.ob.o)


nm -C xx.a 查看这个.a里面的 所有的内容 (全局数据/函数/类定义)

nm -C xx.a:

external0.o:
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata$zzz
00000000 t .text
00000000 T Func0() ' 全局函数 LL Func0(){ return 123;} '
0000000f T Func1()
0000001e T Func2()
0000002d T Foo::Foo() ' 类的构造函数 '
0000002d T Foo::Foo() ' 类的构造函数 '
00000000 D My_data0 ' long long My_data0 = 123; (这里并没有展示123) '
00000008 D My_data1 ' long long My_data1 = 123; '
00000010 D My_data2 ' long long My_data1 = 123; '

external1.o: ' 说明, 这个xx.a 是由 (external0.o 和 external1.o) 两个.o文件组成的) '
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata$zzz
00000000 t .text




nm -g xx.a: 和-C差不多, 但-g输出的是 (符号名称) 而不是你定义的名称

qt使用静态库

.pro文件里: LIBS += "./external/external_lib.a"

qt使用.o文件

比如说, 上面的external_lib.a = external0.o + external1.o
OBJECTS += "./external/external0.o"
OBJECTS += "./external/external1.o"

其实这种方式, 和上面的 (使用静态库), 本质上是差不多的

.dll动态库文件

$GCC32/g++ external0.o -shared -o external.dll -Wl,--output-def,external.def,--out-implib,external.a

  • 根据external0.o (目标文件) 将他写成cpp也可以, 生成一个external.dll动态库 和 一个external.def 和 一个external.a

  • g++.exe "main.o" "./external.dll 或 external.a" -o main.exe 执行exe, 发现一切正常
    但是, 如果你此时将(dll)给删除掉, 再执行exe, 就会报错!!!
    错误信息为: main.exe: error while loading shared libraries: ?: cannot open shared object file: No such file or directory

    也说明一个事情: 假如你要更新dll, (前提是不能修改.h文件), 你只需要去修改dll的cpp源文件 然后重新编译得到新的dll;
    将新的dll, 覆盖掉 当前这个dll; 即可 完全不需修改main.exe

  • 比如, 你 同时 打开了两个main.exe, 你去输出 dll里的data, func, 你会发现, 这两个main.exe里, 他们的dll里的东西, 地址是相同的
    但是, 这个地址, 是虚拟地址, 而虚拟地址 每一个exe程序 都是一个独立的虚拟地址, 其实他们的物理地址 并不是一样的!!!
    比如, dll里有个全局变量data, 那么, 这两个main.exe里的 这个data, 是毫无相关的!!! 并不是同一个内存!!!

32位dll: PE32 executable (DLL) (console) Intel 80386, for MS Windows
64位dll: PE32+ executable (DLL) (console) x86-64, for MS Windows

.def文件

这个文件, 倒是可有可无

EXPORTS
    Data0 @1 DATA		' LL Data 0 '
    Data1 @2 DATA
    _Z5Func0v @3		' LL Func0(); '
    _Z5Func1v @4
    _ZN3FooC1Ev @5		' Foo() 构造 '
    _ZN3FooC2Ev @6

.a/.lib静态库文件

使用动态库, 有一种方式: (隐式使用)
他是: 在链接时 (即生成exe)时, 链接.lib静态库文件, 也称为: dll的 导入库文件

这个.a/.lib, 有两种:

  • (广义上的静态库文件, `即与dll相对应的)
  • (在生成dll时, 也可以产生一个.lib文件, 他称为: 动态库dll的 导入库文件)

.lib的这两种形式, 他的file xx.lib 都是 current ar archive形式
本质上讲, 从文件格式内容来讲, 这两种lib, 其实是一样的
虽然类型是相同的, 但是 你使用ar.exe来查看.lib里的内容, 其实这两种.lib 是不一样的!!!


__declspec( dllexport)

在生成dl (含有: data, func, class)l时, 写不写这个, 都是可以的
即生成的 .lib .dll, 都是一样的

链接.lib文件

$GCC32/g++.exe "./main.cpp" "./dir/external.lib" -o "./main.exe"
(dll 和 exe是同个目录) 但(lib在哪里随意); 此时是可以的

但是, 只要(dll 和 exe) 不在同个目录, 就会报错


其实, 有没有lib文件, 都是可以的
比如: main.cpp, main.exe.; 而libexternal.dll../ (没有lib文件)
$GCC32/g++.exe "./main.cpp" -L"../" -l"external" -o "./main.exe" 此时 (链接是成功了), 即exe生成了
但是, 你执行main.exe 就报错了!!! 因为: dll 和 exe, 不在同一个目录!!!

-L"../" -l"external", 这个链接, 只是在生成exe的阶段 确保 可以找到../libexternal.dll
但是, 等到执行exe时, 他还是找的: ./libexternal.dll


ar -t查看动态库的lib文件:
d00001.o
d00002.o
d00003.o
d00004.o
每一个.o, 对应于dll的一个(data/func)

-------------------------------------------------------------

动态库

我们的源码, 经过 编译后, 产生.dll文件; 他是二进制文件, 不可以单独运行, 需要和其调用者一同运行.

在生成dll时, 通常还会有一个.lib文件, 即一个DLL, 应该是有: 一个.dll 一个.lib
这个.lib, 不是 (静态库文件), 虽然后缀名称相同, 但没有关联
这个.lib, 称为: DLL的 导出库文件, 里面存储了 .dll文件里 函数/类的 (名称和地址)
当使用 (DLL的 隐式使用方式)时, exe会将 这个.lib文件的内容, 复制到 exe文件里, 这样, exe在运行时 就知道.dll里 函数的地址了

分类

从DLL的结构上划分, 分为两类

  • non-MFC DLL, 也称为( Win32 DLL)
    他是用 标准的C语言编写的 (注意, 不是c++), 其函数 自然是 标准的C函数 (不支持重载)
  • MFC DLL
    即里面可以使用MFC, 结构也与Win32 DLL不同, 他的里面 会有一个DLLMain()函数

如果不使用MFC, 自然选择Win32 DLL. 因为他的效率等 更好

使用DLL

exe要使用DLL里的东西, 就必须得知道 这些东西的内存地址, 这个过程 就称为: 链接

链接DLL的方式 (也就是: 使用DLL的方式), 有两种:

  • 隐式
  • 显式

DLL文件的位置, 必须放到 特定的位置上; 否则, exe找不到DLL, 怎么链接呢???
windows下的exe, 会在几个 默认的路径下 , 去找dll:

  • 当前exe文件目录
  • 进程的工作目录 API为: GetCurrentDirectory()
  • Windows系统目录 C:/windows/system32, API为: GetSystemDirectory()
  • Windows目录, C:/windows, API为: GetWindowsDirectory()
  • Path环境变量

隐式链接

开发阶段, 就要得到 DLL的链接信息也就是, .lib文件信息; 即在最终的exe里, 是存储有 DLL的链接信息的

在exe执行时, DLL会加载到内存里; 等exe结束, DLL会被释放

隐式链接使用方式: (导入DLL的 .lib文件

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值