VC++编译libpng

时间:2023-02-14 07:40:04

目录

第1章简介    1

第2章 Visual C++6.0    2

2.1 打开项目    2

2.2 编译宏    3

2.2.1 小结    5

第3章 Visual C++2010    6

3.1 打开项目    6

3.2 编译宏    6

3.2.1 PNG_USE_DLL    6

3.2.2 Z_SOLO    7

3.3 自定义编译    8

3.4 自定义环境变量    8

3.4.1 定义    9

3.4.2 使用    9

第1章简介

libpng是一个读写 .png 文件的 C 函数库,其下载网址如下:

http://sourceforge.net/projects/libpng/files

本文对libpng自带的Visual C++项目进行剖析。

第2章 Visual C++6.0

2.1 打开项目

版本1.0.63至版本1.4.16的libpng带有Visual C++6.0的项目。本章以版本1.4.12进行说明。假定其存放目录为V:\libpng\v1.4.12,如下图所示:

VC++编译libpng

VC++6.0的工作区文件位于V:\libpng\v1.4.12\projects\visualc6\libpng.dsw。首先使用记事本打开这个文件,其内容节选如下:

VC++编译libpng

也就是说libpng.dsw包含了项目zlib.dsp,后者的存放路径为V:\libpng\v1.4.12\projects\visualc6\..\..\..\zlib\projects\visualc6\zlib.dsp,即V:\libpng\zlib\projects\visualc6\zlib.dsp。

zlib也是一个开源的C函数库,其版本1.2.2、1.2.3、1.2.4带有Visual C++6.0的项目。这里,把版本1.2.3的zlib复制到V:\libpng\zlib,其目录结构如下图所示:

VC++编译libpng

现在,可以使用VC++6.0打开V:\libpng\v1.4.12\projects\visualc6\libpng.dsw了。

2.2 编译宏

项目libpng有5个配置项,如下图所示:

VC++编译libpng

"Win32 DLL Release"生成Release版的动态库;

"Win32 DLL Debug"生成Debug版的动态库,用于调试程序;

"Win32 DLL VB"生成供非C语言(如:VB6.0)调用的动态库;

"Win32 LIB Release"生成Release版的静态库;

"Win32 LIB Debug"生成Debug版的静态库,用于调试程序。

"Win32 DLL Release"和"Win32 DLL Debug"定义了宏PNG_BUILD_DLL

"Win32 DLL VB"定义了宏PNG_BUILD_DLL,PNGAPI=__stdcall,PNG_NO_MODULEDEF

"Win32 LIB Release"和"Win32 LIB Debug"没有定义特殊的宏。

这些宏都有什么含义呢?

先看看libpng的一个接口函数定义:

PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));

宏PNG_EXPORT有两份定义,最终形式是一致的即:

#define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol

展开宏PNG_EXPORT和PNGARG,函数png_set_expand的声明如下:

PNG_IMPEXP void PNGAPI png_set_expand(png_structp png_ptr);

PNGAPI默认为 __cdecl,"Win32 DLL VB"配置项里强制规定它为__stdcall。因为VB6.0只能调用__stdcall的函数。

接下来的关键是PNG_IMPEXP,它有三份定义:

//第1份定义("Win32 DLL Release"和"Win32 DLL Debug")

#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF)

# define PNG_IMPEXP

#endif

//第2份定义("Win32 LIB Release"和"Win32 LIB Debug")

# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \

0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */)

# define PNG_IMPEXP

# endif

//第3份定义"Win32 DLL VB"

# ifndef PNG_IMPEXP

# ifdef PNG_BUILD_DLL

# define PNG_IMPEXP __declspec(dllexport)

# else

# define PNG_IMPEXP __declspec(dllimport)

# endif

# endif

也就是说:选中配置"Win32 DLL VB"函数png_set_expand的声明如下:

__declspec(dllexport) void __stdcall png_set_expand(png_structp png_ptr);

否则函数png_set_expand的声明如下:

void __cdecl png_set_expand(png_structp png_ptr);

项目pngtest的"Win32 DLL Release"和"Win32 DLL Debug"用到了libpng的动态库,它们都定义了宏PNG_DLL。此时函数png_set_expand的声明如下:

__declspec(dllimport) void __cdecl png_set_expand(png_structp png_ptr);

2.2.1 小结

1、PNGAPI规定了导出函数的调用约定,默认为__cdecl,可强制改为__stdcall;

2、编译生成libpng动态库时,请定义宏PNG_BUILD_DLL;

3、如果使用.def文件,请不要定义宏PNG_NO_MODULEDEF,导出函数前没有__declspec(dllexport),编译器通过.def文件自动导出函数;pngwin.def文件在"Win32 DLL VB"下是被排除编译的,如下图所示。因为没有使用.def文件,因此需要定义宏PNG_NO_MODULEDEF,给导出函数增加__declspec(dllexport)修饰符;

VC++编译libpng

4、客户端程序要使用libpng动态库,请定义宏PNG_DLL,它会给导出函数前增加__declspec(dllimport)修饰符。

