☰
VS2017编译librtmp静态库:包含依赖库与源码的完整指南
2026/10/15 18:14:34 网站建设 项目流程

简介:本资源面向需要在 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 是用预编译库还是自己编?我的血泪经验是,如果你只是要一个能跑的 librtmp,OpenSSL 直接用官方或可信来源的预编译.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 用/MDd,librtmp 用/MT,链接时会报LNK2038检测到RuntimeLibrary不匹配。我一般统一用/MTd(Debug)和/MT(Release),这样编出来的 exe 不依赖vcruntime140.dll,拷到别的机器上直接能跑。

2.4 链接 OpenSSL 和 zlib 的库文件

静态库工程本身不产生最终链接,但它在编译阶段需要头文件,在「链接器 → 输入 → 附加依赖项」里其实用不到,因为静态库不解析外部符号。真正需要配依赖的是最终调用 librtmp 的 exe 工程。不过为了让 librtmp 工程能通过编译(至少语法检查),头文件路径必须对。等到你建一个测试 exe 来验证时,在 exe 工程的链接器输入里加上:

ws2_32.lib crypt32.lib libssl.lib libcrypto.lib zlib.lib

ws2_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里对应<CharacterSet>MultiByte</CharacterSet>。这个设置不直接影响 librtmp 自己的代码,但影响它包含的windows.h里的宏展开。

结构体对齐方面,librtmp 的RTMPPacket结构里有int、uint32_t、指针混合,默认对齐在 x86 和 x64 下不同。如果你编的是 x64 版本,而调用方是 x86,那肯定链接不上。所以第一步就要确定目标平台:老项目多半是 Win32(x86),那就把解决方案平台设成 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__socket@12。这是典型的 Winsock 库没链接。ws2_32.lib必须加在 exe 工程的附加依赖项里,而且要在libssl.lib之前还是之后?实际上ws2_32和 OpenSSL 没有直接依赖,顺序不敏感,但习惯上放在最前面。如果加了还报错,检查是不是把ws2_32.lib写成了wsock32.lib,后者是旧版,符号名不同。

第三个:error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't 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打印出来,再往主工程里放。这个习惯帮我省过很多次「主工程里一堆依赖,报错不知道是谁的锅」的麻烦。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询