ln -S libhello.so.1.0 libhello.so.1ln -S libhello.so.1 libhello.so使用库当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。
然而,对动态库而言,就不是这样。
动态库会在执行程序内留下一个标记,指明当程序执行时,首先必须载入这个库。
由于动态库节省空间,linUX下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。
现在假设有一个叫hello的程序开发包,它提供一个静态库libhello.a 一个动态库libhello.so,一个头文件hello.h,头文件中提供Sayhello()这个函数/* hello.h */void Sayhello();另外还有一些说明文档。
这一个典型的程序开发包结构1. 与动态库连接]linux默认的就是与动态库连接,下面这段程序testlib.c使用hello库中的Sayhello()函数/*testlib.c*/#i nclude#i ncludeint mai n(){Sayhello();return 0;}使用如下命令进行编译$gcc -C testlib.c -o testlib.o用如下命令连接:$gcc testlib.o -lhello -o testlib在连接时要注意,假设libhello.o和libhello.a都在缺省的库搜索路径下/usr/lib下,如果在3.动态库的路径问题为了让执行程序顺利找到动态库,有三种方法:(1) 把库拷贝到∕usr∕lib和/Iib目录下。
⑵在 LD_LIBRARY_PATH 环境变量中加上库所在路径。
例如动态库IibheIlo.so 在∕home∕ting/lib目录下,以 bash为例,使用命令:|$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ti ng/lib(3)修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。
这样,加入的目录下的所有库文件都可见、4.查看库中的符号有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。
库既可以是静态的也可以是动态的。
nm列出的符号有很多,常见的有三种,一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;一种是库中定义的函数,用T表示,这是最常见的;另外一种是所谓的弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。
例如,假设开发者希望知道上央提到的hello库中是否定义了 Printf():$nm libhello.so |grep Printf/* hello.c */#i ncludevoid Sayhello(){Prin tf("hello,world∖n");}用gcc编绎该文件,在编绎时可以使用任何全法的编绎参数,例如-g加入调试代码等:gcc -C hello.c -o hello.o1. 连接成静态库连接成静态库使用ar命令,其实ar是archive的意思$ar CqS libhello.a hello.o2. 连接成动态库生成动态库用gcc来完成,由于可能存在多个版本,因此通常指定版本号:$gcc -Shared -Wl,-s On ame,libhello.so.1 -o libhello.so.1.0 hello.o另外再建立两个符号连接:$ln -S libhello.so.1.0 libhello.so.1$ln -S libhello.so.1 libhello.so-Wl表示后面的参数也就是-Soname,libhello.so.1 直接传给连接器ld进行处理。
实际上,每-Wl表示后面的参数也就是-Soname,libhello.so.1 直接传给连接器ld进行处理。
实际上,每便会将Soname 嵌入连结中的二进制文件内,而不是它正在运行的实际文件名, 在程序执行期间,程序会查找拥有 Soname 名字的文件,而不是库的文件名,换句话说, Soname 是库的区分标志。
这样做的目的主要是允许系统中多个版本的库文件共存, 习惯上在命名库文件的时候通常与摘要:动态链接库技术实现和设计程序常用的技术,在 WindowS 和LinUX 系统中都有动态 库的概念,采用动态库可以有效的减少程序大小, 节省空间,提高效率,增加程序的可扩展性,便于模块化管理。
但不同操作系统的动态库由于格式 不同,在需要不同操作系统调用时需要进行动态库程序移植。
本文分析和比较了两种操作系统动态库技术,并给出了将 ViSUaI C++编制的动态库移植到 LinUX 上的方法和经验。
动态库(Dynamic Link Library abbr , DLL)技术是程序设计中经常采用的技术。
其目 的减少程序的大小,节省空间,提高效率,具有很高的灵活性。
采用动态库技术对于升级软件版本更加容易。
与静态库(StatiC Link Library )不同,动态库里面的函数不是执行程序本 身的一部分,而是根据执行需要按需载入,其执行代码可以同时在多个程序中共享。
在Windows 和LinUX 操作系统中,都可采用这种方式进行软件设计,但他们的调用方 式以及程序编制方式不尽相同。
本文首先分析了在这两种操作系统中通常采用的动态库调用 方法以及程序编制方式,然后分析比较了这两种方式的不同之处,最后根据实际移植程序经验,介绍了将 VC++编制的Windows 动态库移植到LinUX 下的方法。
2、动态库技术2.1 Windows 动态库技术动态链接库是实现 Windows 应用程序共享资源、节省内存空间、提高使用效率的一个 重要技术手段。
常见的动态库包含外部函数和资源,也有一些动态库只包含资源,如 Windows 字体资源文件,称之为资源动态链接库。
通常动态库以 .dll ,.drv 、.fon 等作为后缀。
相应的 Windows 静态库通常以」ib 结尾,Windows 自己就将一些主要的系统功能以动态库模块的形式实现。
Win dows 动态库在运行时被系统加载到进程的虚拟空间中,使用从调用进程的虚拟地 址空间分配的内存,成为调用进程的一部分。
DLL 也只能被该进程的线程所访问。
DLL 的句柄可以被调用进程使用;调用进程的句柄可以被 DLL使用。
DLL模块中包含各种导出函数,用于向外界提供服务。
DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关,可以通过DLL来实现混合语言编程。
DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。
根据调用方式的不同,对动态库的调用可分为静态调用方式和动态调用方式。
(1) 静态调用,也称为隐式调用,由编译系统完成对DLL的加载和应用程序结束时DLL 卸载的编码(Windows系统负责对DLL调用次数的计数),调用方式简单,能够满足通常的一要求。
通常采用的调用方式是把产生动态连接库时产生的丄IB文件加入到应用程序的工程中,想使用DLL中的函数时,只须在源文件中声明一下。
LIB文件包含了每一个 DLL导出函数的符号名和可选择的标识号以及DLL文件名,不含有实际的代码。
Lib文件包含的信息进入到生成的应用程序中,被调用的DLL文件会在应用程序加载时同时加载在到内存中。
(2) 动态调用,即显式调用方式,是由编程者用 API函数加载和卸载 DLL来达到调用DLL 的目的,比较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。
在Windows系统中,与动态库调用有关的函数包括:在Windows中创建动态库也非常方便和简单。
在ViSUaI C++中,可以创建不用 MFC而直接用C语言写的DLL程序,也可以创建基于 MFC类库的DLL程序。
每一个DLL必须有一个入口点,在VC++中,DIIMain是一个缺省的入口函数。
DllMain负责初始化(InitializatiOn)和结束(Termination)工作。
动态库输出函数也有两种约定,分别是基于调用约定和名字修饰约定。
DLL程序定义的函数分为内部函数和导出函数,动态库导出的函数供其它程序模块调用。
通常可以有下面几种方法导出函数:①采用模块定义文件的EXPoRT部分指定要输入的函数或者变量。
②使用MFC提供的修饰符号_declspec(dllexport)。
③以命令行方式,采用/EXPORT命令行输出有关函数。
在Windows动态库中,有时需要编写模块定义文件(.DEF),它是用于描述 DLL属性的模块语句组成的文本文件。
2.2 LinUX共享对象技术在LinUX操作系统中,采用了很多共享对象技术( Shared ObjeCt ),虽然它和 Windows 里的动态库相对应,但它并不称为动态库。
相应的共享对象文件以.so作为后缀,为了方便,在本文中,对该概念不进行专门区分。
LinUX系统的/Iib以及标准图形界面的∕usr∕X11R6∕lib 等目录里面,就有许多以so结尾的共享对象。
同样,在LinUX下,也有静态函数库这种调用方式,相应的后缀以.a结束。
LinUX采用该共享对象技术以方便程序间共享,节省程序占有空间,增加程序的可扩展性和灵活性。
LinUX还可以通过LD-PRELOAD变量让开发人员可以使用自己的程序库中的模块来替换系统模块。
同Windows系统一样,在 LinUX中创建和使用动态库是比较容易的事情,在编译函数库源程序时加上-Shared选项即可,这样所生成的执行程序就是动态链接库。
通常这样的程序以so为后缀,在LinUX动态库程序设计过程中,通常流程是编写用户的接口文件,通常是.h文件,编写实际的函数文件,以.c或.cpp为后缀,再编写 makefile文件。
对于较小的动态库程序可以不用如此,但这样设计使程序更加合理。
编译生成动态连接库后,进而可以在程序中进行调用。
在LinUX中,可以采用多种调用方式,同 Windows的系统目录(..∖system32 等)一样,可以将动态库文件拷贝到/Iib目录或者在/lib目录里面建立符号连接,以便所有用户使用。
下面介绍LinUX调用动态库经常使用的函数,但在使用动态库时,源程序必须包含dlfcn.h头文件,该文件定义调用动态链接库的函数的原型。
(1) _ 打开动态链接库:dlopen,函数原型 void *dlopen (const Char *filename, int flag);dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。