`
chinamming
  • 浏览: 151336 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

zlib库剖析(2):编译及应用

 
阅读更多
1、编译zlib库
在Linux下编译比较简单,在源码包中的Makefile.in中有说明。要编译和测试,在命令行下输入./configure; make test,通常会生成静态库(.a)和共享库(.so,类似windows下面的.dll)。如果只想编译成静态库,用./configure --static。为了安装到/usr/local/lib/libz.*和/usr/local/include/zlib.h,运行make install,为了安装到$HOME而不是/usr/local,运行make install prefix=$HOME。
对Windows,使用win32/中的相应makefile或contrib/vstudio/中的相应Visual Studio工程文件来编译。对VMS,使用make_vms.com编译。直接用VS 2010打开contrib\vstudio\vc10\下的solution文件,运行"Build Solution,即可编译整个solution,包括zlibvc, miniunz, minizip, testzlib, testzlibdll, zlibstat。为了更好地理解编译过程,我们自己用VS 2010来创建编译工程,把x86版本的zlib编译成DLL动态库或LIB静态库。
打开VS 2010,使用Visual C++视图界面。创建一个Empty Project,Name为zlibvc,Location指向zlib-1.2.7\contrib\目录,去掉勾选“Create directory for solution”。完成后在contrib\libvc\下生成一个zlibvc solution,并有一个空的zlibvc project。
右项目zlibvc,选"Add--->Existing Item...",定位到zlib-1.2.7的根目录,选中所有源文件(.c和.h文件),添加到项目中来。把contrib\minizip\下的除miniunz.c和minizip.c的其他源文件也添加进来,这里包含读写zip文件的导出函数。
添加一个Resource文件zlibvc.rc,在这个资源文件添加一个Version资源,设置DLL的一些描述信息:
FileDescription: zlib data compression and ZIP file I/O library
FileVersion: 1.2.7
InternalName: zlib
LegalCopyright: (C) 1995-2012 Jean-loup Gailly & Mark Adler
OriginalFilename: zlib.dll
ProductName: ZLib.DLL
ProductVersion: 1.0.0.1
然后打开这个项目的属性,设置各个选项。
(1)General选项
Output Directory: x86\ZlibDll$(Configuration)\
Intermediate Directory: x86\ZlibDll$(Configuration)\Tmp\
Target Name: zlib127
Target Extension: .dll
Configuration Type: Dynamic Library (.dll)。这里可以设置编译成动态库还是静态库。
Character Set: Empty
(2)C/C++选项
Additional Include Directories: 添加..\..和..\masmx86,其余从parent继承。这里contrib\masmx86\下包含了函数longest_match()和inflate_fast()的Windows汇编实现,match686.asm和inffas32.asm。
Preprocessor Definitions: 添加WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_DLL;ASMV;ASMINF;其余从parent继承。这里ZLIB_DLL不是必须的,参看zconf.h。它会添加DLL优化标志,使DLL有一些性能优化。注意如果想编译成使用WINAPI/WINAPIV调用方式的DLL,则还需要添加ZLIB_WINAPI预处理宏(参看zconf.h)。我们使用默认的__stdcall调用方式。
Buffer Security Check: No (/GS-)
Program Database File Name: $(OutDir)
(3)Linker选项
Enable Incremental Linking: Yes (/INCREMENTAL)
Additional Dependencies: 添加..\masmx86\match686.obj和..\masmx86\inffas32.obj,即两个汇编文件编译成的目标文件,其余从parent继承。
(4)Resources选项
Preprocessor Definitions: 添加_DEGUG,其余从parent继承。
(5)Build Events选项
Pre-Build Event:Command Line中添加命令cd ..\masmx86和bld_ml32.bat,表示在编译源代码之前要先运行..\masmx86\bld_ml32.bat,以编译match686.asm和inffas32.asm。
右击项目zlibvc,运行"Build",即可在x86\ZlibDllDebug\下生成zlib127.dll,上面会显示DLL的版本1.0.1,及描述"zlib data compression and ZIP file I/O library"。右击zlib127.dll,查看属性--->版本,可以看到Version资源中的一些描述信息。如果没有模块定义文件,VS 2010生成DLL时,不会生成LIB静态库文件。我们需要手动添加def文件,通过"Add--->New Item...",新建一个模块定义文件zlibvc.def,内容参考contrib\vstudio\vc10\中的zlibvc.def,复制过来即可。def文件包含需要导出的所有函数列表。在项目Linker选项的Module Definition File中填写刚才定义的def文件".\zlibvc.def",然后重新编译即可生成LIB文件。注意如果在新建dll项目或空白项目时选择空白文件(即不让VS帮你生成),则一定要自已手动添加def文件,否则在生成dll时不会附带生成lib文件(除非我们直接把项目编译成lib文件)。
使用的时候把lib和dll以及h文件zlib.h, zconf.h导出即可。
2、应用zlib库
我们通过contrib\minizip\下的miniunz.c来使用编译好的zlib127.dll。在solution zlibvc下新建空项目miniunz,生成的三个工程文件在contrib\zlibvc\miniunz\下,可以把它们拷贝到上一级目录contrib\zlibvc\下,在solution中打开它。通过Add--->Existing Item...,添加contrib\minizip\miniunz.c到项目中,在项目属性的"Framework and References"中添加对项目zlibvc的引用,FullPath中会显示zlib127.dll的完整路径。设置各个选项。
(1)General选项
Output Directory: x86\MiniUnzip$(Configuration)\
Intermediate Directory: x86\MiniUnzip$(Configuration)\Tmp\
(2)C/C++选项
Additional Include Directories: 添加根目录..\..和目录..\minizip,其余从parent继承。根目录中有zlib.h和zconf.h,..\minizip中有miniunz的一系列源文件。
Preprocessor Definitions: 添加WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_DLL;_DEBUG;_CONSOLE; 其余从parent继承。如果前面编译的是WINAPI格式的DLL,则使用DLL时这里也
要添加ZLIB_WINAPI。
(3)Linker选项
Additional Dependencies: 添加x86\ZlibDllDebug\zlib127.lib; 其余从parent继承。zlib172.lib在链接器生成miniunz.exe时需要用到。
编译miniunz项目,即可生成miniunz.exe工具,这是一个简单的解压ZIP文件的命令行工具,还需要把zlib127.dll拷贝到miniunz.exe所在目录下,就可以使用了。这种使用zlib127.dll的方法没有对miniunz.c源码做任何改动,因为我们通过IDE添加了项目引用,在C/C++选项中添加了头文件的包含路径,在Linker中添加了导入库的引用。
3、独立使用ZLIB DLL
在开发DLL时,生成的.dll文件就是动态链接库,.lib是供程序开发用的导入库,.h文件包含了导出函数的声明。调用Dll中的导出函数有两种方法:
(1)装载期间动态加载

应用程序可像调用本地函数一样调用从其他Dll导出的函数(Windows API函数就是这样调用的)。装载期间链接必须使用DLL的导入库(.lib)文件,它为系统提供了加载这个Dll和定位Dll中的导出函数所需的信息。应用程序启动时由载入器(加载应用程序的组件)载入zlib127.dll文件。载入器如何知道要载入哪些Dll呢?这些信息记录在执行文件(PE文件)的idata节中。使用这种方法不用自己写代码显式加载DLL。

新建一个zlibtest空项目,将zlib127.dll, zlib127.lib, zlib.h, zconf.h拷贝到zlibtest目录下。在项目中通过"Add--->Existing Item..."添加这两个头文件。新建一个testzlib.cpp源文件,如下:

  1. #include<iostream>
  2. #include<stdlib.h>
  3. #include"zlib.h"
  4. #pragmacomment(lib,"zlib127")
  5. usingnamespacestd;
  6. #defineMaxBufferSize1024*10
  7. intmain(intargc,char*argv[])
  8. {
  9. inti;
  10. FILE*srcFile;
  11. FILE*tmpFile;
  12. FILE*destFile;
  13. unsignedlonglenSrc,lenTmp,lenDest;
  14. unsignedchar*bufferSrc=newunsignedchar[MaxBufferSize];
  15. unsignedchar*bufferTmp=newunsignedchar[MaxBufferSize];
  16. unsignedchar*bufferDest=newunsignedchar[MaxBufferSize];
  17. srcFile=fopen("src.txt","r");
  18. lenSrc=fread(bufferSrc,sizeof(char),MaxBufferSize-1,srcFile);
  19. cout<<"####Currentreadeddata:"<<endl;
  20. for(i=0;i<lenSrc;++i)//printthereadeddata
  21. {
  22. cout<<bufferSrc[i];
  23. }
  24. cout<<endl<<endl;
  25. //compressthereadeddata
  26. compress(bufferTmp,&lenTmp,bufferSrc,lenSrc);
  27. tmpFile=fopen("temp.txt","w");
  28. //writethecompresseddatatotempfile
  29. fwrite(bufferTmp,sizeof(char),lenTmp,tmpFile);
  30. cout<<"####Currentcompresseddata:"<<endl;
  31. for(i=0;i<lenTmp;++i)//printthecompresseddata
  32. {
  33. cout<<bufferTmp[i];
  34. }
  35. cout<<endl<<endl;
  36. //uncompressthedata
  37. uncompress(bufferDest,&lenDest,bufferTmp,lenTmp);
  38. destFile=fopen("dest.txt","w");
  39. //writetheuncompresseddata
  40. fwrite(bufferDest,sizeof(char),lenDest,destFile);
  41. cout<<"####Currentuncompresseddata:"<<endl;
  42. for(i=0;i<lenDest;++i)//printthecompresseddata
  43. {
  44. cout<<bufferDest[i];
  45. }
  46. cout<<endl<<endl;
  47. fclose(srcFile);
  48. fclose(tmpFile);
  49. fclose(destFile);
  50. delete[]bufferSrc;
  51. delete[]bufferTmp;
  52. delete[]bufferDest;
  53. returnEXIT_SUCCESS;
  54. }
编译后生成zlibtest.exe。发布软件时必须将该软件使用的Dll与主程序一起发布。zlibtest.exe和zlib127.dll放在同一个目录下。载入器加载Dll文件时,默认情况是在应用程序的当前目录下查找,如果找不到就到系统盘"\windows\system32"文件夹下查找,还找不到就按错误处理。
(2)运行期间动态加载(只需Dll文件即可)
运行期间动态加载是在程序运行过程中显式得加载Dll库,从中导出需要的函数。为了能够在运行期间动态导出函数,一般需要在创建Dll时建立一个DEF文件来指定要导出的函数,我们在前面已经做了这一步。
回到zlibtest工程,将程序修改为:

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<Windows.h>
  5. usingnamespacestd;
  6. #defineMaxBufferSize1024*10
  7. typedefint(*dll_compress)(unsignedchar*,unsignedlong*,constunsignedchar*,unsignedlong);
  8. typedefint(*dll_uncompress)(unsignedchar*,unsignedlong*,constunsignedchar*,unsignedlong);
  9. intmain(intargc,char*argv[])
  10. {
  11. //loaddll
  12. HMODULEhModule=::LoadLibrary(TEXT("zlib127.dll"));
  13. if(hModule==NULL)//loadfailed
  14. {
  15. cout<<"Can'tloadzlibdll!"<<endl;
  16. return1;
  17. }
  18. //gettheexportedfunctionaddress
  19. dll_compresscompress=(dll_compress)::GetProcAddress(hModule,"compress");
  20. if(compress==NULL)
  21. {
  22. cout<<"Can'tgetfunctioncompressfromdll!"<<endl;
  23. return1;
  24. }
  25. dll_uncompressuncompress=(dll_uncompress)::GetProcAddress(hModule,"uncompress");
  26. if(uncompress==NULL)
  27. {
  28. cout<<"Can'tgetfunctionuncompressfromdll!"<<endl;
  29. return1;
  30. }
  31. inti;
  32. FILE*srcFile;
  33. FILE*tmpFile;
  34. FILE*destFile;
  35. unsignedlonglenSrc,lenTmp,lenDest;
  36. unsignedchar*bufferSrc=newunsignedchar[MaxBufferSize];
  37. unsignedchar*bufferTmp=newunsignedchar[MaxBufferSize];
  38. unsignedchar*bufferDest=newunsignedchar[MaxBufferSize];
  39. srcFile=fopen("src.txt","r");
  40. lenSrc=fread(bufferSrc,sizeof(char),MaxBufferSize-1,srcFile);
  41. cout<<"####Currentreadeddata:"<<endl;
  42. for(i=0;i<lenSrc;++i)//printthereadeddata
  43. {
  44. cout<<bufferSrc[i];
  45. }
  46. cout<<endl<<endl;
  47. //compressthereadeddata
  48. compress(bufferTmp,&lenTmp,bufferSrc,lenSrc);
  49. tmpFile=fopen("temp.txt","w");
  50. //writethecompresseddatatotempfile
  51. fwrite(bufferTmp,sizeof(char),lenTmp,tmpFile);
  52. cout<<"####Currentcompresseddata:"<<endl;
  53. for(i=0;i<lenTmp;++i)//printthecompresseddata
  54. {
  55. cout<<bufferTmp[i];
  56. }
  57. cout<<endl<<endl;
  58. //uncompressthedata
  59. uncompress(bufferDest,&lenDest,bufferTmp,lenTmp);
  60. destFile=fopen("dest.txt","w");
  61. //writetheuncompresseddata
  62. fwrite(bufferDest,sizeof(char),lenDest,destFile);
  63. cout<<"####Currentuncompresseddata:"<<endl;
  64. for(i=0;i<lenDest;++i)//printthecompresseddata
  65. {
  66. cout<<bufferDest[i];
  67. }
  68. cout<<endl<<endl;
  69. fclose(srcFile);
  70. fclose(tmpFile);
  71. fclose(destFile);
  72. delete[]bufferSrc;
  73. delete[]bufferTmp;
  74. delete[]bufferDest;
  75. ::FreeLibrary(hModule);//freethedlllibrary
  76. returnEXIT_SUCCESS;
  77. }
这里只需要一个zlib127.dll即可,无需头文件。包含头文件Windows.h,使用其LoadLibrary、GetProcAddress、FreeLibrary等Win32 API函数来加载Dll,获取导出函数,释放Dll。
注意这里Dll二进制文件中的导出函数名没有改变,因为在zlib.h实现中加了extern "C"修饰导出函数名,表示在C++代码中仍然使用C中的函数命名方式。如果Dll实现时没有加extern "C",则表示使用C++命名方式,Dll中的导出函数名会改变,添加修饰名称,这也是C++函数重载机制得以实现的一个技术支持。打开VS 2010命令行窗口,使用VS 2010附带工具dumpbin可以查看Dll中的导出函数名。用dumpbin /EXPORTS zlib127.dll可查看这个dll所有导出的函数名(可以看到名称没有改变)。在调用GetProcAddress时应该使用查看到的函数名称,否则GetProcAddress会返回空值,这点特别要注意。
动态链接库虽然一定程度上实现了黑盒复用,但仍存在着诸多不足,主要有下面几点。
* Dll节省了编译期的时间,但相应延长了运行期的时间,因为在使用Dll的导出函数时,不但要加载Dll,而且程序将会在模块间跳转,降低了cache的命中率。
* 若采用隐式调用,仍然需要.h、.lib、.dll文件(三件套),并不能有效支持模块的更新。
* 显式调用(即只使用Dll)虽然很好地支持模块的更新,但却不能导出类和变量。
* Dll不支持C++ Template。
二进制级别的代码复用相比源码级别的复用已经有了很大的进步,但在二进制级别的代码复用中,Dll显得太古老。想真正完美实现跨平台、跨语言的黑盒复用,采用COM才是正确的选择。
4、处理zip, gzip(.gz), .tar.gz(.tgz)文件
在contrib和test目录中有相应实现例子。contrib\minizip\中的minizip.c/miniunz.c实现压缩、解压ZIP文件。test\minigzip.c实现压缩、解压gzip文件(用nmake运行win32\下的Makefile.msc可编译它)。不同于zip格式,gzip格式(.gz)只用于压缩单个文件。有多个文件时,通常先将它们合并成一个tar文件,再用gzip进行压缩。contrib\untgz\untgz.c实现一次性解压.tar.gz(.tgz)文件。
分享到:
评论

相关推荐

    已经编译好的zlib的库lib(带源码)

    Zlib是一个广泛使用的开源压缩库,它提供了数据压缩和解压缩功能,被广泛应用于网络传输、文件存储等领域。这个资源包含已经编译好的zlib库lib以及源代码,方便开发者在自己的项目中直接使用或者进行二次开发。 1. ...

    【QGIS跨平台编译】之【zlib跨平台编译】:MacOS环境下编译成果(支撑QGIS跨平台编译,以及二次研发)

    在MacOS环境下,基于Qt Creator进行编译的zlib开源库。包含有头文件include、库文件dylib等,提供了Debug、Release版本。 当前采用的版本为zlib-1.2.12,如果下载者,需要其他版本的zlib,请在评论区留言。

    zlib库包集合

    zlib是一个开源的压缩库,由Jean-loup Gailly和Mark Adler开发,广泛应用于数据压缩和解压缩操作,尤其在软件开发和网络传输中非常常见。这个压缩包包含了多个zlib版本,从zlib1.1.4到zlib1.2.8,涵盖了多个迭代的...

    【QGIS跨平台编译】之【zlib跨平台编译】:Windows环境下编译成果(支撑QGIS跨平台编译,以及二次研发)

    在Windows环境下,基于Qt Creator进行编译的zlib开源库。包含有头文件include、库文件lib、动态库dll等,提供了Debug、Release版本。 当前采用的版本为zlib-1.2.12,如果下载者,需要其他版本的zlib,请在评论区留言...

    【QGIS跨平台编译】之【zlib跨平台编译】:源码及跨平台编译工程(支撑QGIS跨平台编译,以及二次研发)

    QGIS是一个开源的、跨平台的地理信息系统(GIS)软件,用于浏览、编辑和分析地理空间数据,提供了一套丰富的功能,包括地图制作、空间分析、数据管理等。QGIS可以在Windows、Mac OS和Linux等操作系统上运行。 QGIS的...

    zlib源代码以及编译好的win32动态库静态库

    总之,zlib作为一款强大的压缩库,其源代码和预编译的Win32库为开发者提供了便利,使得在Windows平台上实现数据压缩和解压缩功能变得简单易行。无论是在网络通信、文件存储还是其他领域,zlib都是一个不可或缺的工具...

    zlib 64位库

    **zlib 64位库详解** zlib是一个开源、跨平台的压缩和解压缩库,广泛用于数据压缩,尤其在软件开发中扮演着重要角色。它提供了多种压缩算法,如Deflate,使得数据能够在存储和传输时占用更少的空间。在64位操作系统...

    编译好的zlib库和头文件

    在使用预编译的zlib库时,开发者需要确保库与应用程序的编译环境兼容,包括编译器版本、操作系统平台以及是否使用多线程等特性。同时,正确设置链接选项和包含路径,以确保程序能正确找到并使用zlib的头文件和库文件...

    【QGIS跨平台编译】之【zlib跨平台编译】:Linux环境下编译成果(支撑QGIS跨平台编译,以及二次研发)

    在Linux环境下,基于Qt Creator进行编译的zlib开源库。包含有头文件include、库文件so等,提供了Debug、Release版本。 当前采用的版本为zlib-1.2.12,如果下载者,需要其他版本的zlib,请在评论区留言。

    zlib_zlib_

    《深入理解zlib库及其在QT平台的应用》 zlib是一个开源的压缩库,由Jean-loup Gailly和Mark Adler共同开发,广泛应用于数据压缩和解压缩领域。它的核心功能是提供了一套高效的压缩算法,包括Deflate算法,使得...

    zlib源码以及lib、dll库

    在给定的压缩包文件中,包含了Zlib的源码和编译好的静态库(zlib.lib)以及动态链接库(zlib.dll)。 **Zlib源码分析:** Zlib的源代码提供了一个深入理解其内部工作原理的机会。源码通常包括压缩和解压缩的实现,...

    VC6专用zconf.h、zlib.dll、zlib.h、zlib.lib 解压缩GZIP

    标题中的"VC6专用zconf.h、zlib.dll、zlib.h、zlib.lib 解压缩GZIP"提及的是一个专为Visual C++ 6.0(简称VC6)编译环境设计的压缩库,用于处理GZIP格式的压缩数据。这个库的核心是zlib,一个开源的、跨平台的压缩...

    zlib 1.2.11 库demo

    2. **配置编译选项**:在项目属性中,需要指定额外的包含目录以找到zlib的头文件,同时链接器设置中加入zlib的库文件路径。 3. **代码示例**:以下是一个简单的zlib压缩和解压缩数据的C++示例: ```cpp #include ...

    libRTMP去除OPENSSL和zlib

    7. **编译与配置**:在实际应用中,开发者需要按照特定的步骤和配置来编译libRTMP,以确保其在没有OPENSSL和zlib的情况下仍能正常工作。 8. **安全与性能权衡**:去掉加密库可能会降低安全性,因为没有加密的数据更...

    aapt(linux)+zlib库

    3. **安全分析**:对APK进行逆向工程时,分析aapt和zlib的使用可以帮助理解应用的内部工作原理和数据结构。 综上所述,aapt和zlib是Android生态系统中的基础组件,它们共同作用于资源处理和数据压缩,对于理解和...

    curl-7.60.0+openssl-1.1.0f+zlib-1.2.11 DLL编译包

    curl-7.60.0+openssl-1.1.0f+zlib-1.2.11 DLL编译包,就是将curl库与openssl和zlib这两个关键组件打包为DLL格式,以便于Windows应用程序的集成和使用。 openssl是一个强大的安全套接字层密码库,包含各种主要的密码...

    zlib1.1.4源码

    在标签中,“控件”意味着zlib可以作为应用程序的一部分,提供压缩和解压缩功能。“源码”代表我们可以查看和修改zlib的实现,这对于学习、调试或定制功能至关重要。“统计计数”可能指的是zlib在压缩过程中使用的...

    zlib源文件

    zlib是一个开源的压缩库,由Jean-loup Gailly和Mark Adler开发,它提供了一种通用的无损数据压缩和解压缩功能,广泛应用于各种操作系统和应用程序中。zlib库不仅支持常见的DEFLATE压缩算法,还提供了多种接口供...

    mtk android 编译常见错误

    ### MTK Android 编译常见错误及解决方案 在编译 MTK Android 源码时,开发者经常会遇到一些常见的编译错误。这些错误通常与环境配置、依赖库安装不完整等因素有关。以下是一些常见的编译错误及其解决方法: #### ...

    win 7 64上编译 Hadoop 2.7.3 源码

    7. **安装zlib Headers**:安装zlib Headers(如果需要编译zlib的原生代码绑定)。 #### 三、下载Hadoop源码 访问Apache Hadoop官网(http://hadoop.apache.org/),选择稳定版本Hadoop 2.7.3进行下载。下载完成后...

Global site tag (gtag.js) - Google Analytics