简介:本资源为 gRPC 1.28 在 Windows 平台配合 Visual Studio 2015 编译的 C++ 开发库,面向需要在 Windows 环境下搭建 gRPC 服务端与客户端的 C++ 开发者,尤其适合使用 VS2015 工具链、希望跳过繁琐源码编译直接集成静态库的中级工程师。压缩包共 472 个文件,约 24.47MB,以 387 个 h 头文件、34 个 lib 静态库为主,另含 14 个 cmake 构建脚本、12 个 proto 接口定义、11 个 exe 工具及少量 dll、pc、pem 等配置与证书文件,覆盖头文件引用、库链接、CMake 集成与 protoc 代码生成等环节。资源内含 protobuf 3.11 相关组件,可配合 .proto 文件生成服务接口与消息类型,并借助 ServerBuilder、Channel、Stub 等完成服务注册与调用。目前已有 998 人学习下载,适合希望快速在 VS2015 中落地 gRPC 通信、减少环境配置成本的开发者参考使用。
1. gRPC 1.28 在 Windows 上用 VS2015 编译 C++ 库:一条被低估的产线级路径
如果你手上维护的是 VS2015 时代的 C++ 工程,又需要把服务间通信从自研 socket 换成 gRPC,那么“gRPC 1.28 + Windows + VS2015 + C++ 编译库”这个组合大概率是你绕不开的一关。原因很直接:gRPC 从 1.28 开始对 CMake 构建链和第三方依赖做了较明显的收敛,而 VS2015 的 MSVC 工具集(v140)对 C++11/14 的支持刚好卡在可用边界上,再往后的 gRPC 版本对编译器要求会逐步抬高,v140 会越来越难伺候。所以 1.28 常被当成一个“还能在 VS2015 上稳定产出静态库/动态库”的折中点。
这篇文章面向的是需要在 Windows 上把 gRPC 编译成 C++ 库、并集成进既有 VS2015 工程的从业者。我会把依赖准备、CMake 参数、编译命令、库的取舍、以及最容易翻车的几个点讲清楚,目标是让你照着能复现出一套可链接的 gRPC 库,而不是停在“听说要装一堆东西”。
2. 编译前必须想清楚的依赖与工具链选型
2.1 为什么 gRPC 1.28 对 VS2015 是个相对友好的版本
gRPC 的 C++ 实现依赖几个底层库:protobuf、zlib、boringssl(或 openssl)、abseil(1.28 时代还没强绑 abseil,这点很关键)、c-ares、re2。版本越往后,这些依赖的版本要求越新,对 C++ 标准的要求也越高。1.28 这个节点上,protobuf 对应 3.11.x 左右,boringssl 还是随源码 submodule 拉取,整体对 v140 的兼容性尚可。
VS2015 的 MSVC 19.00 工具集有几个硬限制:对constexpr支持不完整、对两阶段名字查找处理粗糙、部分 C++14 特性缺失。gRPC 1.28 的源码里已经尽量规避了这些,但第三方依赖(尤其是 protobuf 的某些生成代码)仍可能触发编译错误。所以选型的第一原则是:不要混用不同来源的依赖库,要么全部用 gRPC 自带的 third_party 子模块编译,要么全部用你自己预编译好的同版本库,混用是后面链接错误的主要来源。
2.2 工具链清单与版本约束
下面这张表是我一般会先对齐的清单,版本对不上后面基本白干:
| 组件 | 建议版本 | 说明 |
|---|---|---|
| Visual Studio | 2015 Update 3 | v140 工具集,Update 3 对 STL 修复较多 |
| CMake | 3.16 ~ 3.20 | 太新会引入 gRPC 1.28 不认识的策略 |
| Git | 任意较新版本 | 需要递归拉取 submodule |
| NASM | 2.13 以上 | boringssl 在 Windows 上编译汇编需要 |
| Perl | 5.x | boringssl 生成部分文件需要 |
| Go | 1.13 左右 | 仅 boringssl 构建脚本需要,非必须可跳过 |
NASM 和 Perl 是最容易被忽略的两个。boringssl 在 Windows 上会编译.asm文件,没有 NASM 会直接报找不到汇编器;Perl 则用于生成部分错误码文件。很多人卡在 boringssl 这一步,以为是 gRPC 本身的问题,其实是环境缺件。
2.3 源码获取与 submodule 拉取
gRPC 的依赖通过 git submodule 管理,必须递归拉取,否则 CMake 配置阶段就会报找不到 third_party 下的目录。
# 拉取 gRPC 1.28 源码,注意递归拉取子模块 git clone --recurse-submodules -b v1.28.0 https://github.com/grpc/grpc.git grpc-1.28 # 如果已经 clone 但忘了递归,补拉 cd grpc-1.28 git submodule update --init --recursive这里-b v1.28.0锁定标签,避免拉到主干上不兼容的提交。--recurse-submodules会一次性把 third_party 下的 protobuf、boringssl、zlib、c-ares、re2 全部拉下来。如果网络不稳导致某个 submodule 失败,单独进对应目录git submodule update --init重试即可,不要删掉整个仓库重来。
提示:third_party 下的依赖版本是 gRPC 1.28 官方锁定过的,不要手动升级其中任何一个,否则编译错误会非常难定位。
3. 用 CMake 生成 VS2015 工程并编译出库
3.1 CMake 配置命令与关键参数
gRPC 1.28 的 CMake 支持直接生成 Visual Studio 工程,也可以直接用命令行编译。我一般先生成工程,方便在 IDE 里看错误,再决定是否走命令行批量编译。
# 在 grpc-1.28 目录下创建构建目录,保持源码干净 mkdir build && cd build # 生成 VS2015 工程,指定 v140 工具集 cmake .. -G "Visual Studio 14 2015 Win64" ^ -DCMAKE_BUILD_TYPE=Release ^ -DgRPC_BUILD_TESTS=OFF ^ -DgRPC_BUILD_CSHARP_EXT=OFF ^ -DgRPC_INSTALL=ON ^ -DCMAKE_INSTALL_PREFIX=../install ^ -DgRPC_SSL_PROVIDER=module ^ -DgRPC_ZLIB_PROVIDER=module ^ -DgRPC_CARES_PROVIDER=module ^ -DgRPC_PROTOBUF_PROVIDER=module ^ -DgRPC_RE2_PROVIDER=module参数逐个说清楚:
-G "Visual Studio 14 2015 Win64":生成 64 位 VS2015 工程。如果你要 32 位,去掉Win64,但 32 位下 boringssl 的汇编路径问题更多,不建议。-DgRPC_BUILD_TESTS=OFF:关掉测试,测试目标会引入 gtest 等额外依赖,编译时间翻倍且容易失败。-DgRPC_INSTALL=ON配合CMAKE_INSTALL_PREFIX:编译后可以install到指定目录,方便集成到别的工程。-DgRPC_*_PROVIDER=module:强制使用 third_party 下的内置依赖,而不是去系统里找。这是避免混用依赖的关键,全部设成module。-DgRPC_SSL_PROVIDER=module:用内置 boringssl,而不是外部 OpenSSL。VS2015 下外部 OpenSSL 的链接问题很多,内置更省心。
3.2 编译命令与目标选择
配置成功后,用 CMake 的 build 命令编译。gRPC 的目标很多,全量编译耗时很长,按需编译能省不少时间。
# 编译 Release 配置,指定并行度 cmake --build . --config Release --target grpc -- /m:8 # 如果需要 protoc 和 grpc_cpp_plugin,单独编译这两个目标 cmake --build . --config Release --target protoc -- /m:8 cmake --build . --config Release --target grpc_cpp_plugin -- /m:8 # 编译完成后安装到 install 目录 cmake --build . --config Release --target install -- /m:8--target grpc会编译出 gRPC 的核心库(grpc.lib或grpc.lib+grpc.dll,取决于BUILD_SHARED_LIBS)。protoc是 protobuf 编译器,grpc_cpp_plugin是生成 gRPC 服务代码的插件,这两个是后续生成代码必须的。/m:8是传给 MSBuild 的并行编译参数,按你机器核数调整。
编译产物里你会看到几个关键库:grpc.lib、grpc++.lib、gpr.lib、protobuf.lib、boringssl.lib、zlib.lib、cares.lib、re2.lib。链接时这些都要带上,缺一个就是一堆 unresolved external。
3.3 静态库与动态库的取舍
gRPC 1.28 默认编译静态库。如果你要动态库,配置时加-DBUILD_SHARED_LIBS=ON。但这里有个血泪经验:在 VS2015 下,gRPC 的动态库导出符号处理并不完美,尤其是涉及 protobuf 生成代码跨 DLL 边界时,容易出现符号找不到或运行时崩溃。除非你有明确的 DLL 需求,否则静态库是更稳的选择。
静态库的代价是最终可执行文件体积大,且每个模块都会带一份 gRPC 代码。如果你的工程是多个 DLL 都要用 gRPC,静态库会导致符号重复,这时候要么统一到一个 DLL 里封装 gRPC,要么老老实实解决动态库的导出问题。
注意:如果选动态库,
protoc生成的代码和 gRPC 库必须用同一套运行时(MT/MD)设置,否则会出现堆跨模块释放的崩溃,这类问题在 Release 下才暴露,调试很痛苦。
4. 把编译好的库集成进 VS2015 工程
4.1 头文件与库目录配置
编译安装后,install目录下会有include和lib两个子目录。在 VS2015 工程里,右键项目属性,做三处配置:
- C/C++ → 常规 → 附加包含目录:加入
install/include。 - 链接器 → 常规 → 附加库目录:加入
install/lib。 - 链接器 → 输入 → 附加依赖项:加入前面列出的那一串
.lib。
附加依赖项的顺序在 MSVC 下不像 GCC 那么敏感,但建议把grpc++.lib、grpc.lib、gpr.lib放前面,底层依赖放后面,减少链接器找不到符号的概率。
4.2 用 protoc 和插件生成 C++ 代码
集成完成后,你需要把.proto文件生成 C++ 代码。这一步用编译出来的protoc和grpc_cpp_plugin。
# 生成消息代码和服务代码 protoc -I ./proto ^ --cpp_out=./generated ^ --grpc_out=./generated ^ --plugin=protoc-gen-grpc=./install/bin/grpc_cpp_plugin.exe ^ ./proto/hello.proto--cpp_out生成消息类的.pb.cc和.pb.h,--grpc_out配合--plugin生成服务桩代码的.grpc.pb.cc和.grpc.pb.h。生成的.pb.cc也要加入工程一起编译,否则链接时会缺消息类的实现。
4.3 一个最小可运行的验证工程
集成完别急着上业务,先写一个最小服务端和客户端验证链路通不通。
// hello.proto 对应的服务端最小实现 #include <grpcpp/grpcpp.h> #include "hello.grpc.pb.h" class HelloServiceImpl final : public Hello::Service { grpc::Status SayHello(grpc::ServerContext* ctx, const HelloRequest* req, HelloReply* resp) override { // 简单回显,验证服务端能收到请求 resp->set_message("echo: " + req->name()); return grpc::Status::OK; } }; int main() { std::string addr("0.0.0.0:50051"); HelloServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(addr, grpc::InsecureServerCredentials()); builder.RegisterService(&service); auto server = builder.BuildAndStart(); server->Wait(); return 0; }这段代码只依赖grpcpp和生成的头文件。编译通过且能启动,说明库链接没问题。客户端用grpc::CreateChannel连上后调SayHello,能拿到回显就说明整条链路通了。这一步过了,再往业务里搬。
5. 编译与集成中的避坑清单
5.1 现象:boringssl 编译报找不到 nasm
原因:环境变量 PATH 里没有 NASM,或者 NASM 版本太老不支持某些指令。解决:装 NASM 2.13 以上,把安装目录加进 PATH,重新配置 CMake(要清空 build 目录重来,CMake 缓存会记住上次的失败状态)。
5.2 现象:protobuf 生成代码报 C2059 语法错误
原因:VS2015 对某些模板语法解析有问题,常见于 protobuf 3.11 生成的代码里嵌套模板。解决:确认你用的是 gRPC 1.28 自带的 protobuf 版本,不要换成更新的 protobuf。如果仍报错,检查是否误开了/permissive-,VS2015 下这个选项要关掉。
5.3 现象:链接时报 unresolved external symbol,符号名带std::__cxx11
原因:混用了不同 STL 实现的库,通常是某个依赖用了 MinGW 或更新版 MSVC 编译。解决:确保所有库都是同一套 VS2015 编译出来的,检查install/lib下有没有混入外部库。
5.4 现象:Release 下运行崩溃,Debug 正常
原因:运行时库设置不一致(MT vs MD),导致跨模块内存分配释放不匹配。解决:统一所有项目和依赖的Runtime Library设置,gRPC 编译时用的什么,你的工程就用什么,通常 Release 下是/MD。
5.5 现象:CMake 配置阶段报找不到gRPCConfig.cmake
原因:CMAKE_INSTALL_PREFIX没设或 install 目标没执行。解决:确认配置时带了-DgRPC_INSTALL=ON,且编译后执行了install目标,然后在你的工程 CMake 里find_package(gRPC CONFIG REQUIRED)并指定gRPC_DIR。
6. 进阶:裁剪库体积与跨工程复用的一个习惯
编译出来的 gRPC 静态库体积不小,Release 下几个库加起来轻松上百 MB。如果你只是用 gRPC 做内部服务通信,不需要反射、不需要健康检查、不需要负载均衡策略,可以在 CMake 配置时关掉对应目标,减少最终链接体积。常见做法是只保留grpc、grpc++、gpr、protobuf、boringssl、zlib、cares、re2这几个核心目标,其余按需裁剪。
另一个我坚持的习惯是:把编译好的 gRPC 库按版本号归档,连同 CMake 配置命令一起写进一个build_notes.txt。VS2015 这种老工具链,半年后你大概率会忘记当时用了哪些参数,重新编译一次可能又是半天。归档时把install目录、build_notes.txt、以及一份CMakeCache.txt的副本放在一起,下次换机器直接拷过去就能用,省掉重新踩坑的时间。
验证库是否可复用的一个具体技巧:新建一个空的控制台工程,只链接 gRPC 库,写一个创建 channel 并立即关闭的最小程序。如果这个能编译链接并正常运行,说明库本身是完整的;如果这个都过不了,说明库的依赖链有缺失,别急着往业务工程里集成。这个最小验证程序我一般会保留在归档目录里,作为每次复用前的“后悔药”。
希望帮到你。
本文还有配套的精品资源,点击获取