ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VS2015 下编译 gRPC C++ 全攻略:版本选型、依赖配置与避坑指南

VS2015 下编译 gRPC C++ 全攻略:版本选型、依赖配置与避坑指南

简介:这份资源面向在 Windows 平台使用 C++ 进行微服务与分布式系统开发的工程师,提供基于 Visual Studio 2015 编译的 gRPC 完整开发环境,解决从源码编译到工程配置的繁琐问题。压缩包共 884 个文件,约 71.97MB,以 430 个 h 头文件、306 个 cc 源文件、64 个 proto 接口定义文件为主,并附带 18 个 lib 静态库、8 个 dll 动态库及 26 个 exe 可执行文件,同时包含 vcxproj、sln、props 等 VS 工程配置,方便直接集成。资源内置 Debug 与 Release 两套编译产物,并自带一个可运行的 helloworld 测试项目,通过 Greeter 服务的 SayHello 方法演示服务定义、Stub 生成与调用流程,便于快速验证环境。已有 1758 人学习下载,适合希望跳过编译踩坑、直接上手 gRPC 服务端与客户端开发的 C++ 开发者参考使用。

1. 从一台老开发机说起:为什么 grpc windows vs2015 这套组合至今还有人踩

上周帮一个做工业上位机的朋友收拾一台 Windows 7 开发机,机器上锁死了 Visual Studio 2015,项目里要接一个跨进程的 RPC 通信层,选来选去还是落到 gRPC C++ 上。结果从 clone 到编译通过,整整折腾了一个下午——不是 gRPC 本身难,而是 grpc windows vs2015 这套组合的坑,几乎全集中在「版本对不对得上」和「依赖从哪来」这两件事上。VS2015 的 MSVC 工具集是 v140,C++11 支持是够的,但 gRPC 从某个版本之后就开始要求 C++14 甚至 C++17,第三方依赖也跟着水涨船高,选错一个 tag,后面就是无穷无尽的编译错误。这篇笔记就是把这套环境从零装到能跑通 Hello World 的完整过程记下来,包括版本怎么挑、依赖怎么拉、CMake 参数怎么配、装崩了怎么退回去。如果你手上也是一台被 VS2015 绑住、又必须上 grpc c++ windows 的机器,照着走一遍能省掉大半天。

2. 版本选型与依赖盘点:VS2015 能吃到哪个 gRPC 版本

2.1 先确认工具集和 C++ 标准这条硬线

VS2015 对应的是 MSVC 19.00,工具集 v140。它完整支持 C++11,对 C++14 是部分支持,C++17 基本没有。gRPC C++ 的版本演进里,v1.30 之前对 C++11 还算友好,越往后越依赖 C++14/17 的语法和标准库设施。所以在这台机器上,我一般会把 gRPC 锁在 v1.28.x 到 v1.33.x 这个区间,再高就容易在编译 abseil 或者 protobuf 的时候炸出一堆constexpr和std::string_view相关的错误。这不是玄学,是工具集能力决定的。

先确认环境,打开 VS2015 的开发者命令提示符,跑一下:

cl

输出里会带版本号,形如19.00.xxxxx。只要主版本是 19.00,就说明是 v140 工具集。如果机器上还装了别的 VS 版本,务必用 VS2015 自带的那个命令提示符,别用系统的 cmd,否则 cl 可能指向别的工具集,后面 CMake 生成的工程会用错编译器。

2.2 依赖清单:gRPC 不是一个人能装完的

gRPC C++ 在 Windows 上编译,绕不开这几个东西:

依赖作用VS2015 下的注意点
CMake生成 VS 工程用 3.15 以上,但别用 3.20+ 里默认的新行为
Git拉源码和子模块必须带 submodule,别下 zip 包
NASM编译 OpenSSL 汇编装完要进 PATH,否则 OpenSSL 编不过
PerlOpenSSL 构建脚本Strawberry Perl 即可
Go部分工具链可选,但 boringssl 某些脚本会用到
Ninja可选加速用 VS 生成器时可不装

