lib 与dll

(1)lib是编译时需要的,dll是运行时需要的。
如果要完成源代码的编译,有lib就够了。
如果也使动态连接的程序运行起来,有dll就够了。
在开发和调试阶段,当然最好都有。
(2)一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。
(3)在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

一般的LIB文件是“导入库”,用来提供给link.exe,作为链接DLL——也就是“动态链接库”的依据。里面记录了类似下面的信息:
调用函数xxx(),连接到x.dll的0xABCDEFGH地址。
早期的LIB,是“静态链接库”,也是用来提供给link.exe,作为链接代码用的。里面的记录如下:

调用xxx(),其代码是……;

DLL的LIB(导入库),不含可执行的具体代码(代码在DLL中)。而最早的LIB(静态链接库),里面含有代码。所以,可以看出来,如果一个函数被调用多次,使用DLL(动态链接技术),可以节省一些硬盘和内存空间!而用LIB(静态链接技术),每次调用,都会链接入相同的代码,造成一些空间上的浪费。不过它的好处是不需要进行一个“查找”工作(也就是找到LIB文件中说的DLL的“函数入口点”,就是例子里的0xABCDEFGH地址,可以获得更高的效率)。

dll的调用方式有静态和动态调用两种方式。
lib 用于静态调用和头文件*.h 结合使用。
如果你只有dll文件,又知道dll文件中函数的格式,也可以使用Loadlibrary ,GetAddress 函数来动态加载调用。

(一).静态调用其步骤如下: 
1.把你的youApp.DLL拷到你目标工程(需调用youApp.DLL的工程)的Debug目录下; 
2.把你的youApp.lib拷到你目标工程(需调用youApp.DLL的工程)目录下; 
3.把你的youApp.h(包含输出函数的定义)拷到你目标工程(需调用youApp.DLL的工程)目 
录下; 
4.打开你的目标工程选中工程,选择Visual   C++的Project主菜单的Settings菜单; 
5.执行第4步后,VC将会弹出一个对话框,在对话框的多页显示控件中选择Link页。然 
后在Object/library   modules输入框中输入:youApp.lib 
6.选择你的目标工程Head   Files加入:youApp.h文件; 
7.最后在你目标工程(*.cpp,需要调用DLL中的函数)中包含你的:#include   "youApp.h " 
注:youApp是你DLL的工程名。

 
2.动态调用: 
动态调用时只需做静态调用步骤1. 

HINSTANCE   hDllInst   =   LoadLibrary( "youApp.DLL "); 
if(hDllInst) 

typedef   DWORD   (WINAPI   *MYFUNC)(DWORD,DWORD); 
MYFUNC   youFuntionNameAlias   =   NULL;   //   youFuntionNameAlias   函数别名 
youFuntionNameAlias   =   (MYFUNC)GetProcAddress 
(hDllInst, "youFuntionName "); 
//   youFuntionName   在DLL中声明的函数名 
if(youFuntionNameAlias) 

youFuntionNameAlias(param1,param2); 

FreeLibrary(hDllInst); 

}

第一: 编译的全过程, 以windows平台为例.

先看看整个编译的过程, 为了防止概念过多,去掉预处理,汇编等繁杂的概念, 因为这些我们触碰不到, 我们关注的核心就两个,编译(compile), 连接(link):

compile ->  link

通过编译,能生成的东东有: .obj文件, lib文件. 注意.obj文件和lib都是源代码生成的符号,包含信息一致,在头脑里不要区分它们,就简单的认为它们都是一个东西.

编译的时候, 大家都是独立编译的, 所以只需要找到函数或者变量的声明 就可以。因此参与这个过程的,  只需要.h文件(没有.h的, 可以通过extern 声明, 也是没有任何问题的)

通过link, 把编译成成的.obj文件, lib文件的符号连接起来, 形成二进制文件(DLL 或者exe)

连接的时候, 这个过程务必要找到编译后的符号文件, 比如函数和变量的定义 。

对于编译生成的DLL, 这个会在运行的时候用到. DLL 包含的是二进制的地址信息, 所以, 如果我们需要用到DLL, 务必知晓其地址信息。 这个地址信息, 可以直接通过windows平台查找dll的方法(比如, 下文提到的DLL三种使用模式中的独立使用方式).  另外一种常见的方式是: 通过lib定位DLL的信息, 对应于下面的DLL + lib或者DLL + .h + lib的方式. 当然lib要参与连接生成exe或者dll, 而.h如果存在的话, 必定是参与compile. 这种方式, 正是上文提到的: 我们采用的库的方式.

