catalog
.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.h
和 a.cpp b.cpp
; (当然, 他们里面是没有main函数的)
然后你编译得到了: a.o
和 b.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.o
和 b.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文件