资讯动态

VS2005编译podofo 0.9.7:依赖链、补丁与链接避坑

发布时间:2026/11/6 10:21:46 来源:尧图企业网站定制
简介podofo 0.9.7 的 VS2005 编译版本面向具备一定 C 基础、需要在 Windows 下进行 PDF 读写与解析的开发者省去自行整合多套第三方库的麻烦。压缩包共 1382 个文件、约 42.38MB以 h 头文件、c 源文件、obj 中间文件、cpp 实现和 vcproj 工程文件为主并含 mk 构建脚本、html 文档及少量 dll/lib完整保留编译产物与示例工程。工程已将 freetype、libjpeg、libpng、libtiff、zlib、openssl、lua、cppunit 等依赖整理为 lib下载后可直接用 VS 打开编译降低逐个链接静态库的配置成本文档加密相关的 OpenSSL 宏、DLL 与 lib 链接方式也留有说明便于按需启用或裁剪。两个依赖 Linux 库的用例处于禁用状态可减少无关报错对主线调试的干扰。已有 573 人学习下载适合研究 PDF 对象结构、内容流解析与加密文档处理的开发者参考。1. 老编译器配老库VS2005 编 podofo 0.9.7 这件事到底卡在哪前阵子要在一台只能装 VS2005 的开发机上做 PDF 读写绕不开的一个选项就是 podofo。它是 C 里少见的、不拖 Qt、不拖 Java、不拖 Poppler 那一大串依赖的 PDF 解析与生成库0.9.7 这一版正好处在 API 相对稳定、功能又够用的位置。真正让人头疼的地方不在 podofo 本身而在 VC8 这个编译器它没有stdint.h、没有snprintf、新版本 CMake 也不再为它生成工程文件。做 VS 编程的人都知道编译不过反而是好事最怕的是编译过了、跑起来才崩。下面按依赖链、补丁层、链接期、运行期四段往下推适合手上维护老 C 工程、又必须离线处理 PDF 的从业者照着走一遍。2. 把依赖先钉死VC8 能链接的 zlib / libjpeg / freetype 怎么编podofo 0.9.7 不是那种改两行就能编的独立库它对第三方依赖的版本和编译参数相当敏感。VC8 时代的东西放到今天依赖的源码版本、CMake 版本、运行时库设置这三样必须一次性对齐任何一项错位都会在最后的链接阶段以 LNK2005 或者运行期应用程序配置不正确的形式报复你。这一章先把依赖链钉死后面 podofo 本体才有得谈。2.1 三个硬依赖和三个可选依赖先做减法podofo 0.9.7 的CMakeLists.txt里挂了一堆PODOFO_HAVE_*开关但真正绕不过去的是 zlib 和 freetypezlib 负责 FlateDecode 解压PDF 里绝大多数内容流都靠它freetype 负责字体度量与嵌入字体解析没有它连文本宽度都算不出来。libjpeg 处理 DCTDecode也就是常见的 JPEG 图像对象虽然理论上能关但关掉之后带图的 PDF 基本没法看实操里建议直接打开。libtiff、libpng、openssl、fontconfig 这四个属于可选而且每个都会额外拉一串依赖进来老工程上能关就关。先做减法的好处是编译失败时排查面从十几个库压缩到三个库这在 VC8 上是实打实的时间成本。顺序上我一般按 zlib → libjpeg → freetype 走。freetype 自己可以选依赖 zlib所以放最后编编的时候把FT_WITH_ZLIB打开让它复用同一份 zlib 头文件和 lib避免两份 zlib 打进一个进程。libjpeg 用 IJG 的原版jpeg-9a更省事它没有 CMakeLists靠jconfig.vc加一份手写工程反而比 CMake 干净libjpeg-turbo 那条路需要 nasm 汇编器在 VS2005 环境里属于自找麻烦。2.2 生成 VS2005 工程CMake 版本卡在 2.8.12 附近新版 CMake 早就不输出 VS2005 工程了手上得常备一份 2.8.12 或 3.0 附近的版本装在独立目录里别和系统 PATH 里的新版打架。生成器名字是固定的Visual Studio 8 2005注意不是VS2005也不是Visual Studio 2005写错会直接报 unknown generator。zlib 和 freetype 都自带 CMakeLists可以直接走这条路。:: 用 2.8.12 的 cmake.exe别用 PATH 里的新版 set CMAKE_OLDC:\tools\cmake-2.8.12\bin\cmake.exe set ROOTD:\build\pdfdep mkdir %ROOT%\zlib cd %ROOT%\zlib :: 生成 VS2005 解决方案安装前缀指向统一目录 %CMAKE_OLD% -G Visual Studio 8 2005 ^ -DCMAKE_INSTALL_PREFIX%ROOT%\install ^ -DCMAKE_C_FLAGS/D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE ^ %ROOT%\src\zlib-1.2.8这段命令的关键在三处生成器字符串必须一字不差CMAKE_INSTALL_PREFIX把三个依赖的产物收拢到同一个install目录后面配 podofo 时只需要写一条 include 路径CMAKE_C_FLAGS里那两个宏是 VS2005 时代对付strcpy、fopen这类 CRT 安全警告的标准做法VS2005 认_CRT_SECURE_NO_DEPRECATE_CRT_SECURE_NO_WARNINGS是 VS2008 才引入的两个都加上最省心。生成完打开.sln只编 Release 和 Debug 两个配置别用 Debug 版去链 Release 版的 podofo。2.3 三个依赖的编译参数必须写成同一套依赖编译最容易翻车的不是编不过而是编过了之后 CRT 不一致。zlib 默认/MD、freetype 默认/MD、libjpeg 的手写工程默认/MT三者混在一起podofo 链接时就会看到一堆_malloc、_free的 LNK2005。我一般把三个依赖的运行时库统一成/MDRelease和/MDdDebug理由是最后交付的 podofo 如果做成 DLL多份 CRT 一定会出问题如果做成静态库/MD也比/MT更容易和第三方组件共存。freetype 的 CMake 参数要显式关掉几个开关不然它会去找 harfbuzz、bzip2、png找到一个就多一份链接依赖%CMAKE_OLD% -G Visual Studio 8 2005 ^ -DCMAKE_INSTALL_PREFIX%ROOT%\install ^ -DFT_WITH_ZLIBON ^ -DFT_WITH_PNGOFF ^ -DFT_WITH_BZIP2OFF ^ -DFT_WITH_HARFBUZZOFF ^ -DCMAKE_DEBUG_POSTFIXd ^ %ROOT%\src\freetype-2.6.5CMAKE_DEBUG_POSTFIXd这个参数值得单独说老工程的习惯是 Debug 版加d后缀这样 Debug 和 Release 的 lib 能在同一个目录里共存配 podofo 时用debug和optimized两个关键字分别指定链接器就不会拿错。FT_WITH_ZLIBON之后 freetype 的头文件里会引用zlib.h所以 zlib 的 include 路径必须在 freetype 的包含路径前面否则 freetype 编得过、podofo 编不过。libjpeg 走的是手写路线。把jconfig.vc复制成jconfig.h新建一个空的 Win32 静态库工程把j*.c全加进去预处理器定义加_CRT_SECURE_NO_DEPRECATE运行时库选/MD。jconfig.vc里已经定义了boolean为unsigned char并#define HAVE_BOOLEAN这一步很关键Windows SDK 的rpcndr.h里也有一份boolean定义不提前用HAVE_BOOLEAN挡住编译期就会撞名。2.4 产物扁平化一条 include、一条 lib三个依赖编完install目录里会是一堆include/zlib.h、include/freetype2/ft2build.h、lib/zlib.lib这样的结构头文件层级深浅不一。freetype 尤其容易踩坑它的入口头文件是ft2build.h但这个文件在include/freetype2/下面而ft2build.h里面又用#include freetype/config/ftheader.h去引别的头。所以 podofo 的包含路径必须同时写install/include和install/include/freetype2只写一条必然报ft2build.h找不到。我把这一步做成了个固定的目录约定后面所有工程都按这个约定配路径内容用途install/includezlib.h、jpeglib.h、jconfig.h直接包含install/include/freetype2ft2build.h、freetype/二级包含根install/lib/releasezlib.lib、jpeg.lib、freetype.libRelease 链接install/lib/debugzlibd.lib、jpegd.lib、freetyped.libDebug 链接整理成这张表之后podofo 的 CMake 配置参数就只剩寥寥几行出问题的时候也好定位到底是哪个库的路径错了。这一步多花十分钟后面能省两小时。3. 让 podofo 0.9.7 通过 VC8 编译器补头、换函数、关开关依赖就位之后podofo 本体才是真正的主战场。0.9.7 的源码主要面向 VS2008 及以上和 GCC 写的里面有不少 C99 和后来才标准化的东西VC8 一个都不给。这一章的处理思路是能补的补、能改的改、能关的关尽量不动 vendored 源码把改动集中在几个补丁头文件和配置宏上方便以后复现和回滚。3.1 补齐 stdint.h 和 inttypes.hVC8 没有stdint.hinttypes.h更是要到 VS2013 才有。podofo 里pdf_uint8、pdf_uint32这类类型定义和不少#include stdint.h都会在这里断掉。最省事的做法是自己写一份放到install/include下让它优先于任何系统路径。VS2005 的编译器其实支持__int64也支持long long作为扩展用__int64更保险因为后面配printf的时候%I64d直接对得上。/* stdint.h —— 放在依赖 include 目录里供 VC8 使用 */ #ifndef PODofo_COMPAT_STDINT_H #define PODofo_COMPAT_STDINT_H typedef signed char int8_t; typedef short int16_t; typedef int int32_t; typedef __int64 int64_t; /* 用 __int64 而不是 long long配 %I64d */ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned __int64 uint64_t; /* 指针宽度类型PDF 解析里偶尔会用到 */ typedef int intptr_t; typedef unsigned int uintptr_t; #define INT32_MAX 2147483647 #define UINT32_MAX 4294967295U #define INT64_MAX 9223372036854775807i64 #endif这份补丁的要点在于不能重复定义如果某个 SDK 头文件已经定义了int8_t重定义会报 C2371。稳妥的做法是在stdint.h外面加一层#ifndef _STDINT_H之类的守卫或者在工程预处理器里加一个PODOFO_COMPAT_STDINT开关只有在 VC8 环境下才引入这个文件。inttypes.h更简单直接#include stdint.h加几个空的PRId32宏即可podofo 里真正用到PRIu64的地方不多。3.2 snprintf 与格式化占位符VC8 的 CRT 里没有snprintf只有_snprintf。很多人图省事直接#define snprintf _snprintf能编过但埋了个隐患_snprintf在缓冲区不够时不会在末尾写\0返回值也不同snprintf返回本应写入的长度_snprintf返回负数。podofo 里生成 PDF 交叉引用表和对象偏移量时大量用到snprintf一旦截断没终止写出去的 PDF 就是坏文件而且这种坏文件用阅读器打开时只是偶尔报错极难复现。/* podofo_compat.h —— 在 podofo 的预编译头里最先包含 */ #ifndef PODofo_COMPAT_CRT_H #define PODofo_COMPAT_CRT_H #include cstdio #include cstdarg #include cstddef /* VC8 没有 snprintf用 _vsnprintf 包一层保证终止且返回值语义正确 */ static int podofo_snprintf(char* buf, size_t n, const char* fmt, ...) { va_list ap; int need; if (n 0) return 0; va_start(ap, fmt); need _vsnprintf(buf, n, fmt, ap); /* 截断时返回 -1 */ va_end(ap); buf[n - 1] \0; /* 强制终止兜住 _vsnprintf 的坑 */ return need; } #define snprintf podofo_snprintf /* VC8 不支持 C99 的 %zusize_t 要走 %Iu */ #ifdef _WIN64 # define PODOFO_SIZET_FMT %I64u #else # define PODOFO_SIZET_FMT %Iu #endif #endif这里buf[n-1] \0那行是血泪经验_vsnprintf在恰好填满缓冲区和不填满两种情况下行为不一致官方文档里写得很含糊实际测试下来只有强制结尾才能保证字符串安全。返回need为负数时上层代码通常当错误处理不会继续用这个缓冲区所以不影响正确性。另外%zu是 C99 的东西podofo 里如果有snprintf(..., %zu, size)的写法在 VC8 里会输出字面的zu排查起来非常玄学把这类格式化串统一换成PODOFO_SIZET_FMT宏最稳。3.3 podofo_config.h 里必须手改的几行podofo 用 CMake 的configure_file生成podofo/base/podofo_config.h但自动探测在 Windows 上经常误判尤其是unistd.h。VC8 环境里绝对没有unistd.h但 CMake 的CheckIncludeFile可能因为某些路径污染而返回真结果编到一半报cannot open include file: unistd.h。我的做法是 CMake 生成完之后手工复核一遍下面这几个宏必须落到位/* podofo/base/podofo_config.h —— 手工复核后的关键项 */ #define PODOFO_HAVE_UNISTD_H 0 /* Windows 上必须为 0否则引 unistd.h */ #define PODOFO_HAVE_OPENSSL 0 /* 老版本 openssl 在 VC8 上编不过先关 */ #define PODOFO_HAVE_FONTCONFIG 0 /* fontconfig 是 Linux 侧的东西 */ #define PODOFO_HAVE_TIFF_LIB 0 /* 不开 tiff少一个依赖 */ #define PODOFO_HAVE_PNG_LIB 0 /* 不开 pnglibpng 1.6 需要 pnglibconf.h */ #define PODOFO_HAVE_JPEG_LIB 1 /* DCTDecode 靠它 */PODOFO_HAVE_PNG_LIB单独说一下libpng 1.6 之后引入了pnglibconf.h这个文件在老版本里是构建时生成的手动编的时候很容易漏表现是png.h里#include pnglibconf.h直接失败。podofo 对 PNG 图像的支持本来就是可选的关掉它不影响绝大多数 PDF 的解析能省一整轮折腾。PODOFO_HAVE_OPENSSL关掉之后加密 PDF 就没法解密了但 0.9.7 时代它依赖的 openssl 接口在 VC8 上编起来极其痛苦如果不是必须处理加密文档直接关。除了 config 头工程级的预处理器定义也要统一_CRT_SECURE_NO_DEPRECATE、_CRT_NONSTDC_NO_DEPRECATE、_SCL_SECURE_NO_DEPRECATE三个都加上WIN32、_LIB静态库时也要有。字符集一项保持未设置即多字节不要切 Unicodepodofo 内部大量用char*和std::string切了 Unicode 反而会引入一堆LPCWSTR转换的麻烦。3.4 分批编译先 base 后 mainpodofo 的源码目录大致分base、main、doc、tools几块base里是PdfString、PdfName、PdfVariant这类基础设施main里才是PdfDocument、PdfPage、PdfImage这些面向用户的类。一次性全编的话几百个错误刷屏根本看不出根因。我一般先在解决方案里把main、doc、tools三个工程全部卸载只留base把它编到零错误零警告再逐个加回来。base编过是个很强的信号说明stdint.h、snprintf、podofo_config.h这三处补丁都生效了因为base里同时用到了整数类型、字符串格式化和配置宏。main加回来之后新出现的错误基本集中在两处一是 C 语法比如嵌套模板在 VC8 里需要加空格二是第三方头文件的包含顺序比如jpeglib.h必须在podofo_config.h之后包含否则HAVE_BOOLEAN没定义就撞名。tools目录里是命令行小工具依赖base和main编不编都行交付的是库本身。注意分批编译时不要在解决方案级别点生成解决方案那样会把卸载的工程一起跳过的同时也跳过依赖关系检查容易编出一个看起来成功、实际缺符号的 lib。正确的是右键单个工程点仅生成。4. 链接期与运行期编译通过之后的三个关卡编译通过那一刻是最容易松懈的时候但 VC8 上的老库恰恰是链接期和运行期问题最多。静态库、动态库、CRT 版本、清单文件这四样东西任意两个不匹配表现都是编译成功、程序起不来。这一章按链接错误、最小验证、异常处理、编码边界四步走把黑匣子拆开。4.1 LNK2005 / LNK2019 的定位顺序LNK2005 的意思是同一个符号被定义了两次在 VC8 配合老库的场景里九成是 CRT 不一致。_malloc、_free、_operator new、_CrtDbgReport这几个符号反复出现就去查每个参与链接的 lib 到底用的是/MT还是/MD。VS2005 没法从.lib文件名看出 CRT 版本得用dumpbin看它引用了哪个 CRT。:: 看一个 lib 到底依赖哪种 CRT dumpbin /directives zlib.lib | findstr /i DEFAULTLIB :: /MD 输出里会有 MSVCRT :: /MT 输出里会有 LIBCMT :: 混用会同时出现 MSVCRT 和 LIBCMT这就是 LNK2005 的根因 :: 看 podofo.lib 里某个符号到底有没有被导出 dumpbin /symbols podofo.lib | findstr PdfMemDocument第一条命令的输出决定了要不要回头重编依赖。如果zlib.lib里同时出现MSVCRT和LIBCMT说明编 zlib 的时候两个配置的 obj 混进了一个 lib只能删掉重来。第二条命令用来对付 LNK2019符号未解析典型场景是 podofo 编成了 DLL 但工程里没有链接podofo.lib对应的导入库或者反过来podofo 编成了静态库但工程里定义了PODOFO_IMPORT。静态库要用PODOFO_STATIC动态库用PODOFO_IMPORT这两个宏定义错了符号修饰名就对不上。还有一种隐蔽的 LNK2019 是 freetype 造成的FT_Init_FreeType找不到时先确认freetype.lib真的被加进了链接器输入再确认 freetype 的FT2_BUILD_LIBRARY宏在你引用它的工程里没有被误定义。这个宏是 freetype 自己编 lib 时用的外部工程定义了它会把__declspec(dllimport)变成dllexport符号方向反了自然找不到。4.2 最小验证打开 PDF、读页数、写一条线链接通过之后第一件事不是跑业务代码而是写一个三十行的最小程序把加载—读结构—写回这条链路走通。这个 Demo 的验证价值很高它能同时验证 zlib内容流解压、freetype字体初始化、CRT内存分配三条链路是否真的通了。#include podofo/podofo.h #include iostream using namespace PoDoFo; int main(int argc, char** argv) { if (argc 2) { std::cerr usage: demo input.pdf\n; return 1; } try { PdfMemDocument doc; doc.Load(argv[1]); // 整份读进内存便于改结构 std::cout pages doc.GetPageCount() std::endl; PdfPage* page doc.GetPage(0); // 0 基下标 PdfRect size page-GetMediaBox(); // 单位是 PDF 点1/72 英寸 std::cout size.GetWidth() x size.GetHeight() std::endl; // 往首页画一条红线验证内容流写入 PdfPainter painter; painter.SetPage(page); painter.SetStrokeColor(1.0, 0.0, 0.0); painter.DrawLine(0, 0, size.GetWidth(), size.GetHeight()); painter.FinishPage(); doc.Save(out.pdf); // 带增量标记不破坏原对象表 std::cout ok std::endl; } catch (PdfError e) { e.PrintErrorMsg(); // 打印错误码与描述 return e.GetCode(); } return 0; }几个参数要说明清楚。doc.Load()和doc.Save()配的是PdfMemDocument适合要改结构的场景只读的话用PdfStreamedDocument更省内存但老版本在 Windows 上的流式读取对文件的独占锁要求更严读的过程中不能有其他句柄。GetMediaBox()返回的是 PDF 点A4 是 595×842这个值可以直接判断页面尺寸读取有没有出错。PdfPainter必须显式FinishPage()不调的话内容流不会真正写回页面对象保存出来的 PDF 看着有页、但画笔的内容全丢这种问题不报错只能靠对比输出文件大小发现。Save()默认走增量更新会保留原对象表对已经加密或者有签名的文档更友好。4.3 异常处理PdfError 不能只 catch 不打印podofo 的错误处理走的是异常所有解析失败都抛PdfError错误码定义在PdfError.h里。VC8 上有个额外的坑如果异常跨 DLL 边界抛出而 DLL 和调用方用的 CRT 不一致catch可能抓不到程序直接终止。这就是为什么前面死磕/MD统一——只要 CRT 一致跨模块异常传播基本可靠。PdfError::PrintErrorMsg()输出的是错误码加上一段描述比如Error: 13对应的是文档结构损坏。实际排查时我一般不用它而是自己把e.GetCode()打到日志里因为错误码是稳定的描述文本会随版本变化。常见的几个码值得记住PdfError::ePdfError_InvalidXRef交叉引用表坏了、ePdfError_UnsupportedFilter不认识的压缩过滤器通常是关了 zlib 或者遇到新格式、ePdfError_InvalidHandle文件不存在或者权限问题。把catch分支写成返回e.GetCode()上层再按码分支处理比打印一堆字符串有用得多。还有一点容易被忽略PdfError里有ePdfError_OutOfMemory这种码VC8 的 CRT 在内存耗尽时行为比新版本更粗暴new可能直接返回空指针而不抛异常。所以 podofo 的调用点外面最好再加一层__try/__except兜底尤其是在批量处理成千上万份 PDF 的服务里单份文档把进程搞崩是绝对不行的。4.4 字体与编码中文 PDF 的真实边界中文 PDF 在 podofo 0.9.7 上的表现取决于两条链路解析和生成。解析侧只要 PDF 里嵌入了字体子集freetype 能加载就能拿到字形度量PdfPage::ExtractTextTo能抽出文本但抽出来的编码是 PDF 内部编码ToUnicode 映射不完整的文档抽出来就是乱码这不是 podofo 的问题换任何库都一样。生成侧更麻烦往页面写中文必须自己指定字体和编码PdfFont用PdfEncoding创建不指定编码默认走 WinAnsi中文会全部变成问号或者直接抛异常。实际项目里的做法是生成中文 PDF 时从系统目录加载一份 CID 字体用PdfFontCache缓存起来复用避免每写一段文字就新建一个字体对象。VS2005 环境下还有个wchar_t宽度的问题VC8 的wchar_t是 2 字节podofo 内部用的是 UTF-8 的pdf_utf8从std::wstring转 UTF-8 得自己写转换函数WideCharToMultiByte加CP_UTF8是最省事的路径别忘了最后补\0。提示处理中文 PDF 时先把PODOFO_HAVE_FONTCONFIG关掉确认fontconfig 打开后 podofo 会走一套 Linux 风格的字体查找逻辑在 Windows 上反而找不到字体表现是中文全部丢字。5. 避坑VS2005 编 podofo 0.9.7 最常见的 5 次翻车这一章记录的是我在复现过程中真的踩过、而且每次重搭环境都可能再踩一遍的问题每一条都按现象 → 原因 → 解决写方便对号入座。有些坑看起来是 podofo 的问题实际根因在 VC8 或者某个依赖上只盯着 podofo 源码改是改不出来的。5.1 C4819 警告刷屏编译到一半中断现象编译 podofo 的源文件时每个.cpp都报 C4819提示当前代码页不能表示某个字符紧接着是几个莫名其妙的语法错误行号指向一段注释。原因podofo 源码里有作者写的非 ASCII 注释文件是 UTF-8 无 BOM 保存的。VC8 在没有任何编码线索时会按系统本地代码页简体中文环境是 GBK解析源文件UTF-8 的多字节序列被拆成两个独立的 GBK 字符其中一个可能正好等于\或者引号把注释提前截断后面的代码就被当成了语句。解决把这些源文件批量转成UTF-8 带 BOMVS2005 看到 BOM 就知道按 UTF-8 解析。没有/utf-8编译开关可用那是 VS2015 之后才有的所以 BOM 是唯一可靠信号。转完之后 C4819 消失那些语法错误也会一起消失。如果不想动源码另一个办法是把文件转成 GB2312但源码里如果同时有日文、德文注释就会丢字符BOM 更稳。5.2 jpeglib.h 报 boolean 重定义现象jmorecfg.h里typedef unsigned char boolean;报 C2371 重定义前面已经有一个boolean的定义。原因Windows SDK 的rpcndr.h里也定义了boolean而且这个头文件经常通过windows.h被间接引入。libjpeg 官方早就知道这事在jmorecfg.h里留了HAVE_BOOLEAN的开关定义了它就跳过自己的typedef。解决在工程的预处理器定义里加HAVE_BOOLEAN。注意不是改jconfig.h因为 podofo 的某些源文件会先包含windows.h再包含jpeglib.h顺序不受控只有全局宏能保证在任何包含顺序下都生效。加完之后如果还报boolean相关错误检查是不是某个第三方头文件里自己写了一份typedef int boolean那种情况只能改包含顺序。5.3 编译链接全过双击 exe 报应用程序配置不正确现象Debug 版在本机 VS 里能跑拷到测试机上双击就弹出由于应用程序的配置不正确应用程序未能启动事件查看器里能看到 SideBySide 错误说找不到某个版本的 CRT 程序集。原因VS2005 的/MDd依赖Microsoft.VC80.DebugCRT这个调试版 CRT 不允许再分发测试机上没有。而 Release 版虽然依赖Microsoft.VC80.CRT但如果编译时把清单嵌错了或者 exe 和 dll 的清单版本号不一致同样起不来。解决交付一律用 Release 版/MD并且把Microsoft.VC80.CRT作为可再发行组件一起部署或者干脆改成/MT静态链接 CRT。后者要注意所有依赖库也得是/MT包括前面的 zlib、freetype、libjpeg只要有一个是/MD链接期就会撞 LNK2005。另一种情况是 exe 和 podofo.dll 用了不同的 CRT 版本号8.0.50608 和 8.0.50727清单里的assemblyIdentity对不上也会报同样的错用mt.exe检查两边的清单版本。5.4 加载 PDF 抛 PdfError 13但文件用阅读器能正常打开现象同一个 PDFAcrobat 和浏览器都能打开podofo 的Load()抛PdfError错误码 13描述是交叉引用表损坏。原因0.9.7 的 xref 修复逻辑比较保守。很多 PDF 生成器尤其是某些报表系统写出来的 xref 偏移量是错的但有经验的阅读器会自动扫描全文件重建 xref 表podofo 也支持这个能力但要显式开启或者传入一个容错参数。解决PdfMemDocument::Load()有个重载接受PdfArchive或者用LoadFromBuffer之后调SetPdfVersion之类的方式绕不过去真正有效的是给PdfParser设容错。0.9.7 里可以在 load 前调用doc.GetParser()-SetStrictParsing(false)具体 API 名以头文件为准关掉严格模式后它会扫描obj ... endobj重建对象表。如果还不行就是文件里用了不支持的过滤器检查ePdfError_UnsupportedFilter对应的对象是不是 LZW 或 JPX 编码这两种 0.9.7 支持得不好。5.5 freetype 头文件找得到链接时 FT_Init_FreeType 找不到现象编译期一切正常#include ft2build.h能过链接期报unresolved external symbol _FT_Init_FreeType。原因有两种。一是 freetype 编成了 DLL但工程里没有定义FT2_BUILD_LIBRARY之外对应的导入宏freetype 的头文件在没有FT2_BUILD_LIBRARY也没有FT_DLL的情况下会把函数声明成普通外部函数符号名和 DLL 里的修饰名不一致。二是 freetype 编的是 Release 版工程链接路径指向了 Debug 目录文件名不匹配但链接器没报错因为路径里恰好有一个同名的旧文件。解决先确认 freetype 是静态库还是动态库。静态库要在引用工程里定义FT2_BUILD_LIBRARY的反面——也就是不定义让FT_EXPORT展开成空同时定义FT_STATIC_LIBRARY部分版本需要。动态库则要确保 freetype 的头文件是按 DLL 模式编出来的。最稳的办法是直接编成静态库FT_DISABLE_DLL一类的开关不用管链接时把freetype.lib放进输入列表符号一定找得到。至于路径我一般把 Debug 和 Release 的 lib 名字用CMAKE_DEBUG_POSTFIX区分开物理上就不会拿错。6. 进阶把这次编译固化成可复用的工程模板单次编过不算本事能在一个新机器上二十分钟内重来一遍才算。我的做法是把整个流程固化成一个属性表加一个批处理脚本属性表podofo-vc8.props里写死 include 路径、lib 路径、预处理器定义、运行时库批处理里按顺序调三个依赖的 CMake 加 podofo 的 CMake全部用-DCMAKE_INSTALL_PREFIX指向同一个根目录。新机器上只要把源码包和 CMake 2.8.12 拷过去跑一遍脚本产物就是一致的。属性表里最值得写死的是这几项AdditionalIncludeDirectories用$(PodoFoRoot)\install\include;$(PodoFoRoot)\install\include\freetype2AdditionalLibraryDirectories用 Release 和 Debug 两条AdditionalDependencies用podofo.lib;freetype.lib;jpeg.lib;zlib.lib其中 Debug 版用podofo.lib;freetyped.lib;jpegd.lib;zlibd.lib。预处理器定义固定成WIN32;_LIB;PODOFO_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;HAVE_BOOLEAN。这几行抄过去新工程就自动具备和 podofo 一致的编译环境不用每次手工配。验证环节我加了一个自检脚本编译完立即跑一遍最小 Demo把输入输出对一遍:: 编完立刻验别等业务代码写完才发现库是坏的 build_demo.bat demo.exe sample.pdf || goto :fail if not exist out.pdf goto :fail :: 用 podofo 自己的工具反读一遍确认写出的文件结构合法 pdfinfo.exe out.pdf out.txt 21 findstr /c:pages 1 out.txt || goto :fail这个脚本的价值在于把编译成功和功能可用分开验证。demo.exe走的是加载加写回pdfinfo走的是纯解析两条路径覆盖的代码不同。任何一条挂了说明问题不在业务代码而在库本身直接回退重编不用浪费时间调业务。goto :fail那几行是刻意的批处理的||对某些退出码不敏感用标签跳转更可靠。版本核对表也建议一起维护我习惯把它放在工程根目录的toolchain.txt里每次换机器先对一遍CMake 必须是 2.8.12 附近zlib 用 1.2.8libjpeg 用jpeg-9a原版freetype 用 2.6.5podofo 固定 0.9.7 的 tag不要拿 master。这几项里最容易被顺手升级的是 freetype升到 2.9 之后 CMake 最低版本要求就到 3.1 了VS2005 生成器直接消失整个流程从第一步就断掉。从那以后我每次搭这类老编译链都会先把toolchain.txt和属性表一起建好、再动一行源码宁可前期多花半小时也不愿意在链接错误里泡一整天。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