这里最容易翻车的是 NASM 和 Perl。很多人 clone 完直接 CMake,结果卡在 OpenSSL 或者 boringssl 的汇编阶段,报错信息还特别隐晦。我的习惯是先把 NASM、Perl、CMake、Git 全部装好并确认在 PATH 里,再动 gRPC 的源码。

2.3 拉源码:submodule 一个都不能少

gRPC 的仓库带了一堆第三方子模块,直接下 zip 是拿不到这些的。正确姿势是:

git clone --recurse-submodules -b v1.33.2 https://github.com/grpc/grpc.git cd grpc git submodule update --init --recursive

--recurse-submodules保证 clone 的时候就把子模块拉下来,后面那条submodule update是双保险,防止某些子模块没跟上。版本号v1.33.2是我在 VS2015 上验证过能编过的 tag,再往前的 v1.28.x 也可以,但 v1.33.x 的 API 更稳一些。如果你拉的是 master,那基本可以放弃 VS2015 了,master 早就要求 C++17。

拉完之后检查一下third_party目录,里面应该有abseil-cpp、boringssl、protobuf、zlib等一堆目录,每个目录里都得有实际文件,空的就说明 submodule 没拉全,得重新git submodule update --init --recursive。

3. 编译安装:CMake 参数怎么配才不炸

3.1 生成 VS2015 工程:生成器名字别写错

CMake 生成工程这一步,生成器的名字必须精确。VS2015 对应的是Visual Studio 14 2015 Win64,注意是 14 不是 15,15 是 VS2017。写错了 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_INSTALL=ON ^ -DCMAKE_INSTALL_PREFIX=C:/grpc-install

逐条说下参数。-G指定生成器,必须和本机 VS 版本严格对应。CMAKE_BUILD_TYPE在 VS 生成器下其实不直接生效,因为 VS 是多配置生成器,真正决定 Release/Debug 的是后面 build 时的--config,但写上没坏处。gRPC_BUILD_TESTS=OFF很关键,gRPC 自带的测试用例编译量巨大,而且很多测试在 VS2015 下编不过,关掉能省一半时间。gRPC_BUILD_CSHARP_EXT=OFF关掉 C# 扩展,用不上就别编。gRPC_INSTALL=ON和CMAKE_INSTALL_PREFIX是为了后面能 install 到一个固定目录,方便项目引用。

如果 CMake 报错说找不到 ZLIB 或者 OpenSSL,说明它想用系统库但没找到。gRPC 默认会自己编 boringssl 和 zlib,一般不用管,但如果你的环境里装了别的 OpenSSL 并且被 CMake 优先找到了,就可能出问题。稳妥做法是加-DgRPC_SSL_PROVIDER=package或者干脆让它用自带的 boringssl,不加额外参数就是默认自带。

3.2 编译:Release 配置 + 并行度控制

工程生成之后,用 CMake 的 build 命令直接编:

cmake --build . --config Release --target install -- /m:4

--config Release指定编 Release 版,VS 生成器下必须显式指定。--target install表示编完直接安装到前面设的CMAKE_INSTALL_PREFIX。最后的/m:4是传给 MSBuild 的并行编译参数,4 是并行项目数。这个数别开太大,gRPC 编译吃内存,开 8 或者 16 很容易把机器内存打满然后卡死,我一般按物理核数的一半来设。

编译过程大概会持续 20 到 40 分钟,取决于机器性能。中途如果报错,最常见的是两类:一类是abseil里的 C++14 语法错误,说明 gRPC 版本还是选高了;另一类是boringssl的汇编错误,说明 NASM 没装好或者没进 PATH。看到这两类错误,先别急着改代码,回头检查版本和依赖。

3.3 安装产物:编完之后装到哪了

install目标跑完,C:/grpc-install下会出现几个目录:

C:/grpc-install/ bin/ # grpc_cpp_plugin.exe 等工具 include/ # grpc++、grpc、google/protobuf 头文件 lib/ # grpc++.lib、grpc.lib、libprotobuf.lib 等 cmake/ # gRPCConfig.cmake,供 find_package 用

