`
Jatula
  • 浏览: 278422 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Windows动态库与Linux共享对象比较

阅读更多

摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理。但不同操作系统的动态库由于格式不同,在需要不同操作系统调用时需要进行动态库程序移植。本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Linux上的方法和经验。

  关键词:动态链接库 Linux编程 程序移植

  1 引言

  动态库(Dynamic Link Library abbr,DLL)技术是程序设计中经常采用的技术。其目的减少程序的大小,节省空间,提高效率,具有很高的灵活性。采用动态库技术对于升级软件版本更加容易。与静态库(Static Link Library)不同,动态库里面的函数不是执行程序本身的一部分,而是根据执行需要按需载入,其执行代码可以同时在多个程序中共享。

  在Windows和Linux操作系统中,都可采用这种方式进行软件设计,但他们的调用方式以及程序编制方式不尽相同。本文首先分析了在这两种操作系统中通常采用的动态库调用方法以及程序编制方式,然后分析比较了这两种方式的不同之处,最后根据实际移植程序经验,介绍了将VC++编制的Windows动态库移植到Linux下的方法。


  2 动态库技术 

  2.1 Windows动态库技术

  动态链接库是实现Windows应用程序共享资源、节省内存空间、提高使用效率的一个重要技术手段。常见的动态库包含外部函数和资源,也有一些动态库只包含资源,如Windows字体资源文件,称之为资源动态链接库。通常动态库以.dll,.drv、.fon等作为后缀。相应的windows静态库通常以.lib结尾,Windows自己就将一些主要的系统功能以动态库模块的形式实现。

  Windows动态库在运行时被系统加载到进程的虚拟空间中,使用从调用进程的虚拟地址空间分配的内存,成为调用进程的一部分。DLL也只能被该进程的线程所访问。DLL的句柄可以被调用进程使用;调用进程的句柄可以被DLL使用。DLL模块中包含各种导出函数,用于向外界提供服务。DLL可以有自己的数据段,但没有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关,可以通过DLL来实现混合语言编程。DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。 

  根据调用方式的不同,对动态库的调用可分为静态调用方式和动态调用方式。

 


  (1)静态调用,也称为隐式调用,由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码(Windows系统负责对DLL调用次数的计数),调用方式简单,能够满足通常的要求。通常采用的调用方式是把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,想使用DLL中的函数时,只须在源文件中声明一下。 LIB文件包含了每一个DLL导出函数的符号名和可选择的标识号以及DLL文件名,不含有实际的代码。Lib文件包含的信息进入到生成的应用程序中,被调用的DLL文件会在应用程序加载时同时加载在到内存中。

  (2)动态调用,即显式调用方式,是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,比较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。在Windows系统中,与动态库调用有关的函数包括:

  ①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。 

  ②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。


  ③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。 

  在windows中创建动态库也非常方便和简单。在Visual C++中,可以创建不用MFC而直接用C语言写的DLL程序,也可以创建基于MFC类库的DLL程序。每一个DLL必须有一个入口点,在VC++中,DllMain是一个缺省的入口函数。DllMain负责初始化(Initialization)和结束(Termination)工作。动态库输出函数也有两种约定,分别是基于调用约定和名字修饰约定。DLL程序定义的函数分为内部函数和导出函数,动态库导出的函数供其它程序模块调用。通常可以有下面几种方法导出函数:


  ①采用模块定义文件的EXPORT部分指定要输入的函数或者变量。

  ②使用MFC提供的修饰符号_declspec(dllexport)。

  ③以命令行方式,采用/EXPORT命令行输出有关函数。 

  在windows动态库中,有时需要编写模块定义文件(.DEF),它是用于描述DLL属性的模块语句组成的文本文件。

  2.2 Linux共享对象技术

  在Linux操作系统中,采用了很多共享对象技术(Shared Object),虽然它和Windows里的动态库相对应,但它并不称为动态库。相应的共享对象文件以.so作为后缀,为了方便,在本文中,对该概念不进行专门区分。Linux系统的/lib以及标准图形界面的/usr/X11R6/lib等目录里面,就有许多以so结尾的共享对象。同样,在Linux下,也有静态函数库这种调用方式,相应的后缀以.a结束。Linux采用该共享对象技术以方便程序间共享,节省程序占有空间,增加程序的可扩展性和灵活性。Linux还可以通过LD-PRELOAD变量让开发人员可以使用自己的程序库中的模块来替换系统模块。

  同Windows系统一样,在Linux中创建和使用动态库是比较容易的事情,在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序就是动态链接库。通常这样的程序以so为后缀,在Linux动态库程序设计过程中,通常流程是编写用户的接口文件,通常是.h文件,编写实际的函数文件,以.c或.cpp为后缀,再编写makefile文件。对于较小的动态库程序可以不用如此,但这样设计使程序更加合理。

  编译生成动态连接库后,进而可以在程序中进行调用。在Linux中,可以采用多种调用方式,同Windows的系统目录(..\system32等)一样,可以将动态库文件拷贝到/lib目录或者在/lib目录里面建立符号连接,以便所有用户使用。下面介绍Linux调用动态库经常使用的函数,但在使用动态库时,源程序必须包含dlfcn.h头文件,该文件定义调用动态链接库的函数的原型。

  (1)_打开动态链接库:dlopen,函数原型void *dlopen (const char *filename, int flag); 网管u家bitscn.net

  dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

  (2)取函数执行地址:dlsym,函数原型为: void *dlsym(void *handle, char *symbol);

  dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。

  (3)关闭动态链接库:dlclose ,函数原型为: int dlclose (void *handle);

  dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。 (4)动态库错误函数:dlerror,函数原型为: const char *dlerror(void); 当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

  在取到函数执行地址后,就可以在动态库的使用程序里面根据动态库提供的函数接口声明调用动态库里面的函数。在编写调用动态库的程序的makefile文件时,需要加入编译选项-rdynamic和-ldl。


  除了采用这种方式编写和调用动态库之外,Linux操作系统也提供了一种更为方便的动态库调用方式,也方便了其它程序调用,这种方式与Windows系统的隐式链接类似。其动态库命名方式为“lib*.so.*”。在这个命名方式中,第一个*表示动态链接库的库名,第二个*通常表示该动态库的版本号,也可以没有版本号。在这种调用方式中,需要维护动态链接库的配置文件/etc/ld.so.conf来让动态链接库为系统所使用,通常将动态链接库所在目录名追加到动态链接库配置文件中。如具有X window窗口系统发行版该文件中都具有/usr/X11R6/lib,它指向X window窗口系统的动态链接库所在目录。为了使动态链接库能为系统所共享,还需运行动态链接库的管理命令./sbin/ldconfig。在编译所引用的动态库时,可以在gcc采用 –l或-L选项或直接引用所需的动态链接库方式进行编译。在Linux里面,可以采用ldd命令来检查程序依赖共享库。

  3 两种系统动态库比较分析

  Windows和Linux采用动态链接库技术目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同,下面从以下几个方面进行阐述。

  (1)动态库程序编写,在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数作为初始化的人口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。Linux下的gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要到函数做特别声明,编写比较方便。

  (2)动态库编译,在windows系统下面,有方便的调试编译环境,通常不用自己去编写makefile文件,但在linux下面,需要自己动手去编写makefile文件,因此,必须掌握一定的makefile编写技巧,另外,通常Linux编译规则相对严格。

  (3)动态库调用方面,Windows和Linux对其下编制的动态库都可以采用显式调用或隐式调用,但具体的调用方式也不尽相同。

  (4)动态库输出函数查看,在Windows中,有许多工具和软件可以进行查看DLL中所输出的函数,例如命令行方式的dumpbin以及VC++工具中的DEPENDS程序。在Linux系统中通常采用nm来查看输出函数,也可以使用ldd查看程序隐式链接的共享对象文件。


  (5)对操作系统的依赖,这两种动态库运行依赖于各自的操作系统,不能跨平台使用。因此,对于实现相同功能的动态库,必须为两种不同的操作系统提供不同的动态库版本。


  4 动态库移植方法


  如果要编制在两个系统中都能使用的动态链接库,通常会先选择在Windows的VC++提供的调试环境中完成初始的开发,毕竟VC++提供的图形化编辑和调试界面比vi和gcc方便许多。完成测试之后,再进行动态库的程序移植。通常gcc默认的编译规则比VC++默认的编译规则严格,即使在VC++下面没有任何警告错误的程序在gcc调试中也会出现许多警告错误,可以在gcc中采用-w选项关闭警告错误。


  下面给出程序移植需要遵循的规则以及经验。


  (1)尽量不要改变原有动态库头文件的顺序。通常在C/C++语言中,头文件的顺序有相当的关系。另外虽然C/C++语言区分大小写,但在包含头文件时,Linux必须与头文件的大小写相同,因为ext2文件系统对文件名是大小写敏感,否则不能正确编译,而在Windows下面,头文件大小写可以正确编译。

  (2)不同系统独有的头文件。在Windows系统中,通常会包括windows.h头文件,如果调用底层的通信函数,则会包含winsock..h头文件。因此在移植到Linux系统时,要注释掉这些Windows系统独有的头文件以及一些windows系统的常量定义说明,增加Linux都底层通信的支持的头文件等。

  (3)数据类型。VC++具有许多独有的数据类型,如__int16,__int32,TRUE,SOCKET等,gcc编译器不支持它们。通常做法是需要将windows.h和basetypes.h中对这些数据进行定义的语句复制到一个头文件中,再在Linux中包含这个头文件。例如将套接字的类型为SOCKET改为int。


  (4)关键字。VC++中具有许多标准C中所没有采用的关键字,如BOOL,BYTE,DWORD,__asm等,通常在为了移植方便,尽量不使用它们,如果实在无法避免可以采用#ifdef 和#endif为LINUX和WINDOWS编写两个版本。 

  (5)函数原型的修改。通常如果采用标准的C/C++语言编写的动态库,基本上不用再重新编写函数,但对于系统调用函数,由于两种系统的区别,需要改变函数的调用方式等,如在Linux编制的网络通信动态库中,用close()函数代替windows操作系统下的closesocket()函数来关闭套接字。另外在Linux下没有文件句柄,要打开文件可用open和fopen函数,具体这两个函数的用法可参考文献[2]。


  (6)makefile的编写。在windows下面通常由VC++编译器来负责调试,但gcc需要自己动手编写makefile文件,也可以参照VC++生成的makefile文件。对于动态库移植,编译动态库时需要加入-shared选项。对于采用数学函数,如幂级数的程序,在调用动态库是,需要加入-lm。 

  (7)其它一些需要注意的地方


  ①程序设计结构分析,对于移植它人编写的动态库程序,程序结构分析是必不可少的步骤,通常在动态库程序中,不会包含界面等操作,所以相对容易一些。


  ②在Linux中,对文件或目录的权限分为拥有者、群组、其它。所以在存取文件时,要注意对文件是读还是写操作,如果是对文件进行写操作,要注意修改文件或目录的权限,否则无法对文件进行写。

  ③指针的使用,定义一个指针只给它分配四个字节的内存,如果要对指针所指向的变量赋值,必须用malloc函数为它分配内存或不把它定义为指针而定义为变量即可,这点在linux下面比windows编译严格。同样结构不能在函数中传值,如果要在函数中进行结构传值,必须把函数中的结构定义为结构指针。

  ④路径标识符,在Linux下是“/”,在Windows下是“\”,注意windows和Linux的对动态库搜索路径的不同。

  ⑤编程和调试技巧方面。对不同的调试环境有不同的调试技巧,在这里不多叙述。

  5 结束语

  本文系统分析了windows和Linux动态库实现和使用方式,从程序编写、编译、调用以及对操作系统依赖等方面综合分析比较了这两种调用方式的不同之处,根据实际程序移植经验,给出了将VC++编制的Windows动态库移植到Linux下的方法以及需要注意的问题,同时并给出了程序示例片断,实际在程序移植过程中,由于系统的设计等方面,可能移植起来需要注意的方面远比上面复杂,本文通过总结归纳进而为不同操作系统程序移植提供了有意的经验和技巧。

  参 考 文 献

  [1] David J.Kruglinski,Visual C++6.0技术内幕(第五版),希望图书创作室译。北京:北京希望电子出版社,1999.5.

  [2] 中科红旗软件技术有限公司 Linux/UNIX高级编程 清华大学出版社 2001.

  [3] Sandra Loosemore et.al. The GNU C Library Reference Manual,机械工业出版社,2000.8.

分享到:
评论

相关推荐

    深入分析Windows和Linux动态库应用异同 动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理。

    #### 三、Windows动态库向Linux移植 对于从Windows到Linux的动态库移植,主要涉及到以下几个步骤: 1. **源代码兼容性处理**:首先需要对源代码进行检查和调整,确保其符合Linux平台的编程规范。这可能包括但不...

    Visual C 编制的Windows动态库移植到Linux.pdf

    【Visual C++ 编制的Windows动态库移植到Linux】专题介绍 动态链接库(DLL)在Windows和Linux操作系统中都是实现代码复用的重要手段,但两者之间存在格式和调用方式的差异,使得直接移植变得复杂。这篇文章主要探讨...

    linux下动态库的建立和使用

    在Linux系统中,动态库是一种共享对象(Shared Object),以.so为后缀的文件。它们可以被多个程序共享,提高了系统的效率和灵活性。 首先,让我们了解一下动态库的优点。在Windows系统中,我们都知道有很多的动态...

    Linux动态函式库解析.pdf

    2. **易于升级和维护**:当动态函式库中的函数实现发生变化时,只需替换该动态库文件即可,而无需重新编译和链接所有依赖它的程序。 3. **节省内存资源**:多个进程可以共享同一个动态函式库的实例,从而减少物理...

    Windows和Linux动态链接库研究及应用.pdf

    【Linux共享对象技术】 在Linux操作系统中,动态链接库被称为共享对象(Shared Objects),通常以.so为扩展名。共享对象同样实现了代码和资源的共享,减少了内存消耗,提高了系统效率。与Windows DLL类似,共享对象...

    Linux静态库和动态库

    ### Linux静态库与动态库详解 #### 基本概念 **库的定义与作用**:库,实质上是预编译的代码集合,旨在提供重复使用的功能或服务,简化软件开发过程。无论是在Windows还是Linux平台,库的存在极大地提高了编程效率...

    windows和linux下生成动态库的cmake示例

    动态库(也称为DLLs在Windows上,共享对象或SOs在Linux上)是在程序运行时加载的代码库,而不是在编译时链接到可执行文件中。这种方式有助于节省磁盘空间和内存,因为多个程序可以共享同一份库的副本。 在Windows...

    在Delphi for Linux中应用共享对象库.pdf

    在Delphi for Linux中应用SO与在Delphi for Windows中应用DLL的异同,并通过剖析SO库文件的组成、SO库文件的函数重载、特殊编译指令、使用Delphi for Linux创建SO的编程规则、使用前的Linux系统设置,以及在Delphi ...

    Qt动态库 导出类

    动态库,也称为动态链接库(DLL),在Windows系统中是可执行代码的共享库,而在其他系统如Linux中,通常被称为共享对象(SO)。动态库在程序运行时被加载,而不是在编译时,这使得多个应用程序可以共享同一份库的...

    Linux和Window x64 Opencv 3.4.3所有动态库so和dll文件,以及jar包

    在本文中,我们将深入探讨与标题和描述相关的Linux和Windows x64环境下的OpenCV 3.4.3版本,特别是其动态库(so和dll文件)以及Java接口(jar包)。 首先,让我们了解一下`so`文件。在Linux系统中,`.so`文件是共享...

    C++创建调用静态动态库

    在Linux中,动态库的扩展名为`.so`(共享对象),在Windows中是`.dll`。创建C++动态库的步骤如下: 1. 同样,编写源代码,如`libfunc.cpp`。 2. 编译生成目标文件:`g++ -c -fpic libfunc.cpp`,这里添加`-fpic`...

    动态库全-实例.rar

    在Linux和macOS等Unix-like系统中,它们通常是.so(共享对象)或.dylib文件。这些库文件包含了可执行代码和数据,可供其他程序调用。在编程时,我们需要通过函数原型声明和链接器指示来告诉编译器我们的代码依赖哪些...

    loadlibrary:将Windows动态链接库移植到Linux

    1. **动态链接库(DLL)与共享对象库(SO)** Windows中的动态链接库是DLL格式,而Linux系统中对应的则是SO(Shared Object)文件。两者都是运行时加载代码和数据的机制,但文件扩展名和加载机制有所不同。 2. **`...

    一个动态库

    在Windows环境下,动态库通常以.dll文件形式存在,而在Linux或macOS等类Unix系统中,它们是.so(共享对象)或.dylib文件。"zlib-1.2.3.exe"可能是Windows上的一个安装程序,用于部署zlib库到用户的系统路径,使得...

    powerbuilder11.0动态库

    动态库文件通常有.DLL(Windows动态链接库)和.SO(Unix/Linux下的共享对象)格式。在PowerBuilder 11.0中,大部分动态库会是.DLL文件,因为它是Windows平台上的标准。这些库文件可能包括以下部分: 1. **数据窗口...

    windows移植linux文档

    Windows依赖于DLL动态链接库,而Linux采用.so共享对象。 2. **编译环境**:移植过程中需要将Windows下的Visual C++等编译工具转换为Linux下的GCC或Clang。这包括配置Makefile、头文件路径、链接器选项等,确保源...

    动态库使用文件

    在Windows系统中,动态库通常以`.dll`扩展名出现,而在Unix/Linux系统中则是`.so`(共享对象)文件。苹果的Mac OS X系统则使用`.dylib`格式。 **链接动态库** 链接动态库分为静态链接和动态链接两种方式。静态链接...

    snmp++/agent++(Linux+Windows)编译通过

    静态库将所有依赖项包含在一个单一文件中,而动态库则在运行时被加载,这有助于减少程序大小并允许多个程序共享相同的代码。 使用 SNMP++ 和 agent++ 库,开发者可以创建 SNMP 客户端应用,用于收集网络设备的状态...

    分析Windows和Linux动态库

    本篇文章将详细介绍Windows和Linux两大操作系统中动态库的特点和技术实现,并着重讨论如何将Visual C++编写的Windows动态库移植到Linux平台。 #### 二、动态库技术概述 ##### 2.1 Windows动态库技术 在Windows...

Global site tag (gtag.js) - Google Analytics