简介面向 Windows 平台使用 Visual Studio 2015 进行 C 开发的工程师这份编译库集成了 gRpc 1.28 与 protobuf 3.11免去手动编译和依赖配置的繁琐环节。压缩包共 472 个文件包括 387 个头文件、34 个静态库、14 个 CMake 构建脚本、12 个 proto 定义文件以及多个 exe 工具整体约 24.47 MB。其中头文件用于调用 gRpc 与 protobuf 接口静态库提供链接所需符号CMake 脚本简化工程配置proto 文件用于定义服务与消息。已有 995 人学习适合需要在 VS2015 中快速接入 RPC 通信的中高级开发者。资源提供了完整的头文件与 lib 库可直接链接使用CMake 脚本与 protoc 编译器可辅助生成服务端和客户端代码proto 示例展示了接口定义与消息结构便于理解 gRpc 的请求-响应流程bin 与 share 目录附带了部分预编译二进制和配置文件可满足快速部署调试。借助这套组件开发者能免去从源码编译 gRpc 的折腾将更多精力放在业务逻辑与分布式架构上快速搭建高性能服务无论是构建微服务还是学习 RPC 框架都是可靠的起点。 最近手头一个老项目要从自研的报文协议迁到 gRPC整体环境定死在 Windows VS2015 C需要把 grpc 1.28 的 C 编译库完整拉起来。开始我以为直接找个现成的二进制导入项目就行结果在 Windows 上找适配 VS2015 的 gRPC 预编译包基本是做梦官方根本不维护 Windows 下的正式产物。最后花了整整一个周末从源码拉取、第三方子模块更新到 CMake 生成、编译安装把 v1.28.2 完整跑通中间踩了一堆文档里没写的坑。这篇文章就是完整实操记录适合还在维护老 C 工程、被迫锁死在 VS2015 的朋友直接照抄。1. 为什么我最终选择自己编译 gRPC 1.281.1 这个组合到底有什么背景先说清楚使用场景。很多公司在 Windows 上做 C 服务端开发工具链常年停在上古版本VS2015 算是非常有代表性的一套大量遗留模块都是基于 v140 工具集编译出来的不是说升就能升。gRPC 1.28 是 2020 年初的版本对应 protobuf 3.11.x编译器要求只要 C11VS2015 对 C11 的支持虽然不完整但编译 grpc 本体是足够的这也是这个版本在老工具链上还能跑起来的关键原因。另外 1.28 本身也在 C 库发展史里算一个分水岭它后面几个大版本开始强制引入 Abseil 并逐步推高 C 标准要求到了 1.40 以后 VS2015 基本就告别支持了。所以如果你的项目既离不开老编译器又必须上 gRPC1.28 不是你找不到新版本才退而求其次而是这个版本本来就处在一个恰到好处的位置上。1.2 为什么预编译包和 vcpkg 都不靠谱我在开始前对比过三条路。第一条是官方预编译二进制gRPC 官方实际上不发布 Windows 的 release 包你能找到的要么是几十个 DLL 塞在一起的第三方产物要么是某个老博客流传的远古版本编译选项、运行库版本、是否带 SSL 全都不透明拿来引入老项目非常危险所以我直接放弃了。第二条是 vcpkg命令很简单vcpkg install grpc一行就能跑但 vcpkg 的默认 triplet 和最新版 gRPC 依赖链对 VS2015 的支持越来越差很多新版 vcpkg 已经要求 VS2017 以上的工具链即使能装装的也不是 grpc 1.28 这个老版本而是最新的大版本改了 ABI 反而更难对接旧代码。第三条就是自己用源码 CMake 编译这一步可控性最强版本、依赖、静态动态、运行库全部能自己定唯一的代价是配置繁琐、第一次容易踩坑。下面我把我最终跑通的完整方案写出来照着走基本能复现。2. 环境准备工具链版本是最大的暗坑2.1 VS2015、CMake、Windows SDK 的版本匹配先把版本对应关系理清这是最容易翻车的地方。VS2015 对应 CMake 生成器名称是Visual Studio 14 201564 位要加Win64即Visual Studio 14 2015 Win64。CMake 版本建议用 3.20.x我实际用的是 3.20.6这个版本对 VS2015 的支持还很友好。3.21 开始 CMake 逐步弱化对老 VS 的支持到 3.22 及以后版本生成 VS2015 工程时会弹 DeprecationWarning更高版本甚至可能直接无法识别 v140 平台工具集所以别手欠装最新版 CMake。VS2015 本身建议打上 Update 3否则编译器对 C11 特性和标准库实现有各种奇奇怪怪的 buggRPC 里某些模板代码会在老编译器上触发奇怪的编译错误。安装时记得勾上“Visual C”组件只装基础版没有 v140 工具集CMake 生成时会报找不到工具集后面链接你的用户工程也会很痛苦。Windows SDK 这块VS2015 默认配的是 8.1保持默认就行不要额外指定更高版本 SDK否则可能出现“需要升级 Platform Toolset”之类的提示。提示VS2015 写死了用 v140 工具集CMake 生成阶段和后续用户项目里都要保持一致这一步错了会在链接阶段报一堆 LNK 错误后面第 5 节会专门讲。2.2 除了编译器和 CMake还要装哪些东西gRPC 在 Windows 下编译不是只靠 CMake 就行的第三方依赖里有几个硬性前置工具少一个都会在配置或编译阶段崩。Git用来拉源码和更新子模块建议最新版老版本对 submodule 并发更新的支持差。Strawberry Perl 或 ActivePerl必须装。gRPC 的 third_party/openssl 在 Windows 下由 Perl 生成 VS 工程没有 PerlOpenSSL 子模块直接过不去。NASM可选但强烈建议装。OpenSSL 的汇编优化依赖 NASM不装也能编出库只是性能会差一些而且某些 OpenSSL 构建脚本在找不到 NASM 时会中断。Python如果你在 CMake 参数里没关掉 Python 插件配置阶段会去找 Python找不到就报错。我后面给的命令直接关掉这些非 C 插件Python 可以不装。这几个工具装完后记得确认都在 PATH 环境变量里因为 CMake 和 Perl 脚本都是通过 PATH 找程序的。Windows 下重启终端再验证一下perl -v和nasm -v免得到时候在一个隐蔽的脚本里报“command not found”。3. CMake 生成工程与编译实操3.1 拉取源码和更新子模块源码目录建议放在短路径下我用的是C:\g\grpc。很多人在这一步偷懒把源码直接放在C:\Users\用户名\source\repos\...这种长目录下后面 OpenSSL 和 CMake 的复制步骤会因为路径超过系统限制直接失败提前规避能省好几个小时。cd C:\g git clone -b v1.28.2 https://github.com/grpc/grpc.git cd grpc git submodule update --init --recursive也可以 clone 时直接带--recurse-submodules不过分开执行更可控。子模块数量很多尤其 protobuf、openssl、abseil-cpp 体积都不小更新过程会比较久如果网速一般就耐心等。更新完成后一定要确认第三方目录不是空的比如third_party\protobuf\CMakeLists.txt必须存在否则 CMake 配置阶段会各种找不着头文件。3.2 CMake 配置命令逐项解析进入源码目录后新建一个构建目录build_vs2015把 CMake 生成指向这里。我给出一整条经过实测的参数再逐个说明为什么这么设。cd C:\g\grpc mkdir build_vs2015 cd build_vs2015 cmake .. -G Visual Studio 14 2015 Win64 ^ -DCMAKE_INSTALL_PREFIXC:\local\grpc ^ -DCMAKE_BUILD_TYPERelease ^ -DgRPC_INSTALLON ^ -DgRPC_BUILD_TESTSOFF ^ -DgRPC_BUILD_CSHARP_EXTOFF ^ -DgRPC_BUILD_GRPC_PYTHON_PLUGINOFF ^ -DgRPC_BUILD_GRPC_NODE_PLUGINOFF ^ -DgRPC_SSL_PROVIDERmodule ^ -DgRPC_PROTOBUF_PROVIDERmodule ^ -DgRPC_ZLIB_PROVIDERmodule ^ -DgRPC_CARES_PROVIDERmoduleCMAKE_INSTALL_PREFIX指定安装根目录后面展示的产物都会装到C:\local\grpc。CMAKE_BUILD_TYPERelease对 VS 生成器来说不直接决定工程配置工程最终是 Debug 还是 Release 由编译时的--config决定但加上它能防止部分第三方脚本判断出现偏差。把gRPC_BUILD_TESTS关掉可以省掉一半左右的编译量我们只需要库本体不需要跑 grpc 自带的单元测试。C#、Python、Node 插件都关掉只保留 C 的 protoc 插件也就是grpc_cpp_plugin.exe这一步默认是开的不用额外指定。后面四个PROVIDERmodule是重点意思是对齐使用 git submodule 里自带的第三方源码来编译对应依赖而不是去找系统安装的版本。这样能彻底锁死 protobuf、OpenSSL、zlib、c-ares 这些组件的版本避免和本机其他开发工具链产生不可控的冲突。我自己第一次编译时就是因为漏了这几个参数CMake 去系统里翻 OpenSSL 和 protobuf结果版本对不上直接退出。3.3 编译安装一次跑通静态库和动态库CMake 配置成功后会生成grpc.sln等工程文件接下来一条命令把 Release 配置的库编译并安装到指定目录cmake --build . --config Release --target install --parallel 8--parallel 8根据 CPU 核心数调整第一次全量编译大概需要 30 到 90 分钟取决于机器性能protobuf compiler 和 OpenSSL 是最耗时的部分。如果不想装到C:\local\grpc也可以只执行cmake --build . --config Release不指定--target install这样只是不拷贝产物库文件仍然会在构建目录下的Release子目录里。默认情况下 CMake 配置会同时生成静态库和少量动态库这里要特别说清楚。gRPC 在 1.28 里默认gRPC_BUILD_STATIC_LIBSON、gRPC_BUILD_SHARED_LIBSOFF所以按上面的命令编出来的是纯静态库.lib文件体积很大后续链接时要把一堆依赖库一起链进去。如果你想编成 DLL需要在 CMake 阶段追加两个参数cmake .. -G Visual Studio 14 2015 Win64 ^ -DgRPC_BUILD_SHARED_LIBSON ^ -DgRPC_BUILD_STATIC_LIBSOFF我个人建议在没有特殊部署需求的前提下尽量用 DLL。原因有两点一是静态库方式需要你把 grpc、protobuf、openssl、zlib、c-ares 等一长串.lib全部手动加到链接器里漏一个就报一堆 LNK2019二是老项目里面很可能还混着其他模块的 DLL动静混合运行时经常出现运行库冲突。编成 DLL 后头文件加导入库就能编译运行时带几个 DLL 文件即可省心得多。安装完成后在C:\local\grpc下能看到这样的结构C:\local\grpc\ ├── bin\ grpc_cpp_plugin.exe、grpc.dll、grpc.dll 等 ├── include\ grpc、grpc、google/protobuf 等头文件 └── lib\ ├── cmake\ grpc、protobuf 的 CMake 配置文件 ├── grpc.lib ├── grpc.dll ├── grpc.lib ├── grpc.dll └── libprotobuf.lib4. 编译结果验证与 C 项目集成4.1 用自带的 helloworld 例子验证库编完先别急着往项目里塞用 gRPC 自带的 helloworld 例子验证一遍确认头文件、导入库、运行时依赖都正常再进正式项目能少排查很多问题。cd C:\g\grpc\examples\cpp\helloworld mkdir build cd build cmake .. -G Visual Studio 14 2015 Win64 ^ -DgRPC_DIRC:\local\grpc\lib\cmake\grpc cmake --build . --config Release编译完成后到Release目录下可以看到greeter_server.exe和greeter_client.exe。如果按默认方式编的是 DLL还需要先把C:\local\grpc\bin下的grpc.dll、grpc.dll、libprotobuf.dll等复制到 exe 同目录或者把C:\local\grpc\bin加入 PATH否则运行时会弹出“找不到 grpc.dll”的对话框。先启动greeter_server.exe再启动greeter_client.exe客户端输出Greeter received: Hello world就说明整条链路通了。4.2 在自己的 VS2015 工程里引用编译产物如果不用 CMake 而是直接用 VS2015 工程手动配置也不复杂。项目属性里“附加包含目录”填C:\local\grpc\include“附加库目录”填C:\local\grpc\lib。链接器的“附加依赖项”是关键如果用的是静态库版本至少需要补这些grpc.lib grpc.unsecure.lib grpc.lib grpc_unsecure.lib gpr.lib upb.lib address_sorting.lib libprotobuf.lib libprotobuf-lite.lib cares.lib zlibstatic.lib ws2_32.lib crypt32.lib其中grpc_unsecure.lib和grpc_unsecure.lib是非 SSL 版本如果你的通信不涉及 TLS并且编译 gRPC 时没有启用 OpenSSL可以只链这两个不链带 SSL 的库。ws2_32.lib和crypt32.lib是 Windows 系统库必须手工加进去很多新手漏了它们会看到莫名其妙的 LNK2019。在“C/C”-“代码生成”-“运行库”这里要确保和 gRPC 库的编译方式一致。如果你用的是默认编出来的库也就是 Release /MD那你的用户工程也必须用 Release 多线程 DLL (/MD)Debug 用 /MDd混用会报运行时库冲突这个坑后面会详细展开。全部配置好后编译你自己的代码能正常出 exe 并把 DLL 带到目标机器上运行就说明落地成功。5. 常见问题与排查记录5.1 VS2015 编译 gRPC 的高频报错速查表我把这次编译过程中遇到和收集到的典型问题整理成一张表方便你直接对照定位报错信息根本原因解决方式CMake Error: Could NOT find OpenSSL没指定 module provider系统也没有匹配的 OpenSSL加-DgRPC_SSL_PROVIDERmodulefatal error C1083: Cannot open include file: openssl/ssl.h子模块没更新完整或 OpenSSL 未编译确认third_party/openssl存在重跑子模块更新error LNK2038: mismatch detected for RuntimeLibrary/MD 和 /MT 混用或者 Debug 和 Release 混链统一运行库和配置error LNK2019: unresolved external symbol依赖库漏链比如没加 ws2_32 或 gpr对照第 4.2 节的依赖清单逐项添加MSB3491: The path is too longWindows 路径超过 260 字符源码放短路径或开启长路径支持找不到 v140 工具集VS2015 安装时没勾 Visual C 组件修改 VS 安装补装 C 工具集OpenSSL 构建时 nasm not found没装 NASM 或不在 PATH安装 NASM并重新打开终端让 PATH 生效Python not found 提示Python 插件没关闭配置命令加-DgRPC_BUILD_GRPC_PYTHON_PLUGINOFF5.2 路径长度和 Windows SDK 问题的深层处理路径长度问题在 VS2015 时代特别坑。gRPC 的第三方目录嵌套很深像 OpenSSL 生成中间文件时文件路径很容易突破 260 字符轻则报警告重则直接中断编译。除了把源码放到C:\g\这类短路径下还可以通过注册表开启 Windows 长路径支持reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f改完需要重启一次操作系统生效。不过要注意光开系统长路径还不够有些老版本工具链内部仍然用 MAX_PATH 判断所以最可靠的办法还是源码路径短这个我在第 3.1 节就反复强调过。Windows SDK 的问题也很典型。VS2015 默认配置的是 SDK 8.1但很多人机器上装了更高版本的 Windows 10 SDKCMake 检测时可能会选一个高版本 SDK导致工程生成后提示 “Windows SDK 版本 10.0.xxxxx 未安装” 或工具集不匹配。遇到这种情况我建议在 CMake 配置命令里显式指定 SDKcmake .. -G Visual Studio 14 2015 Win64 -DCMAKE_SYSTEM_VERSION8.1或者在生成后的 VS 工程里把项目的“平台工具集”改回Visual Studio 2015 (v140)再在“Windows SDK 版本”下拉框里选 8.1重新编译即可。5.3 运行库冲突的深层原因LNK2038 这个错误几乎是所有 Windows C 库集成场景的梦魇它盯的是 MSVC 的运行库标志。MSVC 编译时默认有四种运行库模式多线程 DLL (/MD)、多线程 DLL 调试 (/MDd)、多线程静态 (/MT)、多线程静态调试 (/MTd)。如果 gRPC 库是用 /MD 编的你的代码工程却用 /MT 去链接链接器会认为两边引用的标准库运行时不同直接报 mismatch。这个问题最坑的地方在于它不一定报一个明确的“运行库冲突”字样有时候是抛出一大串 LNK2038 加_ITERATOR_DEBUG_LEVEL不匹配的混合错误。遇到这类错误先不要去翻代码第一步打开项目属性把“运行库”这一项调到和 gRPC 库一致。最简单的方法是统一使用 /MD 或 /MDd这也是主流的默认选择。如果非要编纯静态工程那必须在 CMake 配置阶段给所有依赖一并加上/MT相关参数整体重编一套静态库否则最终一定会卡在链接阶段。除了运行库Debug 和 Release 也必须统一。Debug 版 gRPC 库的内部数据结构带有调试迭代器标记直接拿去给 Release 程序链接会得到各种诡异的崩溃或链接不一致所以编库时编了什么配置用户工程就用什么配置不要混搭。6. 最后说几句大实话gRPC 1.28 在 VS2015 下编译确实麻烦主要折磨人的地方是工具链老、依赖多、坑密。但只要把 CMake 版本卡在 3.20.xVS2015 打好 Update 3子模块完整更新再用我上面那一串 PROVIDERmodule 参数把依赖全部锁死到源码自带版本整个流程其实一次就能跑通后面接自己的工程也就是配几个目录的事。我自己实际用下来这套库在 Windows Server 2016 和 Win10 上都跑得很稳延迟和吞吐表现跟 Linux 下编译的版本没有本质差别。要说最大的收获还是学会了在面对“老编译器 新库”这类组合时不去硬碰硬升级而是想办法把版本组合锁定到一个旧编译器能覆盖的区间。如果你的项目也被工具链版本锁死希望这篇记录能帮你少熬一个周末。本文还有配套的精品资源点击获取