尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VS2010环境下Thrift 0.9.3编译实战:从源码到lib集成全攻略

VS2010环境下Thrift 0.9.3编译实战:从源码到lib集成全攻略 简介Windows环境下使用Visual Studio 2010编译的Thrift 0.11.0资源包同时提供编译好的lib库文件与完整C源码。面向需要在Windows平台集成Thrift进行跨语言服务开发或希望深入阅读框架源码的C工程师可省去自行编译的繁琐配置直接链接库文件即可开始项目开发。包体共158个文件以92个头文件、61个C源文件为主另有2个lib库文件、2个tcc模板文件及1个txt说明压缩包仅3.12MB轻量易用便于快速部署到工作环境。目前已有542人学习下载是Windows下使用Thrift框架的实用参考。除预编译库可直接调用外源码覆盖阻塞与非阻塞服务端、文件传输、SSL套接字、JSON协议等常见模块便于调试、理解序列化与通信机制也可按需修改定制。尤其适合想绕开源码编译障碍、又希望保留底层掌控力的开发者集成到VS2010工程后即可快速构建和验证Thrift服务。 接手这个标题时我第一反应是都什么年代了还有人要在 VS2010 下折腾 Thrift做技术越久越明白一个系统一旦上线变成老资产维护它的人没有太多选择权——要么重构要么继续在旧环境里把新需求补上。而 Thrift 这种跨语言 RPC 框架经常只换一个服务端口就能救活一堆老项目。这篇就完整记录一下我在 Windows VS2010 下编译 Thrift、拿到 lib 和 C 源码的全过程包括版本选型、依赖处理、踩坑记录和最终集成方案给还在维护老工程的朋友一条可以直接走通的路。1. 项目背景与整体思路1.1 为什么还在 VS2010 下编译 Thrift先说点实际的。VS2010 是 2010 年发布的 IDE编译器核心是 VC10对 C11 的支持几乎为零连auto、nullptr这类今天看来最基础的语法都不完整。那为什么还要用它编译 Thrift我接触到的场景主要有三种。一是公司内部的 C 服务端项目一直锁定在 VS2010升级编译器意味着全量回归测试业务部门不会为“技术债”买单二是某些老旧的 Windows Server 环境里只装了 VS2010换版本涉及整个 CI 流水线权限变更成本极高三是第三方 SDK 只提供了 VS2010 编译好的二进制接口新编译器编译出来的 C 代码二进制不兼容被迫统一到 VS2010。不管哪一种核心诉求都是同一个在既有环境里把 Thrift 跑起来而不是把环境重做一遍。我刚接到这个任务时也犹豫过要不要劝对方换编译器但探了探底就放弃了——项目代码量大且很多模块没有自动化测试编译器的任何变动都可能带来隐蔽的运行时崩溃。这种情况下最稳妥的方案就是找一个兼容 VS2010 的 Thrift 版本在本地编译出可用的 lib再集成到现有工程里。1.2 版本选型不是最新的才是对的Thrift 官方版本迭代很快最新版早已要求 VS2015 甚至更高版本但 VS2010 能用的版本被锁定在一个很窄的区间里。我实测下来thrift-0.9.3是最后一个对 VS2010 有较好支持度的版本thrift-0.10.0开始部分代码采用 C11 特性到了0.11.0官方构建脚本直接弃用了 VS2010。有人可能会问能不能用最新版源码自己改一改兼容 VS2010我的建议是别折腾。Thrift 代码量大且涉及模板特化、异常处理、线程模型等重灾区自己改源码的时间成本远超直接使用旧版本。而且旧版本在线上已经跑了十年稳定性经过了充分验证。版本选定的同时还要考虑配套依赖的版本组件推荐版本说明Thrift0.9.3最后一个原生支持 VS2010 的版本Boost1.57 或 1.58太新的 Boost 在 VS2010 下编译报错太老的缺少 Thrift 需要的模块OpenSSL1.0.2 系列新版本 OpenSSL 3.x 完全不支持 VS2010Libevent2.0.22可选非阻塞服务才需要这里多说一句版本匹配的道理。Thrift 的 C 运行时库依赖 Boost 的shared_ptr、thread、system等组件Boost 的版本和编译器的支持程度直接挂钩。VS2010 对 C11 支持弱而 Boost 从 1.59 开始大量使用 C11 特性所以必须卡在 1.58 或更早。OpenSSL 同理1.0.2 是最后支持 VC10 编译的主线版本。1.3 编译前先理清整体流程编译 Thrift 不是一个单一动作而是从 IDL 到运行时完整链条的构建。整个过程我拆成四步准备依赖库Boost、OpenSSL、Libevent按需。编译 Thrift 编译器thrift.exe这是代码生成器负责把.thrift文件转换为 C 代码。编译 Thrift 运行时库libthrift.lib这是运行时支撑库包含协议编解码、传输层、服务端框架等。集成验证写一个最小的 Thrift 服务端/客户端程序确认编译出的库可用。很多人只关心“怎么把 lib 编出来”却忽略了 thrift.exe 编译器的重要性。实际工作中你不可能手写.thrift生成的那些代码——它们都是机器生成的结构复杂、重复度高。所以编译器thrift.exe和运行时库libthrift.lib缺一不可前者是开发期工具后者是运行期支撑两个都要在 VS2010 下成功编译。2. 编译前的环境准备2.1 VS2010 环境细节与注意事项VS2010 安装时需要注意勾选VC 编译器和Windows SDK这两个是编译 C 项目的基础。我见过有人只装了 Visual C# 组件结果打开.sln时提示找不到 C 工具链白白浪费半天。此外一个容易忽略的地方是环境变量。如果你装了多个版本的 Visual Studiolib.exe、cl.exe的默认路径可能被新版本“抢占”。建议在编译 Thrift 前打开“VS2010 命令提示符”来操作而不是用普通的 CMD。VS2010 命令提示符会自动设置好 PATH、INCLUDE、LIB 等环境变量避免目录混乱带来的问题。注意VS2010 默认使用的是 v100 平台工具集。如果中途发现编译器版本不对可以在项目属性里检查“配置属性 → 常规 → 平台工具集”是否显示为 Visual Studio 2010 (v100)。2.2 Boost 依赖库的处理Boost 在 VS2010 下的编译是一个经典命题。我选用的是 Boost 1.58编译步骤如下# 解压 boost_1_58_0 后进入目录执行 bootstrap.bat # 编译必要的库指定编译器和架构 b2 --toolsetmsvc-10.0 architecturex86 address-model32 --with-system --with-thread --with-date_time --with-regex stage这里有几个参数需要解释一下。--toolsetmsvc-10.0明确指定使用 VS2010 的编译器architecturex86 address-model32指定生成 32 位库--with-xxx只编译 Thrift 必需的 Boost 模块。Thrift 0.9.3 实际依赖的 Boost 模块不多主要是 system、thread、date_time 和 regex没必要全量编译全量编译耗时至少半小时。Boost 编译的输出在stage/lib目录下后续配置 Thrift 工程时需要把它加入附加库目录。如果只使用 Thrift 的客户端功能不走非阻塞服务端--with-system和--with-thread就基本够了但我在实际编译时还是把 date_time 和 regex 一并编了因为某些 IDL 生成代码会间接引用到。2.3 OpenSSL 与 Libevent可选项怎么选Thrift 的官方源码里传输层TSSLSocket支持通过 OpenSSL 提供加密能力服务端模型TNonblockingServer依赖 Libevent。如果项目只需要普通的 TCP 通信这两者都可以跳过这也是大多数内部 RPC 场景的实际选择。但如果你需要 SSL 或者非阻塞模式编译 OpenSSL 也是绕不过去的一关。OpenSSL 1.0.2 在 VS2010 下的编译可以借助 Perl 和 NASM步骤稍长但流程稳定perl Configure VC-WIN32 no-asm --prefixC:\OpenSSL ms\do_ms.bat nmake -f ms\nt.makno-asm选项省去汇编优化也省去 NASM 依赖生成的库体积略大但不影响功能。Libevent 2.0.22 在 VS2010 下的编译相对简单直接打开源码里的sln文件编译即可。不过如果走的是同步阻塞服务端TSimpleServer、TThreadedServerLibevent 完全可以不装。3. 编译实操过程3.1 编译 thrift 编译器thrift.exe拿到thrift-0.9.3源码后在contrib目录下能看到thrift.sln解决方案文件。用 VS2010 打开它里面有多个项目关键的是这几个thrift生成 thrift.exe 编译器thriftlib生成 libthrift.lib 静态库thriftnb生成 libthriftnb.lib非阻塞库需要 Libevent先编译 thrift 这个可执行项目。右键项目 → 设为启动项目然后在菜单栏选择 Debug 或 Release 配置。我建议直接用 Release因为 thrift.exe 是开发期工具运行效率更重要。编译 thrift.exe 之前需要确认 boost 头文件路径。进入项目属性 → C/C → 常规 → 附加包含目录添加 Boost 和 Thrift 源码lib\cpp路径。如果不配置会在编译过程中报出成片的“无法打开包含文件: boost/shared_ptr.hpp”错误。C:\boost_1_58_0 C:\thrift-0.9.3\lib\cpp配置完成后直接生成。等待编译输出成功后在Release目录下看到thrift.exe。这时可以在命令行验证thrift.exe -version能输出版本号说明编译器本身已经可用。3.2 编译运行时库libthrift.lib这是整篇博文的核心目标——拿到可链接的静态库。在同一个解决方案中切换/编译thriftlib项目输出是libthrift.lib。这个库包含了 Thrift 运行时的大部分代码协议层TBinaryProtocol、TCompactProtocol 等、传输层TSocket、TBufferedTransport 等、服务端TServer、TSimpleServer、TThreadedServer 等。编译过程中最容易出问题的就是 transport 相关的源码文件。Thrift 会把可选的依赖OpenSSL、Libevent相关的文件也放入目录如果缺少对应依赖头文件编译就直接报错。这时可以手动排除掉用不到的文件或者直接在项目配置里把 SSLSocket 相关的预处理宏去掉。我的做法是直接修改thriftlib项目属性让它只编译我们需要的模块。具体来说在源文件的“排除”选项里将TSSLSocket.cpp、TNonblockingServer.cpp等标记为“从生成中排除”。这需要你对 Thrift 的模块结构有一定了解但值得做——干净的 lib 比带了一堆用不到的依赖的 lib 好维护得多。不过如果你不想这么细致地裁剪最简单的方案是确保 OpenSSL 和 Libevent 的头文件路径都被引入让 Thrfit 源码里所有可选的代码都能找到依赖然后全部编译。这样生成的 lib 会更大但省心。编译成功后Release目录下会看到libthrift.lib大小通常在 1MB 左右取决于编译选项和包含的模块。此外还会生成libthriftnb.lib这是非阻塞服务端的库如果没装 Libevent 可以不编译该项目。3.3 在自己的项目中引用 Thrift拿到 lib 后集成到现有 VS2010 工程里是检验成果的关键一步。以我自己写的测试项目为例步骤如下第一步配置附加包含目录保证能找到 Thrift 和 Boost 头文件C:\boost_1_58_0 C:\thrift-0.9.3\lib\cpp第二步配置附加库目录指向静态库所在目录C:\boost_1_58_0\stage\lib C:\thrift-0.9.3\lib\cpp\Release第三步在代码中包含 Thrift 的头文件并写一个最小测试。下面是一个简单的代码片段演示如何用 Thrift 的传输层和协议层打开一个 socket 连接#include thrift/transport/TSocket.h #include thrift/transport/TBufferTransports.h #include thrift/protocol/TBinaryProtocol.h #include memory using namespace apache::thrift; using namespace apache::thrift::transport; using namespace apache::thrift::protocol; using namespace std; int main() { shared_ptrTSocket socket(new TSocket(127.0.0.1, 9090)); shared_ptrTTransport transport(new TBufferedTransport(socket)); shared_ptrTProtocol protocol(new TBinaryProtocol(transport)); try { transport-open(); // 到这里说明 Thrift 库可用 transport-close(); } catch (const TException tx) { // 连接失败说明服务端没起但库本身没问题 } return 0; }第四步在链接器输入里添加依赖库。项目属性 → 链接器 → 输入 → 附加依赖项添加libthrift.lib libboost_system-vc100-mt-1_58.lib libboost_thread-vc100-mt-1_58.lib ws2_32.libws2_32.lib是 Windows Socket 库Thrift 的 TSocket 依赖它漏掉会出现大量 LNK2019 链接错误。提示如果 Thrift 是编译成 Debug 版本Boost 也要用对应的 debug 库libboost_system-vc100-mt-gd-1_58.lib混用会导致运行时断言失败这个坑我踩过。编译通过后程序能正常启动、连接说明这一整套链路已经通了。这时候你可以把 thrift.exe 和 libthrift.lib 一起收进自己的工具库里后续新写的.thrift文件都能用这套工具链生成代码并编译链接。4. 常见问题与排查4.1 编译时报错头文件与宏定义问题编译 Thrift 源码时最常见的报错是fatal error C1083: Cannot open include file: boost/shared_ptr.hpp: No such file or directory原因很简单附加包含目录没有配置 Boost 路径或者路径写错了。排查时先确认 Boost 确实在这个路径下再检查引号是否用对了——VS2010 的工程配置里路径分割用分号不要用逗号。另一个典型报错是结构体重定义C2011这通常发生在 OpenSSL 头文件和 Windows 头文件冲突的场景。解决方法是引入宏WIN32_LEAN_AND_MEAN这个宏会让 windows.h 不再包含一些网络相关定义避免与 OpenSSL 重复。注意要写在所有系统头文件之前。4.2 链接报错库顺序与缺失依赖链接时报 LNK2019无法解析的外部符号基本就是三类原因依赖库没加全。比如libthrift.lib加上了但 Boost 库没加。Thrift 的运行时依赖 Boost 的boost::system漏了它就会报_Gpsid4之类的错误实际上是最常见的__imp__ ?错误。库的依赖顺序不对。VS2010 的链接器处理静态库时有依赖顺序规则被依赖者要放在依赖者之后。所以写附加依赖项时先写libthrift.lib再写 Boost 库。顺序反了可能出现费解的链接错误。静态库和动态库混用。Thrift 0.9.3 可以编译成动态库DLL和静态库LIB如果你用了静态 lib 但代码里继承了某个 Thrift 类并把方法导出就会触发运行时错误。建议全部静态链接省去部署 DLL 的麻烦。4.3 运行时异常编码、线程模型与版本不匹配运行时最容易遇到的一个问题Thrift 客户端和服务端版本不一致导致协议解析错误。这通常表现为Bad version in readMessageBegin异常。原因是两端使用的协议格式版本不同比如一端用 TBinaryProtocol、另一端用 TCompactProtocol。在集成测试时务必统一两端 Thrift 版本和协议类型。另一个和 VS2010 强相关的问题是编码。VS2010 对 UTF-8 源码文件的支持不好如果你的.thrift文件里包含中文注释生成的 C 代码在 VS2010 里打开可能显示乱码甚至在编译时报 C4819 警告。解决方案有两种一是在.thrift文件里只用英文注释二是在 VS2010 中把源码文件另存为“Unicode (UTF-8 带签名) - 代码页 65001”格式。注意C4819 警告虽然不阻断编译但在大型项目中会刷屏严重干扰真正报错的定位。建议处理掉。4.4 编译机器的选择如何快速验证成果我建议在交付前准备一个干净的 VS2010 环境来验证整个编译流程的可行性。如果你在一台“装了无数软件”的开发机上弄好了依赖路径但交付给别人时别人没有这些路径整个方案就白做了。我在实际项目里就吃过这个亏——本机编译好的 thrift.exe libthrift.lib 发给团队后同事在干净环境里集成时又花了两天排查 Boost 路径问题。一种更稳妥的做法是在公司内部维护一套“共享的 Thrift 工具包”把 thrift.exe、libthrift.lib、以及所需 Boost 头文件/库都打包进一个固定目录团队统一定位到该目录。这样可以避免每个人各配各的环境把不确定性集中在一个地方消除。4.5 常见问题速查表问题现象可能原因解决方案编译时报找不到 boost 头文件未配置 boost 附加包含目录在项目属性中添加 Boost 路径LNK2019 无法解析的外部符号缺少 ws2_32.lib 或 Boost 库在附加依赖项中添加对应的 lib链接时出现大量 LNK4098 警告Debug/Release 混杂确保 Thrift 库和 Boost 库的运行时配置一致运行时 Bad version 异常客户端服务端协议不匹配统一 TBinaryProtocol 或 TCompactProtocol生成代码中文乱码VS2010 不支持无 BOM 的 UTF-8另存为带 BOM 的 UTF-8 格式调用 TSocket.open 崩溃未初始化 Winsock在 main 开头调用 WSAStartup5. 一些实战中的补充体会我用这套方式成功在 VS2010 下跑通了 Thrift 0.9.3 的编译和集成整个过程比想象中顺畅但有几个细节现在回想起来还是值得单独拿出来说。一个是不要贪图最新版的性能优化。Thrift 新版本在异步、非阻塞方面确实做得更好但 VS2010 的编译器无法充分利用这些特性反而会因为语法兼容问题引入不稳定因素。旧版本加上合理的架构设计比如把 Thrift 封装在独立模块内完全能支撑正常业务量。另一个是尽量保持 Thrift 依赖的纯粹性。我的经验是能不开 SSL 就不开能不用非阻塞就不用非阻塞——这不是偷懒而是减少编译期依赖和运行期排查维度。如果确实需要加密传输优先在业务层做数据加密而不是一定要用到 Thrift 的 TLS 功能。最后是我的一个个人习惯在拿到任何开源库时先在干净环境里编译一遍官方 demo确认工具链本身没问题再接入实际项目。这样把“工具链问题”和“业务代码问题”分开排查很多莫名其妙的问题都能快速定位。对 Thrift 这种跨多模块的框架尤其适用。本文还有配套的精品资源点击获取
返回列表