VS2015下gRPC编译避坑指南:版本选型与实战步骤 简介面向Windows平台使用Visual Studio 2015进行C开发的工程师这份gRPC预编译资源包提供了可直接落地的开发环境。包内已编译好Debug与Release两种配置的gRPC库并附带一个可运行的helloworld示例项目开发者无需从源码自行构建即可快速验证服务定义、Stub生成、HTTP/2通信及流式调用等核心机制。压缩包共884个文件以头文件430个h、源码文件306个cc、proto定义64个proto为主体同时包含可执行程序、静态库与动态库exe/lib/dll整体大小约71.97MB。已有1753人学习使用适合初次在Windows上搭建gRPC环境、希望绕过繁琐编译步骤直接开展业务开发的C程序员。借助预编译库与示例可重点理解基于protobuf的服务接口设计、客户端/服务端代码生成流程以及TLS加密和流式传输在实际工程中的集成方式。 本想在老项目里接入gRPC结果一头撞上“Windows VS2015”这个组合网上一搜全是VS2019/2022的教程老工具链的内容几乎绝迹。折腾了几天踩了一堆坑总算把客户端和服务端跑通了。这篇就把完整的版本选型、编译步骤和报错经验整理出来给还在维护老工程的朋友省点时间。1. 为什么VS2015是gRPC编译的“困难模式”先说明白一个核心问题gRPC对编译器版本的要求比很多人想象的激进得多。官方文档长期标注的“最低支持编译器版本”放到VS2015MSVC 19.0v140工具集上基本都跑不通。这不是环境没配好而是新版gRPC源码本身就已经放弃了这套旧工具链。1.1 gRPC对编译器要求的真实变化gRPC C库依赖了Protobuf、absl、c-ares、OpenSSL/BoringSSL等一系列组件。其中abslAbseil C公共库是谷歌官方出品对编译器版本要求一向保守中带严格新版本absl大量使用C14甚至C17特性而VS2015对C14的支持是残缺的对C17基本不认。这就导致只要gRPC版本够新absl一编译就会喷出一堆模板语法错误。类似“std::result_type”找不到、可变参数模板解析失败这类报错在老环境下非常典型。1.2 版本选型是绕不开的第一步在VS2015上编译gRPC第一步不是装依赖而是选对版本。选错了后面全白搭。我的实测经验是gRPC v1.30.x是兼容VS2015的一个相对靠后又能正常工作的版本线再往上到了v1.34以后非要碰VS2015就要费很大力气改源码不值当。Protobuf方面gRPC v1.30.2自己带的submodule版本是v3.11.4这个组合在VS2015上编译通过率最高不用额外去升protobuf。这里给一张我当时参考的版本匹配表是反复试出来的比较稳的组合组件推荐版本备注gRPCv1.30.2老朋友组合VS2015最后的好版本protobufv3.11.4gRPC自带submodule无需单独下载abseil随gRPC submodule认准20200225左右的老版本OpenSSL1.1.1k非BoringSSL1.1.1系列最后一个稳定支持线CMake3.16.x ~ 3.20.x老生成器兼容性最好VS2015Update 3必须打补丁没打寸步难行如果你用的是更新一些的项目代码又必须留在VS2015可以尝试gRPC v1.28.x会更稳但功能也相对老。我用v1.30.2是因为需要一些统一地址相关的特性测试了几天没有发现异常。2. 编译前的工具链准备与依赖选型确定好版本后接下来是准备环境。VS2015不是装上就能用的先检查几个容易被忽略的点不然编译到一半报错会让人崩溃。2.1 基础环境确认清单第一VS2015必须要有Update 3补丁。Update 3是VS2015生命末期一个较大的更新改进了不少C11/14支持细节。没打这个补丁编译gRPC会死在很靠前的阶段。第二需要安装Windows SDK建议用8.1版本对VS2015兼容性最好。第三CMake版本不要追新常见版本的CMake虽然也能识别“Visual Studio 14 2015”生成器但新版本CMake对v140工具集的处理有些行为变化容易引发奇怪问题。我自己用了3.16.5顺利过关。还需要一个Git客户端Windows上直接用git for windows就好。一个容易踩的坑是路径问题整条编译路径最好别有中文字符和空格虽然CMake多数时候能处理但第三方库里总有那么几个组件不按套路出牌。我习惯统一放在D:\build\grpc这种干净路径下。2.2 克隆源码时最容易犯的错很多教程让人用git clone --depth 1来加速拉取这在VS2015版本下是个大坑。gRPC是通过submodule管理第三方依赖的浅克隆后submodule往往拉不完整或者拉下来的目录状态不对导致protobuf源码缺失。仓库明明在一编译就报找不到google/protobuf/...头文件。我建议老老实实加-b v1.30.2拉对应分支不要加depth参数。完整克隆会多花一点时间但后面省心很多git clone -b v1.30.2 https://github.com/grpc/grpc.git cd grpc git submodule update --initsubmodule更新这一步会拉取protobuf、absl、c-ares等一大堆依赖这部分网络耗时很长。如果某个submodule拉取失败国内网络环境大家都懂不要反复重试整个命令而是单独进入对应目录处理或者把网络代理配好再试。2.3 SSL后端选择为什么我放弃了BoringSSLgRPC默认的SSL后端是BoringSSL这是谷歌维护的OpenSSL分支。问题在于BoringSSL在VS2015上编译极其痛苦一是耗时长二是它对老汇编工具链有额外要求经常卡在生成汇编代码阶段报错。我不是没试过折腾了大半天没成果根源在于VS2015自带的nasm/汇编环境跟BoringSSL构建脚本兼容性太差。我的建议是直接切到OpenSSL。CMake提供了明确开关用系统已有的预编译OpenSSL库编译时间大幅度缩短问题也少很多。这里有两点必须注意第一OpenSSL选择1.1.1系列官方从1.1.1版本开始对Windows构建支持了大改1.1.1k的预编译包可以直接用。别用OpenSSL 3.x老项目API兼容性不够。去slproweb.com/products/Win32OpenSSL.html下载Win64 OpenSSL v1.1.1k版带Win64字样的完整安装包。第二安装OpenSSL时DLL建议复制到C:\OpenSSL-Win64\bin里库文件在lib目录头文件在include目录这些路径后面CMake配置要用到。安装完成后重启一次终端让环境变量生效。如果不想装系统目录也可以解压到工程目录下CMake配置时指向那个路径。3. 完整编译流程实录环境准备齐全后就是编译环节了。这部分我把每一步命令和为什么这么写都列出来方便你真正理解而不是机械复制。3.1 CMake配置命令逐项解析在gRPC源码根目录下我习惯建一个单独的build目录不要把编译产物混在源码里mkdir build cd build然后执行CMake配置。关键的配置命令分享给大家cmake .. -G Visual Studio 14 2015 -A x64 -DCMAKE_BUILD_TYPERelease -DgRPC_SSL_PROVIDERpackage -DOPENSSL_ROOT_DIRC:/OpenSSL-Win64 -DOPENSSL_INCLUDE_DIRC:/OpenSSL-Win64/include -DOPENSSL_LIBRARIESC:/OpenSSL-Win64/lib/libssl.lib;C:/OpenSSL-Win64/lib/libcrypto.lib -DCMAKE_INSTALL_PREFIXD:/grpc-install逐项解释一下。-G Visual Studio 14 2015对应的就是VS2015这个生成器名字是固定的网上能搜到新版用Visual Studio 16 2019千万别照抄。-A x64指定64位处理器架构如果你的工程是32位的这里改成Win32但我强烈建议现代项目全用x64。-DCMAKE_BUILD_TYPERelease指定release模式。这里有个隐藏影响gRPC在debug模式下会带一堆断言和调试符号运行效率差很多而且debug库跟release库混用会出现链接错误。-DgRPC_SSL_PROVIDERpackage是切换到OpenSSL的关键默认值是module意思是从submodule拉BoringSSL编译改成package后CMake会去找系统已安装的SSL库。后面三个OPENSSL_*参数分别告诉CMake头文件在哪、库文件在哪比让它自动搜索可靠得多。3.2 编译与安装指定目标进行时配置完成后在build目录下执行编译cmake --build . --config Release --target grpc_cpp_plugin -j 8这里解释两个细节。--target grpc_cpp_plugin只编译生成代码要用到的插件避免全量编译等待过长时间。如果你后面只是要用grpc动态库也可以把target换成grpc。-j 8是并行编译线程数按你机器CPU核心数调整8核心就写8用满就行。编译期间我把最关键的输出贴一下方便大家对照是否正常grpc_cpp_plugin.vcxproj - D:\build\grpc\build\Release\grpc_cpp_plugin.exe看到这行就说明核心工具已经生成。接着全量编译cmake --build . --config Release -j 8这次会生成grpc.dll、grpc.dll、protobuf.dll、absl相关dll等一大票文件。在build目录下的Release文件夹里就能找到。随后执行安装命令把所有产物集中到一个便于引用的目录cmake --install . --config Release这一步会把头文件、库文件、DLL和工具全部复制到前面设置的D:/grpc-install目录下。3.3 生成proto代码与第一个Client实测编译完工具还没大功告成。gRPC开发的核心是编写proto文件然后生成C代码。以最简单的helloworld工程为例假设proto文件长这样syntax proto3; package helloworld; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name 1; } message HelloReply { string message 1; }生成代码的命令分两步。先生成基本的pb消息代码再生成grpc服务代码protoc.exe -I ./proto --cpp_out./gen ./proto/helloworld.proto protoc.exe -I ./proto --grpc_out./gen --pluginprotoc-gen-grpc./build/Release/grpc_cpp_plugin.exe ./proto/helloworld.proto第一步生成的是消息序列化代码helloworld.pb.cc和helloworld.pb.h第二步生成的是gRPC服务骨架代码helloworld.grpc.pb.cc和helloworld.grpc.pb.h。注意第二步里--plugin参数指向的grpc_cpp_plugin.exe路径必须是刚才编译出来的那个不能用其他版本替代。版本不一致轻则报错重则生成代码静默出错到运行时才暴露。然后在VS2015里新建控制台工程把生成的4个文件加进去包含头文件目录设为D:/grpc-install/include库目录设为D:/grpc-install/lib链接时加上grpc.lib、grpc.lib、protobuf.lib、ws2_32.lib等依赖库。运行时会提示缺少grpc.dll之类把install目录里dll都拷贝到exe同目录就行。第一个跑通的client程序核心代码大致如下#include grpcpp/grpcpp.h #include helloworld.grpc.pb.h int main() { auto channel grpc::CreateChannel(localhost:50051, grpc::InsecureChannelCredentials()); auto stub helloworld::Greeter::NewStub(channel); helloworld::HelloRequest request; request.set_name(world); helloworld::HelloReply reply; grpc::ClientContext context; grpc::Status status stub-SayHello(context, request, reply); if (status.ok()) { printf(%s\n, reply.message().c_str()); } return 0; }出现“Hello world”字符串的那一刻整套链路总算是通了。这个过程比预想中费劲得多中间各种报错排查花了不少时间。下面把常见问题整理成一个速查表方便大家直接对着找方案。4. 常见报错与排查技巧实录4.1 编译期报错速查表报错信息根本原因解决方向C2039: “result_type”: 不是“std::binary_function”的成员MSVC 19.0对C14/17支持不全降低gRPC版本至v1.30.x以下或升级到VS2017LNK2038: 检测到“RuntimeLibrary”的不匹配项/MT和/MD混用全工程统一运行时库为/MT或/MDfatal error C1083: 无法打开包括文件: openssl/ssl.hOpenSSL头文件路径没配置检查OPENSSL_INCLUDE_DIR是否有效BoringSSL编译卡住或报nasm错误老汇编器不兼容直接切OpenSSL别硬趟BoringSSLabsl编译时报模板语法错误abseil版本过高拉取老版本submodule或选老gRPC版本第一行的result_type错误是VS2015用户最常见的心理阴影。本质上是新版protobuf的代码期望编译器对标准库支持更完整但VS2015的std库缺少这个类型别名。降级到v1.30.2配套的protobuf v3.11.4后这个报错自然消失。如果你非要用新gRPC可以手工在工程全局定义一些兼容宏比如补一个旧接口别名到头文件里但收益不大折腾半天不如直接降级。第二行的RuntimeLibrary不匹配是我踩过的第二个大坑。VS2015工程默认运行时库是/MD动态多线程DLL但某些依赖库可能编译成了静态库或不带dll的版本链接时就会报这个错。解决办法是在工程属性里找到“C/C → 代码生成 → 运行库”全部改成多线程DLL/MDgRPC默认编译结果就是/MD别改静态库否则后面会有更多麻烦。4.2 链接期与运行期故障编译过了链接不过或者链接过了运行闪退这类问题在Windows下几乎是必然出现的。我总结出三个高频场景。第一个是找不到DLL。安装时虽然指定了目录但Windows程序运行时会优先在当前目录找DLL。如果exe目录下没有grpc.dll、grpc.dll、protobuf.dll、absl_*.dll程序启动就报0xc000007b或提示找不到组件。最省事的方案是把install目录里所有DLL全部复制到exe同目录别偷懒只复制几个关键的。第二个是Failed to create channel或连接报错。排除网卡和防火墙因素外大概率是SSL库没加载成功。切换到OpenSSL后把libcrypto-1_1-x64.dll和libssl-1_1-x64.dll也一起拷过去。gRPC初始化时静态链接了SSL符号但实际运行时还是要加载DLL一旦缺了它CreateChannel会返回一个负数的错误码表现就是客户端起不来。第三个是debug/release配置不一致。我有一次工程调试模式连protobuf库运行到SerializeToString直接崩。原因是protobuf在debug和release下生成的代码有差异混用会导致类型布局不一致。所有依赖库和调用方工程要么全debug要么全release绝对不能交叉。VS2015的解决方案配置管理器里可以分别设置确认gRPC库是release编译的自己的工程就用release。4.3 针对VS2015的几个独家经验调试这块我发现一个比较顺手的结构。在项目下建一个目录放install后的所有内容include、lib、bin然后用环境变量或工程属性统一指向。这样换电脑、换环境时直接把整个目录带上就能重新配置。老项目往往在好几台机器上共享这个方式避免每台都重新编译。还有个小技巧VS2015自带的命令行编译脚本vcvarsall.bat在编译gRPC时比直接开VS更可控。如果用Visual Studio的IDE直接编译CMake生成的工程有时某些第三方目标会莫名其妙失败而用命令行反而稳定。我的建议是配置完CMake后打开“适用于VS2015的开发者命令提示符”在里面执行build步骤避开了IDE环境变量冲突的问题。另外CMake配置的生产环境里不要贪图新版本。CMake 3.22以后对VS2015的支持明显减弱我朋友试过用CMake 3.26编译同一个gRPC工程出现了无法识别v140工具集的问题降到3.16.5后一切正常。这个经验也写在这里避免后来人重蹈覆辙。5. 项目接入gRPC后的几点实践心得编译通过只是第一步真正把gRPC整合进老业务才是更繁琐的阶段。这里写几点我在项目里实际应用时的体会。连接管理方面不要每次调用RPC临时创建一个channel。channel是有复用价值的底层维护了连接池反复创建销毁会带来明显的握手开销。服务启动时创建一个全局的channel和stub之后所有请求共用这一个性能提升明显。超时控制方面gRPC默认等待时间不算太短内部服务之间调用如果对方卡死调用方会僵在那里很久。建议所有调用显式设置deadlinegrpc::ClientContext context; context.set_deadline(std::chrono::system_clock::now() std::chrono::seconds(5));内部接口一般5秒足够外部依赖可以考虑10~15秒。这个方法能避免很多线上故障连锁反应。异常处理上老项目里很多代码不习惯检查每个返回状态但gRPC的grpc::Status是必须每次都检查的。特别是在Windows上偶发的网络瞬断会导致UNAVAILABLE状态码不处理的话程序会继续用无效的响应数据往下走结果非常难排查。我在工程里封装了一个简单的检查函数要么重试要么快速失败并打日志。日志方面VS2015项目里没有现成的日志库的话用Windows事件日志或者OutputDebugString输出到调试器都行。关键请求和错误响应一定要记录参数注意规避敏感信息否则线上问题根本无从查起。整个折腾过程虽然痛苦但走通之后老项目也能稳定地跑起gRPC服务整体收益还是很值的。版本锁定、依赖选型、编译顺序这三件事把握好VS2015这个老伙计并不是完全不能和gRPC共处。希望这个记录能帮同样被困在旧工具链里的朋友少走几次弯路。本文还有配套的精品资源点击获取