VS2005编译podofo静态库:老系统PDF功能集成实战

VS2005编译podofo静态库:老系统PDF功能集成实战
简介针对在VS2005环境下编译Podofo 0.9.7开源PDF读写库的需求这份资源给出了完整可用的VS工程方案能帮助C开发者绕开繁琐的第三方依赖编译。库本体与freetype、libjpeg、libpng、libtiff、zlib、openssl、lua、cppunit等依赖库均已预先编译解压后打开VS工程即可直接编译成lib库同时保留PODOFO_HAVE_OPENSSL等宏开关可按需裁剪文档加密、示例程序等模块并支持在开启后加入对应动态库与静态库完成联调。资源包共1382个文件以头文件、C/C源码、目标文件以及构建脚本为主兼顾工程配置文件和少量dll、lib文件压缩包约42.38MB。头文件便于查阅接口源码可跟踪实现细节构建脚本与工程文件则有助于理解整个开源库的组织方式。目前已有570人学习下载。资源适合具备一定C基础、希望在VS2005中快速集成PDF解析与生成能力的开发者可显著降低该开源库的编译与集成门槛。 这段时间在帮客户改造一个老系统工具链还停在VS2005VC8上。需求倒是不复杂程序里要直接生成PDF、给已有的PDF打个水印、再抽取几页另存。绕来绕去最后选了podofo 0.9.7这个开源库在VC8下编译成静态lib集成进项目。整个过程踩了不少坑把关键步骤记下来给还在和老编译器打交道的朋友做个参考。文章会覆盖编译思路、依赖裁剪、CMake配置、源码兼容性修改、lib调用验证这几个核心环节适合正在用旧版VS维护遗留项目的开发人员。1. 项目背景与整体思路1.1 为什么偏偏是podofo 0.9.7接这个需求之前我其实先盘了一遍市面上能读能写的PDF库。PDFium功能强但依赖重Poppler在Windows上编译麻烦mupdf倒是很锐利但它的API设计偏底层在VC8这种老编译器上想编译通过光是C标准适配就够喝一壶的。podofo的优势在于它是纯粹的C库核心部分只依赖zlib就能跑起来代码结构清晰API风格也比较友好读写PDF、操作页面对象、处理标注和表单这些常规场景都覆盖到了。版本选型也是关键。podofo 0.9.x系列还是经典API用起来顺手0.10之后的版本引入了大量C11特性VC8根本不认识auto、nullptr、右值引用这些语法。而0.9.7正好是0.9系列里比较稳定的一个版本官方文档里还明确保留了过VC8时代编译的痕迹所以我在VC8下折腾它的把握比新版本大得多。最终定在0.9.7不是因为它最先进而是因为它在老平台的兼容性上已经被验证过。1.2 静态lib和动态库怎么选podofo同时支持编译成静态库和动态库我在这个项目里选了静态lib。原因很实际老系统部署环境复杂有些客户机器上连VC8运行库都未必装得齐动态库方案还要额外带上podofo.dll和一堆依赖DLL排查问题的时候很容易踩到“本地能跑客户机器上崩”的经典坑位。静态lib只需要在编译时链进去生成的exe会把用到的代码段直接吸进去运行时不需要额外找DLL部署干净。代价是exe体积会大一点但为了省心这点体积完全可以接受。另外podofo是LGPL协议静态链接时需要注意对外提供relink能力或者选择开源方式发布这块在商业项目里要提前和法务确认好技术上不是难点合规上别忽略就行。2. 环境准备与依赖裁剪2.1 工具链版本清单先说结论VS2005编译podofo 0.9.7我实测可用的工具组合如下。工具版本说明Visual Studio2005 SP1必须打SP1否则部分标准库头文件行为异常CMake3.6或3.7太新版不支持VS8生成器3.7之后官方逐步放弃VS2005zlib1.2.11核心依赖只使用源码文件不用官方预编译包podofo0.9.7官方源码包约2MB左右VS2005的SP1补丁是一定要装的。没打SP1之前我在编译时遇到过不少标准库头文件相关的诡异错误比如int64_t这一类类型定义缺失、部分模板实例化失败等。打好SP1之后再编译这类问题批量消失。CMake版本需要单独强调一下。太新的CMake3.8之后已经不再支持Visual Studio 8 2005生成器你执行cmake -G的时候根本找不到这个选项。我机器上装的3.6.3生成工程一切正常。如果你手头只有高版本CMake也不要急着卸可以直接下载一个绿色版3.6.3两个版本共存没有冲突。2.2 依赖库裁剪策略podofo 0.9.7的外部依赖有zlib、libjpeg、libpng、libtiff、freetype、fontconfig、openssl等。但注意这些依赖里有相当一部分是可裁剪的。如果你只是做PDF的读取、写入、页面级操作不涉及字体嵌入、图片重编码这些高级功能完全可以只保留zlib。我的裁剪策略是先最小化后按需补齐。第一次编译时我把所有可选的PODOFO_HAVE_*开关都关掉只留zlib。等跑通了核心流程再根据实际业务决定要不要开启freetype来做字体嵌入。这样做的原因是依赖越少编译链路上的变量越少排查问题时更容易定位到podofo自身的问题而不是被第三方库的适配问题捆住手脚。依赖开关在CMake配置界面上一般以PODOFO_HAVE_JPEG_LIB、PODOFO_HAVE_PNG_LIB、PODOFO_HAVE_TIFF_LIB、PODOFO_HAVE_FREETYPE、PODOFO_HAVE_FONTCONFIG、PODOFO_HAVE_OPENSSL、PODOFO_HAVE_LIBIDN的形式出现全部设为不勾选。zlib开关保持开启。等基础库编译成功之后再回头单独研究字体相关功能这样风险最小。3. CMake工程生成与关键配置3.1 生成VS2005工程的具体步骤我先在podofo源码根目录下新建了一个build目录把构建产物跟源码隔离开这样源码出错时能随时删掉build重来不会污染原始文件。然后用cmake生成工程。cd podofo-0.9.7 mkdir build cd build cmake -G Visual Studio 8 2005 ..这里有一个比较容易踩的细节Visual Studio 8 2005的生成器名称必须一字不差。CMake在生成时如果提示找不到生成器先确认版本号是否符合前面说的3.6/3.7要求。生成成功后build目录下会有一个podofo.sln。用VS2005打开它之前需要先检查一下CMakeCache.txt里的关键选项。我个人的习惯是用cmake-gui再打开一次工程把输出目录、配置类型这些信息确认一遍再动手编译避免打开sln之后发现问题还得回去改CMake重来。3.2 必须调整的编译参数和宏定义打开sln之后不要急着按F7。先定位到podofo_static项目或者对应静态库项目名打开项目属性逐项检查下面几个地方。第一运行库设置。在“配置属性 - C/C - 代码生成 - 运行时库”里Debug配置对应多线程调试 (/MTd)Release配置对应多线程 (/MT)。这里我选的是静态运行时库因为老系统环境里装VC8运行库不一定可靠静态链进exe最省事。但要注意静态运行时库的配置必须和最终调用方exe保持一致否则malloc和new跨越模块边界时会产生堆管理混乱这种问题在运行时非常隐蔽。第二预处理器定义。项目里需要额外加两个宏_CRT_SECURE_NO_WARNINGS和_CRT_SECURE_NO_DEPRECATE。VS2005对sprintf、strcpy这类非安全函数有一堆C4996警告有些文件甚至会把警告当错误处理直接编译失败。加上这两个宏后这些噪声基本被屏蔽。第三字符集设置。建议直接使用“未设置”或者“使用多字节字符集”不要在podofo这类老库里启用Unicode字符集否则后续字符串相关API的匹配会非常折腾。podofo的字符串类型在0.9.x里和VC8环境下能保持简单就尽量简单。4. 源码兼容性修改与编译排错4.1 VS2005下的典型编译错误即使配置都对了直接编译还是会遇到几个绕不开的代码兼容问题。我把实际遇到的错误和处理方式整理在下面。错误信息问题原因处理方式error C2065: strcasecmp : undeclared identifierLinux风格字符串比较函数在VC8里没有把对应文件中的strcasecmp替换为_stricmperror C3861: snprintf: identifier not foundVC8没有snprintf标准实现替换为_snprintf或定义宏做映射warning C4996: sprintf was declared deprecatedVS2005安全函数警告项目级定义_CRT_SECURE_NO_WARNINGSerror C2059: syntax error : parameter个别头文件在VC8下的模板兼容问题调整包含顺序优先包含windows.h再包含podofo头文件strcasecmp的问题主要出现在podofo的字符串处理模块和元数据解析代码里。这个函数在Linux下是标准POSIX函数Windows没有但Windows提供了功能一致的_stricmp。改起来很简单直接全局替换就行但不建议一次性替换整个源码因为有些文件可能根本没用到只改编译报错的文件就够了。snprintf的问题类似。VC8之前压根没有这个函数只有_snprintf。podofo部分代码里确实用了snprintf编译到具体文件时报错再改改完记住在对应的.cpp文件顶部加上#define snprintf _snprintf也可以但注意这个宏定义可能影响已经被包含的系统头文件所以最稳的方式还是逐个调用点替换。4.2 zlib集成和链接错误处理zlib是podofo 0.9.7的核心依赖如果只是读普通的PDF文件FlateDecode压缩流解压全靠它。zlib 1.2.11源码包里自带contrib/vstudio工程但那些工程最低版本是vc10VC8用不了。我的做法是直接新建一个空的静态库工程把zlib源码目录下的adler32.c、compress.c、crc32.c、deflate.c、infback.c、inffast.c、inflate.c、inftrees.c、trees.c、uncompr.c、zutil.c加进去再把头文件路径指到zlib源码根目录一个可用的zlib静态库就出来了。整个编译过程中最常见的链接错误是error LNK2001: unresolved external symbol _inflate error LNK2001: unresolved external symbol _deflate这个基本可以断定是zlib没有正确链接进来或者zlib工程编译时使用的运行库配置和podofo不一致。解决办法是确认podofo工程和zlib工程的运行库都是/MTRelease或/MTdDebug并且在项目属性的“链接器 - 输入 - 附加依赖项”里明确写上zlib.lib。另外还有一个容易忽略的点podofo静态库工程里可能定义了PODOFO_STATIC但这个宏不会自动传递到调用方。你在自己的工程里引用podofo头文件之前必须手动定义PODOFO_STATIC否则头文件里的导入导出宏会把函数声明成__declspec(dllimport)一链接就报LNK2019 unresolved external symbol。这个问题我最初排查了很久特征就是函数明明就在lib里链接器就是找不到。5. lib验证与调用注意事项5.1 最小验证工程怎么搭编译出podofo.lib之后我不建议直接扔进老项目里联调。先建一个最小的控制台工程验证一下基础的PDF读、写、改流程确认lib可用再接入正式代码。#include podofo/podofo.h #include iostream using namespace PoDoFo; int main() { PdfMemDocument doc; doc.Load(input.pdf); int pageCount doc.GetPageCount(); std::cout page count: pageCount std::endl; PdfPage* pPage doc.GetPage(0); if (pPage) { std::cout page width: pPage-GetPageSize().GetWidth() std::endl; } doc.Save(output.pdf); return 0; }这个代码段能验证三件事加载PDF是否正常、页面数量与尺寸读取是否正常、保存文件是否正常。如果在执行doc.Load(input.pdf)时崩溃先检查输入PDF文件是否损坏如果保存出来的文件打不开优先怀疑zlib链路或者PDF对象流处理存在问题。验证工程和调用方工程都需要设置好头文件路径和lib路径。头文件路径指到podofo源码的src目录lib路径指到编译输出的目录附加依赖项填入podofo.lib。如果是Debug和Release混用注意分别链接对应的静态库版本。5.2 调用方项目里的隐藏坑把lib接入正式项目时有几个隐藏坑需要注意。第一个是头文件包含顺序。在VC8工程中如果先包含了其他第三方头文件再包含podofo.h有时会触发error C2059的模板语法解析错误。我的解决方法是把#include podofo/podofo.h放在所有Windows系统头文件之后、其他第三方库头文件之前。如果还是报错就在包含之前先#include windows.h这个顺序在大量老工程里是兼容性最好的。第二个是全局宏冲突。老系统里可能定义了small、near、far这种旧式宏这些符号会污染podofo头文件中的局部变量名。这个问题我在另一个项目里遇到过解决方式是排查公共头文件里的宏定义把无关的旧式宏限定到对应的源文件里而不是全局暴露。第三个是异常处理模型。podofo的很多接口会抛PdfError异常VC8默认的异常处理模型是/EHsc这个一般没问题。但如果老项目里手工关掉了异常支持设置了/EHs-c-链接或者运行时会出各种怪问题。正确做法是保持/EHsc并在恰当层捕获PdfError输出GetError()和GetMessage()的信息来排查问题。从整个编译过程来看VS2005编译podofo 0.9.7虽然有坑但基本都是可控范围内的老环境兼容问题没有一个需要伤筋动骨改业务逻辑。最花时间的反而是依赖裁剪和宏定义这类前期准备工作。如果手里的项目还能升级编译器我还是建议尽量往VC2015以上的版本走能省掉大量排查时间但如果你和我一样不得不守着一套老工具链希望这篇文章能帮你少走几步冤枉路。本文还有配套的精品资源点击获取

最新新闻

日新闻

周新闻

月新闻