ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows平台下gRPC手动编译与VS2019集成实战指南

Windows平台下gRPC手动编译与VS2019集成实战指南 1. 项目概述为什么要在Windows上手动编译gRPC如果你是一名在Windows平台上使用Visual Studio 2019进行C开发的工程师并且项目需要引入gRPC进行高性能的RPC通信那么你大概率会遇到一个绕不开的坎官方预编译库的“水土不服”。gRPC官方虽然提供了一些预编译的二进制包但在实际项目集成时特别是需要与特定版本的第三方库如特定版本的Protobuf、OpenSSL搭配或者需要开启某些自定义功能如自定义的负载均衡器、追踪插件时直接使用预编译库往往捉襟见肘。更常见的情况是官方库的编译选项如MT/MTd、MD/MDd运行时库与你的项目不匹配导致链接时一堆令人头疼的LNK2038、LNK2005错误。手动编译gRPC听起来像是一项繁琐的底层工作但它带来的收益是实实在在的。首先你获得了完全的掌控权。你可以精确指定编译工具链MSVC的版本、运行时库类型、优化级别以及启用或禁用哪些gRPC功能模块。其次它能确保你的开发环境、构建环境和最终部署环境在库版本和ABI上完全一致这是避免“在我机器上是好的”这类灵异事件的根本方法。最后这个过程本身是对gRPC依赖生态的一次深度梳理你会清楚地知道它依赖了哪些底层库如zlib、c-ares、abseil-cpp等以及它们是如何被组织在一起的这对于后续的疑难排查和性能调优有莫大帮助。本文将基于Windows 10/11 Visual Studio 2019 CMake这一经典组合手把手带你完成gRPC及其核心依赖的完整编译过程。我不会只给你一串冰冷的命令而是会详细解释每个步骤背后的意图、可能遇到的坑以及我趟过这些坑后总结的实战技巧。我们的目标不仅仅是得到几个.lib和.dll文件而是构建一个稳定、可复现、与你的VS2019项目无缝集成的gRPC开发环境。2. 环境准备与工具链选型在开始编译之前搭建一个干净、可控的编译环境至关重要。在Windows上我们主要面临两种选择使用Visual Studio自带的“开发者命令提示符”环境或者使用像MSYS2这样的类Unix环境。我强烈推荐前者即使用VS2019的Native Tools Command Prompt。原因很简单我们要编译的是最终在Windows原生环境Win32 API下运行的库使用微软官方的工具链可以最大程度保证兼容性避免引入MinGW等环境可能带来的潜在链接和运行时问题。2.1 核心工具安装与验证你需要确保以下工具已正确安装并配置在系统路径中Visual Studio 2019安装时务必勾选“使用C的桌面开发”工作负载这包含了MSVC编译器、链接器、Windows SDK以及最重要的——我们即将用到的nmake构建工具。建议安装版本为16.11含以上以获得较好的C17/20标准支持。CMake这是现代C项目的标配构建系统生成器。gRPC使用CMake作为其构建系统。请从官网下载并安装最新稳定版如3.25安装时务必勾选“Add CMake to the system PATH for all users”选项。Git用于克隆gRPC的源代码仓库。同样安装时确保将Git命令添加到系统PATH。Active Perl 或 Strawberry Perl编译OpenSSL等依赖时需要Perl环境来执行配置脚本。Strawberry Perl是一个集成了GCC工具链的Windows版本对于不熟悉Perl的开发者更友好。安装后也需要将其bin目录加入PATH。安装完成后打开“开始”菜单找到“Visual Studio 2019”文件夹在其子目录“Visual Studio Tools”中你会看到“Developer Command Prompt for VS 2019”。请始终在这个命令行窗口中执行后续所有操作。这个环境会自动设置好cl、nmake、msbuild等工具所需的所有环境变量如INCLUDE、LIB。验证环境在打开的开发者命令提示符中依次输入以下命令确认版本无误cl cmake --version git --version perl --version如果cl命令能显示Microsoft C/C编译器的版本信息其他命令也能正确输出版本说明基础环境就绪。2.2 源码获取与目录规划不建议从Releases页面下载源码包因为可能会缺少最新的子模块。我们将使用Git进行克隆。首先规划一个清晰的工作目录。我习惯在非系统盘如D:\下创建一个专门用于编译第三方库的目录例如D:\Dev\Build。在这个目录下为本次编译单独创建一个子文件夹比如D:\Dev\Build\grpc-vs2019。所有操作都将在这个文件夹内进行。打开刚才的“Developer Command Prompt for VS 2019”使用cd命令切换到这个目录D: cd \Dev\Build\grpc-vs2019接下来克隆gRPC仓库。由于gRPC使用了Git子模块来管理其众多依赖如abseil-cpp、c-ares等我们需要使用--recursive参数进行递归克隆。这个过程会下载大量代码请保持网络通畅。git clone --recurse-submodules -b v1.54.0 https://github.com/grpc/grpc.git这里我指定了-b v1.54.0标签这是为了锁定一个稳定的版本进行编译。你可以根据需要选择其他稳定版本标签如v1.55.0,v1.56.0但切忌使用默认的master分支因为主分支处于持续开发中代码状态可能不稳定。注意递归克隆可能会因为网络问题导致部分子模块拉取失败。如果遇到这种情况进入克隆好的grpc目录再次执行git submodule update --init --recursive来补全子模块。克隆完成后你的目录结构应类似于D:\Dev\Build\grpc-vs2019\ └── grpc/ ├── CMakeLists.txt ├── include/ ├── src/ ├── third_party/ │ ├── abseil-cpp/ │ ├── cares/ │ ├── protobuf/ │ └── ... └── ...这个grpc目录就是我们的源码根目录记为GRPC_SOURCE_DIR。3. 编译策略与CMake配置解析直接在最外层的CMakeLists.txt上运行CMake并不是最佳实践尤其是对于gRPC这样结构复杂的项目。标准的做法是进行“外部构建”即在源码目录外创建一个独立的构建目录。这样做的好处是构建产生的所有中间文件、目标文件都集中在构建目录内与源码完全分离。你可以随时删除整个构建目录来重新开始而不会污染源码。这对于尝试不同的CMake配置选项非常方便。3.1 创建构建目录与生成解决方案在我们的工作目录D:\Dev\Build\grpc-vs2019下创建两个子文件夹build用于存放构建文件install用于存放最终编译好的库文件和头文件。mkdir build mkdir install cd build现在我们位于D:\Dev\Build\grpc-vs2019\build。接下来运行CMake来生成Visual Studio的解决方案文件。这是一条核心命令包含了所有关键的配置选项cmake ../grpc ^ -G Visual Studio 16 2019 ^ -A x64 ^ -DCMAKE_INSTALL_PREFIX../install ^ -DgRPC_INSTALLON ^ -DgRPC_BUILD_TESTSOFF ^ -DgRPC_SSL_PROVIDERpackage ^ -DgRPC_ZLIB_PROVIDERpackage ^ -DCMAKE_BUILD_TYPERelease让我们逐一拆解这些参数的含义和背后的考量-G Visual Studio 16 2019指定生成器为Visual Studio 2019。CMake支持多种生成器这个参数告诉CMake我们要生成.sln解决方案文件。-A x64指定目标平台架构为64位。这是现代Windows应用开发的主流选择。如果你需要32位库则使用-A Win32。-DCMAKE_INSTALL_PREFIX../install这是最重要的参数之一。它定义了make install或cmake --install命令执行时编译产物的安装路径。我们将其设置为上一级的install目录这样所有编译好的库.lib、动态链接库.dll和头文件.h都会被集中复制到这个目录下结构清晰便于后续项目引用。-DgRPC_INSTALLON启用gRPC的安装规则。只有打开这个选项后续的安装步骤才会生效。-DgRPC_BUILD_TESTSOFF关闭gRPC测试项目的编译。除非你需要运行gRPC的单元测试否则强烈建议关闭这能显著减少编译时间和生成的解决方案复杂度。-DgRPC_SSL_PROVIDERpackage和-DgRPC_ZLIB_PROVIDERpackage这两个参数指定gRPC使用系统已安装的OpenSSL和zlib库而不是编译它自带的源码。这是另一个关键决策点。gRPC的third_party目录下自带了这些依赖的源码但直接编译它们可能会遇到版本冲突或编译问题。更稳妥的做法是提前使用vcpkg或手动编译好这些依赖并确保CMake能找到它们。这里设为package意味着CMake会通过find_package来查找系统环境中的这些库。为了简化首次编译我们也可以先使用module使用自带源码但为了获得最佳的可控性我建议分开管理。-DCMAKE_BUILD_TYPERelease指定构建类型为发布模式优化开启调试信息关闭。如果你需要调试库可以后续用--config Debug参数来构建Debug版本。执行这条命令后CMake会开始配置过程。它会检查编译器、查找依赖并在当前build目录下生成grpc.sln解决方案文件以及大量的.vcxproj项目文件。3.2 依赖管理系统库还是自带源码在上面的配置中我将SSL和ZLIB的提供者设为了package。这意味着你需要确保系统中有可被找到的OpenSSL和zlib开发库。一个在Windows上管理C库的绝佳工具是vcpkg。如果你已经使用vcpkg可以非常方便地安装这些依赖# 在vcpkg目录下执行 .\vcpkg install openssl:x64-windows zlib:x64-windows安装后在CMake命令中需要添加参数来告诉CMake使用vcpkg的工具链文件cmake ../grpc [其他参数] -DCMAKE_TOOLCHAIN_FILE[你的vcpkg目录]\scripts\buildsystems\vcpkg.cmake实操心得对于首次编译gRPC如果不想额外配置vcpkg一个更简单粗暴的方法是暂时将-DgRPC_SSL_PROVIDER和-DgRPC_ZLIB_PROVIDER的值改为module。这样CMake就会去编译third_party目录下自带的openssl和zlib源码。这能避免因找不到系统库而导致的配置失败让你先走通编译流程。但请注意自带的版本可能不是最新的且编译过程也可能因源码差异而出错。4. 使用MSBuild进行编译与安装CMake成功生成解决方案后我们并没有得到最终的库文件。.sln文件只是一个“项目蓝图”我们需要调用MSBuildVisual Studio的构建引擎来执行实际的编译和链接工作。4.1 执行编译命令在build目录下执行以下命令进行编译cmake --build . --config Release --parallel--build .指定在当前目录即包含.sln文件的目录进行构建。--config Release指定构建Release配置。这与我们之前CMake配置时指定的CMAKE_BUILD_TYPE相对应。如果你想编译Debug版本则使用--config Debug。--parallel启用并行编译充分利用多核CPU大幅加快编译速度。这个命令会启动MSBuild依次编译解决方案中的所有项目包括gRPC核心库grpc、gRPC库grpc、gRPC插件grpc_cpp_plugin等以及我们设置为module的第三方依赖。整个过程视机器性能而定可能需要10到30分钟。期间控制台会输出大量的编译信息只要没有出现红色的错误error提示就可以耐心等待。常见问题1编译过程中内存不足C1060, C1076gRPC的某些目标特别是protobuf在编译时可能会消耗大量内存如果机器内存较小如小于16GB可能会遇到编译器前端c1xx.dll内存不足的致命错误。解决方法有关闭并行编译去掉--parallel但会极大增加编译时间。在CMake配置时添加-Dprotobuf_MSVC_STATIC_RUNTIMEOFF如果使用自带protobuf并确保使用动态运行时库MD/MDd这有时能减少单个编译单元的内存占用。最根本的方法是增加系统的虚拟内存页面文件大小。4.2 安装编译产物编译成功完成后build目录下的Release子文件夹里已经生成了我们需要的.lib和.dll文件。但为了便于管理我们需要执行“安装”步骤将必要的文件复制到我们预设的install目录中。执行安装命令cmake --install . --config Release这个命令会根据CMake配置中定义的安装规则将编译好的库文件、动态链接库、头文件以及CMake配置文件复制到-DCMAKE_INSTALL_PREFIX指定的目录即../install下。完成后查看D:\Dev\Build\grpc-vs2019\install目录你会看到一个标准的UNIX风格布局install/ ├── bin/ # 存放可执行文件如grpc_cpp_plugin.exe和动态库.dll ├── include/ # 存放所有头文件.h │ ├── grpc/ │ ├── grpcpp/ │ └── ... ├── lib/ # 存放导入库.lib和静态库.lib │ ├── CMake/ # gRPC的CMake配置文件供其他项目find_package使用 │ ├── pkgconfig/ │ └── *.lib └── share/这个install目录就是你的“gRPC SDK”后续在VS2019项目中引用它即可。5. 在Visual Studio 2019项目中集成与配置得到编译好的库之后下一步就是将其集成到你的C项目中。这里以创建一个新的Console应用程序为例演示如何配置属性页。5.1 项目属性配置包含目录在项目属性 - C/C - 常规 - 附加包含目录中添加gRPC的头文件路径。你需要添加至少以下路径D:\Dev\Build\grpc-vs2019\install\include(gRPC核心头文件)D:\Dev\Build\grpc-vs2019\install\include(如果你编译了自带protobuf其头文件也在这里如果使用外部protobuf则添加对应路径)可选其他依赖库的头文件路径如OpenSSL的include目录。库目录在项目属性 - 链接器 - 常规 - 附加库目录中添加gRPC的库文件路径D:\Dev\Build\grpc-vs2019\install\lib附加依赖项在项目属性 - 链接器 - 输入 - 附加依赖项中添加需要链接的库文件名。对于Release x64配置下的一个基础gRPC客户端/服务器程序通常需要以下库grpc.lib grpc_reflection.lib grpc.lib gpr.lib address_sorting.lib upb.lib cares.lib re2.lib ssl.lib crypto.lib zlib.lib libprotobuf.lib注意库的列表会根据你编译的模块和依赖的提供者module或package而有所不同。一个简单的方法是去install\lib目录下查看生成了哪些.lib文件按需添加。Debug版本通常有*d.lib后缀如grpcd.lib需要对应添加。运行时库与预处理器定义确保你的项目属性 - C/C - 代码生成 - 运行时库的设置与编译gRPC时使用的设置一致。如果你在CMake时没有特别指定默认可能是/MDRelease和/MDdDebug。不一致会导致链接错误。同时在预处理器定义中可能需要添加_WIN32_WINNT0x0A00Windows 10等宏来确保Windows API版本兼容。5.2 处理Proto文件与代码生成gRPC服务定义使用.proto文件。你需要使用protoc编译器配合grpc_cpp_plugin插件来生成C代码。获取工具编译完成后protoc.exe和grpc_cpp_plugin.exe位于install\bin目录下。确保它们在你的系统PATH中或者你知道它们的完整路径。生成代码通常通过构建事件预生成事件或自定义构建工具来实现自动化。一个典型的命令如下protoc -Iproto文件目录 --cpp_out输出目录 --grpc_out输出目录 --pluginprotoc-gen-grpcgrpc_cpp_plugin.exe路径 你的proto文件.proto例如protoc -I. --cpp_out./generated --grpc_out./generated --pluginprotoc-gen-grpcD:\Dev\Build\grpc-vs2019\install\bin\grpc_cpp_plugin.exe helloworld.proto这会在./generated目录下生成helloworld.pb.h、helloworld.pb.cc、helloworld.grpc.pb.h、helloworld.grpc.pb.cc四个文件。将生成文件加入项目将这些生成的.cc和.h文件添加到你的VS项目中并像普通源文件一样参与编译。5.3 部署注意事项DLL处理如果你的项目是动态链接使用了.dll那么在发布可执行文件时需要将对应的.dll文件位于install\bin复制到你的可执行文件同级目录下。关键的DLL通常包括grpc.dllgrpc.dlllibprotobuf.dlllibcrypto-1_1-x64.dll(OpenSSL)libssl-1_1-x64.dll(OpenSSL)zlib.dll你可以使用Visual Studio的“生成事件”中的“后期生成事件”用xcopy命令自动复制这些DLL到输出目录避免手动操作的繁琐和遗漏。6. 疑难排查与进阶技巧即使按照步骤操作编译和集成过程也可能遇到各种问题。这里记录一些典型问题的排查思路。6.1 编译阶段常见错误LNK2001/LNK2019: 无法解析的外部符号这是最常见的链接错误。检查库列表首先确认“附加依赖项”中是否包含了所有必需的库。对比install\lib目录下的文件看是否有遗漏。检查运行时库确认项目属性中的“运行时库”/MT、/MTd、/MD、/MDd与gRPC库编译时使用的选项完全一致。不一致是导致此问题的首要原因。gRPC默认CMake配置通常生成的是动态运行时库/MD或/MDd。如果你在CMake配置时没有动过CMAKE_MSVC_RUNTIME_LIBRARY变量那么它很可能就是MultiThreadedDLL对应/MD或MultiThreadedDebugDLL对应/MDd。检查架构确保项目平台x86/x64与编译的库平台一致。检查库目录确认“附加库目录”路径正确且该目录下确实有对应配置Release/Debug的库文件。C1083: 无法打开包括文件找不到头文件。检查包含目录仔细核对“附加包含目录”中的路径是否正确特别是路径中是否包含中文字符或特殊字符建议全英文路径。检查依赖项头文件如果错误是关于openssl/ssl.h或zlib.h说明CMake没有找到这些依赖。你需要确保系统已安装这些库并且其include目录被正确添加到项目的包含目录中或者在CMake配置gRPC时正确设置了gRPC_SSL_PROVIDER和gRPC_ZLIB_PROVIDER。CMake配置失败找不到工具链或包确保在Developer Command Prompt for VS 2019中运行CMake。如果使用vcpkg确保-DCMAKE_TOOLCHAIN_FILE的路径正确并且vcpkg已安装所需的三方库openssl:x64-windows等。6.2 运行时常见问题程序无法启动因为缺少xxx.dll这是典型的动态链接库缺失。按照5.3节的说明将所需的DLL复制到可执行文件目录。可以使用Dependencies原Dependency Walker工具来查看你的exe具体依赖哪些DLL。程序崩溃在gRPC初始化或调用时Debug/Release不匹配最常见的原因是在Debug模式下链接了Release版本的库或者反之。确保配置一致。堆损坏这通常是由于运行时库不匹配如/MD链接了/MT编译的库导致的内存分配/释放跨堆进行。彻底检查所有依赖库的编译选项。Protobuf版本冲突如果你的项目中其他地方也引用了Protobuf必须确保整个项目使用的Protobuf头文件和库版本与gRPC所使用的完全一致。版本不匹配会导致序列化/反序列化出现未定义行为。6.3 进阶编译选项与优化编译静态库默认CMake配置生成的是动态库DLL。如果你想生成静态库.lib可以在CMake配置时添加-DBUILD_SHARED_LIBSOFF。注意静态链接会显著增大最终可执行文件的体积并且需要注意运行时库的匹配问题静态链接gRPC通常也需要静态链接C运行时库。自定义依赖版本如果你想使用特定版本的第三方库如自己编译的OpenSSL 3.0而不是gRPC自带的或vcpkg提供的你需要确保该库的CMake配置文件如OpenSSLConfig.cmake或pkg-config文件能被CMake找到并在CMake配置gRPC前通过环境变量或CMake变量指定其路径。启用/禁用特定功能gRPC的CMake提供了许多选项来启用或禁用功能例如-DgRPC_BUILD_CSHARP_EXTOFF禁用C#扩展、-DgRPC_BACKWARDS_COMPATIBILITY_MODEOFF禁用向后兼容模式以使用最新API。你可以查阅gRPC源码根目录下的CMakeLists.txt或cmake目录下的文件来了解所有可用选项。手动编译gRPC的确比直接下载预编译二进制包要复杂但这份付出是值得的。它让你对自己的技术栈有了更深的理解和更强的掌控力。当你的服务需要处理海量并发RPC调用时你会感激自己当初花时间搭建的这个稳固的基础。整个过程最磨人的部分往往是环境配置和依赖处理一旦打通后续的更新和迭代就会顺畅很多。建议将成功的编译脚本包括CMake命令、环境设置等保存下来方便未来复现或迁移到新的机器上。
返回列表