第3章 Visual C++2010

3.1 打开项目

版本1.4.12至版本1.6.18的libpng带有Visual C++2010的项目。本章以版本1.6.18进行说明。假定其存放目录为V:\libpng\v1.6.18,如下图所示:

VC++编译libpng

使用vc2010打开V:\libpng\v1.6.18\projects\vstudio\vstudio.sln

3.2 编译宏

3.2.1 PNG_USE_DLL

libpng没有定义什么特殊的宏。客户端程序pngstest、pngunknown、pngvalid在使用libpng动态库时,定义了宏PNG_USE_DLL。

现在简单了,只要记住宏PNG_USE_DLL即可。问题是:libpng是如何简化这个问题的?

首先看pngpriv.h,这是libpng内部使用的头文件。

#ifndef PNG_BUILD_DLL

#ifdef DLL_EXPORT

#else

#ifdef _WINDLL

#define PNG_BUILD_DLL

#else

#endif

#endif

#endif

#ifndef PNG_IMPEXP

#ifdef PNG_BUILD_DLL

#define PNG_IMPEXP PNG_DLL_EXPORT

#else

#define PNG_IMPEXP

#endif

#endif

当编译生成libpng动态库时,宏_WINDLL被定义。上面的代码将定义PNG_BUILD_DLL,并定义PNG_IMPEXP为PNG_DLL_EXPORT,即__declspec(dllexport);

当编译生成libpng静态库时,宏PNG_BUILD_DLL不会被定义,因此PNG_IMPEXP会被定义为空。

这里有必要说明一下宏_WINDLL,在VC++6.0里它的含义是:是否使用MFC共享库,使用了就会定义它,未使用就不会定义它。所以,这里用_WINDLL是不兼容VC++6.0的,为了兼容VC++6.0应该把_WINDLL更改为_USERDLL。

再来看看客户端程序,它会包含png.h,后者会包含pngconf.h。下面的代码节选自pngconf.h

#ifndef PNG_IMPEXP

# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)

/* This forces use of a DLL, disallowing static linking */

# define PNG_IMPEXP PNG_DLL_IMPORT

# endif

# ifndef PNG_IMPEXP

# define PNG_IMPEXP

# endif

#endif

很简单:定义PNG_USE_DLL时,PNG_IMPEXP为PNG_DLL_IMPORT即__declspec(dllimport);未定义PNG_USE_DLL时,PNG_IMPEXP为空。

3.2.2 Z_SOLO

编译zlib时用到了宏Z_SOLO。它的含义是对zlib进行裁剪。zlib被裁剪后,以下函数不会被实现:

compress,compress2,compressBound,gzFile,gz_error,gz_intmax,gz_strwinerror,gzbuffer,gzclearerr,gzclose,gzclose_r,gzclose_w,gzdirect,gzdopen,gzeof,gzerror,gzflush,gzgetc,gzgetc_,gzgets,gzoffset,gzoffset64,gzopen,gzopen64,gzopen_w,gzprintf,gzputc,gzputs,gzread,gzrewind,gzseek,gzseek64,gzsetparams,gztell,gztell64,gzungetc,gzvprintf,gzwrite,uncompress,zcalloc,zcfree

简而言之就是libpng用不了那么多的zlib函数,编译时对zlib进行了裁剪。

3.3 自定义编译

libpng依赖于pnglibconf。pnglibconf没有任何文件,编译时它做了什么?

它其实就做了一件事儿——复制文件。如下图所示:

VC++编译libpng

编译pnglibconf时将执行自定义编译。上图里就是执行如下命令

copy ..\..\..\scripts\pnglibconf.h.prebuilt ..\..\..\pnglibconf.h

上面的相对路径是相对于项目文件V:\libpng\v1.6.18\projects\vstudio\pnglibconf\pnglibconf.vcxproj的,所以其实就是把V:\libpng\v1.6.18\scripts\pnglibconf.h.prebuilt复制到V:\libpng\v1.6.18\pnglibconf.h。

3.4 自定义环境变量

选中zlib项目的任一文件,可以查看它的属性。如下图所示:

VC++编译libpng

上图的ZLibSrcDir就是一个环境变量,它指明了zlib源代码所在的目录。

3.4.1 定义

ZLibSrcDir的定义在文件V:\libpng\v1.6.18\projects\vstudio\zlib.props里,如下图所示:

VC++编译libpng

上图将设置环境变量ZLibSrcDir为..\..\..\..\zlib-1.2.8

3.4.2 使用

需要使用环境变量ZLibSrcDir的项目,请在相应的.vcxproj文件里插入一行语句,如下图所示:

VC++编译libpng

ZLibSrcDir是一个相对路径,它是相对于各个vc项目文件的(*.vcxproj)。以libpng.vcxproj为例,该文件位于V:\libpng\v1.6.18\projects\vstudio\libpng,因此ZLibSrcDir指向的绝对路径就是V:\libpng\v1.6.18\projects\vstudio\libpng\..\..\..\..\zlib-1.2.8,即V:\libpng\zlib-1.2.8。也就是说需要把zlib-1.2.8的文件都复制到V:\libpng\zlib-1.2.8目录,或者修改环境变量ZLibSrcDir。