bin目录里的grpc_cpp_plugin.exe是后面生成 C++ 代码要用的插件,必须能找到。lib目录里的库文件分 Debug 和 Release,Release 版不带后缀,Debug 版带d后缀,链接的时候别搞混。cmake目录里的配置文件是给find_package(gRPC CONFIG)用的,后面在项目里引用会很方便。

4. 项目集成:从 proto 到可执行文件

4.1 写一个最小 proto 并生成代码

先建一个测试目录,写个最简单的 proto:

syntax = "proto3"; package demo; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }

存成greeter.proto。然后用前面装好的工具生成 C++ 代码:

C:/grpc-install/bin/protoc.exe ^ --grpc_out=. ^ --cpp_out=. ^ --plugin=protoc-gen-grpc=C:/grpc-install/bin/grpc_cpp_plugin.exe ^ -I . ^ greeter.proto

--grpc_out和--cpp_out都指定输出到当前目录。--plugin告诉 protoc 用哪个插件生成 gRPC 服务代码,路径必须指到grpc_cpp_plugin.exe。-I .是 proto 的搜索路径。跑完会生成greeter.pb.cc、greeter.pb.h、greeter.grpc.pb.cc、greeter.grpc.pb.h四个文件,前两个是消息类,后两个是服务桩类。

4.2 写服务端和客户端

服务端最小实现:

#include <grpcpp/grpcpp.h> #include "greeter.grpc.pb.h" class GreeterServiceImpl final : public demo::Greeter::Service { grpc::Status SayHello(grpc::ServerContext* context, const demo::HelloRequest* request, demo::HelloReply* reply) override { std::string prefix("Hello "); reply->set_message(prefix + request->name()); return grpc::Status::OK; } }; int main() { std::string address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); server->Wait(); return 0; }

客户端最小实现:

#include <grpcpp/grpcpp.h> #include "greeter.grpc.pb.h" int main() { auto channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()); auto stub = demo::Greeter::NewStub(channel); demo::HelloRequest request; request.set_name("VS2015"); demo::HelloReply reply; grpc::ClientContext context; grpc::Status status = stub->SayHello(&context, request, &reply); if (status.ok()) { std::cout << reply.message() << std::endl; } return 0; }

这两个文件里,grpcpp/grpcpp.h是 gRPC C++ 的总头文件,InsecureServerCredentials和InsecureChannelCredentials表示不加密,本地测试够用。ServerBuilder负责组装服务,BuildAndStart之后调Wait阻塞住。客户端用CreateChannel建通道,NewStub拿桩对象,然后像调本地函数一样调远程方法。

4.3 CMake 集成:find_package 的写法

在自己的项目里,用find_package引用前面装好的 gRPC:

cmake_minimum_required(VERSION 3.15) project(demo) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(gRPC CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED) add_executable(server server.cpp greeter.pb.cc greeter.grpc.pb.cc) target_link_libraries(server PRIVATE gRPC::grpc++ gRPC::grpc++_reflection) add_executable(client client.cpp greeter.pb.cc greeter.grpc.pb.cc) target_link_libraries(client PRIVATE gRPC::grpc++)

CMAKE_CXX_STANDARD 11是因为 VS2015 只稳到 C++11,写 14 或 17 可能编不过。find_package(gRPC CONFIG REQUIRED)会去找前面 install 出来的gRPCConfig.cmake,所以配置的时候要加-DCMAKE_PREFIX_PATH=C:/grpc-install。gRPC::grpc++是 gRPC 导出的目标名,链接它会自动带上依赖的 protobuf 和底层库。grpc++_reflection是反射库,服务端调试用得上,不需要可以去掉。

配置和编译:

cmake .. -G "Visual Studio 14 2015 Win64" ^ -DCMAKE_PREFIX_PATH=C:/grpc-install cmake --build . --config Release

跑起来先起 server,再起 client,client 那边应该打印出Hello VS2015。到这一步,整套 grpc c++ windows 环境就算通了。

5. 避坑与排查:VS2015 下最容易翻车的五个点

5.1 现象:CMake 报找不到生成器

