简介:zlib是一个开源、跨平台的压缩库,这份资源是其1.2.11版本在Windows x64下的已编译产物,面向C++开发者,可直接用于数据压缩、网络传输、文件存储及游戏资源打包等场景。压缩包共19个文件,以4个lib库、2个dll动态库为主,另包含Release/Debug对应的pdb调试符号、ilk增量链接文件、exp导入库及zlib.h头文件,整体仅876KB,非常轻量。目前已有2393人学习/下载,适合需要快速集成压缩能力、又不想从源码编译的工程实践。拿到后可在Visual Studio x64项目中直接引用:Release版满足高吞吐与性能优化,Debug版配合pdb可定位调用细节;头文件与lib齐备后,调用gzopen、gzwrite、gzread等接口即可完成常见压缩解压需求,同时规避了网上虚假或含毒库的风险。
1. 为什么我决定自己编译 zlib 1.2.11 for Windows x64
先说结论:zlib 1.2.11 这版库,虽然官方源码里自带了好几种编译方式,但如果你直接在 Windows x64 环境下去找现成的预编译包,很容易碰到三个头疼问题:要么是 Debug 和 Release 混在一起,要么是 x86/x64 分不清楚,要么干脆是从某个第三方仓库拉来的,没人告诉你编译参数是什么。我自己在项目里需要同时用 zlib 的 debug 版和 release 版,又要保证 x64 架构下链接稳定,折腾了一圈之后决定自己动手,把整个编译流程固化下来。
zlib 是个什么层次的库,稍微接触过压缩相关开发的人都清楚。它几乎是半个操作系统级的基础组件,PNG 图片、HTTP gzip、zip 文件、各种游戏资源打包都离不开它。1.2.11 这个版本在 2017 年发布之后用了很长时间,虽然 1.2.12 和后续版本修复了一些安全告警,但很多老项目、老工具链仍然锁死在 1.2.11,因为 API 行为变更会带来回归风险。所以“zlib 1.2.11 + Windows + x64 + Debug/Release”这个组合,看着简单,实际是很多 C/C++ 工程师都会遇到的真实需求。
这篇文章我不会讲太虚的东西,直接把整个过程拆开:环境怎么搭、CMake 参数怎么配、Debug 和 Release 怎么分别产出、最终拿到哪些文件、怎么快速验证。如果你跟我一样,是个需要把 zlib 集成进自己工程的人,照着做基本不会翻车。
2. 编译前的准备工作:环境与源码
2.1 工具链选择
Windows 下编译 zlib,主流路子有这么几条:用 MSVC 的 nmake 走 zlib 自带的 makefile,用 MinGW 的 mingw32-make,还有用 CMake 生成 Visual Studio 工程。三条路我都试过,最省心的其实是 CMake + Visual Studio。
原因很简单。zlib 源码里虽然自带win32/Makefile.msc,但那个 makefile 对 x64 的支持不如 CMake 直观,需要手动设置 CPU 和架构相关的宏。用 MinGW 遇到的问题是生成出来的 import library 格式跟 MSVC 不完全兼容,如果后续主工程是 MSVC 编译的,链接时会有符号格式的坑。CMake 直接把 VS 工程文件生成好,Debug/Release 配置天然分层,x64 平台一选就出来了。
我的环境是:
- Windows 10/11 x64 系统
- Visual Studio 2019(16.x),主要是用它的 MSVC 工具链和 CMake 支持
- zlib 1.2.11 源码包
如果你只有 Visual Studio 2022,也完全没问题,下面所有参数基本通用。
2.2 获取源码与目录说明
zlib 1.2.11 的源码包解压之后,目录结构很清爽,核心就几个东西:
zlib.h、zconf.h:对外头文件adler32.c、compress.c、crc32.c、deflate.c、inflate.c、trees.c、zutil.c等:实现文件CMakeLists.txt:官方提供的 CMake 工程win32/:Windows 相关的 makefile 和 DLL 工程定义
这里有个细节要注意:如果你是用 git clone 拉取的官方仓库而不是下载 release 压缩包,记得先检查子模块,不过 zlib 没有子模块,所以问题不大。我习惯把源码放在一个不带空格的路径下,比如D:\zlib-1.2.11,这能避免很多 Windows 下的 CMake 路径解析问题。
3. 用 CMake 生成 VS2019 工程并编译
3.1 配置 CMake 参数
我采用的是源码目录外构建的方式,也就是 out-of-source build,避免把生成文件弄脏源码目录。操作如下:
cd /d D:\ mkdir zlib-build-debug mkdir zlib-build-release然后分别进入两个目录执行 CMake 配置。Debug 版本:
cmake ..\zlib-1.2.11 -G "Visual Studio 16 2019" -A x64 -DCMAKE_CONFIGURATION_TYPES=DebugRelease 版本:
cmake ..\zlib-1.2.11 -G "Visual Studio 16 2019" -A x64 -DCMAKE_CONFIGURATION_TYPES=Release这里面的关键参数拆开说一下:
-G "Visual Studio 16 2019"指定生成器。-A x64指定目标架构,千万别漏掉。如果不写,默认可能是 Win32,后面编译出来的是 32 位库,放到 x64 工程里链接直接报 unresolved external symbol。-DCMAKE_CONFIGURATION_TYPES=Debug或Release的目的是让 VS 工程只保留对应配置,编译时不会把另一个配置也带出来。实际用cmake --build . --config Debug也能锁定目标。
3.2 分别产出 Debug 和 Release 配置
配置完成后,直接执行编译。Debug 目录下:
cmake --build . --config DebugRelease 目录下:
cmake --build . --config Release这里我多说一句:zlib 1.2.11 的 CMake 默认会同时生成静态库和动态库,取决于配置项。默认情况下,BUILD_SHARED_LIBS不显式指定时会按 CMake 的默认行为来,但 zlib 的 CMakeLists 有自己的一套逻辑。官方默认倾向于生成动态库 zlib.dll,同时也会生成静态库 zlibstatic.lib。编译完你会看到Debug或Release子目录下有一堆文件,最核心的产出物是:
- 动态库版本:
zlib.dll、zlib.lib - 静态库版本:
zlibstatic.lib - 头文件:
zlib.h、zconf.h
如果你的项目只需要静态链接,推荐直接链接zlibstatic.lib,省去运行时带 DLL 的麻烦。如果你需要动态加载,那就用zlib.dll和对应的zlib.lib。
4. 原生 CMake 与 zlib 自带 makefile 的取舍
4.1 zlib 自带 makefile 的局限
很多人一开始图省事,会打开win32/Makefile.msc直接用 nmake 编。这条路不是不通,但有几个比较隐蔽的问题。
一个是架构选择。Makefile.msc里的默认目标并没有把 x64 的编译选项写得特别直白,你得自己设置CPU=AMD64或者修改 CFLAGS 加入/D_AMD64_。我在 1.2.11 上做过一次,编出来的库放到 Debug 工程里可以,Release 工程里就出乱子,后来发现是因为宏没配对。
另一个问题是 Debug 和 Release 的命名。nmake 编出来的文件默认是zlib.lib、zdll.lib,不会自动区分zlibd.lib这种命名。你如果同时需要 Debug 版和 Release 版,就得手动改输出名,或者放到不同目录。相比之下,CMake 在生成的 VS 工程里会自动生成zlibd.lib/zlib.lib这种命名差异,方便很多。
4.2 我踩过的坑:文件名映射问题
这里分享一个真实教训。CMake 生成的动态库 Debug 版本,输出文件名往往是zlibd.dll,而不是zlib.dll。这个d后缀是 MSVC 环境下很常见的“Debug 标记”。我头一回在 Debug 工程里配链接器输入时,顺手写了zlib.lib,结果链接报错“找不到 zlib.lib”,去Debug目录一看,明明文件名就叫zlibd.lib。
所以如果你用 CMake 生成工程,链接时注意区分:
- Debug 动态库对应
zlibd.lib+zlibd.dll - Release 动态库对应
zlib.lib+zlib.dll - 静态库 Debug 是
zlibstaticd.lib - 静态库 Release 是
zlibstatic.lib
这个命名差异不搞清楚,后面花在排查链接错误上的时间会比编译本身还多。
5. 构建产物整理与验证
5.1 产出文件说明
我每次编译完后不会直接去 VS 输出目录里翻文件,而是自己重新整理一份干净的产物目录,方便后续接入项目。会做成这样:
D:\zlib-dist\x64\debug\ zlib.h zconf.h zlibd.dll zlibd.lib zlibstaticd.lib D:\zlib-dist\x64\release\ zlib.h zconf.h zlib.dll zlib.lib zlibstatic.lib这样做的好处是,集成到 CMake 工程时可以直接用target_link_libraries指向特定目录,不用再跟 VS 的默认输出路径纠缠。头文件两份可以保持一致,不用分别复制。
5.2 快速自测与跨架构说明
编译完成后,我习惯写一个最简单的 C 文件验证 zlib 版本和压缩函数是否正常:
#include <stdio.h> #include <string.h> #include "zlib.h" int main() { const char *src = "hello zlib 1.2.11"; unsigned char comp[256] = {0}; uLongf compLen = sizeof(comp); int ret = compress(comp, &compLen, (const Bytef*)src, strlen(src)); if (ret != Z_OK) { printf("compress failed: %d\n", ret); return 1; } printf("zlib version: %s\n", zlibVersion()); return 0; }把这段代码分别用 Debug 和 Release 配置编译链接,能打印出zlib version: 1.2.11就说明库本身没问题。这里还得多提一句:自测代码的架构必须跟库一致,既然库是 x64 的,那验证程序也要用 x64 的编译选项,不然加载 DLL 时会报“模块计算机类型与目标计算机类型冲突”。
6. 常见问题与排查技巧实录
6.1 常见问题速查表
我把这段时间编译 zlib 时遇到的典型问题整理成了一张表,以后你遇到相同报错可以直接照着查。
| 现象 | 原因 | 解决办法 |
|---|---|---|
| link 时找不到 zlib.lib | Debug 配置下库名是 zlibd.lib | 检查链接依赖是否写错,Debug 用 zlibd.lib,Release 用 zlib.lib |
unresolved external symbol_compress | 库是 C 语言库,C++ 工程没加 extern "C" | 包含 zlib.h 时确保头文件里有extern "C"保护,或者使用 zlib 自带的头文件 |
| DLL 运行时找不到 zlibd.dll | 程序所在目录或 PATH 里没有 DLL | 把 DLL 复制到 exe 同目录,或者设置 PATH |
| LNK1112: module machine type 'x86' conflicts with target machine type 'x64' | 编译出的库是 32 位,但工程是 64 位 | 重新用-A x64生成工程并编译 |
| 编译时 C2065 undeclared identifier Z_OK | 头文件路径配置错误 | 检查 include 路径是否指向 zlib.h 所在目录 |
| 调用 compress 后输出数据长度不对 | 缓冲区传参问题 | 确认uLongf类型的长度变量先被赋值为缓冲区大小 |
6.2 经验心得:静态库与动态库怎么选
最后讲一下我个人的选择逻辑。如果是做一个内部工具或者插件,我倾向用静态库zlibstatic.lib,因为部署时少一个 DLL,不会因为环境变量问题导致运行时崩溃。如果是做 SDK 或给第三方集成,动态库更合适,方便大家统一升级 zlib 版本,也能减小最终二进制体积。
从调试角度看,Debug 版本必须用 Debug 配置,不能拿 Release 库去调试,否则断点命中不了,变量值也是优化过后的,体验非常差。Release 版本则要注意开启足够的优化,zlib 在 O2 下的压缩性能和不开优化差别肉眼可见。
还有一个小技巧:如果你自己用 CMake 维护整个项目,可以在 zlib 的 CMakeLists 里把ZLIB_BUILD_EXAMPLES关掉,默认它可能会编译 examples,纯属浪费时间。我是这么加的:
cmake ..\zlib-1.2.11 -G "Visual Studio 16 2019" -A x64 -DZLIB_BUILD_EXAMPLES=OFF这个开关在 1.2.11 里有效,能少编两个 exe。
再补充一个跟 zlib 1.2.11 本身有关的小提醒:这个版本在 2018 年被爆出 CVE-2018-25032 之类的安全公告,后续版本里才修复。如果你的产品要过安全扫描,建议要么在 1.2.11 基础上做内部合规评估,要么尽快升级到 1.2.13。如果只是本地工具、学习验证或个人项目,1.2.11 编译使用没有太大问题,但不要在面向公网的服务里长期放着不升。
我实际编译的经验是,整个流程第一次跑大概十几分钟,主要是等 VS 安装组件和 CMake 生成,真正编译时间很短。把两个配置分别沉淀成两个目录后,后面每次接入新工程都特别快,再也不用到处找“谁有没有编译好的 zlib”。如果你也想省掉这些麻烦,建议就按我这个流程走一遍,然后把产物目录压缩一份放进团队公共盘,以后谁用谁拷。
本文还有配套的精品资源,点击获取