使用环境变量ZLibSrcDir指向zlib源代码的位置,这是个非常好的功能。

VC++编译libpng的更多相关文章

  1. [libpng]CMake+VS2015下编译libpng,及使用小例

    编译前的工作 在编译libpng前,需要把zlib编译好,并加载到编译环境里. CMake + VS2015 下编译zlib,及使用小例 下载与解压 libpng的官网是 http://www.lib ...

  2. Win7 64位 VS2015环境编译Libpng

    第3次编译Libpng依然想不起任何东西,为了不浪费第4次的时间... http://libmng.com/pub/png/libpng.html http://www.zlib.net/ 解压两个压 ...

  3. 用VC编译lua源码,生成lua语言的解释器和编译器

    用VC编译lua源码,生成lua语言的解释器和编译器 1.去网址下载源码 http://www.lua.org/download.html 2.装一个VC++,我用的是VC6.0 3.接下来我们开始编 ...

  4. VC++编译MPIR 2.7.0

    目录 第1章编译    2 1.1 简介    2 1.2 下载    3 1.3 解决方案    4 1.4 创建项目    5 1.5 复制文件树    6 1.6 不使用预编译头文件    8 ...

  5. VC++编译GSL

    目录 第1章 VC++    1 1.1 修改行结束符    1 1.2 修改#include "*.c" 为 #include "*.inl"    2 1. ...

  6. 让VC编译出来的程序不依赖于msvcr80.dll/msvcr90.dll/msvcr100.dll等文件

    ---转载:http://hi.baidu.com/liu_haitao/item/e2157ac3a3c32a0bc610b253 让VC编译出来的程序不依赖于msvcr80.dll/msvcr90 ...

  7. 【Python学习】由于windows环境问题导致的不能安装某些需要VC编译的插件

    由于windows环境问题导致的不能安装某些需要VC编译的插件 下载地址:http://www.lfd.uci.edu/~gohlke/pythonlibs/ 安装方法: 在CMD中输入 pip in ...

  8. Win7 VS2015环境编译Libpng

    第3次编译Libpng依然想不起任何东西,为了不浪费第4次的时间... http://libpng.com/pub/png/libpng.html http://www.zlib.net/ 解压两个压 ...

  9. VC编译连接选项详解

    VC编译连接选项详解 大家可能一直在用VC开发软件,但是对于这个编译器却未必很了解.原因是多方面的.大多数情况下,我们只停留在“使用”它,而不会想去“了解”它.因为它只是一个工具,我们宁可把更多的精力 ...

随机推荐

  1. 正确遍历ElasticSearch索引

    1:ElasticSearch的查询过程 2:由ES查询模式引起的深度分页问题 3:如何正确遍历索引中的数据 ElasticSearch的查询过程 es的数据查询分两步: 第一步是的结果是获取满足查询 ...

  2. Android Studio ndk-Jni开发详细

    http://www.open-open.com/lib/view/open1451917048573.html Java Native Interface (JNI)标准是java平台的一部分,它允 ...

  3. UNIX网络编程——原始套接字的魔力【下】

    可以接收链路层MAC帧的原始套接字 前面我们介绍过了通过原始套接字socket(AF_INET, SOCK_RAW, protocol)我们可以直接实现自行构造整个IP报文,然后对其收发.提醒一点,在 ...

  4. SQL中ON和WHERE的区别

    SQL中ON和WHERE的区别 - 邃蓝星空 - 博客园 https://www.cnblogs.com/guanshan/articles/guan062.html

  5. 一些日期的计算方式 PHP

    一些日期的计算 某个月内的所有天数: public function getMonthDay ($date) { $stattime = strtotime(date('Ym01',strtotime ...

  6. Android Profiler内存检测

    Memory Profiler是Android Profiler中的一个组件,Android Profiler是Android3.0用来替换之前Android Monitor的观察工具,主要用来观察内 ...

  7. 【HDU - 1429】胜利大逃亡(续) (高级搜索)【状态压缩+BFS】

    Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)…… 这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带锁的门,钥匙藏在地牢另外的某些地方.刚开 ...

  8. Universal-Image-Loader源码分析(二)——载入图片的过程分析

    之前的文章,在上面建立完config之后,UIl通过ImageLoader.getInstance().init(config.build());来初始化ImageLoader对象,之后就可以用Ima ...

  9. BFS-迷宫问题-用宽度(广度)优先搜索解决最优路径问题

    题目: 给定一个大小为 N×M 的迷宫.迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格 的通道移动.请求出从起点到终点所需的最小步数.请注意,本题假定从起点一定可以移动 到终点. 限制条件;N, ...

  10. [独孤九剑]Oracle知识点梳理(十)%type与%rowtype及常用函数

    本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...