原因:生成器名字写错,或者本机没装对应版本的 VS。VS2015 的生成器名是Visual Studio 14 2015,不是 15。如果装的是 64 位工具集,还要加Win64。

解决:先用cmake --help看本机支持的生成器列表,找到带2015的那一行,原样抄过来。如果列表里没有 2015,说明 VS2015 的 C++ 组件没装全,回安装器里补上。

5.2 现象:编译 abseil 时报一堆 C++14 语法错误

原因:gRPC 版本选高了,高版本的 abseil 用了 VS2015 不支持的 C++14 特性。

解决:退到 v1.33.x 或更低。如果已经拉了高版本,git checkout v1.33.2然后重新git submodule update --init --recursive,再清空 build 目录重新 CMake。别想着改 abseil 源码去兼容,改不完的。

5.3 现象:boringssl 编译报 NASM 相关错误

原因:NASM 没装,或者装了但没进 PATH,CMake 找不到。

解决:装 NASM 后确认nasm -v能在命令行里跑通。如果 PATH 里有了还是报错,检查是不是 32 位和 64 位版本混了,64 位工具集要用 64 位 NASM。实在不行,CMake 加-DgRPC_SSL_PROVIDER=package用系统 OpenSSL 绕过去,但系统 OpenSSL 的版本也得对得上。

5.4 现象:链接时报LNK2038或RuntimeLibrary不匹配

原因:Debug 和 Release 的库混用了,或者运行库选项(/MT 和 /MD)不一致。

解决:确认项目里链接的 gRPC 库和当前编译配置一致,Release 配 Release,Debug 配 Debug。运行库选项上,gRPC 默认用 /MD,自己的项目也保持一致,别改成 /MT。

5.5 现象:运行时报DLL load failed

原因:grpc++.dll、libprotobuf.dll这些动态库不在可执行文件的搜索路径里。

解决:把C:/grpc-install/bin加到系统 PATH,或者把需要的 DLL 拷到 exe 同目录。用dumpbin /dependents server.exe可以看 exe 依赖哪些 DLL,缺哪个补哪个。

6. 装完怎么验证:三步确认这套环境真的通了

装完不算完,得有一套能重复跑的验证流程,不然下次换台机器又得从头猜。我一般按三步走,每步都有明确的通过标准。

第一步,验证工具链本身。在命令行里跑:

C:/grpc-install/bin/protoc.exe --version C:/grpc-install/bin/grpc_cpp_plugin.exe --version

protoc会打印 libprotoc 的版本号,grpc_cpp_plugin一般没有--version参数,直接跑会报用法错误,但只要能报出用法而不是「不是内部或外部命令」,就说明插件本身是可执行的。这一步过了,说明安装产物是完整的。

第二步,验证 proto 生成链路。拿前面那个greeter.proto,重新生成一遍代码,然后检查四个输出文件是否都非空:

dir greeter.pb.cc greeter.pb.h greeter.grpc.pb.cc greeter.grpc.pb.h

四个文件大小都不为 0,且greeter.grpc.pb.h里能搜到class Greeter和SayHello,说明插件工作正常。这一步是最容易被忽略的,很多人装完 gRPC 就直接写业务代码,结果 proto 生成失败,后面全是连锁错误。

第三步,端到端跑通。先起 server,再起 client,client 输出Hello VS2015就算全通。为了确认不是偶然,我会把 server 停掉再跑一次 client,这时候 client 应该报连接失败而不是崩溃,说明错误处理路径也是通的。

验证项通过标准失败时先查
protoc 版本打印 libprotoc 版本号PATH 和安装目录
插件可执行报用法而非找不到命令bin 目录是否在 PATH
proto 生成四个文件非空且含服务类插件路径和 proto 语法
端到端client 打印 Hello VS2015端口占用和 DLL 依赖
断连处理client 报错不崩溃错误处理代码

这套流程我每次在新机器上装完都会走一遍,前后不到五分钟,但能挡掉后面百分之八十的「明明装好了却跑不起来」。从那以后我每次配 grpc windows vs2015 环境,都强制先跑完这三步再动业务代码,省下来的排查时间远比这五分钟多。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进