简介:这份资源面向在 Windows 平台使用 C++ 进行微服务与分布式系统开发的工程师,提供基于 Visual Studio 2015 编译的 gRPC 预编译库与示例工程,帮助开发者跳过繁琐的源码编译环节,快速搭建可运行的 gRPC 开发环境。压缩包共 884 个文件,约 71.97MB,以 430 个 h 头文件、306 个 cc 源文件、64 个 proto 接口定义文件为主,并包含 18 个 lib 静态库、8 个 dll 动态库及 26 个 exe 可执行文件,同时提供 sln 解决方案与 vcxproj 工程文件,覆盖 Debug 与 Release 两种配置。包内自带 helloworld 测试项目,定义 Greeter 服务与 SayHello 方法,可直接编译运行,便于理解服务定义、Stub 生成、HTTP/2 通信与流式调用等核心机制。目前已有 1758 人学习下载,适合希望掌握 gRPC 在 Windows 下 C++ 工程化落地的开发者参考实践。
1. 在 Windows 上把 gRPC C++ 塞进 VS2015:一次版本对齐的硬仗
如果你手头有一个必须用 Visual Studio 2015 维护的老项目,又想在里面接入 gRPC C++ 做服务间通信,那你大概率已经体会过那种“每一步都像在拆盲盒”的感觉。VS2015 的 MSVC 编译器版本是 1900,C++11 支持只能算“基本够用”,而 gRPC 从某个版本之后就开始要求 C++14 甚至更高,再加上它依赖的 protobuf、abseil、c-ares、zlib、openssl 这一长串第三方库,版本稍微错开一点,编译期就是满屏的模板报错。更麻烦的是,网上大多数 gRPC 编译教程默认你用的是 VS2019 或 VS2022,直接照搬过来,CMake 配置阶段就会因为工具集不匹配而翻车。这篇笔记记录的就是我如何在 Windows + VS2015 这套“老而弥坚”的组合上,把 gRPC C++ 从零编译出来、配进项目、跑通第一个 Hello World 的完整过程,包括版本怎么选、依赖怎么装、CMake 参数怎么给,以及编译失败时该往哪个方向排查。
2. 环境准备:VS2015 下 gRPC 的版本选择与依赖清单
2.1 为什么 gRPC 版本不能随便挑
gRPC C++ 的版本和 MSVC 工具集之间存在一条隐形的兼容线。VS2015 对应_MSC_VER = 1900,它对 C++14 的支持是残缺的,而 gRPC 从 v1.30 左右开始大量使用 C++14 特性(比如泛型 lambda、std::make_unique的完整支持),到 v1.40 之后更是直接要求 C++17。所以如果你在 VS2015 上拉最新版 gRPC,基本是自找麻烦。
我一般会把 gRPC 版本锁定在v1.28.x 到 v1.33.x这个区间。这个区间的 gRPC 对 C++11 的依赖还比较重,MSVC 1900 能扛住,同时它依赖的 protobuf 版本是 3.11 到 3.13 左右,abseil 还没有被强制引入(abseil 是从 gRPC v1.35 开始成为硬依赖的,那玩意儿在 VS2015 上编译简直是噩梦)。具体选哪个小版本,取决于你项目里其他库的 protobuf 版本——如果项目里已经有 protobuf 3.11.4,那就选 gRPC v1.28.1;如果 protobuf 是 3.13.0,那就选 gRPC v1.33.2。版本对齐比选“最新”重要得多。
2.2 依赖库清单与获取方式
在 Windows 上编译 gRPC C++,你不可能只下载一个 gRPC 源码包就完事。它依赖以下这些库,而且每个库的版本也要和 gRPC 版本匹配:
| 依赖库 | 作用 | 推荐版本(配合 gRPC v1.33.x) |
|---|---|---|
| protobuf | 序列化与代码生成 | 3.13.0 |
| c-ares | 异步 DNS 解析 | 1.16.1 |
| zlib | 压缩 | 1.2.11 |
| openssl | TLS/SSL | 1.1.1g |
| benchmark | 性能测试(可选) | 1.5.2 |
| googletest | 单元测试(可选) | 1.10.0 |
这些库不需要你手动一个个下载。gRPC 源码包里有一个third_party目录,里面以 git submodule 的形式引用了这些依赖。但问题是,如果你直接git clone不带--recursive,这些子模块是空的;带了--recursive,拉下来的又是各子模块的最新版,版本可能对不上。所以我一般会这样做:先克隆 gRPC 主仓库并切换到指定 tag,然后手动进入third_party下的每个子目录,把它们也切换到 gRPC 该版本所要求的 commit。gRPC 每个 release 的third_party目录下都有一个*.version文件或者.gitmodules里记录了对应的 commit hash,照着切就行。
2.3 工具链检查:CMake、Git、NASM 一个都不能少
在开始编译之前,先确认你机器上这几样东西都装好了:
- CMake:版本至少 3.15,我一般用 3.18.6 的 Windows 安装包。注意安装时勾选“Add CMake to the system PATH”。
- Git:用于拉取源码和子模块,版本 2.28 以上即可。
- NASM:openssl 编译时需要,下载后把
nasm.exe所在目录加入 PATH。 - Perl:openssl 的构建脚本依赖 Perl,推荐用 Strawberry Perl。
装完之后在命令行里逐个验证:
cmake --version git --version nasm -v perl --version如果nasm或perl提示找不到命令,说明 PATH 没配好,后面编译 openssl 一定会失败。这一步看起来简单,但我见过太多人卡在这里,编译报错半天才发现是 NASM 没装。
3. 编译 gRPC:从 CMake 配置到生成 VS2015 解决方案
3.1 拉取源码与子模块对齐
先找一个空间足够的目录,比如D:\dev\grpc-build,然后执行:
git clone --branch v1.33.2 https://github.com/grpc/grpc.git cd grpc git submodule update --init --recursive这里--branch v1.33.2指定了我们要的 gRPC 版本,--recursive会把third_party下的子模块一并拉下来。拉完之后,进入third_party/protobuf、third_party/cares/cares、third_party/zlib等目录,分别 checkout 到 gRPC v1.33.2 所要求的 commit。具体 commit hash 可以看 gRPC 仓库根目录下的.gitmodules文件,或者直接看third_party下每个子目录里的README。
提示:如果你网络环境拉取子模块经常断,可以先用
git submodule update --init拉主模块,再逐个进入子目录手动git clone对应版本,最后把目录名改成 gRPC 期望的名字。
3.2 CMake 配置参数详解
gRPC 的 CMake 配置是整个编译过程中最关键的一步。参数给错了,要么编译不过,要么编出来的库缺功能。我一般会在 gRPC 源码根目录下新建一个build目录,然后在这个目录里执行 CMake 命令:
mkdir build cd build cmake .. -G "Visual Studio 14 2015 Win64" ^ -DCMAKE_BUILD_TYPE=Release ^ -DgRPC_BUILD_TESTS=OFF ^ -DgRPC_BUILD_CSHARP_EXT=OFF ^ -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF ^ -DgRPC_BUILD_GRPC_NODE_PLUGIN=OFF ^ -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF ^ -DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF ^ -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF ^ -DgRPC_INSTALL=ON ^ -DCMAKE_INSTALL_PREFIX=D:/dev/grpc-install ^ -DgRPC_SSL_PROVIDER=package ^ -DOPENSSL_ROOT_DIR=D:/dev/openssl-install ^ -DgRPC_ZLIB_PROVIDER=package ^ -DZLIB_ROOT=D:/dev/zlib-install ^ -DgRPC_CARES_PROVIDER=package ^ -DCARES_ROOT_DIR=D:/dev/cares-install ^ -DgRPC_PROTOBUF_PROVIDER=package ^ -DProtobuf_ROOT=D:/dev/protobuf-install逐条解释一下这些参数:
-G "Visual Studio 14 2015 Win64":指定生成 VS2015 的 64 位解决方案。如果你要 32 位,把Win64去掉。-DCMAKE_BUILD_TYPE=Release:生成 Release 版本。Debug 版本在 VS2015 下编译 gRPC 会非常慢,而且体积巨大,除非你要调试 gRPC 内部逻辑,否则一律用 Release。-DgRPC_BUILD_TESTS=OFF:关掉测试代码。gRPC 自带的测试用例非常多,编译它们会额外花一两个小时,而且容易因为 googletest 版本问题报错。-DgRPC_BUILD_GRPC_*_PLUGIN=OFF:关掉其他语言的插件。你只用 C++,这些插件编出来也没用。-DgRPC_INSTALL=ON和-DCMAKE_INSTALL_PREFIX:指定安装目录,后面cmake --install会把头文件、库文件、protoc 插件都放到这个目录下,方便项目引用。-DgRPC_SSL_PROVIDER=package等:告诉 gRPC 不要用third_party里的源码编译依赖,而是用你已经编译好的库。这样做的前提是你已经提前把 openssl、zlib、c-ares、protobuf 都编译并安装到了指定目录。如果你不想提前编译这些,可以把package改成module,让 gRPC 自己编译它们,但那样编译时间会翻倍,而且 openssl 在 VS2015 下用 module 模式编译经常出问题。
3.3 提前编译依赖库的实操
如果你选择了package模式,就需要先把 openssl、zlib、c-ares、protobuf 这四个库编译好。以 protobuf 为例:
cd D:\dev\protobuf-3.13.0 mkdir build && cd build cmake .. -G "Visual Studio 14 2015 Win64" ^ -DCMAKE_BUILD_TYPE=Release ^ -Dprotobuf_BUILD_TESTS=OFF ^ -Dprotobuf_MSVC_STATIC_RUNTIME=OFF ^ -DCMAKE_INSTALL_PREFIX=D:/dev/protobuf-install cmake --build . --config Release --target install-Dprotobuf_MSVC_STATIC_RUNTIME=OFF这个参数很关键。它让 protobuf 使用动态运行时库(/MD),而不是静态运行时(/MT)。gRPC 默认用的是/MD,如果你这里用了/MT,链接时会出现运行时库冲突,报一堆LNK2038错误。openssl 和 c-ares 的编译也类似,注意 openssl 要用VC-WIN64A目标,并且指定--prefix和--openssldir。
3.4 生成解决方案并编译
CMake 配置成功后,会在build目录下生成grpc.sln。用 VS2015 打开这个解决方案,选择Release x64配置,然后编译ALL_BUILD目标。编译过程大概需要 30 到 60 分钟,取决于机器性能。编译完成后,再编译INSTALL目标,把产物安装到D:/dev/grpc-install。
如果你不想用 VS 界面,也可以在命令行里直接:
cmake --build . --config Release --target INSTALL编译过程中如果遇到某个项目报错,先看错误信息里是哪个源文件、哪个依赖库的问题。常见的错误包括:找不到openssl/ssl.h(OPENSSL_ROOT_DIR 没设对)、cares.h找不到(CARES_ROOT_DIR 没设对)、protobuf 版本不匹配导致的google::protobuf命名空间报错。
4. 避坑与排查:VS2015 编译 gRPC 最常见的五类翻车
4.1 现象:CMake 配置阶段报 “Could NOT find OpenSSL”
原因:OPENSSL_ROOT_DIR指向的目录里没有include和lib子目录,或者 openssl 编译时没有生成libssl.lib和libcrypto.lib。
解决:确认 openssl 安装目录结构是D:/dev/openssl-install/include/openssl/ssl.h和D:/dev/openssl-install/lib/libssl.lib。如果 lib 目录下只有.dll没有.lib,说明编译时没有生成静态导入库,需要重新编译 openssl 并确保no-shared没有开启。
4.2 现象:编译 protobuf 时出现大量std::string相关模板错误
原因:VS2015 的 STL 对某些 C++11 特性支持不完整,而 protobuf 3.13 的部分代码用了较新的写法。
解决:把 protobuf 版本降到 3.11.4 或 3.12.4。如果项目必须用 3.13,可以尝试在 CMake 里加上-DCMAKE_CXX_FLAGS="/D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING",但这只是掩盖警告,根本问题还是编译器版本。
4.3 现象:链接时出现LNK2038: mismatch detected for 'RuntimeLibrary'
原因:gRPC 和它依赖的库使用了不同的运行时库选项。gRPC 默认用/MD,而某个依赖库编译时用了/MT。
解决:统一所有库的运行时库选项。在编译 protobuf、openssl、c-ares、zlib 时,都加上-DCMAKE_CXX_FLAGS_RELEASE="/MD"或对应的 CMake 选项。protobuf 用-Dprotobuf_MSVC_STATIC_RUNTIME=OFF,openssl 用no-static配置。
4.4 现象:编译到一半报 “fatal error C1060: compiler is out of heap space”
原因:VS2015 的 32 位编译器在处理 gRPC 的大型模板文件时内存不足。
解决:确保你用的是 64 位工具集(Visual Studio 14 2015 Win64),并且在 VS 的“项目属性 -> C/C++ -> 命令行”里加上/Zm200或/Zm500,增加编译器内存分配上限。如果还是不行,把grpc.sln里的项目分批编译,不要一次性ALL_BUILD。
4.5 现象:生成的grpc_cpp_plugin.exe运行时提示缺少libprotoc.dll
原因:protobuf 编译时生成了动态库,但grpc_cpp_plugin依赖的libprotoc.dll没有放到同一目录或 PATH 里。
解决:把D:/dev/protobuf-install/bin加入系统 PATH,或者把libprotoc.dll复制到grpc_cpp_plugin.exe所在目录。更彻底的做法是编译 protobuf 时用静态库(-Dprotobuf_BUILD_SHARED_LIBS=OFF),这样就不存在 DLL 依赖问题。
5. 项目集成与验证:让第一个 gRPC 服务在 VS2015 里跑起来
5.1 在 VS2015 项目中配置 gRPC 头文件与库路径
编译安装完成后,D:/dev/grpc-install目录下会有include、lib、bin三个子目录。在你的 VS2015 项目里,右键项目 -> 属性,做以下配置:
- C/C++ -> 常规 -> 附加包含目录:添加
D:/dev/grpc-install/include和D:/dev/protobuf-install/include。 - 链接器 -> 常规 -> 附加库目录:添加
D:/dev/grpc-install/lib和D:/dev/protobuf-install/lib。 - 链接器 -> 输入 -> 附加依赖项:添加
grpc.lib、grpc++.lib、libprotobuf.lib、libprotoc.lib、zlib.lib、libssl.lib、libcrypto.lib、cares.lib、ws2_32.lib。
注意ws2_32.lib是 Windows Socket 库,gRPC 的网络层依赖它,不加会报WSAStartup相关的链接错误。
5.2 编写 proto 文件并生成 C++ 代码
新建一个hello.proto文件:
syntax = "proto3"; package hello; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }然后用 gRPC 安装目录下的protoc.exe和grpc_cpp_plugin.exe生成代码:
D:/dev/grpc-install/bin/protoc.exe ^ --proto_path=. ^ --cpp_out=. ^ --grpc_out=. ^ --plugin=protoc-gen-grpc=D:/dev/grpc-install/bin/grpc_cpp_plugin.exe ^ hello.proto执行成功后会生成hello.pb.cc、hello.pb.h、hello.grpc.pb.cc、hello.grpc.pb.h四个文件。把这四个文件加入 VS 项目,然后写一个简单的服务端和客户端代码,编译链接。
5.3 验证服务端与客户端通信
服务端核心代码:
#include <grpcpp/grpcpp.h> #include "hello.grpc.pb.h" class GreeterServiceImpl final : public hello::Greeter::Service { grpc::Status SayHello(grpc::ServerContext* context, const hello::HelloRequest* request, hello::HelloReply* reply) override { std::string prefix("Hello "); reply->set_message(prefix + request->name()); return grpc::Status::OK; } }; int main() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); return 0; }客户端核心代码:
#include <grpcpp/grpcpp.h> #include "hello.grpc.pb.h" int main() { auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); std::unique_ptr<hello::Greeter::Stub> stub = hello::Greeter::NewStub(channel); hello::HelloRequest request; request.set_name("VS2015"); hello::HelloReply reply; grpc::ClientContext context; grpc::Status status = stub->SayHello(&context, request, &reply); if (status.ok()) { std::cout << "Server replied: " << reply.message() << std::endl; } else { std::cout << "RPC failed: " << status.error_message() << std::endl; } return 0; }先运行服务端,再运行客户端。如果客户端输出Server replied: Hello VS2015,说明整条链路已经打通。如果客户端报14: Connect Failed,检查服务端是否真的在监听 50051 端口,以及防火墙有没有拦截。
5.4 一个容易忽略的验证细节
编译链接成功后,不要只跑一次就完事。我一般会做三件事来确认环境真的稳了:第一,把服务端和客户端分别编译成 Debug 和 Release 两个版本,确认两种配置下都能跑通;第二,把客户端里的localhost换成127.0.0.1再跑一次,排除 DNS 解析的干扰;第三,故意把服务端关掉,看客户端是否能正确返回Connect Failed而不是直接崩溃。这三步走完,基本可以确定 gRPC 在你的 VS2015 环境里已经落地了。
从那以后我每次在 VS2015 上配 gRPC,都会先把版本对照表和依赖清单写在纸上,编译前逐项打勾,再也不敢凭感觉拉最新版了。希望帮到你。
本文还有配套的精品资源,点击获取