ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VS2017编译librtmp.lib静态库:依赖配置与避坑指南

VS2017编译librtmp.lib静态库:依赖配置与避坑指南 简介这份资源面向需要在 Windows 10 与 VS2017 环境下使用 RTMP 协议的 C/C 开发者提供可直接编译的 librtmp.lib 静态库工程解决自行编译时依赖库难找、配置繁琐的问题。压缩包共 238 个文件约 49.12MB以 163 个 h 头文件、28 个 dll 动态库、8 个 lib 库文件及 7 个 c 源文件为主另含 sln 解决方案、vcxproj 工程与编译日志等目录按 lib、librtmp、openssl-1.0.1c、zlib-1.2.8、vs2017 分层组织依赖关系一目了然。已有 637 人学习下载说明该编译方案在同类需求中具备一定参考价值。读者可直接打开 librtmp.sln 编译出目标库省去 OpenSSL 与 zlib 的交叉配置环节同时借助随附源码理解 RTMP 握手、AMF 编解码与 URL 解析等模块的实现适合流媒体推流、直播客户端开发及协议学习场景。1. VS2017 编译 librtmp.lib从源码到静态库的完整路径手上拿到一个 RTMP 推流模块编译环境是 VS2017依赖里写着 librtmp.lib但翻遍系统目录和 NuGet 都找不到现成的库文件。这不是个例——librtmp 本身是 RTMPDump 项目的一部分官方并不提供 Windows 下的预编译静态库VS2017 的工程文件也需要自己补。所以「vs2017 编译 librtmp.lib」这件事本质上就是拿 RTMPDump 的源代码在 VS2017 里建一个静态库工程把依赖的 zlib 和 OpenSSL 配好最终产出一个能在自己项目里直接引用的 librtmp.lib。这个方案适合谁适合需要在 Windows 桌面端做 RTMP 推流、拉流又不想引入 FFmpeg 这种重量级依赖的开发者。编译出来的 librtmp.lib 体积小、接口直接配合头文件就能调RTMP_Init、RTMP_Connect、RTMP_SendPacket这些函数。整条路径不复杂但坑集中在依赖库的链接顺序和 VS2017 的工程配置上下面按实际操作顺序拆开讲。2. 编译前的环境准备与源码获取2.1 VS2017 需要装哪些工作负载VS2017 的安装器是模块化的默认的「桌面开发用 C」工作负载不一定装全。编译 librtmp 需要的是 C 编译器、Windows SDK 和静态库工具链。打开 Visual Studio Installer确认以下组件已勾选「使用 C 的桌面开发」工作负载「Windows 10 SDK」版本选 10.0.17763.0 或更高与 VS2017 兼容即可「C 静态分析工具」可选不影响编译「MSBuild」和「VC 2017 v141 工具集」如果 VS2017 是离线安装的注意离线包里的组件可能被裁剪过。检查VC\Tools\MSVC\14.16.27023\目录下是否有lib\x64\和lib\x86\这两个目录里是运行库的静态版本缺了会导致链接阶段报LNK1104。提示VS2017 的版本号是 15.x工具集是 v141。如果机器上同时装了 VS2019 或 VS2022用 MSBuild 命令行编译时要显式指定-p:PlatformToolsetv141否则会默认走高版本工具集可能引入不兼容的运行时符号。2.2 源码目录结构怎么摆RTMPDump 的源码可以从其官方发布渠道获取核心文件不多。下载后解压目录里通常包含rtmpdump/ ├── librtmp/ │ ├── rtmp.c │ ├── rtmp.h │ ├── rtmpsrv.c │ ├── rtmpsuck.c │ ├── log.c │ ├── log.h │ ├── amf.c │ ├── amf.h │ ├── hashswf.c │ ├── handshake.h │ ├── dh.h │ ├── dhgroups.h │ ├── bytes.h │ ├── rtmp_sys.h │ └── ... ├── zlib/ 可选如果系统已有 zlib 静态库 └── openssl/ 可选如果系统已有 OpenSSL 静态库编译 librtmp.lib 只需要librtmp/目录下的.c和.h文件。但rtmp.c里会#include zlib.h和#include openssl/ssl.h所以必须先把这两个依赖的静态库准备好。2.3 zlib 和 OpenSSL 静态库的准备zlib 的编译相对简单。下载 zlib 源码后用 VS2017 的开发者命令提示符进入zlib-1.2.x目录执行nmake -f win32/Makefile.msc zlib.lib这条命令会生成zlib.lib静态库。注意Makefile.msc默认走的是 x86 还是 x64取决于你打开的是哪个命令提示符。要编 x64 版本用「x64 Native Tools Command Prompt for VS 2017」。OpenSSL 的静态库编译麻烦一些。需要先装 Perl 和 NASM然后在 OpenSSL 源码目录下执行perl Configure VC-WIN64A no-shared --prefixC:\openssl-static nmake nmake installno-shared是关键它确保生成的是静态库libssl.lib和libcrypto.lib而不是 DLL。--prefix指定安装目录后面在 VS2017 工程里配头文件和库路径时要用到。注意OpenSSL 1.1.x 和 3.x 的 API 有差异librtmp 的源码对 1.1.x 兼容性更好。如果手头是 3.x 版本rtmp.c里部分 SSL 调用可能需要微调常见做法是回退到 1.1.1 系列。2.4 建 VS2017 静态库工程的步骤打开 VS2017新建项目选择「Visual C」→「Windows 桌面」→「静态库」项目名填librtmp。建好后做三件事第一把librtmp/下的所有.c和.h文件通过「添加 → 现有项」加入工程。注意rtmpsrv.c和rtmpsuck.c是服务端示例编译静态库时不需要可以排除。第二配置头文件搜索路径。右键项目 → 属性 → C/C → 常规 → 附加包含目录加入C:\openssl-static\include C:\zlib-1.2.x第三配置库目录。链接器 → 常规 → 附加库目录加入C:\openssl-static\lib C:\zlib-1.2.x然后在链接器 → 输入 → 附加依赖项里填libssl.lib libcrypto.lib zlib.lib ws2_32.lib winmm.libws2_32.lib是 Windows Socket 库winmm.lib是多媒体定时器库librtmp 内部会用到。这两个是系统库不需要额外下载。3. 编译参数配置与常见报错处理3.1 预处理器定义怎么设librtmp 的源码里有几处条件编译需要根据平台定义宏。在项目属性 → C/C → 预处理器 → 预处理器定义里加上WIN32 _WINDOWS _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE_CRT_SECURE_NO_WARNINGS是为了压掉strcpy、sprintf这类函数的安全警告。VS2017 默认把这些警告当错误处理不加这个宏会在编译rtmp.c时报C4996。如果用的是 OpenSSL 1.1.x还需要加OPENSSL_API_COMPAT0x10100000L这个宏告诉 OpenSSL 头文件按 1.1.0 的 API 来暴露符号避免因为版本检测逻辑导致某些函数声明被隐藏。3.2 运行库选项必须和主工程一致这是最容易翻车的地方。librtmp.lib 是静态库它本身不链接运行库但编译时的/MT或/MD选项会决定目标文件里引用的运行库符号。如果 librtmp 用/MT静态运行库而调用它的主工程用/MD动态运行库链接时会报一堆LNK2005重复定义或LNK2019无法解析的外部符号。在项目属性 → C/C → 代码生成 → 运行库选「多线程 (/MT)」或「多线程调试 (/MTd)」。Debug 配置用/MTdRelease 配置用/MT。主工程也必须用同样的选项。提示如果主工程是 Qt 或 MFC 项目它们默认可能用/MD。这种情况下要么改主工程要么把 librtmp 也改成/MD。但/MD意味着最终 exe 需要带 VC 运行库 DLL部署时多几个文件。我一般倾向统一用/MT省去部署麻烦。3.3 编译 rtmp.c 时的典型报错报错一fatal error C1083: 无法打开包括文件: zlib.h原因附加包含目录没配对或者 zlib 源码目录路径写错了。检查C:\zlib-1.2.x下是否真的有zlib.h。有些 zlib 发行包里头文件在zlib-1.2.x\根目录有些在zlib-1.2.x\include\路径要对应。报错二error LNK2019: 无法解析的外部符号 __imp__closesocket原因没链接ws2_32.lib。在附加依赖项里补上即可。如果补了还报检查是不是 x86 和 x64 的库混用了——x64 工程必须链接 x64 的ws2_32.lib系统库一般不会错但第三方库容易搞混。报错三error C2065: SSLEAY_VERSION: 未声明的标识符原因OpenSSL 版本不匹配。1.1.x 里SSLEAY_VERSION被OPENSSL_VERSION替代。如果用的是 1.1.x 头文件但源码里写了旧宏要么改源码要么加兼容宏。常见做法是在rtmp.c开头加#if OPENSSL_VERSION_NUMBER 0x10100000L #define SSLEAY_VERSION OPENSSL_VERSION #endif3.4 生成 librtmp.lib 并验证配置完成后在 VS2017 里选 Release x64右键项目 → 生成。如果一切顺利输出窗口会显示librtmp.vcxproj - C:\path\to\librtmp\x64\Release\librtmp.lib验证这个库能不能用写一个最小测试程序#include stdio.h #include rtmp.h int main() { RTMP *r RTMP_Alloc(); if (r) { RTMP_Init(r); printf(librtmp init ok\n); RTMP_Free(r); } return 0; }把这个test.c和librtmp.lib、libssl.lib、libcrypto.lib、zlib.lib、ws2_32.lib、winmm.lib一起链接。如果编译通过且运行输出librtmp init ok说明静态库可用。cl test.c librtmp.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib winmm.lib /IC:\path\to\librtmp /IC:\openssl-static\include /IC:\zlib-1.2.x这条命令里的/I指定头文件路径库文件直接列在源文件后面。注意顺序librtmp.lib在前它依赖的库在后链接器从左到右解析符号顺序反了会报未解析。4. 避坑与排查编译 librtmp 时最容易踩的五个坑4.1 坑一x86 和 x64 库混用导致 LNK1112现象链接时报LNK1112: 模块计算机类型“x86”与目标计算机类型“x64”冲突。原因librtmp 编的是 x64但依赖的 zlib 或 OpenSSL 是 x86 版本。或者反过来。静态库不区分平台是假象目标文件里的机器码类型是写死的。解决统一所有依赖库的平台。用dumpbin /headers zlib.lib | findstr machine查看库的机器类型x64 显示8664x86 显示14C。确保 librtmp、zlib、OpenSSL 三者一致。4.2 坑二Debug 和 Release 运行库不匹配现象Debug 配置下编译通过Release 下报LNK2005: _malloc 已经在 libcmt.lib 中定义。原因librtmp 的 Debug 配置用了/MTdRelease 配置忘了改成/MT或者主工程和库工程的运行库选项不一致。解决四个配置组合Debug/x86、Debug/x64、Release/x86、Release/x64逐一检查运行库选项。Debug 用/MTdRelease 用/MT主工程和所有静态库保持一致。4.3 坑三OpenSSL 符号找不到现象LNK2019: 无法解析的外部符号 _SSL_new、_SSL_connect等。原因OpenSSL 编译时用了no-shared但没生成静态库或者链接时漏了libssl.lib和libcrypto.lib。还有一种可能是 OpenSSL 编译时开了no-ssl2、no-ssl3而 librtmp 源码里引用了被裁掉的函数。解决确认C:\openssl-static\lib\下存在libssl.lib和libcrypto.lib。如果 OpenSSL 编译时裁了协议在rtmp.c里把对应的#ifdef分支关掉或者重新编译 OpenSSL 时不要加no-ssl2、no-ssl3。4.4 坑四rtmp.c 里的 handshake 失败现象编译没问题但运行RTMP_Connect时返回失败日志显示Handshake failed。原因librtmp 的握手依赖hashswf.c里的 SWF 哈希校验。如果服务端要求特定的 SWF 校验而客户端没提供握手会被拒绝。这不是编译问题但很多人编译完第一次跑就卡在这里误以为是库没编对。解决在RTMP_Init之后、RTMP_Connect之前调用RTMP_SetSWFHash或RTMP_SetSWFSize传入正确的 SWF 信息。如果服务端不校验可以跳过。另外检查RTMP_Connect的第二个参数——如果是NULL表示不指定流路径有些服务端会因此拒绝。4.5 坑五静态库里的符号被裁剪现象链接时提示某个函数未定义但dumpbin /symbols librtmp.lib里明明有这个符号。原因VS2017 的链接器默认开启/OPT:REF会裁掉未被引用的符号。如果主工程通过函数指针动态调用 librtmp 的函数链接器可能认为这些符号没被引用直接裁掉。解决在主工程的链接器 → 优化 → 引用设为「否 (/OPT:NOREF)」。或者在代码里显式引用一下这些函数比如取个地址赋给volatile指针骗过链接器。5. 进阶技巧用 MSBuild 命令行批量编译和版本管理5.1 用 MSBuild 命令行替代 IDE 编译在 CI 环境或需要批量出包时用 MSBuild 命令行比开 IDE 更可控。VS2017 的 MSBuild 路径通常在C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe编译 librtmp 工程的命令MSBuild.exe librtmp.vcxproj /p:ConfigurationRelease /p:Platformx64 /p:PlatformToolsetv141 /m/m开启多核并行编译/p:PlatformToolsetv141强制用 VS2017 工具集。如果机器上装了多个 VS 版本不加这个参数可能走高版本工具集导致生成的 lib 在 VS2017 主工程里链接失败。5.2 把依赖库版本写进工程文件多人协作时zlib 和 OpenSSL 的路径不能写死在某台机器的绝对路径里。在.vcxproj文件里用属性变量PropertyGroup OpenSSLDir$(SolutionDir)third_party\openssl/OpenSSLDir ZlibDir$(SolutionDir)third_party\zlib/ZlibDir /PropertyGroup ItemDefinitionGroup ClCompile AdditionalIncludeDirectories$(OpenSSLDir)\include;$(ZlibDir);%(AdditionalIncludeDirectories)/AdditionalIncludeDirectories /ClCompile Link AdditionalLibraryDirectories$(OpenSSLDir)\lib;$(ZlibDir);%(AdditionalLibraryDirectories)/AdditionalLibraryDirectories AdditionalDependencieslibssl.lib;libcrypto.lib;zlib.lib;ws2_32.lib;winmm.lib;%(AdditionalDependencies)/AdditionalDependencies /Link /ItemDefinitionGroup这样把third_party目录和源码一起提交到版本库任何人拉下来都能直接编译不用手动配路径。5.3 验证 librtmp.lib 的 ABI 兼容性静态库的 ABI 兼容性比动态库更敏感。如果主工程和 librtmp 用的编译器版本不同或者结构体对齐方式不同链接可能通过但运行崩溃。验证方法是用dumpbin /headers librtmp.lib看目标文件的机器类型和节区对齐再用dumpbin /symbols librtmp.lib | findstr RTMP_确认关键函数符号存在。我一般会在主工程里加一个静态断言检查RTMP结构体的大小static_assert(sizeof(RTMP) EXPECTED_SIZE, RTMP struct size mismatch);EXPECTED_SIZE从编译成功的 librtmp 版本里用sizeof打印出来写死在主工程里。这样一旦库的 ABI 变了编译期就能发现不用等到运行时出玄学崩溃。5.4 一个我踩过的坑别用预编译头librtmp 的源码是纯 C没有stdafx.h或pch.h。如果在 VS2017 工程里开了「预编译头」选项编译rtmp.c时会报C1010: 在查找预编译头时遇到意外的文件结尾。解决办法是在项目属性 → C/C → 预编译头设为「不使用预编译头」。这个设置对每个.c文件都生效改一次就行。编译 librtmp.lib 这件事说到底是「依赖管理 工程配置」的功夫代码本身一行不用改。我习惯在编完第一个版本后把整个工程目录连同third_party一起打包存档下次换机器直接解压就能用省得重新踩一遍 OpenSSL 的编译坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表