第二:windows平台下的动态链接库和静态链接库 
但对一个项目而言,可以切分,比如将项目分为A模块,其它模块。

如果我们先将A模块编译成二进制的DLL,然后再和其他模块合并,这个时候,就称为动态链接;
如果我们现将A模块编译成lib文件, 然后在和其他模块合并,这个时候,成为静态链接;

接下来,我们关注什么是静态链接,什么是静态链接。

对于静态连接,已经没有任何可讲的地方了, 还记得吗,lib文件相当于obj文件, 我们如何用obj文件,就如何用lib文件,也许你真的明白obj文件的使用,但这里还是要让你重温一下:
如果有三个C源文件:a.c, b.c , c.c,及其配套的.h文件:a.h, b.h,c.h, 通过编译,将产生a.obj, b.obj, c.obj三个obj文件.

这里,如果a,b,c之间不存在相互引用, 根本不需要头文件参与进来编译的, 但是,如果,a用了b的变量或者函数,在编译a的时候,必须要一个头文件来声明所引用的函数(可以不必是b.h文件,甚至是x.h文件,但里面必须有用到变量或者函数的声明)。

当这三个文件编译之后,再进行连接,则肯定可以成功。

静态链接的道理跟obj文件的编译是一个道理,假如把b看做是静态库lib,b.h则是静态库所对应的lib文件. 当a.c需要用到b.c

中的函数来编译时, 它只需要b.h文件,生成a.obj, 最后a.obj和b.lib文件连接生成我们需要的二进制文件。


动态链接库,即有dll参与的库文件使用,也就是dll的使用方式,可以有以下几种:

1. dll独立使用

2. dll + lib

3. dll + lib + .h

在DLL独立使用的情况下:windows下会有一个loadLibray的机制,将生成的DLL二进制地址信息加入,直接调用,所以DLL既不需要编译,也不需要连接, 扔给exe文件就可以调用,有人称之为动态加载 。

在含有lib文件的情况下, 库函数的使用,是要参与连接的, 这就是传说中的静态加载 . 其原理如下:

此时的lib文件,跟上面静态链接不同,不再是所有的源文件的函数和变量内容,而是仅仅是DLL中函数或者变量的符号,通过lib的指引,其它的函数调用DLL库中的函数,轻而易举。

至于.h文件的作用,当然是参与编译了;如果源文件中用到dll的函数, 不声明为extern或者通过dll发布的头文件生命的话,是无法编译通过的。

一般而言,发布了lib文件, 最好发布一下头文件,不然怎么知道lib中带了什么函数呢?当然如果你是lib的制作者,你了解lib里面的蛛丝马迹,当然,你用个extern搞定这些lib中的函数和变量,也未尝不可。


OK,这里一句话可以做结Windows下的库调用:

.h参与compile, lib参与link, dll 参与excute

第三: Linux平台下的动态链接库和静态链接库

在静态链接技术上,两者五区别,中间的.o文件相当与.a静态文件, 跟Windows平台类似,动态连接技术上,两者存在区别:动态链接文件叫做share object, .so文件,但理论一致,只是,这个.so文件,包含的信息不同,相当于windows下dll + lib的信息, 也就是说, so文件,要参与连接, 也参与执行,但是, 可执行程序并不依赖于参与连接的so文件,可以是其它任何时间任何地点,只要接口相同的so文件。这点跟windows下的dll完全一样。

在gcc平台可以测试上面的原理。编译器所作的工作,各个平台也是有一些区别的。如果用gcc编译,会对其中的奥秘有更多的理解,这样会让你更多的思考利用vc和windows平台时,你没有考虑过的问题。


最后开篇的第三个问题没有解决:

stdio的引用方式是哪种: 应该是动态链接库, 但是加载的方式是静态的。

stdio库包含了dll(system32目录下), stdio.h, stdio.lib.

标准库大多是采用这样的方式. 动态的加载方式, 仅限于自己自导自演的游戏。开源库,标准库,都是动态链接库的静态加载。

猜你喜欢

转载自blog.csdn.net/liudongdong19/article/details/81428182
今日推荐