|
| 1 | +# 新增 mcpplibs.grpc 1.83.0(2026-08-05) |
| 2 | + |
| 3 | +[gRPC 收录可行性分析](2026-08-04-grpc-feasibility-analysis.md) 的终点。索引侧此前已备齐依赖 |
| 4 | +([abseil+protobuf](2026-08-04-add-abseil-and-protobuf-plan.md)、 |
| 5 | +[re2+upb](2026-08-04-add-re2-and-protobuf-upb-plan.md)、 |
| 6 | +[c-ares](2026-08-04-add-c-ares-plan.md)),本次加入 gRPC 本体。 |
| 7 | + |
| 8 | +产出:`pkgs/g/grpc.lua`(Form A,指向 [mcpplibs/grpc-m](https://github.com/mcpplibs/grpc-m) |
| 9 | +的 release)+ workspace 成员 `tests/examples/grpc-module`。 |
| 10 | + |
| 11 | +## 1. 为什么是独立仓库 |
| 12 | + |
| 13 | +这是本次唯一一个不能用 compat 描述符表达的库,理由只有一条但很硬:**gRPC 不发布任何自包含的 |
| 14 | +源码产物**。v1.83.0 完全没有 release asset,而其 tag 归档里 abseil / protobuf / re2 / |
| 15 | +boringssl / zlib 全是**空的 submodule 占位**(每个只有一个目录条目),`url` + `sha256` 无处可指。 |
| 16 | + |
| 17 | +`grpc-m` 的 release tarball 就是那个缺失的产物:上游 `src/` 与 `include/` **零补丁** vendor, |
| 18 | +外加 gRPC 自己真正带内容的两块 third_party(`address_sorting`、`xxhash`)。 |
| 19 | + |
| 20 | +**而它不 vendor 的东西才是它属于本索引的理由**:abseil、protobuf(+upb)、re2、c-ares、 |
| 21 | +OpenSSL、zlib 全部取自本索引的包。于是一个同时直接使用 protobuf 或 abseil 的消费者链进去的是 |
| 22 | +**同一份**,而不是和第二份 vendored 副本撞车。 |
| 23 | + |
| 24 | +## 2. 构建形态 |
| 25 | + |
| 26 | +无 CMake、无 Bazel、无 configure —— 这不是取巧,而是核实过的事实:gRPC 源码树里**没有任何 |
| 27 | +`.h.in` 或 `config.h.cmake`**,且其 upb 生成码上游已 check-in,所以 mcpp 只需要 include 路径。 |
| 28 | +1001 个 TU 全部由解析出的工具链编译,**没有任何外部构建系统参与**,因此不存在 |
| 29 | +`compat.openssl` 那种"外部 `c++` 编出的产物与 mcpp 链接侧 C++ ABI 不一致"的风险 |
| 30 | +(那正是可行性分析里否掉 `install()` + CMake 路线的原因)。 |
| 31 | + |
| 32 | +源码清单是**上游自己的**:`add_library(gpr)` + `add_library(grpc)` + `add_library(grpc++)` + |
| 33 | +`add_library(address_sorting)` 之并(995 条,c-ares 的 7 条另计)。`grpc-m` 的 |
| 34 | +`tools/gen_sources.py` 能从上游 checkout 重新生成它,`--check` 在该仓 CI 里运行,证明 manifest |
| 35 | +与 vendored 源码树没有漂移。 |
| 36 | + |
| 37 | +刻意排除一个文件:`src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c` —— |
| 38 | +与 `compat.protobuf` 的 `upb` feature 已编译的 bootstrap 版本**逐字节完全相同**,两份同编会重复符号。 |
| 39 | + |
| 40 | +## 3. `import grpc;` 与顺序约束 |
| 41 | + |
| 42 | +`grpc-m` 提供真实的 C++23 模块层(`src/grpc.cppm`),它同时也充当 mcpp `kind = "lib"` 约定要求的 |
| 43 | +lib root。导出面只取**公开 API**:`namespace grpc` 里还有约 280 个实现细节名字 |
| 44 | +(`grpc::internal`、`CallOp*` 机器),整表扫描会把它们一起导出。每个名字都由编译器验证 —— |
| 45 | +`export using ::grpc::X;` 在 X 不存在时直接编译失败 —— 这已经当场抓出三个并不存在的名字 |
| 46 | +(`GrpcLibraryCodegen`、`DisableDefaultHealthCheckService`,以及补 include 之前的 |
| 47 | +`ServerReaderWriter`)。 |
| 48 | + |
| 49 | +**`import grpc;` 必须放在该 TU 所有 textual `#include` 之后**,标准库头也算。全局模块片段把大半个 |
| 50 | +标准库带进了 BMI,import 之后再 textual include 会让同一批声明到达两次。两种顺序都实测过 |
| 51 | +(gcc 16.1.0): |
| 52 | + |
| 53 | +- import 在前 → `redefinition of std::__is_constant_evaluated` 加一大片 `<limits>` 冲突 |
| 54 | +- 仅有 std 头跟在 import 之后 → `std::string` 上的 `ambiguous overload for operator==` |
| 55 | +- **include 全部在前、import 在最后 → 正常**,因为导出实体属于**全局模块**,textual 视图与 |
| 56 | + import 视图是同一批实体 |
| 57 | + |
| 58 | +这不是本包发明的约束:gRPC 的代码生成器产出的是**头文件**,任何真实程序都会同时用到两个世界。 |
| 59 | + |
| 60 | +## 4. `ares` feature 的方向是被迫的 |
| 61 | + |
| 62 | +c-ares **默认开启**,与上游 gRPC 及各发行版一致;`default-features = false` 关闭。 |
| 63 | + |
| 64 | +方向不能反过来:mcpp 的 feature 是**只增不减**的,若把 `-DGRPC_ARES=0` 写进基础 flag,再让 |
| 65 | +feature 翻成 1,两个 `-DGRPC_ARES` 会同时出现在命令行。因此 manifest 对 `GRPC_ARES` **只字不提** |
| 66 | +(`port_platform.h` 用 `#ifndef` 兜底成 1,所以"沉默"就是开启态),关闭态由 `build.mcpp` 在 |
| 67 | +feature 缺席时发 `GRPC_ARES=0`;而那 7 个解析器 TU 走相反方向 —— 声明式地放在 |
| 68 | +`[features.ares].sources` 里。 |
| 69 | + |
| 70 | +## 5. 验证结论 |
| 71 | + |
| 72 | +`grpc-m` 侧(与本索引 CI 同款配置:mcpp 2026.8.3.3、gcc@16.1.0、`MCPP_BUILD_CACHE=local`, |
| 73 | +且**从已发布索引解析、无任何本地重定向**),1412 个目标文件入链: |
| 74 | + |
| 75 | +``` |
| 76 | +mcpp test -> grpc::Version() = 1.83.0 ; module: OK |
| 77 | +examples/helloworld -> server listening on 127.0.0.1:34733 |
| 78 | + Greeter replied: Hello mcpp |
| 79 | + Greeter rejected the empty name: name must not be empty |
| 80 | +``` |
| 81 | + |
| 82 | +helloworld 刻意做成**单进程**:在真实 loopback 端口上起真实服务端,经真实 HTTP/2 通道发起真实 |
| 83 | +unary RPC,所以 `mcpp run` 用退出码回答"gRPC 到底能不能用"。**错误路径也走线** —— 空 name 必须 |
| 84 | +从服务端回 `INVALID_ARGUMENT` —— 因此一个"什么都答 OK"的桩通不过。 |
| 85 | + |
| 86 | +索引侧成员 `tests/examples/grpc-module` 全程只用 `import grpc;`,不含任何 protoc 产物: |
| 87 | +gRPC 的 codegen 需要 mcpp 无法交付给消费者的宿主工具,所以生成物那条路径由 grpc-m 自己的 |
| 88 | +example 覆盖,索引成员验证模块面。 |
| 89 | + |
| 90 | +## 6. 遗留:codegen 工具的分发 |
| 91 | + |
| 92 | +`protoc` 与 `grpc_cpp_plugin` 目前仍需用户自备(`grpc-m` 的模板与 example 把生成产物**签入**, |
| 93 | +所以开箱即用)。根本原因是 mcpp 没有把依赖的构建产物交给消费者的机制:`mcpp::dep_dir()` 给的是 |
| 94 | +依赖的**源码目录**,而 `kind = "bin"` 的 target 不对消费者暴露。 |
| 95 | + |
| 96 | +有利条件已核实:protobuf 上游发布**全平台预编译 protoc**,所以缺口只有 `grpc_cpp_plugin` |
| 97 | +(本次为生成 helloworld 的 stub,已用 vendored 源码在本地编出过它,157 TU 的 libprotoc + 3 个 |
| 98 | +grpc compiler TU)。后续可做成 `xim:grpc-tools` 预编译包,消费者以 `[xlings] deps` 声明, |
| 99 | +再由 `build.mcpp` 调用 —— 这条链路 mcpp 已经具备,只差把工具打包。 |
0 commit comments