VS2017编译librtmp静态库:包含依赖库与源码的完整指南 简介本资源面向需要在 Windows 10 与 Visual Studio 2017 环境下使用 librtmp 的开发者提供一套可直接编译的 librtmp.lib 静态库工程解决 RTMP 协议推流、拉流开发中库文件获取困难、依赖配置繁琐的问题。压缩包共 238 个文件约 49.12MB以 163 个 h 头文件、28 个 dll 动态库、8 个 lib 库文件及 7 个 c 源文件为主另含 sln 解决方案、vcxproj 工程文件与编译日志覆盖 zlib-1.2.8、openssl-1.0.1c 等依赖模块目录按 lib、librtmp、vs2017 分层组织结构清晰。已有 637 人学习下载适合音视频直播、流媒体客户端开发的中高级 C/C 工程师参考。读者可直接打开 librtmp.sln 编译生成库文件省去依赖库单独配置与版本适配环节同时借助源码与头文件理解 RTMP 握手、AMF 编解码等实现细节为二次开发与排错提供完整基础。1. 为什么还有人要在 VS2017 里手编 librtmp.lib如果你手上有一个老流媒体项目或者维护着一套基于 RTMP 协议的推流/拉流模块大概率绕不开 librtmp。它本身是 C 写的跨平台但到了 Windows Visual Studio 这套工具链里官方并没有给现成的.lib和.dll网上流传的预编译包又常常对不上运行库版本链接阶段一堆LNK2019未解析外部符号能把人折腾到怀疑人生。标题里说的「vs2017 编译 librtmp.lib 库包含引用库和源代码可直接编译」本质就是解决这件事把 librtmp 的源码、它依赖的 zlib 和 OpenSSL或 mbedTLS一起放进 VS2017 的解决方案里编出一个能在自己工程里直接引用的静态库。适合两类人一是接手了老项目的维护者二是想搞懂 RTMP 底层握手、分块、消息封装不想只调 API 的开发者。这一章先把「为什么是 VS2017、为什么是静态库、为什么必须自己编」讲清楚后面再动手。VS2017 这个版本很微妙。它默认用 MSVC v141 工具集对 C99 的支持比 VS2015 好不少但又不像 VS2019/2022 那样默认开启/std:c11之类的新标准选项。librtmp 的源码里有不少 C89/C99 混写的痕迹比如变量声明位置、snprintf的可用性在 v141 下编译基本能过但需要手动处理几个头文件包含顺序问题。另一个现实原因是很多老项目的.vcxproj就是 v141 格式你拿 VS2022 编出来的.lib混进去运行库/MT vs /MD和工具集版本对不上链接器会直接报错。所以「锁死 VS2017」不是守旧而是为了和现有工程 ABI 兼容。静态库.lib和动态库.dll的选择也值得说一句。librtmp 如果编成 DLL你需要导出符号、处理__declspec(dllexport)还要在调用方配好导入库和运行时 DLL 路径部署时多一个文件。而静态库直接把目标文件打包进你的 exe没有运行时依赖问题特别适合那种「一个 exe 走天下」的推流工具。代价是每个用到它的工程都要重新链接一遍体积略大但对老项目来说省心比省空间重要。标题里强调「包含引用库和源代码」意思就是依赖项zlib、ssl、crypto的源码和头文件都齐了不用你再去满世界找zlib.lib和libssl.lib这是最实在的地方。2. 把源码、依赖和 VS2017 工程拼成一个能编的解决方案2.1 目录结构怎么摆才不乱拿到源码包后第一件事不是急着打开.sln而是把目录理清楚。librtmp 本体只有几个文件rtmp.c、rtmpproto.c、handshake.c、amf.c、hashswf.c、log.c、parseurl.c加上rtmp.h、rtmpproto.h等头文件。它依赖 zlib 做压缩依赖 OpenSSL 的libssl和libcrypto做握手阶段的 DH 交换和 HMAC 校验。一个不容易翻车的目录布局是这样librtmp_solution/ ├── librtmp/ │ ├── src/ # rtmp.c、amf.c 等 .c 文件 │ ├── include/ # rtmp.h、log.h 等对外头文件 │ └── librtmp.vcxproj ├── deps/ │ ├── zlib/ │ │ ├── src/ # adler32.c、deflate.c 等 │ │ └── include/ # zlib.h、zconf.h │ ├── openssl/ │ │ ├── include/ # openssl/*.h │ │ └── lib/ # 预编译的 libssl.lib、libcrypto.lib │ └── ... └── librtmp.sln这里有个关键决策OpenSSL 是用预编译库还是自己编我的血泪经验是如果你只是要一个能跑的 librtmpOpenSSL 直接用官方或可信来源的预编译.lib就行但必须确认它是用/MT还是/MD编的并且和你的 librtmp 工程保持一致。zlib 则建议把源码加进解决方案一起编因为它文件少、编译快而且能避免zlib.lib版本混乱导致的inflate符号冲突。把 zlib 的.c文件直接拖进 librtmp 工程或者单独建一个静态库工程两种都行我一般单独建方便复用。2.2 新建静态库工程并导入源文件打开 VS2017新建「Windows 桌面」→「静态库」项目命名librtmp。建好后把librtmp/src下的.c文件通过「添加 → 现有项」加进来头文件目录在项目属性里配。注意不要一股脑全加hashswf.c在不需要 SWF 校验的场景可以排除减少依赖。然后配置头文件搜索路径项目属性 → C/C → 常规 → 附加包含目录 $(SolutionDir)librtmp\include $(SolutionDir)deps\zlib\include $(SolutionDir)deps\openssl\include这一步的坑在于路径里的反斜杠和空格。如果解决方案放在「我的文档」这种带空格的路径下某些老版本 MSBuild 解析会出问题建议整个工程放在纯英文、无空格的短路径下比如D:\work\librtmp_solution。另外rtmp.h里会#include openssl/ssl.h所以 OpenSSL 的 include 目录必须指向openssl文件夹的上一级而不是openssl文件夹本身否则会报找不到openssl/ssl.h。2.3 预处理宏和运行库设置librtmp 在 Windows 下编译需要定义几个宏否则会走 Linux 分支或者缺少size_t定义。在「C/C → 预处理器 → 预处理器定义」里加上WIN32 _WINDOWS _CRT_SECURE_NO_WARNINGS NO_CRYPTO等等NO_CRYPTO要不要加这取决于你是否需要 RTMPE 加密。如果只是普通 RTMP 推流加上NO_CRYPTO可以彻底摆脱 OpenSSL 依赖编译会简单很多。但标题里明确说「包含引用库」通常意味着要支持 RTMPS/RTMPE所以不加NO_CRYPTO而是老老实实链接 OpenSSL。_CRT_SECURE_NO_WARNINGS是为了压掉strcpy、sprintf这类函数的警告老代码里到处都是不压掉编译输出没法看。运行库设置是链接阶段最容易翻车的地方。在「C/C → 代码生成 → 运行库」里四个选项对应关系要记牢/MT是静态链接 CRT/MTd是调试版静态 CRT/MD是动态链接 CRT/MDd是调试版动态。你的 librtmp 工程和最终调用它的 exe 工程必须一致。如果 exe 用/MDdlibrtmp 用/MT链接时会报LNK2038检测到RuntimeLibrary不匹配。我一般统一用/MTdDebug和/MTRelease这样编出来的 exe 不依赖vcruntime140.dll拷到别的机器上直接能跑。2.4 链接 OpenSSL 和 zlib 的库文件静态库工程本身不产生最终链接但它在编译阶段需要头文件在「链接器 → 输入 → 附加依赖项」里其实用不到因为静态库不解析外部符号。真正需要配依赖的是最终调用 librtmp 的 exe 工程。不过为了让 librtmp 工程能通过编译至少语法检查头文件路径必须对。等到你建一个测试 exe 来验证时在 exe 工程的链接器输入里加上ws2_32.lib crypt32.lib libssl.lib libcrypto.lib zlib.libws2_32.lib是 Windows socket 库librtmp 的网络部分要用。crypt32.lib是 OpenSSL 在某些 Windows 构建下需要的证书存储相关库。顺序上libssl依赖libcrypto所以libssl.lib写在libcrypto.lib前面。如果报LNK2019说SSL_CTX_new找不到先检查这两个库的路径有没有加到「链接器 → 常规 → 附加库目录」。3. 编译参数、报错定位和链接顺序的实战处理3.1 字符集和结构体对齐VS2017 默认用 Unicode 字符集但 librtmp 内部大量使用char*和sprintf如果项目属性里「常规 → 字符集」设成「使用 Unicode 字符集」某些 Windows API 调用会变成宽字符版本导致类型不匹配。稳妥做法是把 librtmp 工程的字符集改成「未设置」或者「使用多字节字符集」。在.vcxproj里对应CharacterSetMultiByte/CharacterSet。这个设置不直接影响 librtmp 自己的代码但影响它包含的windows.h里的宏展开。结构体对齐方面librtmp 的RTMPPacket结构里有int、uint32_t、指针混合默认对齐在 x86 和 x64 下不同。如果你编的是 x64 版本而调用方是 x86那肯定链接不上。所以第一步就要确定目标平台老项目多半是 Win32x86那就把解决方案平台设成 x86所有依赖库也必须是 x86 版本。OpenSSL 的预编译库分 Win32 和 Win64拿错了会在链接时报「模块计算机类型 x64 与目标计算机类型 x86 冲突」。3.2 常见编译错误逐条拆解第一个高频错误error C2065: snprintf: undeclared identifier。VS2017 的 v141 工具集其实已经支持snprintf但需要包含stdio.h而且不能定义_CRT_SECURE_NO_WARNINGS之外的旧宏。如果还是报错检查是不是有代码把snprintf重定义成了_snprintf。librtmp 的log.c里有条件编译Windows 下走_snprintf分支如果宏没配对就会两边不讨好。第二个error LNK2019: unresolved external symbol __imp__socket12。这是典型的 Winsock 库没链接。ws2_32.lib必须加在 exe 工程的附加依赖项里而且要在libssl.lib之前还是之后实际上ws2_32和 OpenSSL 没有直接依赖顺序不敏感但习惯上放在最前面。如果加了还报错检查是不是把ws2_32.lib写成了wsock32.lib后者是旧版符号名不同。第三个error LNK2038: mismatch detected for RuntimeLibrary: value MT_StaticRelease doesnt match value MD_DynamicRelease。这就是运行库不一致。解决办法是把所有参与链接的静态库工程librtmp、zlib和 exe 工程的「运行库」设置统一。如果 OpenSSL 是预编译的你没法改它那就只能让自己的工程去适配它。用dumpbin /directives libcrypto.lib可以查看它用的是/MT还是/MD然后把自己的工程改成一样。3.3 用 dumpbin 和 depends 做链接前检查在动手链接之前花两分钟用dumpbin检查一下手头的.lib文件能省掉大量试错时间。打开「VS2017 开发人员命令提示符」切到库文件目录dumpbin /headers libcrypto.lib | findstr machine dumpbin /directives libcrypto.lib | findstr RuntimeLibrary第一条看架构输出x86还是x64。第二条看运行库指令输出MT_StaticRelease或MD_DynamicRelease。把 librtmp 工程设成和它一致。对于 zlib如果你是自己编的那就不用查直接控制。对于 librtmp 编出来的.lib也可以用同样方法验证它是不是你想要的架构。还有一个工具是dumpbin /symbols librtmp.lib可以列出所有导出的符号。如果你在 exe 里调用RTMP_Init报未解析就用这个命令确认librtmp.lib里到底有没有RTMP_Init这个符号。有时候符号存在但名字被修饰了C 名称修饰而 librtmp 是 C 代码头文件里必须用extern C包住否则 C 编译器会按 C 规则去修饰符号名导致找不到。检查rtmp.h里有没有#ifdef __cplusplus extern C { #endif如果没有就在包含头文件时自己包一层。4. 避坑编译 librtmp 时最容易翻车的五个地方4.1 现象编译通过但链接时提示找不到 SSL 符号原因OpenSSL 的头文件版本和.lib版本不一致。比如头文件是 1.1.1库文件是 3.0函数签名变了SSL_library_init在 3.0 里被废弃链接时自然找不到。解决确认deps/openssl/include和deps/openssl/lib来自同一个发行包不要混用。用openssl version命令看库版本或者看头文件里的OPENSSL_VERSION_NUMBER宏。4.2 现象Debug 版能编过Release 版报一堆警告当错误原因Release 配置默认开了/WX警告视为错误而 librtmp 老代码里有大量类型转换警告。解决在 Release 配置的「C/C → 常规 → 将警告视为错误」设为「否」或者把警告等级降到/W3。不要试图去改源码消警告老代码改一处可能引出十处新问题。4.3 现象运行测试程序时崩溃在RTMP_Connect里原因RTMP结构体没有清零就使用或者RTMP_Init之前调用了其他函数。librtmp 的 API 要求先RTMP_Init再RTMP_SetupURL顺序错了内部指针是野指针。解决严格按RTMP_Init→RTMP_SetupURL→RTMP_Connect→RTMP_ConnectStream的顺序调用并且RTMP结构体用calloc分配或memset清零。4.4 现象推流几秒后断开日志显示握手失败原因OpenSSL 的随机数种子没初始化或者系统时间不对导致证书校验失败RTMPS 场景。解决在程序启动时调用SSL_library_init()和SSL_load_error_strings()虽然 1.1.1 之后这些函数自动初始化但老代码里显式调用没坏处。如果是 RTMPS检查服务器证书是否过期以及本机时间是否准确。4.5 现象x86 工程链接 x64 的 zlib.lib 报模块计算机类型冲突原因下载的 zlib 预编译包是 x64 的而你的解决方案平台是 Win32。解决要么把解决方案平台切成 x64要么重新编一个 x86 的 zlib。我一般选后者因为老项目多半锁死 x86。自己编 zlib 很简单把zlib/src下的.c加进一个静态库工程运行库设成和 librtmp 一致编出来就是对的。5. 验证静态库可用性的最小测试工程与进阶技巧编出librtmp.lib只是第一步真正要确认它能用得建一个最小的测试 exe 来跑通一次 RTMP 连接。新建一个「Windows 控制台应用」在main.c里写一段最简代码#include stdio.h #include rtmp.h int main(void) { RTMP *r RTMP_Alloc(); if (!r) { printf(alloc failed\n); return 1; } RTMP_Init(r); // 这里替换成一个可用的 rtmp 地址做测试 if (!RTMP_SetupURL(r, rtmp://127.0.0.1/live/test)) { printf(setup url failed\n); RTMP_Free(r); return 1; } RTMP_EnableWrite(r); // 推流模式 if (!RTMP_Connect(r, NULL)) { printf(connect failed\n); RTMP_Free(r); return 1; } printf(connected ok\n); RTMP_Close(r); RTMP_Free(r); return 0; }这段代码的逻辑是分配RTMP结构体、初始化、设置 URL、开启写模式、发起连接。参数说明RTMP_EnableWrite表示这是推流端如果只拉流就不调用。RTMP_Connect的第二个参数是RTMPPacket*传NULL表示不携带额外参数。编译这个 exe 时链接器输入加上librtmp.lib、ws2_32.lib、libssl.lib、libcrypto.lib、zlib.lib附加库目录指向各自的位置。如果连接成功说明静态库的符号解析、运行库匹配、架构一致性都没问题。如果失败看RTMP_Connect返回前的日志librtmp 内部有RTMP_Log可以输出详细握手过程把日志级别调到RTMP_LOGDEBUG能看到每一步的字节数。进阶用法上有两个技巧值得掌握。一是把 librtmp 的日志重定向到自己的日志系统通过RTMP_LogSetCallback注册回调这样推流失败时能拿到具体是握手阶段还是 publish 阶段出错。二是如果你只需要 AMF 编解码而不需要网络部分可以单独把amf.c和amf.h抽出来编成一个小库体积小、依赖少适合做 RTMP 消息的离线解析工具。我自己的习惯是每次编完静态库先不急着集成到主工程而是用上面那个最小 exe 跑一遍本地 RTMP 服务比如自己搭一个简单的接收端确认connected ok打印出来再往主工程里放。这个习惯帮我省过很多次「主工程里一堆依赖报错不知道是谁的锅」的麻烦。希望帮到你。本文还有配套的精品资源点击获取