ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Windows平台手动编译gRPC 1.54.0完整指南:从源码到VS2019集成

Windows平台手动编译gRPC 1.54.0完整指南:从源码到VS2019集成 1. 项目概述为什么要在Windows上手动编译gRPC如果你是一个在Windows平台上用C做服务端或高性能中间件开发的工程师最近恰好需要用到gRPC那么你很可能已经发现了一个“坑”gRPC官方提供的预编译二进制包在Windows上要么版本老旧要么和你项目里使用的Visual Studio版本、运行时库MT/MD对不上。直接从vcpkg或conan安装有时也会因为网络或编译选项问题而失败。这时候自己动手从源码编译就成了最可靠、最灵活的选择。我最近在一个需要集成gRPC 1.54.0版本到VS2019项目中的任务里就不得不走了这条路。整个过程就像一次精细的外科手术你需要准备好手术刀CMake、Git、手术台一个干净的构建环境然后按照正确的顺序一步步处理依赖、配置参数、解决编译错误。网上能找到的教程要么太旧针对VS2015/2017要么过于简略跳过了很多关键细节导致新手照着做十有八九会卡住。这篇文章就是我这次“手术”的完整记录和复盘。我会详细拆解从环境准备、源码获取、CMake配置、Visual Studio编译到最终生成可用库文件的每一个步骤并重点分享那些官方文档没写、但实践中一定会遇到的“坑”和解决技巧。无论你是想编译特定版本的gRPC还是需要定制编译选项比如开启SSL、使用特定的zlib版本这篇文章都能给你一份可直接“抄作业”的指南。2. 环境准备与工具链确认手动编译gRPC第一步不是急着下载代码而是确保你的“工作台”是平整且工具齐全的。在Windows上这主要指两样东西合适的Visual Studio版本和正确的CMake。2.1 Visual Studio 2019的安装与组件选择很多人以为安装了VS2019就能编译一切其实不然。gRPC的编译对C编译器和Windows SDK版本有特定要求。首先确保你安装的是Visual Studio 2019的16.11版本或更高。早期版本如16.0的MSVC编译器在对C17标准的支持上可能存在一些边缘问题可能导致gRPC源码中的某些现代C特性编译失败。你可以在VS安装器的“修改”界面查看已安装的版本号。其次在安装时必须勾选以下工作负载和组件“使用C的桌面开发”这是核心工作负载。在该工作负载下确保以下个体组件被选中MSVC v142 - VS 2019 C x64/x86 生成工具这是编译器本身。Windows 10 SDK (10.0.xxxxx.0)选择一个较新的版本如10.0.19041.0或更高。gRPC的某些网络和线程特性依赖较新的SDK。C CMake 工具这个非常重要它集成了CMake和Ninja能让我们在VS内或命令行中直接使用CMake比单独安装配置要方便很多。测试适配器可选但如果你打算编译并运行gRPC的单元测试则需要。注意不建议使用VS2019自带的“适用于最新 v142 生成工具的 C CMake 工具”之外的独立CMake版本除非你非常熟悉如何让独立CMake正确找到VS2019的工具链。使用VS集成的可以避免大量环境变量问题。2.2 CMake的安装与配置虽然VS集成了CMake但在命令行环境下操作有时一个独立安装的CMake GUI会更直观。建议从CMake官网下载并安装3.15或更高版本的稳定版。安装后将CMake的bin目录例如C:\Program Files\CMake\bin添加到系统的PATH环境变量中。这样你可以在任何命令行窗口如PowerShell或CMD中直接使用cmake和cmake-gui命令。验证安装打开一个**“Developer Command Prompt for VS 2019”**在开始菜单搜索这个它自动配置好了VS环境变量输入cmake --version和msbuild /version确认都能正确输出版本信息。2.3 其他辅助工具Git用于克隆gRPC源码及其子模块。确保已安装Git for Windows并能在命令行中使用git命令。Active Perl 或 Strawberry Perl编译OpenSSL依赖时需要。gRPC默认会下载并编译BoringSSLGoogle的一个OpenSSL分支这个过程需要Perl。Strawberry Perl是Windows上不错的选择因为它自带了很多有用的工具。7-Zip用于解压一些依赖的源码包虽然CMake通常能自动处理但备着无患。准备好这些我们的“手术台”才算搭建完毕。3. 源码获取与依赖管理gRPC不是一个孤立的库它像一棵树有主干核心库和许多枝干依赖项。官方使用Git子模块Submodule来管理这些依赖这是编译过程中第一个容易出错的地方。3.1 克隆gRPC仓库与子模块千万不要只用git clone https://github.com/grpc/grpc.git就了事这样下载的代码是不完整的缺少关键的第三方库如abseil-cpp, re2, cares等会导致后续CMake配置失败。正确的做法是使用--recursive参数进行递归克隆git clone --recursive -b v1.54.0 https://github.com/grpc/grpc.git cd grpc这里的-b v1.54.0指定了版本标签。你可以替换成你需要的版本如v1.48.0或者移除-b参数克隆主分支最新开发版可能不稳定。如果你已经克隆了非递归的仓库可以进入目录后执行以下命令来初始化和更新子模块git submodule update --init --recursive这个过程会下载大量代码网络状况不好的话可能需要较长时间甚至可能因某些子模块仓库访问超时而失败。如果遇到fatal: clone of https://... failed之类的错误可以尝试多次执行git submodule update --init --recursive或者配置Git使用SSH协议。3.2 理解gRPC的依赖生态gRPC核心依赖几个重要的第三方库了解它们有助于排查问题abseil-cppGoogle开源的C通用库提供了字符串、容器、算法等基础组件。gRPC大量使用它。re2Google的正则表达式库。c-ares异步DNS解析库。protobuf序列化库。gRPC的消息格式基于protobuf。注意gRPC仓库的third_party/protobuf子模块包含了protobuf源码编译gRPC时会自动编译它。通常不建议使用系统已安装的protobuf以免版本冲突。zlib压缩库。可选但建议编译进去以支持压缩功能。BoringSSL/OpenSSL加密库。用于TLS/SSL支持。gRPC默认使用BoringSSL。这些依赖的源码都已经通过子模块包含在仓库里了。CMake在配置时会检查这些依赖如果没找到它会尝试从网络下载通过FetchContent但这往往更慢且容易失败。因此确保子模块完整是成功的第一步。4. CMake配置详解与关键参数拿到完整的源码后我们进入核心环节使用CMake生成Visual Studio解决方案.sln文件。这一步的配置选项直接决定了编译出的库是否适合你的项目。4.1 构建目录与生成器选择不要在源码目录内直接构建创建一个独立的构建目录例如grpc/build是一个好习惯这保持了源码的纯净。cd grpc mkdir build cd build接下来在构建目录中运行CMake。这里有两种主流方式方式一使用CMake命令行推荐可复现性强打开“Developer Command Prompt for VS 2019”导航到build目录执行cmake .. -G Visual Studio 16 2019 -A x64 -DCMAKE_BUILD_TYPERelease-G “Visual Studio 16 2019”指定生成器为VS2019。-A x64指定目标平台为64位。如果你需要32位库则使用-A Win32。-DCMAKE_BUILD_TYPERelease指定构建类型为发布版。对于多配置生成器如Visual Studio这个变量在命令行中可能被忽略因为VS可以在IDE里选择Debug/Release。但显式指定是个好习惯。如果要调试可以设为Debug。方式二使用CMake GUI打开CMake GUI“Where is the source code”选择grpc目录“Where to build the binaries”选择grpc/build目录。点击“Configure”在弹出的对话框中选择“Visual Studio 16 2019”和“x64”。配置完成后界面上会列出所有可配置的变量。4.2 必须关注的核心CMake选项在CMake GUI中点击“Configure”后你会看到一大堆以gRPC_或_gRPC开头的选项。以下是一些关键选项你需要根据需求调整选项名推荐值/说明影响与考量CMAKE_INSTALL_PREFIXC:/grpc_install指定make install或INSTALL项目的安装路径。自定义一个路径方便管理。gRPC_BUILD_TESTSOFF除非你需要运行gRPC的单元测试否则一定关掉。编译测试会极大增加编译时间和复杂度。gRPC_BUILD_CODEGENON生成protobuf编译插件grpc_cpp_plugin.exe等这是必须的。gRPC_BUILD_CSHARP_EXTOFF如果你不用C#关掉。gRPC_INSTALLON生成INSTALL项目便于一键安装头文件和库到CMAKE_INSTALL_PREFIX。gRPC_SSL_PROVIDERpackageSSL库提供方。可选package使用已安装的OpenSSL、module编译自带的BoringSSL。新手强烈建议设为module让CMake自动处理BoringSSL的编译避免链接错误。gRPC_ZLIB_PROVIDERmodule类似SSL使用自带的zlib源码编译。gRPC_ABSL_PROVIDERmodule使用自带的abseil-cpp源码编译。这是最省心的方式。gRPC_PROTOBUF_PROVIDERmodule至关重要务必使用module即编译gRPC仓库内自带的protobuf子模块。使用package系统已安装的极易导致protobuf版本不匹配的运行时错误。BUILD_SHARED_LIBSOFF默认生成静态库.lib。如果你需要动态链接库.dll则设为ON。但要注意gRPC的依赖项如protobuf也需要统一为动态或静态。静态库更简单分发方便。实操心得第一次配置时可以先保持大部分选项为默认只确保gRPC_BUILD_TESTSOFF以及各个PROVIDER设为module。这样CMake会尝试下载或使用子模块源码编译所有依赖成功率最高。配置完成后CMake GUI中红色的条目会变成白色下方输出“Configuring done”且无错误即可点击“Generate”生成解决方案文件。5. Visual Studio 2019编译与安装CMake生成成功后在build目录下会看到grpc.sln解决方案文件。用Visual Studio 2019打开它。5.1 解决方案配置与项目选择打开后首先在顶部的工具栏确认解决方案配置为Release平台为x64与你CMake配置时一致。在解决方案资源管理器中你会看到上百个项目。我们不需要编译所有。通常对于C开发我们需要的是以下几个核心库文件及其依赖grpcC同步/异步客户端服务器库。grpc_alts替代通道安全凭证库。grpc_error_details、grpc_reflection、grpc_unsecure如果不需要SSL一些辅助库。grpcC语言核心库。grpc_cpp_plugin用于从.proto文件生成C gRPC代码的插件可执行文件。protobufprotobuf核心库。abseil-cpp相关的一系列库如absl_base, absl_strings等。手动选择这些项目进行编译非常繁琐。更高效的方法是编译ALL_BUILD项目它会构建所有项目或者编译INSTALL项目。5.2 编译ALL_BUILD与解决常见编译错误右键点击ALL_BUILD项目选择“生成”。这个过程会持续较长时间取决于电脑性能可能10分钟到半小时。在这个过程中你很可能会遇到一些编译错误。以下是两个最常见的“坑”及其解决方案错误1C1083: 无法打开包括文件: “openssl/ssl.h”或类似BoringSSL头文件找不到的错误。原因这通常是因为BoringSSL的编译步骤没有在grpc项目编译之前完成。CMake虽然配置了依赖关系但有时Visual Studio的并行编译MSBuild可能会打乱顺序。解决方案在解决方案资源管理器中找到boringssl、crypto等相关项目。右键点击grpc或出错的grpc项目选择“项目依赖项”。在弹出的对话框中确保grpc项目依赖于boringssl和crypto等项目。如果没有手动添加。更简单粗暴的方法是先单独对boringssl和crypto项目进行“生成”确保它们成功编译后再编译grpc和grpc。错误2LNK2005: “void * __cdecl operator new(unsigned __int64)” 已经在 libcpmt.lib(xthrow.obj) 中定义等链接器重定义错误。原因这是Windows CRTC运行时库链接冲突的经典问题。gRPC和一些第三方库可能使用了不同的运行时库设置/MT, /MD, /MTd, /MDd。解决方案我们需要统一整个解决方案的运行时库。这不能在VS里一个个项目改而需要在CMake配置时指定。关闭VS回到CMake GUI或命令行。添加或修改以下CMake变量在CMake GUI中点击“Add Entry”CMAKE_MSVC_RUNTIME_LIBRARY: 设置为MultiThreaded$$CONFIG:Debug:Debug。这个生成器表达式表示Release用/MTDebug用/MTd。如果你需要动态链接/MD则设为MultiThreaded$$CONFIG:Debug:DebugDLL。或者通过命令行传递-DCMAKE_MSVC_RUNTIME_LIBRARYMultiThreaded。重新Configure和Generate然后重新打开解决方案并清理、重新编译。5.3 使用INSTALL项目部署编译结果编译ALL_BUILD成功后库文件.lib和编译中间文件会散落在build目录下各个子项目的输出目录里不方便管理。这时INSTALL项目就派上用场了。在解决方案资源管理器中右键点击INSTALL项目选择“仅生成项目” - “仅生成INSTALL”。这个操作会将所有必要的头文件.h、库文件.lib、可执行文件如grpc_cpp_plugin.exe以及CMake配置文件复制到你在CMAKE_INSTALL_PREFIX例如C:/grpc_install中指定的目录。安装后的目录结构通常如下C:/grpc_install/ ├── bin/ │ ├── grpc_cpp_plugin.exe # Protobuf插件 │ └── (其他工具) ├── include/ │ ├── grpc/ # gRPC C/C 头文件 │ ├── grpcpp/ # gRPC C 头文件 │ └── google/protobuf/ # Protobuf 头文件 └── lib/ ├── grpc.lib # Release静态库 ├── grpcd.lib # Debug静态库 ├── grpc.lib ├── grpcd.lib ├── libprotobuf.lib └── (其他abseil等库)现在你就可以在你的VS2019项目中通过设置“附加包含目录”指向include设置“附加库目录”指向lib并在“附加依赖项”中添加grpc.lib;grpc.lib;libprotobuf.lib;...来使用手动编译的gRPC了。6. 高级配置与疑难问题排查掌握了基本流程后你可能会有一些定制化需求或者遇到更棘手的问题。6.1 编译动态库DLL如果你需要生成动态链接库.dll和.lib导入库需要在CMake配置时将BUILD_SHARED_LIBS设置为ON。但要注意这会产生连锁反应依赖项一致性所有gRPC依赖的库如protobuf、abseil、zlib等也必须被编译为动态库。如果它们被编译为静态库链接gRPC动态库时会产生冲突。将gRPC_*_PROVIDER设为module时CMake通常会处理好这一点。定义宏使用gRPC动态库时在你的客户端代码中必须在包含gRPC头文件之前定义宏GRPC_DLL。例如#define GRPC_DLL #include grpcpp/grpcpp.h运行时部署发布你的应用程序时需要将gRPC相关的.dll文件如grpc.dll,grpc.dll,libprotobuf.dll等一同分发并确保它们在系统的PATH环境变量能找到的目录下或者放在你的可执行文件同级目录。6.2 集成到现有CMake项目手动编译安装后在你的项目中使用find_package来查找gRPC是最优雅的方式。因为INSTALL步骤会生成grpc-config.cmake等文件。在你的项目CMakeLists.txt中# 告诉CMake去哪里找我们自定义安装的gRPC set(grpc_DIR “C:/grpc_install/lib/cmake/grpc”) find_package(grpc CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED) # 链接到你的目标 target_link_libraries(YourTarget PRIVATE grpc grpc protobuf::libprotobuf)这种方式能自动处理头文件路径、库文件路径以及依赖关系。6.3 网络问题导致依赖下载失败在CMake配置阶段即使子模块完整某些依赖特别是当*_PROVIDER设置为package但没找到时CMake会回退到下载也可能尝试从GitHub等地址下载。在国内网络环境下这很容易失败。症状CMake配置时长时间卡在Downloading...或Fetching...最终报错。解决方案首选方案尽可能将所有*_PROVIDER设置为module利用已有的子模块源码。设置代理如果必须下载可以为CMake设置HTTP/HTTPS代理。可以通过环境变量set HTTPS_PROXYhttp://127.0.0.1:1080或在CMake GUI中设置变量CMAKE_TLS_VERIFYOFF不推荐不安全并配合代理。手动下载根据CMake输出日志中的URL手动用下载工具下载对应的压缩包放到build目录下的_deps相关子目录中然后重试。6.4 版本兼容性与符号冲突这是最令人头疼的问题之一。如果你的项目还引用了其他第三方库如另一个版本的protobuf或者使用了abseil的库可能会发生链接时符号重复定义或运行时崩溃。排查思路统一版本确保你的整个项目生态主工程、所有依赖库使用相同的主要版本的protobuf和abseil。强制使用gRPC内置的module模式是最佳实践。检查运行时库如前所述使用CMAKE_MSVC_RUNTIME_LIBRARY统一所有项目的/MT或/MD设置。使用动态库隔离考虑将gRPC及其依赖编译为动态库利用Windows DLL的符号隔离机制在一定程度上可以缓解冲突。查看依赖关系使用Visual Studio的“项目属性” - “链接器” - “输入” - “显示所有符号”或者使用Dependency Walker等工具分析最终生成的二进制文件确认链接了哪些库是否有重复。手动编译gRPC的过程本质上是对现代C项目依赖管理和构建系统的一次深度实践。它繁琐但能给你带来对项目架构最彻底的控制力。当你终于编译成功并看到自己的客户端程序通过你亲手构建的库与服务器成功通信时那种成就感是直接使用预编译二进制包无法比拟的。这份指南里的每一个步骤和“坑”都是我亲身踩过并填平的希望它能帮你更顺畅地完成这次构建之旅。
返回列表