From 8c34417d1040385b19d6b403ab4cb176c83e9ed9 Mon Sep 17 00:00:00 2001 From: speak-agent Date: Wed, 5 Aug 2026 16:45:19 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(codegen):=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=E4=BA=A7=E7=89=A9=E4=B8=8D=E5=86=8D=E7=AD=BE=E5=85=A5=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20protoc=20=E4=B8=8E=20grpc=5Fcpp=5Fplugin?= =?UTF-8?q?=20=E7=94=B1=20mcpp=20=E8=87=AA=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本仓库的 mcpp.toml / README 里一直写着「mcpp 没有把依赖的构建产物交给消费者的 机制,所以生成产物签入仓库」。mcpp 2026.8.5.1 之后那句话不成立了。 ## 最重要的验证结果 用 mcpp 从源码构建出的 protoc 与 grpc_cpp_plugin,对 helloworld.proto 生成的 **四个文件与仓库里签入的逐字节相同**: helloworld.pb.h / .pb.cc ✓ 逐字节相同 helloworld.grpc.pb.h / .grpc.pb.cc ✓ 逐字节相同 也就是说这条自建工具链的产物 ≡ 官方 protoc 35.1 + 官方 gRPC 1.83.0 插件的产物。 签入的 gen/ 因此可以删掉,而不是「大概等价」。 ## 新增 plugin/ 包 —— 为什么不是 grpc 里的一个 target 初版就是在主包里加 [features.codegen] + [targets.grpc_cpp_plugin],语法上全部成立。 不行的原因是 mcpp 把一个包编成**一个对象池**(Target 没有 sources 字段),所以 kind="bin" 会链接该包的**全部对象**。而上游的插件只链 grpc_plugin_support + protobuf: add_executable(grpc_cpp_plugin src/compiler/cpp_plugin.cc) target_link_libraries(grpc_cpp_plugin grpc_plugin_support) 放主包里意味着这个代码生成器要链进 gRPC 的 ~1000 个 TU,并继承整套依赖 —— OpenSSL、re2、c-ares、zlib。实测直接失败: error: xlings install_packages failed for 'compat.openssl@3.5.1' **一个代码生成器因为装不上 TLS 库而构建失败** —— 这不只是大和慢,是依赖图错了。 拆成独立包后恢复上游的真实依赖图:3 个 TU + libprotoc,没有 TLS/DNS/正则。 实测构建 **2.19s**(protobuf 命中全局缓存)。 ## 插件只取 C++ 的那条闭包 上游的 grpc_plugin_support 带全部 8 个语言 generator,因为它同时支撑 grpc_php_plugin / grpc_python_plugin 等。本包只建 grpc_cpp_plugin,所以只取 cpp_plugin.cc 真正够得到的 cpp_generator.cc + proto_parser_helper.cc。 **这不是抄近路而是正确的闭包,并且它 MATTERS**:php 与 objective-c 的 generator 引用 libprotoc 内部符号(compiler::objectivec::FileClassPrefix 等),而 compat.protobuf 编译 的源码集不导出它们 —— 带上它们会在**链接期**因为「没人要求生成的语言」而失败。实测。 ## 用户侧 grpc = "1.83.0" grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } compat.protobuf = { version = "35.1", tools = ["protoc"] } 改 .proto 然后重新构建,就这样。三个手工管理给不了的性质: - **版本错配不可表达** —— 工具版本就是依赖版本。protoc 与运行时对不上是**运行期** 才炸、也是这类问题里最难查的,现在语法上无法发生。(Conan 为近似这一点专门引入了 ;protobuf 自己的 CMake 至今有 open issue:CONFIG 模式下 Protobuf_PROTOC_EXECUTABLE 被忽略。) - **增量** —— 生成是一条 ninja 边,.proto 变了才重跑。 - **交叉编译构造上就对** —— --target 下工具仍为构建机器构建,用户零操作。 ## 改动 - 新增 plugin/(独立包)+ 3 个 vendored gRPC 公开头(自包含;vendor 在本包内而不是 去主包 third_party 取 —— 它会作为自己的 tarball 发布) - examples/helloworld 与 templates/greeter:删掉签入的 gen/,改由 build.mcpp 声明 一条 action 生成 - CI:MCPP_VERSION → 2026.8.5.1(这是**下限**不是例行 pin:tools=[...] 与 mcpp:action= 在它之前不存在);新增「grpc-plugin 版本 == grpc 版本」校验 —— 两个索引条目出自同一个 tag,除了校验没有别的东西能让它们保持相等,而版本漂移正是 本设计要消灭的那类错配 - .agents/docs/2026-08-05-codegen-ecosystem-design.md:完整方案与实测数据 ## 顺序依赖 / 未在本地验证的部分 - 需要 **mcpp-index 先合入 compat.protobuf 的 protoc target**,否则拿不到 protoc。 - 模板里的 `grpc-plugin = { version = ... }` 需要索引里有 mcpplibs.grpc-plugin 条目, 那要等本仓库打出 tag 之后再发一个索引 PR。example 用的是 path 依赖,不受此限。 - **example 的完整构建没有在本地跑通**:本机 compat.openssl 的从源码 install() 钩子 跑不起来(与本次改动无关,主包一直如此),由 CI 覆盖。已在本地验证的是:两个工具 都能建出来、生成产物与签入的逐字节相同。 --- .../2026-08-05-codegen-ecosystem-design.md | 207 ++ .github/workflows/ci.yml | 25 +- README.md | 48 +- README.zh.md | 44 +- examples/helloworld/build.mcpp | 69 + examples/helloworld/gen/helloworld.grpc.pb.cc | 88 - examples/helloworld/gen/helloworld.grpc.pb.h | 248 -- examples/helloworld/gen/helloworld.pb.cc | 827 ------ examples/helloworld/gen/helloworld.pb.h | 658 ----- examples/helloworld/mcpp.toml | 38 +- .../grpcpp/impl/codegen/config_protobuf.h | 123 + plugin/include/grpcpp/ports_def.inc | 137 + plugin/include/grpcpp/ports_undef.inc | 75 + plugin/mcpp.toml | 70 + plugin/src/compiler/config.h | 68 + plugin/src/compiler/config_protobuf.h | 64 + plugin/src/compiler/cpp_generator.cc | 2509 +++++++++++++++++ plugin/src/compiler/cpp_generator.h | 141 + plugin/src/compiler/cpp_generator_helpers.h | 63 + plugin/src/compiler/cpp_plugin.cc | 26 + plugin/src/compiler/cpp_plugin.h | 206 ++ plugin/src/compiler/csharp_generator.h | 32 + .../src/compiler/csharp_generator_helpers.h | 61 + plugin/src/compiler/generator_helpers.h | 286 ++ plugin/src/compiler/node_generator.h | 37 + plugin/src/compiler/node_generator_helpers.h | 42 + plugin/src/compiler/objective_c_generator.h | 59 + .../compiler/objective_c_generator_helpers.h | 125 + plugin/src/compiler/php_generator.h | 33 + plugin/src/compiler/php_generator_helpers.h | 80 + plugin/src/compiler/proto_parser_helper.cc | 29 + plugin/src/compiler/proto_parser_helper.h | 22 + plugin/src/compiler/protobuf_plugin.h | 207 ++ plugin/src/compiler/python_generator.h | 83 + .../src/compiler/python_generator_helpers.h | 162 ++ .../src/compiler/python_private_generator.h | 87 + plugin/src/compiler/ruby_generator.h | 30 + .../src/compiler/ruby_generator_helpers-inl.h | 58 + plugin/src/compiler/ruby_generator_map-inl.h | 57 + .../src/compiler/ruby_generator_string-inl.h | 151 + plugin/src/compiler/schema_interface.h | 120 + templates/greeter/build.mcpp.in | 70 + templates/greeter/gen/helloworld.grpc.pb.cc | 88 - templates/greeter/gen/helloworld.grpc.pb.h | 248 -- templates/greeter/gen/helloworld.pb.cc | 827 ------ templates/greeter/gen/helloworld.pb.h | 658 ----- templates/greeter/mcpp.toml.in | 28 +- templates/greeter/src/main.cpp.in | 4 +- templates/greeter/template.toml | 2 +- 49 files changed, 5729 insertions(+), 3691 deletions(-) create mode 100644 .agents/docs/2026-08-05-codegen-ecosystem-design.md create mode 100644 examples/helloworld/build.mcpp delete mode 100644 examples/helloworld/gen/helloworld.grpc.pb.cc delete mode 100644 examples/helloworld/gen/helloworld.grpc.pb.h delete mode 100644 examples/helloworld/gen/helloworld.pb.cc delete mode 100644 examples/helloworld/gen/helloworld.pb.h create mode 100644 plugin/include/grpcpp/impl/codegen/config_protobuf.h create mode 100644 plugin/include/grpcpp/ports_def.inc create mode 100644 plugin/include/grpcpp/ports_undef.inc create mode 100644 plugin/mcpp.toml create mode 100644 plugin/src/compiler/config.h create mode 100644 plugin/src/compiler/config_protobuf.h create mode 100644 plugin/src/compiler/cpp_generator.cc create mode 100644 plugin/src/compiler/cpp_generator.h create mode 100644 plugin/src/compiler/cpp_generator_helpers.h create mode 100644 plugin/src/compiler/cpp_plugin.cc create mode 100644 plugin/src/compiler/cpp_plugin.h create mode 100644 plugin/src/compiler/csharp_generator.h create mode 100644 plugin/src/compiler/csharp_generator_helpers.h create mode 100644 plugin/src/compiler/generator_helpers.h create mode 100644 plugin/src/compiler/node_generator.h create mode 100644 plugin/src/compiler/node_generator_helpers.h create mode 100644 plugin/src/compiler/objective_c_generator.h create mode 100644 plugin/src/compiler/objective_c_generator_helpers.h create mode 100644 plugin/src/compiler/php_generator.h create mode 100644 plugin/src/compiler/php_generator_helpers.h create mode 100644 plugin/src/compiler/proto_parser_helper.cc create mode 100644 plugin/src/compiler/proto_parser_helper.h create mode 100644 plugin/src/compiler/protobuf_plugin.h create mode 100644 plugin/src/compiler/python_generator.h create mode 100644 plugin/src/compiler/python_generator_helpers.h create mode 100644 plugin/src/compiler/python_private_generator.h create mode 100644 plugin/src/compiler/ruby_generator.h create mode 100644 plugin/src/compiler/ruby_generator_helpers-inl.h create mode 100644 plugin/src/compiler/ruby_generator_map-inl.h create mode 100644 plugin/src/compiler/ruby_generator_string-inl.h create mode 100644 plugin/src/compiler/schema_interface.h create mode 100644 templates/greeter/build.mcpp.in delete mode 100644 templates/greeter/gen/helloworld.grpc.pb.cc delete mode 100644 templates/greeter/gen/helloworld.grpc.pb.h delete mode 100644 templates/greeter/gen/helloworld.pb.cc delete mode 100644 templates/greeter/gen/helloworld.pb.h diff --git a/.agents/docs/2026-08-05-codegen-ecosystem-design.md b/.agents/docs/2026-08-05-codegen-ecosystem-design.md new file mode 100644 index 0000000..f9bf37c --- /dev/null +++ b/.agents/docs/2026-08-05-codegen-ecosystem-design.md @@ -0,0 +1,207 @@ +# grpc-m 全生态打通:让 codegen 不再签入仓库 + +> 状态:**已验证,实施中** +> 依赖:mcpp **2026.8.5.1**(#355 依赖产出的 host 工具、`mcpp:action=` 构建图节点、 +> `host-module = true` 规则包) +> 涉及:本仓库的 `plugin/`(新)、`templates/`、`examples/`、`.github/workflows/ci.yml`; +> `mcpp-index` 的 `compat.protobuf` 与新条目 `mcpplibs.grpc-plugin` + +--- + +## 0. 结论摘要 + +今天本仓库的 `mcpp.toml` 里写着: + +``` +# gen/ holds protoc output, CHECKED IN on purpose. gRPC's codegen needs two +# host tools — protoc and grpc_cpp_plugin — and mcpp has no way to hand a +# dependency's built binaries to a consumer. +``` + +那个「mcpp 没有办法」在 **2026.8.5.1** 之后不成立了。 + +**最重要的验证结果**:用 mcpp 从源码构建出的 `protoc` 与 `grpc_cpp_plugin`,对 +`examples/helloworld/proto/helloworld.proto` 生成的**四个文件与仓库里签入的 +逐字节相同**。也就是说,这条自建工具链的产物 ≡ 官方 protoc 35.1 + 官方 gRPC 1.83.0 +插件的产物。 + +| 文件 | 结果 | +|---|---| +| `helloworld.pb.h` / `.pb.cc` | ✓ 逐字节相同 | +| `helloworld.grpc.pb.h` / `.grpc.pb.cc` | ✓ 逐字节相同 | + +**三个此前不可能、现在结构性成立的性质**: + +| 性质 | 今天(签入 gen/) | 本方案 | +|---|---|---| +| 改 `.proto` 后 | 手工重跑 protoc,忘了就一直用旧桩子 | ninja 边自动重跑,且只重跑受影响的 | +| protoc 与 protobuf 运行时版本 | **用户自己保证**,错配是**运行期**才炸 | **不可表达** —— 工具版本 ≡ 依赖版本 | +| 交叉编译 | 用户得自己找一个 host protoc | **构造上就对** —— 工具永远为 host 构建 | + +--- + +## 1. gRPC codegen 需要什么 + +两个 host 二进制,且两者的版本都不自由: + +| 工具 | 来自 | 版本约束 | +|---|---|---| +| `protoc` | `compat.protobuf` | 必须与链接的 protobuf **运行时**一致(35.1)—— 错配是运行期错误 | +| `grpc_cpp_plugin` | 本仓库(新 `plugin/` 包) | 必须与链接的 gRPC 一致(1.83.0)—— 生成代码调用 gRPC 内部 API | + +「两个工具、两条版本约束、错配在运行期才炸」正是 `tools = [...]` 的**单一版本轴**要 +解决的:工具的版本**就是**那条依赖的版本,所以错配**在语法上无法表达**。 + +对照业界:Conan 专门引入 `protobuf/` 占位符来补这一点;protobuf 自己的 +CMake 至今有一个 open issue(#14576)是 CONFIG 模式下 `Protobuf_PROTOC_EXECUTABLE` +被忽略;xmake 的 protobuf 包在交叉编译时**直接删掉** protoc 并且不接进 PATH。 +mcpp 这里不需要额外机制,因为版本轴本来就只有一条。 + +## 2. 插件必须是**独立的包**,不能是 grpc-m 的一个 target + +这是本方案里唯一一个「先猜错、被数据纠正」的决定,值得完整记下来。 + +**初版做法**:在 grpc-m 主包里加 `[features.codegen]` + `[targets.grpc_cpp_plugin]`, +用 `forward = ["compat.protobuf/protoc"]` 把成本门跨包传过去。语法上全部成立。 + +**为什么不行**:mcpp 把一个包编成**一个对象池**,`Target` 没有 `sources` 字段, +所以一个 `kind="bin"` 目标会链接**该包的全部对象**。而 upstream 的插件只链 +`grpc_plugin_support` + protobuf,**完全不碰 gRPC 运行时**: + +``` +add_executable(grpc_cpp_plugin src/compiler/cpp_plugin.cc) +target_link_libraries(grpc_cpp_plugin grpc_plugin_support) +``` + +放进主包意味着这个代码生成器要链接 gRPC 的 ~1000 个 TU,并**继承 grpc-m 的整套依赖**: +OpenSSL、re2、c-ares、zlib。实测直接失败: + +``` +error: xlings install_packages failed for 'compat.openssl@3.5.1' +``` + +一个代码生成器因为**装不上 TLS 库**而构建失败 —— 这不只是「大和慢」,是依赖图本身错了。 + +**结论**:拆成独立的 `plugin/` 包,依赖只有 `compat.protobuf`。这恢复了 upstream 的 +真实依赖图:3 个 TU + libprotoc,没有 TLS、没有 DNS、没有正则引擎。实测构建 **2.19s** +(protobuf 走全局缓存)。 + +## 3. 插件包只取 C++ 的那条闭包 + +upstream 的 `grpc_plugin_support`(CMakeLists.txt:6474)带全部 8 个语言 generator, +因为它同时支撑 `grpc_php_plugin` / `grpc_python_plugin` 等。本包只建 `grpc_cpp_plugin`, +所以只取 `cpp_plugin.cc` 实际够得到的: + +``` +src/compiler/cpp_generator.cc C++ 发射器 +src/compiler/proto_parser_helper.cc cpp_generator 用它取注释/前导细节 +``` + +**这不是抄近路,而是正确的闭包,并且它 MATTERS**:php 与 objective-c 的 generator 引用 +libprotoc 内部符号(`compiler::objectivec::FileClassPrefix`、php 的若干 helper), +而 compat.protobuf 编译的源码集并不导出它们 —— 把它们带上会在**链接期**因为「没人要求 +生成的语言」而失败。实测确认。 + +> 本仓库既有的纪律是「vendored 源码列表是 upstream 自己的,转录而来」 +> (`tools/gen_sources.py --check` 为此存在)。那条纪律说的是**库**的源码列表;插件包 +> 取的是「`grpc_cpp_plugin` 这一个可执行文件的闭包」,与 upstream 的 +> `add_executable(grpc_cpp_plugin …)` 一致。 + +### 3.1 三个 vendored 头 + +插件源码只引用两个 gRPC 公开头:`grpcpp/impl/codegen/config_protobuf.h` 与 +`grpcpp/ports_undef.inc`(连带 `ports_def.inc`)。三个都**自包含** +(`config_protobuf.h` 只 include protobuf 的头)。 + +它们 vendor 在 `plugin/include/` **而不是**去主包的 `third_party/…` 里取:这个包会作为 +**自己的 tarball** 发布,`../third_party/…` 的 include 在本地能解析,一旦从索引消费就断。 + +## 4. 索引侧(mcpp-index) + +### 4.1 `compat.protobuf` 加 protoc 目标 + +```lua +targets = { + ["protobuf"] = { kind = "lib" }, + ["protoc"] = { kind = "bin", + main = "*/src/google/protobuf/compiler/main.cc", + required_features = { "protoc", "upb" } }, +}, +features = { + ["protoc"] = { sources = { … 138 项 libprotoc_srcs … } }, +} +``` + +三个实测要点: + +1. **138 项来自 upstream 自己的 `src/file_lists.cmake` 的 `libprotoc_srcs`**,不是手挑; + 与 libprotobuf 的源码集**零重叠**(`importer.cc`/`parser.cc` 早在 libprotobuf 里)。 + 源码树里**没有** `.h.in` / `.cmake.in`,不需要任何 configure 步骤。 +2. **必须同时要求 `upb`**:只开 `protoc` 会在链接期缺一批 `upb_*` 符号 —— libprotoc 的 + upb 生成器需要 upb 运行时。 +3. **`main` 要写成 `*/src/...`**:Form B 包的源码在版本目录下的包装目录里,`*` 代表 + tarball 顶层文件夹名。mcpp 2026.8.5.1 起 `main` 会像 `sources` 一样展开这个 glob。 + +### 4.2 新条目 `mcpplibs.grpc-plugin` + +与 `mcpplibs.grpc` 同一个仓库、同一个 tag,Form A(自带 `plugin/mcpp.toml`)。 +平台覆盖是 **linux/macos/windows** —— 它只需要 libprotoc,**不受 compat.openssl 的 +windows 缺口限制**(主包受)。 + +## 5. 用户侧:怎样才算「最方便」 + +### 5.1 本方案落地后 + +```toml +[dependencies] +grpc = "1.83.0" +grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } +compat.protobuf = { version = "35.1", tools = ["protoc"] } +``` + +模板直接给出可用的 `build.mcpp`,用户 `mcpp new --template greeter` 之后改 `.proto` +即可,**不需要理解 action 的细节**。 + +### 5.2 下一步:规则包(不在本次范围,设计在此) + +| | 用户要写 | +|---|---| +| CMake + vcpkg/Conan | `protobuf_generate(TARGET app)` ≈ 1 行(交叉时要自己处理 host protoc) | +| xmake | `add_rules("protobuf.cpp")` ≈ 1 行(交叉下 protoc **没接通**) | +| **mcpp 本方案** | 约 20 行 build.mcpp | +| mcpp + 规则包 | **约 3 行** | + +`host-module = true` 就是为这一步做的:规则以**普通 mcpp 包**分发,消费者 +`import mcpp.rules.grpc;`。规则因此有版本、能测试、能发布,而且是 **C++** 写的 —— +不引入第二门语言(xmake 用 Lua rule、Bazel 用 Starlark)。 + +**为什么不在本次做**:规则包要有自己的发布节奏;而且有一个**已知的引擎缺口**要先补 —— +一个 `host-module` 规则包**带不动自己的 tools**:工具的环境变量按「请求它的那个包」 +记账,而规则代码是在**消费者**的 build.mcpp 里执行的,于是消费者看不到那个变量。 +补法是让 host-module 依赖的 tools 转发给消费者,是一处小改动,但要单独做。 + +## 6. 已知缺口(都不阻塞本方案) + +1. **工具子构建不继承 root 的 `[indices]`**。子构建以工具包为 root 重新解析依赖, + 用的是工具包自己的 manifest;消费者写在自己 manifest 里的 `[indices]` 覆盖不过去。 + 对**已发布**的索引没有影响,但用本地索引做验证时会踩:现象是工具包解析到了**线上** + 的依赖版本而不是你改过的那份。 +2. **插件包与主包同 tag 但是两个索引条目**,版本必须一起 bump。CI 应当校验二者相等 —— + 否则用一个 1.83.0 的 gRPC 配一个别的版本的插件,正是本方案要消灭的那类错配。 + +## 7. 验证矩阵(✓ = 已实测) + +| 项 | 结果 | +|---|---| +| ✓ protoc 可从 compat.protobuf 源码构建 | 138 TU,无 configure 步骤 | +| ✓ grpc_cpp_plugin 可构建 | 3 TU + libprotoc,**2.19s**(protobuf 命中全局缓存) | +| ✓ 两者生成的桩子正确 | 四个文件与仓库签入的**逐字节相同** | +| ✓ 工具进全局 store 并跨工程复用 | 二次构建不重建 | +| 生成的桩子能编能跑 | example 去签入 gen/ 后 `mcpp run` 完成真实 RPC | +| 改 `.proto` 触发重新生成 | 且不相关的重建不触发 | + +## 8. 明确不做 + +- **不裁剪主包的库源码列表**:那条 `gen_sources.py --check` 的保证不动。 +- **不在本次发规则包**:先补 §5.2 的引擎缺口。 +- **不动主包的平台覆盖**:它等于 `compat.openssl` 的,与 codegen 无关;插件包不受此限。 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1b1b2d..91b45ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,10 @@ on: env: # Keep in step with the mcpp-index CI pin: this package's dependencies are # index packages, and they are validated against that same mcpp. - MCPP_VERSION: "2026.8.3.3" + # 2026.8.5.1 is the FLOOR, not a routine pin: `tools = [...]` host tools and + # `mcpp:action=` build-graph nodes — what the codegen in templates/ and + # examples/ is built on — do not exist before it. + MCPP_VERSION: "2026.8.5.1" jobs: build: @@ -79,6 +82,26 @@ jobs: run: | "$MCPP" run + plugin-version-matches: + name: grpc-plugin version == grpc version + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # The plugin generates code that calls gRPC internals, so a plugin built + # from a different release than the runtime being linked is exactly the + # mismatch this whole design exists to make impossible. They ship as two + # index entries from one tag, so nothing but a check keeps them equal. + - name: versions must match + shell: bash + run: | + lib=$(awk -F'"' '/^version/{print $2; exit}' mcpp.toml) + plug=$(awk -F'"' '/^version/{print $2; exit}' plugin/mcpp.toml) + echo "grpc=$lib grpc-plugin=$plug" + if [ "$lib" != "$plug" ]; then + echo "FAIL: grpc-plugin version ($plug) must equal grpc version ($lib)" + exit 1 + fi + manifest-matches-upstream: name: source list == upstream CMakeLists runs-on: ubuntu-latest diff --git a/README.md b/README.md index 7aa7274..4320c22 100644 --- a/README.md +++ b/README.md @@ -76,18 +76,48 @@ Prefer plain headers instead? That works too and needs no import at all: ## Code generation -gRPC needs two host tools — `protoc` and `grpc_cpp_plugin` — and mcpp has no mechanism -for handing a dependency's built binaries to a consumer. So generated stubs are checked -in, both in the template and in `examples/helloworld`: +gRPC needs two host tools — `protoc` and `grpc_cpp_plugin` — and since **mcpp 2026.8.5.1** +you no longer supply them yourself. Declare them on the dependencies they belong to and +mcpp builds them for your machine: -```bash -protoc -I proto --cpp_out=gen --grpc_out=gen \ - --plugin=protoc-gen-grpc=$(which grpc_cpp_plugin) \ - proto/helloworld.proto +```toml +[dependencies] +grpc = "1.83.0" +grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } +compat.protobuf = { version = "35.1", tools = ["protoc"] } +``` + +```cpp +// build.mcpp — declare the generation as a build-graph edge +mcpp::action gen; +gen.role = "source"; +gen.arg(mcpp::dep_bin("protobuf", "protoc")) + .arg("--cpp_out=…").arg("--grpc_out=…") + .arg(std::string("--plugin=protoc-gen-grpc=") + mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin")) + .input("proto/helloworld.proto") + .output("…/helloworld.pb.cc").output("…/helloworld.grpc.pb.cc") + .submit(); ``` -`protoc` must be **35.1** to match `compat.protobuf` (upstream publishes prebuilt protoc -for every platform), and `grpc_cpp_plugin` must come from **gRPC 1.83.0**. +`templates/greeter` and `examples/helloworld` both do exactly this — **no generated file +is checked in any more**. Edit the `.proto` and rebuild. + +Three properties this buys, none of which hand-managed codegen can offer: + +- **A version mismatch is not expressible.** A tool's version *is* its dependency's + version, so a `protoc` that disagrees with the protobuf runtime — a **runtime** failure, + and the nastiest thing about protobuf codegen — cannot happen. (Conan needed a + `` placeholder to approximate this; protobuf's own CMake still has an open + issue where `Protobuf_PROTOC_EXECUTABLE` is ignored in CONFIG mode.) +- **Incremental.** Generation is a ninja edge, so it re-runs when its `.proto` changes and + not otherwise. +- **Cross-compilation is correct by construction.** Under `--target` the tools are still + built for the build machine, with no action from you. + +> `grpc-plugin` is a package of its own rather than a target inside `grpc`, because +> upstream's plugin links `grpc_plugin_support` + protobuf and nothing else — a code +> generator needs a `.proto` parser and a C++ emitter, not TLS, DNS and a regex engine. +> See `.agents/docs/2026-08-05-codegen-ecosystem-design.md` §2. ## Platform support diff --git a/README.zh.md b/README.zh.md index 5b4df3b..9efee62 100644 --- a/README.zh.md +++ b/README.zh.md @@ -74,17 +74,45 @@ class Greeter final : public helloworld::Greeter::Service { ## 代码生成 -gRPC 需要两个宿主工具 —— `protoc` 与 `grpc_cpp_plugin` —— 而 mcpp 没有把依赖的构建产物 -交给消费者的机制。因此模板与 `examples/helloworld` 里的生成产物是**签入**的: +gRPC 需要两个宿主工具 —— `protoc` 与 `grpc_cpp_plugin` —— 自 **mcpp 2026.8.5.1** 起 +你不再需要自己准备它们。把它们声明在各自所属的依赖上,mcpp 会为你的机器构建出来: -```bash -protoc -I proto --cpp_out=gen --grpc_out=gen \ - --plugin=protoc-gen-grpc=$(which grpc_cpp_plugin) \ - proto/helloworld.proto +```toml +[dependencies] +grpc = "1.83.0" +grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } +compat.protobuf = { version = "35.1", tools = ["protoc"] } +``` + +```cpp +// build.mcpp —— 把生成声明成构建图的一条边 +mcpp::action gen; +gen.role = "source"; +gen.arg(mcpp::dep_bin("protobuf", "protoc")) + .arg("--cpp_out=…").arg("--grpc_out=…") + .arg(std::string("--plugin=protoc-gen-grpc=") + mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin")) + .input("proto/helloworld.proto") + .output("…/helloworld.pb.cc").output("…/helloworld.grpc.pb.cc") + .submit(); ``` -`protoc` 必须是 **35.1**(与 `compat.protobuf` 对齐,上游提供全平台预编译包), -`grpc_cpp_plugin` 必须来自 **gRPC 1.83.0**。 +`templates/greeter` 与 `examples/helloworld` 都是这么做的 —— **仓库里不再签入任何生成 +产物**。改 `.proto` 然后重新构建,就这样。 + +由此得到三个手工管理 codegen 给不了的性质: + +- **版本错配不可表达。** 工具的版本**就是**那条依赖的版本,所以「protoc 与 protobuf + 运行时对不上」——这是**运行期**才炸、也是 protobuf codegen 最难查的一类问题—— + 在语法上无法发生。(Conan 为了近似这一点专门引入了 `` 占位符; + protobuf 自己的 CMake 至今有一个 open issue:CONFIG 模式下 `Protobuf_PROTOC_EXECUTABLE` + 被忽略。) +- **增量。** 生成是一条 ninja 边,`.proto` 变了才重跑,不变就不跑。 +- **交叉编译构造上就对。** `--target` 下工具依然为构建机器构建,你什么都不用做。 + +> `grpc-plugin` 是独立的包而不是 `grpc` 里的一个 target,因为上游的插件只链 +> `grpc_plugin_support` + protobuf,别的都不链 —— 一个代码生成器需要的是 `.proto` +> 解析器和 C++ 发射器,不是 TLS、DNS 和正则引擎。 +> 详见 `.agents/docs/2026-08-05-codegen-ecosystem-design.md` §2。 ## 平台支持 diff --git a/examples/helloworld/build.mcpp b/examples/helloworld/build.mcpp new file mode 100644 index 0000000..c1e653e --- /dev/null +++ b/examples/helloworld/build.mcpp @@ -0,0 +1,69 @@ +// gRPC codegen, as build-graph nodes. +// +// The two tools come from the dependency graph — `mcpp::dep_bin()` reads the +// path mcpp published after building them for THIS machine. Nothing here knows +// or cares whether they were built from source, taken from the global store, or +// pointed at by a `[tools.overrides]` escape hatch. +// +// The work is DECLARED, not done. Running protoc here would be the easy path +// and the wrong one: it would re-run on every prepare, for every .proto at +// once, serially, and a failure would surface as "build.mcpp exited 1". +// Declared as an action it becomes an edge in the build graph — it re-runs +// exactly when its .proto changes, in parallel with everything else, and a +// failure is attributed to the edge that produced it. +// +// See ../../.agents/docs/2026-08-05-codegen-ecosystem-design.md. +#include +#include +import mcpp; + +int main() { + const std::string root = mcpp::manifest_dir(); + const std::string out = mcpp::out_dir(); + + const char* protoc = mcpp::dep_bin("protobuf", "protoc"); + const char* plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); + if (!protoc || !*protoc) { + std::fprintf(stderr, + "no protoc: declare compat.protobuf = { version = \"35.1\", " + "tools = [\"protoc\"] }\n"); + return 1; + } + if (!plugin || !*plugin) { + std::fprintf(stderr, + "no grpc_cpp_plugin: declare grpc-plugin = { ..., " + "tools = [\"grpc_cpp_plugin\"] }\n"); + return 1; + } + + const std::string proto = root + "/proto/helloworld.proto"; + + // ONE action, four declared outputs. protoc emits the message code and the + // service stubs in a single invocation, so splitting it would run protoc + // twice for no reason. + // + // The .pb.h / .grpc.pb.h are declared too: they must be PRODUCED by this + // edge (main.cpp and the generated .cc include them), but mcpp knows a + // header is not a translation unit and keeps them out of the compile set. + mcpp::action gen; + gen.id = "protoc:helloworld"; + gen.role = "source"; + gen.description = "protoc + grpc_cpp_plugin -> helloworld"; + gen.arg(protoc) + .arg(("-I" + root + "/proto").c_str()) + .arg(("--cpp_out=" + out).c_str()) + .arg(("--grpc_out=" + out).c_str()) + .arg((std::string("--plugin=protoc-gen-grpc=") + plugin).c_str()) + .arg(proto.c_str()) + .input(proto.c_str()) + .output((out + "/helloworld.pb.cc").c_str()) + .output((out + "/helloworld.pb.h").c_str()) + .output((out + "/helloworld.grpc.pb.cc").c_str()) + .output((out + "/helloworld.grpc.pb.h").c_str()) + .submit(); + + // Where the generated headers live. PRIVATE to this package by design — + // an include dir a consumer must see belongs in the manifest, not in a + // build program. + mcpp::include_dir(out.c_str()); +} diff --git a/examples/helloworld/gen/helloworld.grpc.pb.cc b/examples/helloworld/gen/helloworld.grpc.pb.cc deleted file mode 100644 index 9c4c819..0000000 --- a/examples/helloworld/gen/helloworld.grpc.pb.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto - -#include "helloworld.pb.h" -#include "helloworld.grpc.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace helloworld { - -static const char* Greeter_method_names[] = { - "/helloworld.Greeter/SayHello", -}; - -std::unique_ptr< Greeter::Stub> Greeter::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { - (void)options; - std::unique_ptr< Greeter::Stub> stub(new Greeter::Stub(channel, options)); - return stub; -} - -Greeter::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) - : channel_(channel), rpcmethod_SayHello_(Greeter_method_names[0], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - {} - -::grpc::Status Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) { - return ::grpc::internal::BlockingUnaryCall< ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_SayHello_, context, request, response); -} - -void Greeter::Stub::async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function f) { - ::grpc::internal::CallbackUnaryCall< ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, std::move(f)); -} - -void Greeter::Stub::async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) { - ::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, reactor); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::helloworld::HelloReply, ::helloworld::HelloRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_SayHello_, context, request); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - auto* result = - this->PrepareAsyncSayHelloRaw(context, request, cq); - result->StartCall(); - return result; -} - -Greeter::Service::Service() { - AddMethod(new ::grpc::internal::RpcServiceMethod( - Greeter_method_names[0], - ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Greeter::Service, ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( - [](Greeter::Service* service, - ::grpc::ServerContext* ctx, - const ::helloworld::HelloRequest* req, - ::helloworld::HelloReply* resp) { - return service->SayHello(ctx, req, resp); - }, this))); -} - -Greeter::Service::~Service() { -} - -::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { - (void) context; - (void) request; - (void) response; - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); -} - - -} // namespace helloworld -#include - diff --git a/examples/helloworld/gen/helloworld.grpc.pb.h b/examples/helloworld/gen/helloworld.grpc.pb.h deleted file mode 100644 index 551fa9c..0000000 --- a/examples/helloworld/gen/helloworld.grpc.pb.h +++ /dev/null @@ -1,248 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto -// Original file comments: -// The canonical gRPC "hello world" service, matching -// https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld -#ifndef GRPC_helloworld_2eproto__INCLUDED -#define GRPC_helloworld_2eproto__INCLUDED - -#include "helloworld.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace helloworld { - -class Greeter final { - public: - static constexpr char const* service_full_name() { - return "helloworld.Greeter"; - } - class StubInterface { - public: - virtual ~StubInterface() {} - // Sends a greeting. - virtual ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) = 0; - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class async_interface { - public: - virtual ~async_interface() {} - // Sends a greeting. - virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) = 0; - virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) = 0; - }; - typedef class async_interface experimental_async_interface; - virtual class async_interface* async() { return nullptr; } - class async_interface* experimental_async() { return async(); } - private: - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - }; - class Stub final : public StubInterface { - public: - Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); - ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) override; - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class async final : - public StubInterface::async_interface { - public: - void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) override; - void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) override; - private: - friend class Stub; - explicit async(Stub* stub): stub_(stub) { } - Stub* stub() { return stub_; } - Stub* stub_; - }; - class async* async() override { return &async_stub_; } - - private: - std::shared_ptr< ::grpc::ChannelInterface> channel_; - class async async_stub_{this}; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - const ::grpc::internal::RpcMethod rpcmethod_SayHello_; - }; - static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); - - class Service : public ::grpc::Service { - public: - Service(); - virtual ~Service(); - // Sends a greeting. - virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response); - }; - template - class WithAsyncMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithAsyncMethod_SayHello() { - ::grpc::Service::MarkMethodAsync(0); - } - ~WithAsyncMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - typedef WithAsyncMethod_SayHello AsyncService; - template - class WithCallbackMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithCallbackMethod_SayHello() { - ::grpc::Service::MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>( - [this]( - ::grpc::CallbackServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { return this->SayHello(context, request, response); }));} - void SetMessageAllocatorFor_SayHello( - ::grpc::MessageAllocator< ::helloworld::HelloRequest, ::helloworld::HelloReply>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(0); - static_cast<::grpc::internal::CallbackUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>*>(handler) - ->SetMessageAllocator(allocator); - } - ~WithCallbackMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - virtual ::grpc::ServerUnaryReactor* SayHello( - ::grpc::CallbackServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) { return nullptr; } - }; - typedef WithCallbackMethod_SayHello CallbackService; - typedef CallbackService ExperimentalCallbackService; - template - class WithGenericMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithGenericMethod_SayHello() { - ::grpc::Service::MarkMethodGeneric(0); - } - ~WithGenericMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - }; - template - class WithRawMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithRawMethod_SayHello() { - ::grpc::Service::MarkMethodRaw(0); - } - ~WithRawMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - template - class WithRawCallbackMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithRawCallbackMethod_SayHello() { - ::grpc::Service::MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( - [this]( - ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SayHello(context, request, response); })); - } - ~WithRawCallbackMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - virtual ::grpc::ServerUnaryReactor* SayHello( - ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; } - }; - template - class WithStreamedUnaryMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithStreamedUnaryMethod_SayHello() { - ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::internal::StreamedUnaryHandler< - ::helloworld::HelloRequest, ::helloworld::HelloReply>( - [this](::grpc::ServerContext* context, - ::grpc::ServerUnaryStreamer< - ::helloworld::HelloRequest, ::helloworld::HelloReply>* streamer) { - return this->StreamedSayHello(context, - streamer); - })); - } - ~WithStreamedUnaryMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable regular version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - // replace default version of method with streamed unary - virtual ::grpc::Status StreamedSayHello(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::helloworld::HelloRequest,::helloworld::HelloReply>* server_unary_streamer) = 0; - }; - typedef WithStreamedUnaryMethod_SayHello StreamedUnaryService; - typedef Service SplitStreamedService; - typedef WithStreamedUnaryMethod_SayHello StreamedService; -}; - -} // namespace helloworld - - -#include -#endif // GRPC_helloworld_2eproto__INCLUDED diff --git a/examples/helloworld/gen/helloworld.pb.cc b/examples/helloworld/gen/helloworld.pb.cc deleted file mode 100644 index df83265..0000000 --- a/examples/helloworld/gen/helloworld.pb.cc +++ /dev/null @@ -1,827 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: helloworld.proto -// Protobuf C++ Version: 7.35.1 - -#include "helloworld.pb.h" - -#include -#include -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/generated_message_tctable_impl.h" -#include "google/protobuf/internal_visibility.h" -#include "google/protobuf/extension_set.h" -#include "google/protobuf/generated_message_util.h" -#include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/generated_message_reflection.h" -#include "google/protobuf/reflection_ops.h" -#include "google/protobuf/wire_format.h" -// @@protoc_insertion_point(includes) - -// Must be included last. -#include "google/protobuf/port_def.inc" -PROTOBUF_PRAGMA_INIT_SEG -namespace _pb = ::google::protobuf; -namespace _pbi = ::google::protobuf::internal; -namespace _fl = ::google::protobuf::internal::field_layout; -#ifdef PROTOBUF_MESSAGE_GLOBALS -namespace { -PROTOBUF_CONSTINIT ::google::protobuf::internal::ReflectionData - file_reflection_data[] = { - // ::helloworld::HelloRequest - {&::_pbi::kDescriptorMethods, &::descriptor_table_helloworld_2eproto, /* tracker*/ nullptr,}, - // ::helloworld::HelloReply - {&::_pbi::kDescriptorMethods, &::descriptor_table_helloworld_2eproto, /* tracker*/ nullptr,}, -}; -} // namespace -#endif -namespace helloworld { -class HelloRequest::_Internal { - public: - using HasBits = decltype(::std::declval()._impl_._has_bits_); - static constexpr ::int32_t kHasBitsOffset = - 8 * PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._has_bits_); -}; - -constexpr HelloRequest::ParseTableT_ HelloRequest::InternalGenerateParseTable_(const ::_pbi::ClassData* class_data) { - return ParseTableT_{ - { - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._has_bits_), - 0, // no _extensions_ - 1, 0, // max_field_number, fast_idx_mask - offsetof(ParseTableT_, field_lookup_table), - 4294967294, // skipmap - offsetof(ParseTableT_, field_entries), - 1, // num_field_entries - 0, // num_aux_entries - offsetof(ParseTableT_, field_names), // no aux_entries - class_data, - nullptr, // post_loop_handler - ::_pbi::TcParser::GenericFallback, // fallback - #ifdef PROTOBUF_PREFETCH_PARSE_TABLE - ::_pbi::TcParser::GetTable<::helloworld::HelloRequest>(), // to_prefetch - #endif // PROTOBUF_PREFETCH_PARSE_TABLE - }, {{ - // string name = 1; - {::_pbi::TcParser::FastUS1, - {10, 0, 0, - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_.name_)}}, - }}, {{ - 65535, 65535 - }}, {{ - // string name = 1; - {PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_.name_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kUtf8String | ::_fl::kRepAString)}, - }}, - // no aux_entries - {{ - "\27\4\0\0\0\0\0\0" - "helloworld.HelloRequest" - "name" - }}, - }; -} - - -inline constexpr HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - ::_pbi::ConstantInitialized) noexcept - : _cached_size_{0}, - name_( - &::google::protobuf::internal::fixed_address_empty_string, - ::_pbi::ConstantInitialized()) {} - -template -constexpr HelloRequest::HelloRequest(::_pbi::ConstantInitialized, - const ::_pbi::ClassData* PROTOBUF_NONNULL class_data) - : ::google::protobuf::Message( -#if defined(PROTOBUF_CUSTOM_VTABLE) - class_data -#endif // PROTOBUF_CUSTOM_VTABLE - ), - _impl_(internal_visibility(), ::_pbi::ConstantInitialized()) { -} -inline void* PROTOBUF_NONNULL HelloRequest::PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) { - return ::new (mem) HelloRequest(arena); -} -constexpr auto HelloRequest::InternalNewImpl_() { - return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(HelloRequest), alignof(HelloRequest)); -} -constexpr auto HelloRequest::InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* tc_table) { - return ::google::protobuf::internal::ClassDataFull{ - ::google::protobuf::internal::ClassData{ - &prototype, -#ifndef PROTOBUF_MESSAGE_GLOBALS - &_table_.header, -#else - tc_table, -#endif - nullptr, // IsInitialized - &HelloRequest::MergeImpl, - ::google::protobuf::Message::GetNewImpl(), -#if defined(PROTOBUF_CUSTOM_VTABLE) - &HelloRequest::SharedDtor, - ::google::protobuf::Message::GetClearImpl(), &HelloRequest::ByteSizeLong, - &HelloRequest::_InternalSerialize, -#endif // PROTOBUF_CUSTOM_VTABLE - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._cached_size_), - false, - }, -#ifdef PROTOBUF_MESSAGE_GLOBALS - &file_reflection_data[0], -#else // !PROTOBUF_MESSAGE_GLOBALS - &::_pbi::kDescriptorMethods, - &descriptor_table_helloworld_2eproto, - nullptr, // tracker -#endif // PROTOBUF_MESSAGE_GLOBALS - }; -} -struct HelloRequestGlobalsTypeInternal : ::_pbi::MessageGlobalsBase { - constexpr HelloRequestGlobalsTypeInternal() - : -#ifndef PROTOBUF_MESSAGE_GLOBALS - _default(::_pbi::ConstantInitialized{}, - HelloRequest_class_data_.base()) -#else // !PROTOBUF_MESSAGE_GLOBALS - MessageGlobalsBase(HelloRequest::InternalGenerateClassData_( - _default, &HelloRequest_globals_._table.header)), - _default(::_pbi::ConstantInitialized{}, GetClassData()), - _table(::_pbi::PrivateAccess::GenerateParseTable( - GetClassData())) -#endif // PROTOBUF_MESSAGE_GLOBALS - { - } - ~HelloRequestGlobalsTypeInternal() {} - union { - alignas(::_pbi::kMaxMessageAlignment) HelloRequest _default; - }; -#ifdef PROTOBUF_MESSAGE_GLOBALS - decltype(::_pbi::PrivateAccess::GenerateParseTable( - ::std::declval())) _table; -#endif -}; -#ifdef PROTOBUF_MESSAGE_GLOBALS -static_assert(PROTOBUF_FIELD_OFFSET(HelloRequestGlobalsTypeInternal, _default) == - ::_pbi::MessageGlobalsBase::OffsetToDefault()); -#endif // PROTOBUF_MESSAGE_GLOBALS - -PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT - PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PROTOBUF_MESSAGE_GLOBALS_CONST HelloRequestGlobalsTypeInternal HelloRequest_globals_ - PROTOBUF_MESSAGE_GLOBALS_SECTION(.data.rel.ro); -#if defined(PROTOBUF_CUSTOM_VTABLE) -namespace { -const ::_pbi::ClassData* HelloRequest_get_class_data() { -#ifdef PROTOBUF_MESSAGE_GLOBALS - return HelloRequest_globals_.GetClassData(); -#else - return HelloRequest_class_data_.base(); -#endif // PROTOBUF_MESSAGE_GLOBALS -} -} // namespace -#endif // PROTOBUF_CUSTOM_VTABLE -class HelloReply::_Internal { - public: - using HasBits = decltype(::std::declval()._impl_._has_bits_); - static constexpr ::int32_t kHasBitsOffset = - 8 * PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._has_bits_); -}; - -constexpr HelloReply::ParseTableT_ HelloReply::InternalGenerateParseTable_(const ::_pbi::ClassData* class_data) { - return ParseTableT_{ - { - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._has_bits_), - 0, // no _extensions_ - 1, 0, // max_field_number, fast_idx_mask - offsetof(ParseTableT_, field_lookup_table), - 4294967294, // skipmap - offsetof(ParseTableT_, field_entries), - 1, // num_field_entries - 0, // num_aux_entries - offsetof(ParseTableT_, field_names), // no aux_entries - class_data, - nullptr, // post_loop_handler - ::_pbi::TcParser::GenericFallback, // fallback - #ifdef PROTOBUF_PREFETCH_PARSE_TABLE - ::_pbi::TcParser::GetTable<::helloworld::HelloReply>(), // to_prefetch - #endif // PROTOBUF_PREFETCH_PARSE_TABLE - }, {{ - // string message = 1; - {::_pbi::TcParser::FastUS1, - {10, 0, 0, - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_.message_)}}, - }}, {{ - 65535, 65535 - }}, {{ - // string message = 1; - {PROTOBUF_FIELD_OFFSET(HelloReply, _impl_.message_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kUtf8String | ::_fl::kRepAString)}, - }}, - // no aux_entries - {{ - "\25\7\0\0\0\0\0\0" - "helloworld.HelloReply" - "message" - }}, - }; -} - - -inline constexpr HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - ::_pbi::ConstantInitialized) noexcept - : _cached_size_{0}, - message_( - &::google::protobuf::internal::fixed_address_empty_string, - ::_pbi::ConstantInitialized()) {} - -template -constexpr HelloReply::HelloReply(::_pbi::ConstantInitialized, - const ::_pbi::ClassData* PROTOBUF_NONNULL class_data) - : ::google::protobuf::Message( -#if defined(PROTOBUF_CUSTOM_VTABLE) - class_data -#endif // PROTOBUF_CUSTOM_VTABLE - ), - _impl_(internal_visibility(), ::_pbi::ConstantInitialized()) { -} -inline void* PROTOBUF_NONNULL HelloReply::PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) { - return ::new (mem) HelloReply(arena); -} -constexpr auto HelloReply::InternalNewImpl_() { - return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(HelloReply), alignof(HelloReply)); -} -constexpr auto HelloReply::InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* tc_table) { - return ::google::protobuf::internal::ClassDataFull{ - ::google::protobuf::internal::ClassData{ - &prototype, -#ifndef PROTOBUF_MESSAGE_GLOBALS - &_table_.header, -#else - tc_table, -#endif - nullptr, // IsInitialized - &HelloReply::MergeImpl, - ::google::protobuf::Message::GetNewImpl(), -#if defined(PROTOBUF_CUSTOM_VTABLE) - &HelloReply::SharedDtor, - ::google::protobuf::Message::GetClearImpl(), &HelloReply::ByteSizeLong, - &HelloReply::_InternalSerialize, -#endif // PROTOBUF_CUSTOM_VTABLE - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._cached_size_), - false, - }, -#ifdef PROTOBUF_MESSAGE_GLOBALS - &file_reflection_data[1], -#else // !PROTOBUF_MESSAGE_GLOBALS - &::_pbi::kDescriptorMethods, - &descriptor_table_helloworld_2eproto, - nullptr, // tracker -#endif // PROTOBUF_MESSAGE_GLOBALS - }; -} -struct HelloReplyGlobalsTypeInternal : ::_pbi::MessageGlobalsBase { - constexpr HelloReplyGlobalsTypeInternal() - : -#ifndef PROTOBUF_MESSAGE_GLOBALS - _default(::_pbi::ConstantInitialized{}, - HelloReply_class_data_.base()) -#else // !PROTOBUF_MESSAGE_GLOBALS - MessageGlobalsBase(HelloReply::InternalGenerateClassData_( - _default, &HelloReply_globals_._table.header)), - _default(::_pbi::ConstantInitialized{}, GetClassData()), - _table(::_pbi::PrivateAccess::GenerateParseTable( - GetClassData())) -#endif // PROTOBUF_MESSAGE_GLOBALS - { - } - ~HelloReplyGlobalsTypeInternal() {} - union { - alignas(::_pbi::kMaxMessageAlignment) HelloReply _default; - }; -#ifdef PROTOBUF_MESSAGE_GLOBALS - decltype(::_pbi::PrivateAccess::GenerateParseTable( - ::std::declval())) _table; -#endif -}; -#ifdef PROTOBUF_MESSAGE_GLOBALS -static_assert(PROTOBUF_FIELD_OFFSET(HelloReplyGlobalsTypeInternal, _default) == - ::_pbi::MessageGlobalsBase::OffsetToDefault()); -#endif // PROTOBUF_MESSAGE_GLOBALS - -PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT - PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PROTOBUF_MESSAGE_GLOBALS_CONST HelloReplyGlobalsTypeInternal HelloReply_globals_ - PROTOBUF_MESSAGE_GLOBALS_SECTION(.data.rel.ro); -#if defined(PROTOBUF_CUSTOM_VTABLE) -namespace { -const ::_pbi::ClassData* HelloReply_get_class_data() { -#ifdef PROTOBUF_MESSAGE_GLOBALS - return HelloReply_globals_.GetClassData(); -#else - return HelloReply_class_data_.base(); -#endif // PROTOBUF_MESSAGE_GLOBALS -} -} // namespace -#endif // PROTOBUF_CUSTOM_VTABLE -} // namespace helloworld -static constexpr const ::_pb::EnumDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE - file_level_enum_descriptors_helloworld_2eproto = nullptr; -static constexpr const ::_pb::ServiceDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE - file_level_service_descriptors_helloworld_2eproto = nullptr; -const ::uint32_t - TableStruct_helloworld_2eproto::offsets[] ABSL_ATTRIBUTE_SECTION_VARIABLE( - protodesc_cold) = { - 0x081, // bitmap - PROTOBUF_FIELD_OFFSET(::helloworld::HelloRequest, _impl_._has_bits_), - 4, // hasbit index offset - PROTOBUF_FIELD_OFFSET(::helloworld::HelloRequest, _impl_.name_), - 0, - 0x081, // bitmap - PROTOBUF_FIELD_OFFSET(::helloworld::HelloReply, _impl_._has_bits_), - 4, // hasbit index offset - PROTOBUF_FIELD_OFFSET(::helloworld::HelloReply, _impl_.message_), - 0, -}; - -static const ::_pbi::MigrationSchema - schemas[] ABSL_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - {0, sizeof(::helloworld::HelloRequest)}, - {5, sizeof(::helloworld::HelloReply)}, -}; -static const ::_pbi::MessageGlobalsBase* PROTOBUF_NONNULL const - file_message_globals[] = { - &::helloworld::HelloRequest_globals_, - &::helloworld::HelloReply_globals_, -}; -const char descriptor_table_protodef_helloworld_2eproto[] ABSL_ATTRIBUTE_SECTION_VARIABLE( - protodesc_cold) = { - "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" - "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" - "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" - "loworld.HelloRequest\032\026.helloworld.HelloR" - "eply\"\000b\006proto3" -}; -static ::absl::once_flag descriptor_table_helloworld_2eproto_once; -PROTOBUF_CONSTINIT const ::_pbi::DescriptorTable descriptor_table_helloworld_2eproto = { - false, - false, - 174, - descriptor_table_protodef_helloworld_2eproto, - "helloworld.proto", - &descriptor_table_helloworld_2eproto_once, - nullptr, - 0, - 2, - schemas, - file_message_globals, - TableStruct_helloworld_2eproto::offsets, - file_level_enum_descriptors_helloworld_2eproto, - file_level_service_descriptors_helloworld_2eproto, -}; -namespace helloworld { -// =================================================================== - -HelloRequest::HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloRequest_get_class_data()) { -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:helloworld.HelloRequest) -} -PROTOBUF_NDEBUG_INLINE HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - [[maybe_unused]] const ::helloworld::HelloRequest& from_msg) - : _has_bits_{from._has_bits_}, - _cached_size_{0}, - name_(arena, from.name_) {} - -HelloRequest::HelloRequest( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, - const HelloRequest& from) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloRequest_get_class_data()) { - -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - HelloRequest* const _this = this; - (void)_this; - _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); - new (&_impl_) Impl_(internal_visibility(), arena, from._impl_, from); - - // @@protoc_insertion_point(copy_constructor:helloworld.HelloRequest) -} -PROTOBUF_NDEBUG_INLINE HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) - : _cached_size_{0}, - name_(arena) {} - -inline void HelloRequest::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) { - new (&_impl_) Impl_(internal_visibility(), arena); -} -HelloRequest::~HelloRequest() { - // @@protoc_insertion_point(destructor:helloworld.HelloRequest) - SharedDtor(*this); -} -inline void HelloRequest::SharedDtor(MessageLite& self) { - HelloRequest& this_ = static_cast(self); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - this_._internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); - ABSL_DCHECK(this_.GetArena() == nullptr); - this_._impl_.name_.Destroy(); - this_._impl_.~Impl_(); -} - -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const - ::google::protobuf::internal::ClassDataFull HelloRequest_class_data_ = - HelloRequest::InternalGenerateClassData_(HelloRequest_globals_._default); - -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloRequest::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloRequest_class_data_); - ::google::protobuf::internal::PrefetchToLocalCache(HelloRequest_class_data_.tc_table); - return HelloRequest_class_data_.base(); -} -#else -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloRequest::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloRequest_globals_); - ::google::protobuf::internal::PrefetchToLocalCache( - ::google::protobuf::internal::MessageGlobalsBase::ToParseTableBase(&HelloRequest_globals_)); - return HelloRequest_globals_.GetClassData(); -} -#endif // !PROTOBUF_MESSAGE_GLOBALS -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT -PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const HelloRequest::ParseTableT_ - HelloRequest::_table_ = - HelloRequest::InternalGenerateParseTable_(HelloRequest_class_data_.base()); -#endif // !PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_NOINLINE void HelloRequest::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloRequest) - ::google::protobuf::internal::TSanWrite(&_impl_); - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - cached_has_bits = _impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - _impl_.name_.ClearNonDefaultToEmpty(); - } - _impl_._has_bits_.Clear(); - _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::uint8_t* PROTOBUF_NONNULL HelloRequest::_InternalSerialize( - const ::google::protobuf::MessageLite& base, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) { - const HelloRequest& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::uint8_t* PROTOBUF_NONNULL HelloRequest::_InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - const HelloRequest& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloRequest) - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = this_._impl_._has_bits_[0]; - // string name = 1; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_name().empty()) { - const ::std::string& _s = this_._internal_name(); - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "helloworld.HelloRequest.name"); - target = stream->WriteStringMaybeAliased(1, _s, target); - } - } - - if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) { - target = - ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( - this_._internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloRequest) - return target; -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::size_t HelloRequest::ByteSizeLong(const MessageLite& base) { - const HelloRequest& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::size_t HelloRequest::ByteSizeLong() const { - const HelloRequest& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - // @@protoc_insertion_point(message_byte_size_start:helloworld.HelloRequest) - ::size_t total_size = 0; - - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void)cached_has_bits; - - { - // string name = 1; - cached_has_bits = this_._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_name().empty()) { - total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( - this_._internal_name()); - } - } - } - return this_.MaybeComputeUnknownFieldsSize(total_size, - &this_._impl_._cached_size_); -} - -void HelloRequest::MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg) { - auto* const _this = static_cast(&to_msg); - auto& from = static_cast(from_msg); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - from.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloRequest) - ABSL_DCHECK_NE(&from, _this); - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = from._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!from._internal_name().empty()) { - _this->_internal_set_name(from._internal_name()); - } else { - if (_this->_impl_.name_.IsDefault()) { - _this->_internal_set_name(""); - } - } - } - _this->_impl_._has_bits_[0] |= cached_has_bits; - _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); -} - -void HelloRequest::CopyFrom(const HelloRequest& from) { - // @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloRequest) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - - -void HelloRequest::InternalSwap(HelloRequest* PROTOBUF_RESTRICT PROTOBUF_NONNULL other) { - using ::std::swap; - auto* arena = GetArena(); - ABSL_DCHECK_EQ(arena, other->GetArena()); - _internal_metadata_.InternalSwap(&other->_internal_metadata_); - swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); - ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, &other->_impl_.name_, arena); -} - -::google::protobuf::Metadata HelloRequest::GetMetadata() const { - return ::google::protobuf::Message::GetMetadataImpl(GetClassData()->full()); -} -// =================================================================== - -HelloReply::HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloReply_get_class_data()) { -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:helloworld.HelloReply) -} -PROTOBUF_NDEBUG_INLINE HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - [[maybe_unused]] const ::helloworld::HelloReply& from_msg) - : _has_bits_{from._has_bits_}, - _cached_size_{0}, - message_(arena, from.message_) {} - -HelloReply::HelloReply( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, - const HelloReply& from) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloReply_get_class_data()) { - -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - HelloReply* const _this = this; - (void)_this; - _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); - new (&_impl_) Impl_(internal_visibility(), arena, from._impl_, from); - - // @@protoc_insertion_point(copy_constructor:helloworld.HelloReply) -} -PROTOBUF_NDEBUG_INLINE HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) - : _cached_size_{0}, - message_(arena) {} - -inline void HelloReply::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) { - new (&_impl_) Impl_(internal_visibility(), arena); -} -HelloReply::~HelloReply() { - // @@protoc_insertion_point(destructor:helloworld.HelloReply) - SharedDtor(*this); -} -inline void HelloReply::SharedDtor(MessageLite& self) { - HelloReply& this_ = static_cast(self); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - this_._internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); - ABSL_DCHECK(this_.GetArena() == nullptr); - this_._impl_.message_.Destroy(); - this_._impl_.~Impl_(); -} - -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const - ::google::protobuf::internal::ClassDataFull HelloReply_class_data_ = - HelloReply::InternalGenerateClassData_(HelloReply_globals_._default); - -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloReply::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloReply_class_data_); - ::google::protobuf::internal::PrefetchToLocalCache(HelloReply_class_data_.tc_table); - return HelloReply_class_data_.base(); -} -#else -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloReply::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloReply_globals_); - ::google::protobuf::internal::PrefetchToLocalCache( - ::google::protobuf::internal::MessageGlobalsBase::ToParseTableBase(&HelloReply_globals_)); - return HelloReply_globals_.GetClassData(); -} -#endif // !PROTOBUF_MESSAGE_GLOBALS -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT -PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const HelloReply::ParseTableT_ - HelloReply::_table_ = - HelloReply::InternalGenerateParseTable_(HelloReply_class_data_.base()); -#endif // !PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_NOINLINE void HelloReply::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloReply) - ::google::protobuf::internal::TSanWrite(&_impl_); - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - cached_has_bits = _impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - _impl_.message_.ClearNonDefaultToEmpty(); - } - _impl_._has_bits_.Clear(); - _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::uint8_t* PROTOBUF_NONNULL HelloReply::_InternalSerialize( - const ::google::protobuf::MessageLite& base, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) { - const HelloReply& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::uint8_t* PROTOBUF_NONNULL HelloReply::_InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - const HelloReply& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloReply) - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = this_._impl_._has_bits_[0]; - // string message = 1; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_message().empty()) { - const ::std::string& _s = this_._internal_message(); - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "helloworld.HelloReply.message"); - target = stream->WriteStringMaybeAliased(1, _s, target); - } - } - - if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) { - target = - ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( - this_._internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloReply) - return target; -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::size_t HelloReply::ByteSizeLong(const MessageLite& base) { - const HelloReply& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::size_t HelloReply::ByteSizeLong() const { - const HelloReply& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - // @@protoc_insertion_point(message_byte_size_start:helloworld.HelloReply) - ::size_t total_size = 0; - - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void)cached_has_bits; - - { - // string message = 1; - cached_has_bits = this_._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_message().empty()) { - total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( - this_._internal_message()); - } - } - } - return this_.MaybeComputeUnknownFieldsSize(total_size, - &this_._impl_._cached_size_); -} - -void HelloReply::MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg) { - auto* const _this = static_cast(&to_msg); - auto& from = static_cast(from_msg); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - from.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloReply) - ABSL_DCHECK_NE(&from, _this); - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = from._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!from._internal_message().empty()) { - _this->_internal_set_message(from._internal_message()); - } else { - if (_this->_impl_.message_.IsDefault()) { - _this->_internal_set_message(""); - } - } - } - _this->_impl_._has_bits_[0] |= cached_has_bits; - _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); -} - -void HelloReply::CopyFrom(const HelloReply& from) { - // @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloReply) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - - -void HelloReply::InternalSwap(HelloReply* PROTOBUF_RESTRICT PROTOBUF_NONNULL other) { - using ::std::swap; - auto* arena = GetArena(); - ABSL_DCHECK_EQ(arena, other->GetArena()); - _internal_metadata_.InternalSwap(&other->_internal_metadata_); - swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); - ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.message_, &other->_impl_.message_, arena); -} - -::google::protobuf::Metadata HelloReply::GetMetadata() const { - return ::google::protobuf::Message::GetMetadataImpl(GetClassData()->full()); -} -// @@protoc_insertion_point(namespace_scope) -} // namespace helloworld -namespace google { -namespace protobuf { -} // namespace protobuf -} // namespace google -// @@protoc_insertion_point(global_scope) -PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::std::false_type - _static_init2_ [[maybe_unused]] = - (::_pbi::AddDescriptors(&descriptor_table_helloworld_2eproto), - ::std::false_type{}); -#include "google/protobuf/port_undef.inc" diff --git a/examples/helloworld/gen/helloworld.pb.h b/examples/helloworld/gen/helloworld.pb.h deleted file mode 100644 index 19c8c15..0000000 --- a/examples/helloworld/gen/helloworld.pb.h +++ /dev/null @@ -1,658 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: helloworld.proto -// Protobuf C++ Version: 7.35.1 - -#ifndef helloworld_2eproto_2epb_2eh -#define helloworld_2eproto_2epb_2eh - -#include -#include -#include -#include - -// clang-format off -#include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 7035001 -#error "Protobuf C++ gencode is built with an incompatible version of" -#error "Protobuf C++ headers/runtime. See" -#error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" -#endif -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/arena.h" -#include "google/protobuf/arenastring.h" -#include "google/protobuf/generated_message_tctable_decl.h" -#include "google/protobuf/generated_message_util.h" -#include "google/protobuf/metadata_lite.h" -#include "google/protobuf/generated_message_reflection.h" -#include "google/protobuf/message.h" -#include "google/protobuf/message_lite.h" -#include "google/protobuf/repeated_field.h" // IWYU pragma: export -#include "google/protobuf/extension_set.h" // IWYU pragma: export -#include "google/protobuf/unknown_field_set.h" -// @@protoc_insertion_point(includes) - -// Must be included last. -#include "google/protobuf/port_def.inc" - -#define PROTOBUF_INTERNAL_EXPORT_helloworld_2eproto - -namespace google { -namespace protobuf { -namespace internal { -template -::absl::string_view GetAnyMessageName(); -} // namespace internal -} // namespace protobuf -} // namespace google - -// Internal implementation detail -- do not use these members. -struct TableStruct_helloworld_2eproto { - static const ::uint32_t offsets[]; -}; -extern "C" { -extern const ::google::protobuf::internal::DescriptorTable descriptor_table_helloworld_2eproto; -} // extern "C" -namespace helloworld { -class HelloReply; -struct HelloReplyGlobalsTypeInternal; -#ifndef PROTOBUF_MESSAGE_GLOBALS -extern HelloReplyGlobalsTypeInternal HelloReply_globals_; -extern const ::google::protobuf::internal::ClassDataFull HelloReply_class_data_; -#else -extern const HelloReplyGlobalsTypeInternal HelloReply_globals_; -#endif // PROTOBUF_MESSAGE_GLOBALS -class HelloRequest; -struct HelloRequestGlobalsTypeInternal; -#ifndef PROTOBUF_MESSAGE_GLOBALS -extern HelloRequestGlobalsTypeInternal HelloRequest_globals_; -extern const ::google::protobuf::internal::ClassDataFull HelloRequest_class_data_; -#else -extern const HelloRequestGlobalsTypeInternal HelloRequest_globals_; -#endif // PROTOBUF_MESSAGE_GLOBALS -} // namespace helloworld -namespace google { -namespace protobuf { -} // namespace protobuf -} // namespace google - -namespace helloworld { - -// =================================================================== - - -// ------------------------------------------------------------------- - -class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED HelloRequest final : public ::google::protobuf::Message -/* @@protoc_insertion_point(class_definition:helloworld.HelloRequest) */ { - public: - inline HelloRequest() : HelloRequest(nullptr) {} - ~HelloRequest() PROTOBUF_FINAL; - -#if defined(PROTOBUF_CUSTOM_VTABLE) - void operator delete(HelloRequest* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) { - SharedDtor(*msg); - ::google::protobuf::internal::SizedDelete(msg, sizeof(HelloRequest)); - } -#endif - - template - explicit constexpr HelloRequest(::google::protobuf::internal::ConstantInitialized, - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL - class_data); - - inline HelloRequest(const HelloRequest& from) : HelloRequest(nullptr, from) {} - inline HelloRequest(HelloRequest&& from) noexcept : HelloRequest(nullptr, ::std::move(from)) {} - inline HelloRequest& operator=(const HelloRequest& from) { - CopyFrom(from); - return *this; - } - inline HelloRequest& operator=(HelloRequest&& from) noexcept { - if (this == &from) return *this; - if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) { - InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - - [[nodiscard]] inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); - } - [[nodiscard]] inline ::google::protobuf::UnknownFieldSet* PROTOBUF_NONNULL - mutable_unknown_fields() ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); - } - - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL descriptor() { - return GetDescriptor(); - } - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL - GetDescriptor() { - return default_instance().GetMetadata().descriptor; - } - [[nodiscard]] static const ::google::protobuf::Reflection* PROTOBUF_NONNULL GetReflection() { - return default_instance().GetMetadata().reflection; - } - [[nodiscard]] static const HelloRequest& default_instance() { - return *::google::protobuf::internal::MessageGlobalsBase::ToDefaultInstance(&HelloRequest_globals_); - } - static constexpr int kIndexInFileMessages = 0; - friend void swap(HelloRequest& a, HelloRequest& b) { a.Swap(&b); } - inline void Swap(HelloRequest* PROTOBUF_NONNULL other) { - if (other == this) return; - if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) { - InternalSwap(other); - } else { - ::google::protobuf::internal::GenericSwap(this, other); - } - } - void UnsafeArenaSwap(HelloRequest* PROTOBUF_NONNULL other) { - if (other == this) return; - ABSL_DCHECK(GetArena() == other->GetArena()); - InternalSwap(other); - } - - // implements Message ---------------------------------------------- - - [[nodiscard]] HelloRequest* PROTOBUF_NONNULL - New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const { - return ::google::protobuf::Message::DefaultConstruct(arena); - } - using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const HelloRequest& from); - using ::google::protobuf::Message::MergeFrom; - void MergeFrom(const HelloRequest& from) { HelloRequest::MergeImpl(*this, from); } - - private: - static void MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg); - - public: - [[nodiscard]] bool IsInitialized() const { - return true; - } - ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL; - #if defined(PROTOBUF_CUSTOM_VTABLE) - private: - [[nodiscard]] static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg); - [[nodiscard]] static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream); - - public: - [[nodiscard]] ::size_t ByteSizeLong() const { return ByteSizeLong(*this); } - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - return _InternalSerialize(*this, target, stream); - } - #else // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] ::size_t ByteSizeLong() const final; - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final; - #endif // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] int GetCachedSize() const { - return _impl_._cached_size_.Get(); - } - - private: - void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static void SharedDtor(MessageLite& self); - void InternalSwap(HelloRequest* PROTOBUF_NONNULL other); - private: - template - friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)(); - static ::absl::string_view FullMessageName() { return "helloworld.HelloRequest"; } - - explicit HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const HelloRequest& from); - HelloRequest( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, HelloRequest&& from) noexcept - : HelloRequest(arena) { - *this = ::std::move(from); - } - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL; - static void* PROTOBUF_NONNULL PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static constexpr auto InternalNewImpl_(); - - public: - static constexpr auto InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* PROTOBUF_NULLABLE tc_table = nullptr); - - [[nodiscard]] ::google::protobuf::Metadata GetMetadata() const; - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - enum : int { - kNameFieldNumber = 1, - }; - // string name = 1; - void clear_name() ; - [[nodiscard]] const ::std::string& name() const; - template - void set_name(Arg_&& arg, Args_... args); - ::std::string* PROTOBUF_NONNULL mutable_name(); - [[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_name(); - void set_allocated_name(::std::string* PROTOBUF_NULLABLE value); - - private: - const ::std::string& _internal_name() const; - PROTOBUF_ALWAYS_INLINE void _internal_set_name(const ::std::string& value); - ::std::string* PROTOBUF_NONNULL _internal_mutable_name(); - - public: - // @@protoc_insertion_point(class_scope:helloworld.HelloRequest) - private: - class _Internal; - using ParseTableT_ = - ::google::protobuf::internal::TcParseTable<0, 1, - 0, 36, - 2>; - static constexpr ParseTableT_ InternalGenerateParseTable_( - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL class_data); - friend class ::google::protobuf::internal::TcParser; - #ifndef PROTOBUF_MESSAGE_GLOBALS - static const ParseTableT_ _table_; - #endif - - friend class ::google::protobuf::MessageLite; - friend class ::google::protobuf::Arena; - friend ::google::protobuf::internal::PrivateAccess; - template - friend class ::google::protobuf::Arena::InternalHelper; - using InternalArenaConstructable_ = void; - using DestructorSkippable_ = void; - struct Impl_ { - inline explicit constexpr Impl_(::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::internal::ConstantInitialized) noexcept; - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - const HelloRequest& from_msg); - ::google::protobuf::internal::HasBits<1> _has_bits_; - ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr name_; - PROTOBUF_TSAN_DECLARE_MEMBER - }; - union { Impl_ _impl_; }; - friend struct ::TableStruct_helloworld_2eproto; -}; -// ------------------------------------------------------------------- - -class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED HelloReply final : public ::google::protobuf::Message -/* @@protoc_insertion_point(class_definition:helloworld.HelloReply) */ { - public: - inline HelloReply() : HelloReply(nullptr) {} - ~HelloReply() PROTOBUF_FINAL; - -#if defined(PROTOBUF_CUSTOM_VTABLE) - void operator delete(HelloReply* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) { - SharedDtor(*msg); - ::google::protobuf::internal::SizedDelete(msg, sizeof(HelloReply)); - } -#endif - - template - explicit constexpr HelloReply(::google::protobuf::internal::ConstantInitialized, - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL - class_data); - - inline HelloReply(const HelloReply& from) : HelloReply(nullptr, from) {} - inline HelloReply(HelloReply&& from) noexcept : HelloReply(nullptr, ::std::move(from)) {} - inline HelloReply& operator=(const HelloReply& from) { - CopyFrom(from); - return *this; - } - inline HelloReply& operator=(HelloReply&& from) noexcept { - if (this == &from) return *this; - if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) { - InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - - [[nodiscard]] inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); - } - [[nodiscard]] inline ::google::protobuf::UnknownFieldSet* PROTOBUF_NONNULL - mutable_unknown_fields() ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); - } - - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL descriptor() { - return GetDescriptor(); - } - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL - GetDescriptor() { - return default_instance().GetMetadata().descriptor; - } - [[nodiscard]] static const ::google::protobuf::Reflection* PROTOBUF_NONNULL GetReflection() { - return default_instance().GetMetadata().reflection; - } - [[nodiscard]] static const HelloReply& default_instance() { - return *::google::protobuf::internal::MessageGlobalsBase::ToDefaultInstance(&HelloReply_globals_); - } - static constexpr int kIndexInFileMessages = 1; - friend void swap(HelloReply& a, HelloReply& b) { a.Swap(&b); } - inline void Swap(HelloReply* PROTOBUF_NONNULL other) { - if (other == this) return; - if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) { - InternalSwap(other); - } else { - ::google::protobuf::internal::GenericSwap(this, other); - } - } - void UnsafeArenaSwap(HelloReply* PROTOBUF_NONNULL other) { - if (other == this) return; - ABSL_DCHECK(GetArena() == other->GetArena()); - InternalSwap(other); - } - - // implements Message ---------------------------------------------- - - [[nodiscard]] HelloReply* PROTOBUF_NONNULL - New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const { - return ::google::protobuf::Message::DefaultConstruct(arena); - } - using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const HelloReply& from); - using ::google::protobuf::Message::MergeFrom; - void MergeFrom(const HelloReply& from) { HelloReply::MergeImpl(*this, from); } - - private: - static void MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg); - - public: - [[nodiscard]] bool IsInitialized() const { - return true; - } - ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL; - #if defined(PROTOBUF_CUSTOM_VTABLE) - private: - [[nodiscard]] static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg); - [[nodiscard]] static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream); - - public: - [[nodiscard]] ::size_t ByteSizeLong() const { return ByteSizeLong(*this); } - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - return _InternalSerialize(*this, target, stream); - } - #else // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] ::size_t ByteSizeLong() const final; - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final; - #endif // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] int GetCachedSize() const { - return _impl_._cached_size_.Get(); - } - - private: - void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static void SharedDtor(MessageLite& self); - void InternalSwap(HelloReply* PROTOBUF_NONNULL other); - private: - template - friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)(); - static ::absl::string_view FullMessageName() { return "helloworld.HelloReply"; } - - explicit HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const HelloReply& from); - HelloReply( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, HelloReply&& from) noexcept - : HelloReply(arena) { - *this = ::std::move(from); - } - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL; - static void* PROTOBUF_NONNULL PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static constexpr auto InternalNewImpl_(); - - public: - static constexpr auto InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* PROTOBUF_NULLABLE tc_table = nullptr); - - [[nodiscard]] ::google::protobuf::Metadata GetMetadata() const; - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - enum : int { - kMessageFieldNumber = 1, - }; - // string message = 1; - void clear_message() ; - [[nodiscard]] const ::std::string& message() const; - template - void set_message(Arg_&& arg, Args_... args); - ::std::string* PROTOBUF_NONNULL mutable_message(); - [[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_message(); - void set_allocated_message(::std::string* PROTOBUF_NULLABLE value); - - private: - const ::std::string& _internal_message() const; - PROTOBUF_ALWAYS_INLINE void _internal_set_message(const ::std::string& value); - ::std::string* PROTOBUF_NONNULL _internal_mutable_message(); - - public: - // @@protoc_insertion_point(class_scope:helloworld.HelloReply) - private: - class _Internal; - using ParseTableT_ = - ::google::protobuf::internal::TcParseTable<0, 1, - 0, 37, - 2>; - static constexpr ParseTableT_ InternalGenerateParseTable_( - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL class_data); - friend class ::google::protobuf::internal::TcParser; - #ifndef PROTOBUF_MESSAGE_GLOBALS - static const ParseTableT_ _table_; - #endif - - friend class ::google::protobuf::MessageLite; - friend class ::google::protobuf::Arena; - friend ::google::protobuf::internal::PrivateAccess; - template - friend class ::google::protobuf::Arena::InternalHelper; - using InternalArenaConstructable_ = void; - using DestructorSkippable_ = void; - struct Impl_ { - inline explicit constexpr Impl_(::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::internal::ConstantInitialized) noexcept; - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - const HelloReply& from_msg); - ::google::protobuf::internal::HasBits<1> _has_bits_; - ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr message_; - PROTOBUF_TSAN_DECLARE_MEMBER - }; - union { Impl_ _impl_; }; - friend struct ::TableStruct_helloworld_2eproto; -}; - -// =================================================================== - - - - -// =================================================================== - - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif // __GNUC__ -// ------------------------------------------------------------------- - -// HelloRequest - -// string name = 1; -inline void HelloRequest::clear_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.name_.ClearToEmpty(); - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); -} -inline const ::std::string& HelloRequest::name() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:helloworld.HelloRequest.name) - return _internal_name(); -} -template -PROTOBUF_ALWAYS_INLINE void HelloRequest::set_name(Arg_&& arg, Args_... args) { - ::google::protobuf::internal::TSanWrite(&_impl_); - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - _impl_.name_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:helloworld.HelloRequest.name) -} -inline ::std::string* PROTOBUF_NONNULL HelloRequest::mutable_name() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - ::std::string* _s = _internal_mutable_name(); - // @@protoc_insertion_point(field_mutable:helloworld.HelloRequest.name) - return _s; -} -inline const ::std::string& HelloRequest::_internal_name() const { - ::google::protobuf::internal::TSanRead(&_impl_); - return _impl_.name_.Get(); -} -inline void HelloRequest::_internal_set_name(const ::std::string& value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.name_.Set(value, GetArena()); -} -inline ::std::string* PROTOBUF_NONNULL HelloRequest::_internal_mutable_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - return _impl_.name_.Mutable( GetArena()); -} -inline ::std::string* PROTOBUF_NULLABLE HelloRequest::release_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - // @@protoc_insertion_point(field_release:helloworld.HelloRequest.name) - if (!CheckHasBit(_impl_._has_bits_[0], 0x00000001U)) { - return nullptr; - } - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - auto* released = _impl_.name_.Release(); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) { - _impl_.name_.Set("", GetArena()); - } - return released; -} -inline void HelloRequest::set_allocated_name(::std::string* PROTOBUF_NULLABLE value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - if (value != nullptr) { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - } else { - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - } - _impl_.name_.SetAllocated(value, GetArena()); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.name_.IsDefault()) { - _impl_.name_.Set("", GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloRequest.name) -} - -// ------------------------------------------------------------------- - -// HelloReply - -// string message = 1; -inline void HelloReply::clear_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.message_.ClearToEmpty(); - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); -} -inline const ::std::string& HelloReply::message() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:helloworld.HelloReply.message) - return _internal_message(); -} -template -PROTOBUF_ALWAYS_INLINE void HelloReply::set_message(Arg_&& arg, Args_... args) { - ::google::protobuf::internal::TSanWrite(&_impl_); - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - _impl_.message_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:helloworld.HelloReply.message) -} -inline ::std::string* PROTOBUF_NONNULL HelloReply::mutable_message() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - ::std::string* _s = _internal_mutable_message(); - // @@protoc_insertion_point(field_mutable:helloworld.HelloReply.message) - return _s; -} -inline const ::std::string& HelloReply::_internal_message() const { - ::google::protobuf::internal::TSanRead(&_impl_); - return _impl_.message_.Get(); -} -inline void HelloReply::_internal_set_message(const ::std::string& value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.message_.Set(value, GetArena()); -} -inline ::std::string* PROTOBUF_NONNULL HelloReply::_internal_mutable_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - return _impl_.message_.Mutable( GetArena()); -} -inline ::std::string* PROTOBUF_NULLABLE HelloReply::release_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - // @@protoc_insertion_point(field_release:helloworld.HelloReply.message) - if (!CheckHasBit(_impl_._has_bits_[0], 0x00000001U)) { - return nullptr; - } - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - auto* released = _impl_.message_.Release(); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) { - _impl_.message_.Set("", GetArena()); - } - return released; -} -inline void HelloReply::set_allocated_message(::std::string* PROTOBUF_NULLABLE value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - if (value != nullptr) { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - } else { - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - } - _impl_.message_.SetAllocated(value, GetArena()); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.message_.IsDefault()) { - _impl_.message_.Set("", GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloReply.message) -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif // __GNUC__ - -// @@protoc_insertion_point(namespace_scope) -} // namespace helloworld - - -// @@protoc_insertion_point(global_scope) - -#include "google/protobuf/port_undef.inc" -// clang-format on - -#endif // helloworld_2eproto_2epb_2eh diff --git a/examples/helloworld/mcpp.toml b/examples/helloworld/mcpp.toml index a88b191..aa115d4 100644 --- a/examples/helloworld/mcpp.toml +++ b/examples/helloworld/mcpp.toml @@ -4,21 +4,20 @@ # that stands the server up on a loopback port and calls it, so `mcpp run` # answers "does gRPC actually work" with an exit code. # -# CODE GENERATION. gen/ holds protoc output, CHECKED IN on purpose. gRPC's -# codegen needs two host tools — protoc and grpc_cpp_plugin — and mcpp has no -# way to hand a dependency's built binaries to a consumer (`mcpp::dep_dir()` -# gives a package's source dir, and there is no mechanism that exposes a -# dependency's `kind = "bin"` targets). Distributing those tools is tracked -# separately; until then the generated files are committed so this example -# builds with nothing but mcpp. Regenerate with: +# CODE GENERATION (mcpp 2026.8.5.1+). There is no gen/ directory any more. The +# stubs are generated during the build, by protoc and grpc_cpp_plugin that mcpp +# builds FROM THE SAME PACKAGES this project links against: # -# protoc -I proto \ -# --cpp_out=gen --grpc_out=gen \ -# --plugin=protoc-gen-grpc=$(which grpc_cpp_plugin) \ -# proto/helloworld.proto +# compat.protobuf → protoc (matches the protobuf runtime) +# grpc-plugin → grpc_cpp_plugin (matches the gRPC being linked) # -# protoc must be 35.1 to match compat.protobuf (upstream publishes prebuilt -# protoc for every platform); grpc_cpp_plugin must come from gRPC 1.83.0. +# Both are declared with `tools = [...]`, so a tool's version IS its +# dependency's version — a protoc/runtime mismatch, which is a RUNTIME failure +# and the nastiest thing about hand-managed protobuf codegen, is not +# expressible here. Under `--target` both tools are still built for the build +# machine, because a code generator has to run here. +# +# See ../../.agents/docs/2026-08-05-codegen-ecosystem-design.md. [package] name = "helloworld" version = "0.1.0" @@ -27,9 +26,10 @@ description = "gRPC hello-world: real server + real client + real RPC, in one pr license = "Apache-2.0" [build] -sources = ["src/main.cpp", "gen/helloworld.pb.cc", "gen/helloworld.grpc.pb.cc"] -# gen/ so the generated .grpc.pb.cc can find its own "helloworld.pb.h". -include_dirs = ["gen"] +# Only the hand-written source. The generated .pb.cc / .grpc.pb.cc join the +# build as declared outputs of build.mcpp's actions, and the include dir for +# their headers comes from there too — nothing generated is checked in. +sources = ["src/main.cpp"] [targets.helloworld] kind = "bin" @@ -37,4 +37,8 @@ main = "src/main.cpp" [dependencies] grpc = { path = "../.." } - +# The two host tools. `grpc-plugin` is a package separate from `grpc` on +# purpose: a code generator needs a .proto parser and a C++ emitter, not TLS, +# DNS and a regex engine — see the design doc §2. +grpc-plugin = { path = "../../plugin", tools = ["grpc_cpp_plugin"] } +compat.protobuf = { version = "35.1", tools = ["protoc"] } diff --git a/plugin/include/grpcpp/impl/codegen/config_protobuf.h b/plugin/include/grpcpp/impl/codegen/config_protobuf.h new file mode 100644 index 0000000..ddf56aa --- /dev/null +++ b/plugin/include/grpcpp/impl/codegen/config_protobuf.h @@ -0,0 +1,123 @@ +// +// +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#ifndef GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H +#define GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H + +// IWYU pragma: private + +// #define GRPC_OPEN_SOURCE_PROTO + +#define GRPC_PROTOBUF_CORD_SUPPORT_ENABLED + +#ifndef GRPC_CUSTOM_MESSAGE +#ifdef GRPC_USE_PROTO_LITE +#include +#define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite +#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite +#else +#include +#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message +#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite +#endif +#endif + +#ifndef GRPC_CUSTOM_DESCRIPTOR +#include +#include +#if !defined(GOOGLE_PROTOBUF_VERSION) || GOOGLE_PROTOBUF_VERSION >= 4025000 +#define GRPC_PROTOBUF_EDITION_SUPPORT +#endif +#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor +#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT +#define GRPC_CUSTOM_EDITION ::google::protobuf::Edition +#endif +#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor +#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor +#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto +#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor +#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor +#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation +#endif + +#ifndef GRPC_CUSTOM_DESCRIPTORDATABASE +#include +#define GRPC_CUSTOM_DESCRIPTORDATABASE ::google::protobuf::DescriptorDatabase +#define GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE \ + ::google::protobuf::SimpleDescriptorDatabase +#endif + +#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM +#include +#include +#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \ + ::google::protobuf::io::ZeroCopyOutputStream +#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \ + ::google::protobuf::io::ZeroCopyInputStream +#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream +#define GRPC_CUSTOM_CODEDOUTPUTSTREAM ::google::protobuf::io::CodedOutputStream +#endif + +#ifndef GRPC_CUSTOM_JSONUTIL +#include +#include + +#include "absl/status/status.h" +#define GRPC_CUSTOM_JSONUTIL ::google::protobuf::util +#define GRPC_CUSTOM_UTIL_STATUS ::absl::Status +#endif + +namespace grpc { +namespace protobuf { + +typedef GRPC_CUSTOM_MESSAGE Message; +typedef GRPC_CUSTOM_MESSAGELITE MessageLite; + +typedef GRPC_CUSTOM_DESCRIPTOR Descriptor; +typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool; +typedef GRPC_CUSTOM_DESCRIPTORDATABASE DescriptorDatabase; +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT +typedef GRPC_CUSTOM_EDITION Edition; +#endif +typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor; +typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor; +typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto; +typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor; +typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor; +typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase; +typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation; + +namespace util { +typedef GRPC_CUSTOM_UTIL_STATUS Status; +} // namespace util + +// NOLINTNEXTLINE(misc-unused-alias-decls) +namespace json = GRPC_CUSTOM_JSONUTIL; + +namespace io { +typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream; +typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream; +typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream; +typedef GRPC_CUSTOM_CODEDOUTPUTSTREAM CodedOutputStream; +} // namespace io + +} // namespace protobuf +} // namespace grpc + +#endif // GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H diff --git a/plugin/include/grpcpp/ports_def.inc b/plugin/include/grpcpp/ports_def.inc new file mode 100644 index 0000000..9c94e84 --- /dev/null +++ b/plugin/include/grpcpp/ports_def.inc @@ -0,0 +1,137 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Protect Code from unwanted/inconvienet macros + * you must follow this pattern when #including port_def.inc in a header file: + * + * #include "other_header.h" + * #include "message.h" + * etc. + * + * #include "port_def.inc" // MUST be last header included + * + * Definitions for this header. + * + * #include "port_undef.inc" //At end of file + * + * This is a textual header with no include guard, because we want to + * detect/prohibit anytime it is #included twice without a corresponding + * #undef. + */ + +#ifdef GRPC_PORT_ +#error "port_def.inc included multiple times" +#endif +#define GRPC_PORT_ + + +// Windows declares several inconvenient macro names. We #undef them and then +// restore them in port_undef.inc. +#ifdef _WIN32 +#pragma push_macro("CompareString") +#undef CompareString +#pragma push_macro("CREATE_NEW") +#undef CREATE_NEW +#pragma push_macro("DELETE") +#undef DELETE +#pragma push_macro("DOUBLE_CLICK") +#undef DOUBLE_CLICK +#pragma push_macro("ERROR") +#undef ERROR +#pragma push_macro("ERROR_BUSY") +#undef ERROR_BUSY +#pragma push_macro("ERROR_INSTALL_FAILED") +#undef ERROR_INSTALL_FAILED +#pragma push_macro("ERROR_NOT_FOUND") +#undef ERROR_NOT_FOUND +#pragma push_macro("ERROR_RETRY") +#undef ERROR_RETRY +#pragma push_macro("ERROR_TIMEOUT") +#undef ERROR_TIMEOUT +#pragma push_macro("GetClassName") +#undef GetClassName +#pragma push_macro("GetCurrentTime") +#undef GetCurrentTime +#pragma push_macro("GetMessage") +#undef GetMessage +#pragma push_macro("GetObject") +#undef GetObject +#pragma push_macro("IGNORE") +#undef IGNORE +#pragma push_macro("IN") +#undef IN +#pragma push_macro("INPUT_KEYBOARD") +#undef INPUT_KEYBOARD +#pragma push_macro("NO_ERROR") +#undef NO_ERROR +#pragma push_macro("OUT") +#undef OUT +#pragma push_macro("OPTIONAL") +#undef OPTIONAL +#pragma push_macro("min") +#undef min +#pragma push_macro("max") +#undef max +#pragma push_macro("NEAR") +#undef NEAR +#pragma push_macro("NO_DATA") +#undef NO_DATA +#pragma push_macro("REASON_UNKNOWN") +#undef REASON_UNKNOWN +#pragma push_macro("SERVICE_DISABLED") +#undef SERVICE_DISABLED +#pragma push_macro("SERVICE_STOP") +#undef SERVICE_STOP +#pragma push_macro("SEVERITY_ERROR") +#undef SEVERITY_ERROR +#pragma push_macro("STATUS_PENDING") +#undef STATUS_PENDING +#pragma push_macro("STRICT") +#undef STRICT +#pragma push_macro("timezone") +#undef timezone +#pragma push_macro("TRUE") +#undef TRUE +#pragma push_macro("FALSE") +#undef FALSE +#pragma push_macro("UNICODE") +#undef UNICODE +#endif // _WIN32 + +#ifdef __APPLE__ +// Inconvenient macro names from /usr/include/mach/boolean.h in some macOS SDKs. +#pragma push_macro("TRUE") +#undef TRUE +#pragma push_macro("FALSE") +#undef FALSE +// Inconvenient macro names from usr/include/sys/syslimits.h in some macOS SDKs. +#pragma push_macro("UID_MAX") +#undef UID_MAX +#pragma push_macro("GID_MAX") +#undef GID_MAX +// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. +#pragma push_macro("TYPE_BOOL") +#undef TYPE_BOOL +#endif // __APPLE__ + +#if defined(ANDROID) || defined(__ANDROID__) +// Inconvenient macro names from usr/include/limits.h in some Android NDKs. +#pragma push_macro("UID_MAX") +#undef UID_MAX +#pragma push_macro("GID_MAX") +#undef GID_MAX +#endif // defined(ANDROID) || defined(__ANDROID__) + diff --git a/plugin/include/grpcpp/ports_undef.inc b/plugin/include/grpcpp/ports_undef.inc new file mode 100644 index 0000000..b9df388 --- /dev/null +++ b/plugin/include/grpcpp/ports_undef.inc @@ -0,0 +1,75 @@ +/* + * + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * #undefs all macros defined in port_def.inc. See comments in port_def.inc + * for more info. + */ + +#ifndef GRPC_PORT_ +#error "port_undef.inc must be included after port_def.inc" +#endif +#undef GRPC_PORT_ + +#ifdef _WIN32 +#pragma pop_macro("CompareString") +#pragma pop_macro("CREATE_NEW") +#pragma pop_macro("DELETE") +#pragma pop_macro("DOUBLE_CLICK") +#pragma pop_macro("ERROR") +#pragma pop_macro("ERROR_BUSY") +#pragma pop_macro("ERROR_INSTALL_FAILED") +#pragma pop_macro("ERROR_NOT_FOUND") +#pragma pop_macro("ERROR_RETRY") +#pragma pop_macro("ERROR_TIMEOUT") +#pragma pop_macro("GetClassName") +#pragma pop_macro("GetCurrentTime") +#pragma pop_macro("GetMessage") +#pragma pop_macro("GetObject") +#pragma pop_macro("IGNORE") +#pragma pop_macro("IN") +#pragma pop_macro("INPUT_KEYBOARD") +#pragma pop_macro("NO_ERROR") +#pragma pop_macro("OUT") +#pragma pop_macro("OPTIONAL") +#pragma pop_macro("min") +#pragma pop_macro("max") +#pragma pop_macro("NEAR") +#pragma pop_macro("NO_DATA") +#pragma pop_macro("REASON_UNKNOWN") +#pragma pop_macro("SERVICE_DISABLED") +#pragma pop_macro("SERVICE_STOP") +#pragma pop_macro("SEVERITY_ERROR") +#pragma pop_macro("STRICT") +#pragma pop_macro("STATUS_PENDING") +#pragma pop_macro("timezone") +#pragma pop_macro("TRUE") +#pragma pop_macro("FALSE") +#pragma pop_macro("UNICODE") +#endif + +#ifdef __APPLE__ +#pragma pop_macro("TRUE") +#pragma pop_macro("FALSE") +#pragma pop_macro("UID_MAX") +#pragma pop_macro("GID_MAX") +#pragma pop_macro("TYPE_BOOL") +#endif // __APPLE__ + +#if defined(ANDROID) || defined(__ANDROID__) +#pragma pop_macro("UID_MAX") +#pragma pop_macro("GID_MAX") +#endif // defined(ANDROID) || defined(__ANDROID__) + diff --git a/plugin/mcpp.toml b/plugin/mcpp.toml new file mode 100644 index 0000000..6772320 --- /dev/null +++ b/plugin/mcpp.toml @@ -0,0 +1,70 @@ +# grpc-plugin — the gRPC C++ codegen plugin (`grpc_cpp_plugin`) as a HOST tool. +# +# WHY THIS IS A SEPARATE PACKAGE, NOT A TARGET IN `grpc-m` +# +# Upstream links the plugin against `grpc_plugin_support` + protobuf and NOTHING +# else — a code generator needs a .proto parser and a C++ emitter, not TLS, not +# DNS, not a regex engine: +# +# add_executable(grpc_cpp_plugin src/compiler/cpp_plugin.cc) +# target_link_libraries(grpc_cpp_plugin grpc_plugin_support) +# +# mcpp compiles a package into ONE object pool and links every object into each +# of its `kind = "bin"` targets (there is no per-target source partition). So a +# plugin target living inside grpc-m would link all ~1000 gRPC TUs and inherit +# grpc-m's whole dependency set — OpenSSL, re2, c-ares, zlib. Measured: the +# build fails outright on a machine where OpenSSL's from-source hook cannot run, +# for a tool that never needed OpenSSL in the first place. +# +# Splitting it restores upstream's real dependency graph: 9 TUs plus protobuf's +# libprotoc, and nothing else. That is also why this package deliberately has NO +# feature gate — its entire purpose IS the tool, so there is no cost to gate. +# +# See ../.agents/docs/2026-08-05-codegen-ecosystem-design.md §3. +[package] +name = "grpc-plugin" +version = "1.83.0" +standard = "c++23" +description = "grpc_cpp_plugin — the gRPC C++ code generator, buildable as an mcpp host tool" +license = "Apache-2.0" +repo = "https://github.com/mcpplibs/grpc-m" +# Same coverage as protobuf's: this needs only libprotoc, not gRPC's runtime, +# so it is NOT limited by compat.openssl the way the main package is. +platforms = ["linux", "macos", "windows"] + +[build] +# Upstream's `grpc_plugin_support` (CMakeLists.txt:6474) carries all eight +# language generators because it also backs grpc_php_plugin, grpc_python_plugin +# and friends. This package builds ONLY grpc_cpp_plugin, so it takes only what +# cpp_plugin.cc actually reaches: +# +# cpp_generator.cc the C++ emitter +# proto_parser_helper.cc used by cpp_generator for comment/leading-detail +# +# That is not a shortcut, it is the correct closure — and it MATTERS: the php +# and objective-c generators reference libprotoc internals +# (`compiler::objectivec::FileClassPrefix`, the php helpers) that protobuf does +# not export in the source set compat.protobuf compiles, so including them fails +# at LINK with undefined symbols for languages nobody asked to generate. +sources = [ + "src/compiler/cpp_generator.cc", + "src/compiler/proto_parser_helper.cc", +] +# `.` — the generators include each other as "src/compiler/…". +# `include` — three gRPC PUBLIC headers the compiler needs +# (grpcpp/impl/codegen/config_protobuf.h and the ports_def/undef .inc pair). +# They are vendored HERE rather than reached for in the main package's tree: +# this package ships as its own tarball, so a `../third_party/…` include would +# resolve locally and break the moment it is consumed from the index. All three +# are self-contained — config_protobuf.h includes only protobuf headers. +include_dirs = [".", "include"] + +[targets.grpc_cpp_plugin] +kind = "bin" +main = "src/compiler/cpp_plugin.cc" + +[dependencies] +# libprotoc — the plugin is a protoc plugin: it links protobuf's compiler +# library, not its runtime alone. `protoc` also pulls `upb`, which libprotoc's +# upb generator needs (leaving it out fails at LINK with undefined upb_* symbols). +compat.protobuf = { version = "35.1", features = ["protoc", "upb"] } diff --git a/plugin/src/compiler/config.h b/plugin/src/compiler/config.h new file mode 100644 index 0000000..0738370 --- /dev/null +++ b/plugin/src/compiler/config.h @@ -0,0 +1,68 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SRC_COMPILER_CONFIG_H +#define SRC_COMPILER_CONFIG_H + +#include + +#include "src/compiler/config_protobuf.h" + +#ifdef GRPC_CUSTOM_STRING +#warning GRPC_CUSTOM_STRING is no longer supported. Please use std::string. +#endif + +namespace grpc { + +// Using grpc::string and grpc::to_string is discouraged in favor of +// std::string and std::to_string. This is only for legacy code using +// them explicitly. +using std::string; // deprecated +using std::to_string; // deprecated + +namespace protobuf { + +namespace compiler { +typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator; +typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext; +static inline int PluginMain(int argc, char* argv[], + const CodeGenerator* generator) { + return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator); +} +static inline void ParseGeneratorParameter( + const string& parameter, std::vector >* options) { + GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options); +} + +} // namespace compiler +namespace io { +typedef GRPC_CUSTOM_PRINTER Printer; +typedef GRPC_CUSTOM_CODEDOUTPUTSTREAM CodedOutputStream; +typedef GRPC_CUSTOM_STRINGOUTPUTSTREAM StringOutputStream; +} // namespace io +} // namespace protobuf +} // namespace grpc + +namespace grpc_cpp_generator { + +static const char* const kCppGeneratorMessageHeaderExt = ".pb.h"; +static const char* const kCppGeneratorServiceHeaderExt = ".grpc.pb.h"; + +} // namespace grpc_cpp_generator + +#endif // SRC_COMPILER_CONFIG_H diff --git a/plugin/src/compiler/config_protobuf.h b/plugin/src/compiler/config_protobuf.h new file mode 100644 index 0000000..dc0178a --- /dev/null +++ b/plugin/src/compiler/config_protobuf.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SRC_COMPILER_CONFIG_PROTOBUF_H +#define SRC_COMPILER_CONFIG_PROTOBUF_H + +#include + +#ifndef GRPC_CUSTOM_CODEGENERATOR +#include +#define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator +#define GRPC_CUSTOM_GENERATORCONTEXT \ + ::google::protobuf::compiler::GeneratorContext +#endif + +#ifndef GRPC_CUSTOM_PRINTER +#include +#include +#include +#define GRPC_CUSTOM_PRINTER ::google::protobuf::io::Printer +#define GRPC_CUSTOM_CODEDOUTPUTSTREAM ::google::protobuf::io::CodedOutputStream +#define GRPC_CUSTOM_STRINGOUTPUTSTREAM \ + ::google::protobuf::io::StringOutputStream +#endif + +#ifndef GRPC_CUSTOM_PLUGINMAIN +#include +#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain +#endif + +#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER +#include +#define GRPC_CUSTOM_PARSEGENERATORPARAMETER \ + ::google::protobuf::compiler::ParseGeneratorParameter +#endif + +#ifndef GRPC_CUSTOM_CSHARP_GETCLASSNAME +#include +#define GRPC_CUSTOM_CSHARP_GETCLASSNAME \ + ::google::protobuf::compiler::csharp::GetClassName +#define GRPC_CUSTOM_CSHARP_GETFILENAMESPACE \ + ::google::protobuf::compiler::csharp::GetFileNamespace +#define GRPC_CUSTOM_CSHARP_GETOUTPUTFILE \ + ::google::protobuf::compiler::csharp::GetOutputFile +#define GRPC_CUSTOM_CSHARP_GETREFLECTIONCLASSNAME \ + ::google::protobuf::compiler::csharp::GetReflectionClassName +#endif + +#endif // SRC_COMPILER_CONFIG_PROTOBUF_H diff --git a/plugin/src/compiler/cpp_generator.cc b/plugin/src/compiler/cpp_generator.cc new file mode 100644 index 0000000..160d869 --- /dev/null +++ b/plugin/src/compiler/cpp_generator.cc @@ -0,0 +1,2509 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/compiler/cpp_generator.h" + +#include +#include +#include + +namespace grpc_cpp_generator { +namespace { + +template +std::string as_string(T x) { + std::ostringstream out; + out << x; + return out.str(); +} + +inline bool ClientOnlyStreaming(const grpc_generator::Method* method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +inline bool ServerOnlyStreaming(const grpc_generator::Method* method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + +std::string FilenameIdentifier(const std::string& filename) { + std::string result; + for (unsigned i = 0; i < filename.size(); i++) { + char c = filename[i]; + if (isalnum(c)) { + result.push_back(c); + } else { + static char hex[] = "0123456789abcdef"; + result.push_back('_'); + result.push_back(hex[(c >> 4) & 0xf]); + result.push_back(hex[c & 0xf]); + } + } + return result; +} + +} // namespace + +template +T* array_end(T (&array)[N]) { + return array + N; +} + +void PrintIncludes(grpc_generator::Printer* printer, + const std::vector& headers, + bool use_system_headers, const std::string& search_path) { + std::map vars; + + vars["l"] = use_system_headers ? '<' : '"'; + vars["r"] = use_system_headers ? '>' : '"'; + + if (!search_path.empty()) { + vars["l"] += search_path; + if (search_path[search_path.size() - 1] != '/') { + vars["l"] += '/'; + } + } + + for (auto i = headers.begin(); i != headers.end(); i++) { + vars["h"] = *i; + printer->Print(vars, "#include $l$$h$$r$\n"); + } +} + +std::string GetHeaderPrologue(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension.empty() + ? kCppGeneratorMessageHeaderExt + : params.message_header_extension; + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n"); + std::string leading_comments = file->GetLeadingComments("//"); + if (!leading_comments.empty()) { + printer->Print(vars, "// Original file comments:\n"); + printer->PrintRaw(leading_comments.c_str()); + } + printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "\n"); + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +// Convert from "a/b/c.proto" to "#include \"a/b/c$message_header_ext$\"\n" +std::string ImportInludeFromProtoName(const std::string& proto_name) { + return std::string("#include \"") + + proto_name.substr(0, proto_name.size() - 6) + + std::string("$message_header_ext$\"\n"); +} + +std::string GetHeaderIncludes(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + if (!params.additional_header_includes.empty()) { + PrintIncludes(printer.get(), params.additional_header_includes, false, + ""); + } + static const char* headers_strs[] = { + "functional", + "grpcpp/generic/async_generic_service.h", + "grpcpp/support/async_stream.h", + "grpcpp/support/async_unary_call.h", + "grpcpp/support/client_callback.h", + "grpcpp/client_context.h", + "grpcpp/completion_queue.h", + "grpcpp/support/message_allocator.h", + "grpcpp/support/method_handler.h", + "grpcpp/impl/proto_utils.h", + "grpcpp/impl/rpc_method.h", + "grpcpp/support/server_callback.h", + "grpcpp/impl/server_callback_handlers.h", + "grpcpp/server_context.h", + "grpcpp/impl/service_type.h", + "grpcpp/support/status.h", + "grpcpp/support/stub_options.h", + "grpcpp/support/sync_stream.h", + // ports_def.inc Must be included at last + "grpcpp/ports_def.inc", + }; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params.use_system_headers, + params.grpc_search_path); + printer->Print(vars, "\n"); + + vars["message_header_ext"] = params.message_header_extension.empty() + ? kCppGeneratorMessageHeaderExt + : params.message_header_extension; + + if (params.include_import_headers) { + const std::vector import_names = file->GetImportNames(); + for (const auto& import_name : import_names) { + const std::string include_name = ImportInludeFromProtoName(import_name); + printer->Print(vars, include_name.c_str()); + } + printer->PrintRaw("\n"); + } + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + printer->Print(vars, "\n"); + } + } + return output; +} + +void PrintHeaderClientMethodInterfaces(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars, + bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + std::string prefix; + std::string method_params; // extra arguments to method + std::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = {{"Async", ", void* tag", ", tag"}, + {"PrepareAsync", "", ""}}; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) = 0;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* " + "response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncWriterInterface< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< " + "$Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientReaderWriterInterface< " + "$Request$, $Response$>> " + "$Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, " + "$Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, " + "$Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } + } else { + if (method->NoStreaming()) { + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncResponseReaderInterface< " + "$Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) = 0;\n"); + } + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientWriterInterface< $Request$>*" + " $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) = 0;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*" + " $AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientReaderInterface< $Response$>* " + "$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* " + "$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "virtual ::grpc::ClientReaderWriterInterface< $Request$, " + "$Response$>* " + "$Method$Raw(::grpc::ClientContext* context) = 0;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderWriterInterface< " + "$Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } + } + } +} + +void PrintHeaderClientMethod(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars, + bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + std::string prefix; + std::string method_params; // extra arguments to method + std::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = {{"Async", ", void* tag", ", tag"}, + {"PrepareAsync", "", ""}}; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) override;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncResponseReader< " + "$Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReader< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReader< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>" + " $Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriter< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " + "$Request$, $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } + } else { + if (method->NoStreaming()) { + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) override;\n"); + } + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) " + "override;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncWriter< $Request$>* $AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientReader< $Response$>* $Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request)" + " override;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* " + "$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$Method$Raw(::grpc::ClientContext* context) override;\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } + } + } +} + +void PrintHeaderClientMethodCallbackInterfacesStart( + grpc_generator::Printer* printer, + std::map* /*vars*/) { + // This declares the interface for the callback-based API. The components + // are pure; even though this is new (post-1.0) API, it can be pure because + // it is an entirely new interface that happens to be scoped within + // StubInterface, not new additions to StubInterface itself + printer->Print("class async_interface {\n"); + // All methods in this new interface are public. There is no need for private + // "Raw" methods since the callback-based API returns unowned raw pointers + printer->Print(" public:\n"); + printer->Indent(); + printer->Print("virtual ~async_interface() {}\n"); +} + +void PrintHeaderClientMethodCallbackInterfaces( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + if (method->NoStreaming()) { + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function) = 0;\n"); + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "::grpc::ClientUnaryReactor* reactor) = 0;\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::ClientWriteReactor< $Request$>* " + "reactor) = 0;\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, " + "::grpc::ClientReadReactor< $Response$>* " + "reactor) = 0;\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "virtual void $Method$(::grpc::ClientContext* context, " + "::grpc::ClientBidiReactor< " + "$Request$,$Response$>* reactor) = 0;\n"); + } +} + +void PrintHeaderClientMethodCallbackInterfacesEnd( + grpc_generator::Printer* printer, + std::map* /*vars*/) { + printer->Outdent(); + printer->Print("};\n"); + // TODO: Remove typedef when all uses of experimental_async are migrated off. + printer->Print( + "typedef class async_interface experimental_async_interface;\n"); + + // Declare a function to give the async stub contents. It can't be pure + // since this is a new API in StubInterface, but it is meaningless by default + // (since any stub that wants to use it must have its own implementation of + // the callback functions therein), so make the default return value nullptr. + // Intentionally include the word "class" to avoid possible shadowing. + // TODO: Remove experimental_async call when possible, replace with nullptr. + printer->Print( + "virtual class async_interface* async() { return nullptr; }\n"); + + // TODO: Remove experimental_async call when possible. + printer->Print( + "class async_interface* experimental_async() { return async(); }\n"); +} + +void PrintHeaderClientMethodCallbackStart( + grpc_generator::Printer* printer, + std::map* /*vars*/) { + // This declares the stub entry for the callback-based API. + printer->Print("class async final :\n"); + printer->Print(" public StubInterface::async_interface {\n"); + printer->Print(" public:\n"); + printer->Indent(); +} + +void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + if (method->NoStreaming()) { + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function) override;\n"); + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "::grpc::ClientUnaryReactor* reactor) override;\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::ClientWriteReactor< $Request$>* " + "reactor) override;\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "const $Request$* request, " + "::grpc::ClientReadReactor< $Response$>* " + "reactor) override;\n"); + + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "void $Method$(::grpc::ClientContext* context, " + "::grpc::ClientBidiReactor< " + "$Request$,$Response$>* reactor) override;\n"); + } +} + +void PrintHeaderClientMethodCallbackEnd( + grpc_generator::Printer* printer, + std::map* /*vars*/) { + printer->Outdent(); + printer->Print(" private:\n"); + printer->Indent(); + printer->Print("friend class Stub;\n"); + printer->Print("explicit async(Stub* stub): stub_(stub) { }\n"); + // include a function with a phony use of stub_ to avoid an unused + // private member warning for service with no methods + printer->Print("Stub* stub() { return stub_; }\n"); + printer->Print("Stub* stub_;\n"); + printer->Outdent(); + printer->Print("};\n"); + + printer->Print( + "class async* async() override { " + "return &async_stub_; }\n"); +} + +void PrintHeaderClientMethodData(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + std::map* vars) { + (*vars)["Method"] = method->name(); + printer->Print(*vars, + "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n"); +} + +void PrintHeaderServerMethodSync(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(method->GetLeadingComments("//").c_str()); + if (params.allow_sync_server_api) { + printer->Print("virtual "); + } + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response);\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response);\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer);\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);" + "\n"); + } + printer->Print(method->GetTrailingComments("//").c_str()); +} + +// Helper generator. Disables the sync API for Request and Response, then adds +// in an async API for RealRequest and RealResponse types. This is to be used +// to generate async and raw async APIs. +void PrintHeaderServerAsyncMethodsHelper( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + const Parameters& params, std::map* vars) { + if (method->NoStreaming()) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $RealRequest$* request, " + "::grpc::ServerAsyncResponseWriter< $RealResponse$>* response, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncUnary($Idx$, context, " + "request, response, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ClientOnlyStreaming(method)) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReader< $RealResponse$, $RealRequest$>* reader, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncClientStreaming($Idx$, " + "context, reader, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ServerOnlyStreaming(method)) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $RealRequest$* request, " + "::grpc::ServerAsyncWriter< $RealResponse$>* writer, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print( + *vars, + " ::grpc::Service::RequestAsyncServerStreaming($Idx$, " + "context, request, writer, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (method->BidiStreaming()) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* /*stream*/) " + " override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReaderWriter< $RealResponse$, $RealRequest$>* " + "stream, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncBidiStreaming($Idx$, " + "context, stream, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } +} + +void PrintHeaderServerMethodAsync(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for the async API + (*vars)["RealRequest"] = method->input_type_name(); + (*vars)["RealResponse"] = method->output_type_name(); + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithAsyncMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithAsyncMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodAsync($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithAsyncMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerAsyncMethodsHelper(printer, method, params, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +// Helper generator. Disables the sync API for Request and Response, then adds +// in a callback API for RealRequest and RealResponse types. This is to be used +// to generate callback and raw callback APIs. +void PrintHeaderServerCallbackMethodsHelper( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + const Parameters& params, std::map* vars) { + if (method->NoStreaming()) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print(*vars, + "virtual ::grpc::ServerUnaryReactor* $Method$(\n" + " ::grpc::CallbackServerContext* /*context*/, " + "const $RealRequest$* /*request*/, " + "$RealResponse$* /*response*/)" + " { return nullptr; }\n"); + } else if (ClientOnlyStreaming(method)) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print(*vars, + "virtual ::grpc::ServerReadReactor< " + "$RealRequest$>* $Method$(\n" + " ::grpc::CallbackServerContext* " + "/*context*/, $RealResponse$* /*response*/)" + " { return nullptr; }\n"); + } else if (ServerOnlyStreaming(method)) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "virtual ::grpc::ServerWriteReactor< $RealResponse$>* $Method$(\n" + " ::grpc::CallbackServerContext* " + "/*context*/, const $RealRequest$* /*request*/)" + " { return nullptr; }\n"); + } else if (method->BidiStreaming()) { + if (params.allow_sync_server_api) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* /*stream*/) " + " override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Print( + *vars, + "virtual ::grpc::ServerBidiReactor< $RealRequest$, $RealResponse$>* " + "$Method$(\n" + " ::grpc::CallbackServerContext* /*context*/)\n" + " { return nullptr; }\n"); + } +} + +void PrintHeaderServerMethodCallback(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for the callback API + (*vars)["RealRequest"] = method->input_type_name(); + (*vars)["RealResponse"] = method->output_type_name(); + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithCallbackMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, "WithCallbackMethod_$Method$() {\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + " ::grpc::Service::MarkMethodCallback($Idx$,\n" + " new ::grpc::internal::CallbackUnaryHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "const $RealRequest$* " + "request, " + "$RealResponse$* response) { " + "return this->$Method$(context, request, response); }));}\n"); + printer->Print(*vars, + "void SetMessageAllocatorFor_$Method$(\n" + " ::grpc::MessageAllocator< " + "$RealRequest$, $RealResponse$>* allocator) {\n" + " ::grpc::internal::MethodHandler* const handler = " + "::grpc::Service::GetHandler($Idx$);\n" + " static_cast<::grpc::internal::CallbackUnaryHandler< " + "$RealRequest$, $RealResponse$>*>(handler)\n" + " ->SetMessageAllocator(allocator);\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + " ::grpc::Service::MarkMethodCallback($Idx$,\n" + " new ::grpc::internal::CallbackClientStreamingHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "$RealResponse$* " + "response) { " + "return this->$Method$(context, response); }));\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + " ::grpc::Service::MarkMethodCallback($Idx$,\n" + " new ::grpc::internal::CallbackServerStreamingHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "const $RealRequest$* " + "request) { " + "return this->$Method$(context, request); }));\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + " ::grpc::Service::MarkMethodCallback($Idx$,\n" + " new ::grpc::internal::CallbackBidiHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context) " + "{ return this->$Method$(context); }));\n"); + } + printer->Print(*vars, "}\n"); + printer->Print(*vars, + "~WithCallbackMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerCallbackMethodsHelper(printer, method, params, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderServerMethodRawCallback( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + const Parameters& params, std::map* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for raw API + (*vars)["RealRequest"] = "::grpc::ByteBuffer"; + (*vars)["RealResponse"] = "::grpc::ByteBuffer"; + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithRawCallbackMethod_$Method$ : public " + "BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, "WithRawCallbackMethod_$Method$() {\n"); + if (method->NoStreaming()) { + printer->Print(*vars, + " ::grpc::Service::MarkMethodRawCallback($Idx$,\n" + " new ::grpc::internal::CallbackUnaryHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "const $RealRequest$* " + "request, " + "$RealResponse$* response) { return " + "this->$Method$(context, request, response); }));\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + " ::grpc::Service::MarkMethodRawCallback($Idx$,\n" + " new ::grpc::internal::CallbackClientStreamingHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "$RealResponse$* response) " + "{ return this->$Method$(context, response); }));\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + " ::grpc::Service::MarkMethodRawCallback($Idx$,\n" + " new ::grpc::internal::CallbackServerStreamingHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context, " + "const" + "$RealRequest$* request) { return " + "this->$Method$(context, request); }));\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + " ::grpc::Service::MarkMethodRawCallback($Idx$,\n" + " new ::grpc::internal::CallbackBidiHandler< " + "$RealRequest$, $RealResponse$>(\n" + " [this](\n" + " ::grpc::CallbackServerContext* context) " + "{ return this->$Method$(context); }));\n"); + } + printer->Print(*vars, "}\n"); + printer->Print(*vars, + "~WithRawCallbackMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerCallbackMethodsHelper(printer, method, params, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderServerMethodStreamedUnary( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithStreamedUnaryMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithStreamedUnaryMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::StreamedUnaryHandler<\n" + " $Request$, $Response$>(\n" + " [this](::grpc::ServerContext* context,\n" + " ::grpc::ServerUnaryStreamer<\n" + " $Request$, $Response$>* streamer) {\n" + " return this->Streamed$Method$(context,\n" + " streamer);\n" + " }));\n" + "}\n"); + printer->Print(*vars, + "~WithStreamedUnaryMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with streamed unary\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerUnaryStreamer< " + "$Request$,$Response$>* server_unary_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +void PrintHeaderServerMethodSplitStreaming( + grpc_generator::Printer* printer, const grpc_generator::Method* method, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (ServerOnlyStreaming(method)) { + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithSplitStreamingMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithSplitStreamingMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::SplitServerStreamingHandler<\n" + " $Request$, $Response$>(\n" + " [this](::grpc::ServerContext* context,\n" + " ::grpc::ServerSplitStreamer<\n" + " $Request$, $Response$>* streamer) {\n" + " return this->Streamed$Method$(context,\n" + " streamer);\n" + " }));\n" + "}\n"); + printer->Print(*vars, + "~WithSplitStreamingMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with split streamed\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerSplitStreamer< " + "$Request$,$Response$>* server_split_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +void PrintHeaderServerMethodGeneric(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithGenericMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithGenericMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodGeneric($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithGenericMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + if (params.allow_sync_server_api) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* /*stream*/) " + " override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + } + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderServerMethodRaw(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + // These will be disabled + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + // These will be used for raw API + (*vars)["RealRequest"] = "::grpc::ByteBuffer"; + (*vars)["RealResponse"] = "::grpc::ByteBuffer"; + printer->Print(*vars, "template \n"); + printer->Print(*vars, "class WithRawMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service* /*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithRawMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodRaw($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithRawMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + PrintHeaderServerAsyncMethodsHelper(printer, method, params, vars); + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderService(grpc_generator::Printer* printer, + const grpc_generator::Service* service, + const Parameters& params, + std::map* vars) { + (*vars)["Service"] = service->name(); + + printer->Print(service->GetLeadingComments("//").c_str()); + if (params.allow_deprecated && service->is_deprecated()) { + printer->Print(*vars, + "class [[deprecated]] $Service$ final {\n" + " public:\n"); + } else { + printer->Print(*vars, + "class $Service$ final {\n" + " public:\n"); + } + printer->Indent(); + + // Service metadata + printer->Print(*vars, + "static constexpr char const* service_full_name() {\n" + " return \"$Package$$Service$\";\n" + "}\n"); + + // Client side + printer->Print( + "class StubInterface {\n" + " public:\n"); + printer->Indent(); + printer->Print("virtual ~StubInterface() {}\n"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), params, + vars, true); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); + } + PrintHeaderClientMethodCallbackInterfacesStart(printer, vars); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); + PrintHeaderClientMethodCallbackInterfaces(printer, service->method(i).get(), + vars); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); + } + PrintHeaderClientMethodCallbackInterfacesEnd(printer, vars); + printer->Outdent(); + printer->Print(" private:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), params, + vars, false); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "class Stub final : public StubInterface" + " {\n public:\n"); + printer->Indent(); + printer->Print( + "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& " + "channel, const ::grpc::StubOptions& options = " + "::grpc::StubOptions());\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), params, vars, + true); + } + PrintHeaderClientMethodCallbackStart(printer, vars); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodCallback(printer, service->method(i).get(), vars); + } + PrintHeaderClientMethodCallbackEnd(printer, vars); + printer->Outdent(); + printer->Print("\n private:\n"); + printer->Indent(); + printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n"); + printer->Print("class async async_stub_{this};\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), params, vars, + false); + } + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodData(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "static std::unique_ptr NewStub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n"); + + printer->Print("\n"); + + // Server side - base + printer->Print( + "class Service : public ::grpc::Service {\n" + " public:\n"); + printer->Indent(); + printer->Print("Service();\n"); + printer->Print("virtual ~Service();\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderServerMethodSync(printer, service->method(i).get(), params, + vars); + } + printer->Outdent(); + printer->Print("};\n"); + + if (params.allow_cq_api) { + // Server side - Asynchronous + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodAsync(printer, service->method(i).get(), params, + vars); + } + + printer->Print("typedef "); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + printer->Print(*vars, "WithAsyncMethod_$method_name$<"); + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(" >"); + } + printer->Print(" AsyncService;\n"); + } + + // Server side - Callback + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodCallback(printer, service->method(i).get(), params, + vars); + } + + printer->Print("typedef "); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + printer->Print(*vars, "WithCallbackMethod_$method_name$<"); + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(" >"); + } + printer->Print(" CallbackService;\n"); + + // TODO: Remove following typedef once all uses of ExperimentalCallbackService + // are migrated to CallbackService + printer->Print("typedef CallbackService ExperimentalCallbackService;\n"); + + // Server side - Generic + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodGeneric(printer, service->method(i).get(), params, + vars); + } + + // Server side - Raw Async + if (params.allow_cq_api) { + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodRaw(printer, service->method(i).get(), params, + vars); + } + } + + // Server side - Raw Callback + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodRawCallback(printer, service->method(i).get(), + params, vars); + } + + if (params.allow_sync_server_api) { + // Server side - Streamed Unary + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodStreamedUnary(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + if (service->method(i)->NoStreaming()) { + printer->Print(" >"); + } + } + printer->Print(" StreamedUnaryService;\n"); + + // Server side - controlled server-side streaming + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodSplitStreaming(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(" >"); + } + } + printer->Print(" SplitStreamedService;\n"); + + // Server side - typedef for controlled both unary and server-side streaming + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i)->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (service->method(i)->NoStreaming() || + ServerOnlyStreaming(method.get())) { + printer->Print(" >"); + } + } + printer->Print(" StreamedService;\n"); + } + + printer->Outdent(); + printer->Print("};\n"); + printer->Print(service->GetTrailingComments("//").c_str()); +} + +std::string GetHeaderServices(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintHeaderService(printer.get(), file->service(i).get(), params, &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +std::string GetHeaderEpilogue(grpc_generator::File* file, + const Parameters& /*params*/) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.rbegin(); part != parts.rend(); part++) { + vars["part"] = *part; + printer->Print(vars, "} // namespace $part$\n"); + } + printer->Print(vars, "\n"); + } + + printer->Print(vars, "\n"); + + // Must be included at end of file + printer->Print("#include \n"); + printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n"); + + printer->Print(file->GetTrailingComments("//").c_str()); + } + return output; +} + +std::string GetSourcePrologue(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension.empty() + ? kCppGeneratorMessageHeaderExt + : params.message_header_extension; + vars["service_header_ext"] = kCppGeneratorServiceHeaderExt; + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + printer->Print(vars, "\n"); + } + return output; +} + +std::string GetSourceIncludes(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + static const char* headers_strs[] = { + "functional", "grpcpp/support/async_stream.h", + "grpcpp/support/async_unary_call.h", "grpcpp/impl/channel_interface.h", + "grpcpp/impl/client_unary_call.h", "grpcpp/support/client_callback.h", + "grpcpp/support/message_allocator.h", "grpcpp/support/method_handler.h", + "grpcpp/impl/rpc_service_method.h", "grpcpp/support/server_callback.h", + "grpcpp/impl/server_callback_handlers.h", "grpcpp/server_context.h", + "grpcpp/impl/service_type.h", "grpcpp/support/sync_stream.h", + // ports_def.inc Must be included as last + "grpcpp/ports_def.inc"}; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params.use_system_headers, + params.grpc_search_path); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + +void PrintSourceClientMethod(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + std::string prefix; + std::string start; // bool literal expressed as string + std::string method_params; // extra arguments to method + std::string create_args; // extra arguments to creator + } async_prefixes[] = {{"Async", "true", ", void* tag", ", tag"}, + {"PrepareAsync", "false", "", ", nullptr"}}; + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Stub::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) {\n"); + printer->Print(*vars, + " return ::grpc::internal::BlockingUnaryCall" + "< $Request$, $Response$, ::grpc::protobuf::MessageLite, " + "::grpc::protobuf::MessageLite>" + "(channel_.get(), rpcmethod_$Method$_, " + "context, request, response);\n}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::Stub::async::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "std::function f) {\n"); + printer->Print(*vars, + " ::grpc::internal::CallbackUnaryCall" + "< $Request$, $Response$, ::grpc::protobuf::MessageLite, " + "::grpc::protobuf::MessageLite>" + "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " + "context, request, response, std::move(f));\n}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::Stub::async::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$* request, $Response$* response, " + "::grpc::ClientUnaryReactor* reactor) {\n"); + printer->Print(*vars, + " ::grpc::internal::ClientCallbackUnaryFactory::Create" + "< ::grpc::protobuf::MessageLite, " + "::grpc::protobuf::MessageLite>" + "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, " + "context, request, response, reactor);\n}\n\n"); + + if (params.allow_cq_api) { + printer->Print(*vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$ns$$Service$::Stub::PrepareAsync$Method$Raw(::grpc::" + "ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Print(*vars, + " return " + "::grpc::internal::ClientAsyncResponseReaderHelper::Create" + "< $Response$, $Request$, ::grpc::protobuf::MessageLite, " + "::grpc::protobuf::MessageLite>" + "(channel_.get(), cq, rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); + printer->Print(*vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$ns$$Service$::Stub::Async$Method$Raw(::grpc::" + "ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Print( + *vars, + " auto* result =\n" + " this->PrepareAsync$Method$Raw(context, request, cq);\n" + " result->StartCall();\n" + " return result;\n" + "}\n\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientWriterFactory< " + "$Request$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::" + "Stub::async::$Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::ClientWriteReactor< $Request$>* reactor) {\n"); + printer->Print(*vars, + " ::grpc::internal::ClientCallbackWriterFactory< " + "$Request$>::Create(" + "stub_->channel_.get(), " + "stub_->rpcmethod_$Method$_, " + "context, response, reactor);\n" + "}\n\n"); + + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print(*vars, + "::grpc::ClientAsyncWriter< $Request$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, response, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientReader< $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientReaderFactory< " + "$Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::Stub::async::$Method$(::grpc::" + "ClientContext* context, " + "const $Request$* request, " + "::grpc::ClientReadReactor< $Response$>* reactor) {\n"); + printer->Print(*vars, + " ::grpc::internal::ClientCallbackReaderFactory< " + "$Response$>::Create(" + "stub_->channel_.get(), " + "stub_->rpcmethod_$Method$_, " + "context, request, reactor);\n" + "}\n\n"); + + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientAsyncReaderFactory< " + "$Response$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context);\n" + "}\n\n"); + + printer->Print(*vars, + "void $ns$$Service$::Stub::async::$Method$(::grpc::" + "ClientContext* context, " + "::grpc::ClientBidiReactor< $Request$,$Response$>* " + "reactor) {\n"); + printer->Print(*vars, + " ::grpc::internal::ClientCallbackReaderWriterFactory< " + "$Request$,$Response$>::Create(" + "stub_->channel_.get(), " + "stub_->rpcmethod_$Method$_, " + "context, reactor);\n" + "}\n\n"); + + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" + "ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print(*vars, + " return " + "::grpc::internal::ClientAsyncReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } + } +} + +void PrintSourceServerMethod(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "const $Request$* request, $Response$* response) {\n"); + if (!params.allow_sync_server_api) { + printer->Print(" abort();\n"); + } + printer->Print(" (void) context;\n"); + printer->Print(" (void) request;\n"); + printer->Print(" (void) response;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response) {\n"); + if (!params.allow_sync_server_api) { + printer->Print(" abort();\n"); + } + printer->Print(" (void) context;\n"); + printer->Print(" (void) reader;\n"); + printer->Print(" (void) response;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) {\n"); + if (!params.allow_sync_server_api) { + printer->Print(" abort();\n"); + } + printer->Print(" (void) context;\n"); + printer->Print(" (void) request;\n"); + printer->Print(" (void) writer;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* " + "stream) {\n"); + if (!params.allow_sync_server_api) { + printer->Print(" abort();\n"); + } + printer->Print(" (void) context;\n"); + printer->Print(" (void) stream;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } +} + +void PrintSourceService(grpc_generator::Printer* printer, + const grpc_generator::Service* service, + const Parameters& params, + std::map* vars) { + (*vars)["Service"] = service->name(); + + if (service->method_count() > 0) { + printer->Print(*vars, + "static const char* $prefix$$Service$_method_names[] = {\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Method"] = service->method(i)->name(); + printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n"); + } + printer->Print(*vars, "};\n\n"); + } + + printer->Print(*vars, + "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub(" + "const std::shared_ptr< ::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& options) {\n" + " (void)options;\n" + " std::unique_ptr< $ns$$Service$::Stub> stub(new " + "$ns$$Service$::Stub(channel, options));\n" + " return stub;\n" + "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Stub::Stub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel, const " + "::grpc::StubOptions& options)\n"); + printer->Indent(); + printer->Print(": channel_(channel)"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + (*vars)["Method"] = method->name(); + (*vars)["Idx"] = as_string(i); + if (method->NoStreaming()) { + (*vars)["StreamingType"] = "NORMAL_RPC"; + // NOTE: There is no reason to consider streamed-unary as a separate + // category here since this part is setting up the client-side stub + // and this appears as a NORMAL_RPC from the client-side. + } else if (ClientOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "CLIENT_STREAMING"; + } else if (ServerOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "SERVER_STREAMING"; + } else { + (*vars)["StreamingType"] = "BIDI_STREAMING"; + } + printer->Print( + *vars, + ", rpcmethod_$Method$_(" + "$prefix$$Service$_method_names[$Idx$], options.suffix_for_stats()," + "::grpc::internal::RpcMethod::$StreamingType$, " + "channel" + ")\n"); + } + printer->Print("{}\n\n"); + printer->Outdent(); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceClientMethod(printer, service->method(i).get(), params, vars); + } + + printer->Print(*vars, "$ns$$Service$::Service::Service() {\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + (*vars)["Idx"] = as_string(i); + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::NORMAL_RPC,\n" + " new ::grpc::internal::RpcMethodHandler< $ns$$Service$::Service, " + "$Request$, $Response$, ::grpc::protobuf::MessageLite, " + "::grpc::protobuf::MessageLite>(\n" + " []($ns$$Service$::Service* service,\n" + " ::grpc::ServerContext* ctx,\n" + " const $Request$* req,\n" + " $Response$* resp) {\n" + " return service->$Method$(ctx, req, resp);\n" + " }, this)));\n"); + } else if (ClientOnlyStreaming(method.get())) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n" + " new ::grpc::internal::ClientStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " []($ns$$Service$::Service* service,\n" + " ::grpc::ServerContext* ctx,\n" + " ::grpc::ServerReader<$Request$>* reader,\n" + " $Response$* resp) {\n" + " return service->$Method$(ctx, reader, resp);\n" + " }, this)));\n"); + } else if (ServerOnlyStreaming(method.get())) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::SERVER_STREAMING,\n" + " new ::grpc::internal::ServerStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " []($ns$$Service$::Service* service,\n" + " ::grpc::ServerContext* ctx,\n" + " const $Request$* req,\n" + " ::grpc::ServerWriter<$Response$>* writer) {\n" + " return service->$Method$(ctx, req, writer);\n" + " }, this)));\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::BIDI_STREAMING,\n" + " new ::grpc::internal::BidiStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " []($ns$$Service$::Service* service,\n" + " ::grpc::ServerContext* ctx,\n" + " ::grpc::ServerReaderWriter<$Response$,\n" + " $Request$>* stream) {\n" + " return service->$Method$(ctx, stream);\n" + " }, this)));\n"); + } + } + printer->Outdent(); + printer->Print(*vars, "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Service::~Service() {\n" + "}\n\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceServerMethod(printer, service->method(i).get(), params, vars); + } +} + +std::string GetSourceServices(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + if (!params.services_namespace.empty()) { + vars["ns"] = params.services_namespace + "::"; + vars["prefix"] = params.services_namespace; + } else { + vars["ns"] = ""; + vars["prefix"] = ""; + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintSourceService(printer.get(), file->service(i).get(), params, &vars); + printer->Print("\n"); + } + } + return output; +} + +std::string GetSourceEpilogue(grpc_generator::File* file, + const Parameters& /*params*/) { + std::string temp; + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + // Must be included at end of file + temp.append("#include \n"); + temp.append("\n"); + } + + return temp; +} + +// TODO(mmukhi): Make sure we need parameters or not. +std::string GetMockPrologue(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension.empty() + ? kCppGeneratorMessageHeaderExt + : params.message_header_extension; + vars["service_header_ext"] = kCppGeneratorServiceHeaderExt; + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#ifndef GRPC_MOCK_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "#define GRPC_MOCK_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "\n"); + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + if (params.include_import_headers) { + const std::vector import_names = file->GetImportNames(); + for (const auto& import_name : import_names) { + const std::string include_name = ImportInludeFromProtoName(import_name); + printer->Print(vars, include_name.c_str()); + } + printer->PrintRaw("\n"); + } + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +// TODO(mmukhi): Add client-stream and completion-queue headers. +std::string GetMockIncludes(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + static const char* headers_strs[] = { + "grpcpp/support/async_stream.h", + "grpcpp/support/sync_stream.h", + }; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params.use_system_headers, + params.grpc_search_path); + + std::vector gmock_header; + if (params.gmock_search_path.empty()) { + gmock_header.push_back("gmock/gmock.h"); + PrintIncludes(printer.get(), gmock_header, params.use_system_headers, + params.grpc_search_path); + } else { + gmock_header.push_back("gmock.h"); + // We use local includes when a gmock_search_path is given + PrintIncludes(printer.get(), gmock_header, false, + params.gmock_search_path); + } + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + +void PrintMockClientMethods(grpc_generator::Printer* printer, + const grpc_generator::Method* method, + const Parameters& params, + std::map* vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + std::string prefix; + std::string method_params; // extra arguments to method + int extra_method_param_count; + } async_prefixes[] = {{"Async", ", void* tag", 1}, {"PrepareAsync", "", 0}}; + + if (method->NoStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response));\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "MOCK_METHOD3($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq));\n"); + } + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response));\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + std::to_string(3 + async_prefix.extra_method_param_count); + printer->Print(*vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request));\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + std::to_string(3 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD1($Method$Raw, " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>*" + "(::grpc::ClientContext* context));\n"); + if (params.allow_cq_api) { + for (const auto& async_prefix : async_prefixes) { + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + std::to_string(2 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderWriterInterface<$Request$, " + "$Response$>*" + "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq" + "$AsyncMethodParams$));\n"); + } + } + } +} + +void PrintMockService(grpc_generator::Printer* printer, + const grpc_generator::Service* service, + const Parameters& params, + std::map* vars) { + (*vars)["Service"] = service->name(); + + printer->Print(*vars, + "class Mock$Service$Stub : public $Service$::StubInterface {\n" + " public:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintMockClientMethods(printer, service->method(i).get(), params, vars); + } + printer->Outdent(); + printer->Print("};\n"); +} + +std::string GetMockServices(grpc_generator::File* file, + const Parameters& params) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); i++) { + PrintMockService(printer.get(), file->service(i).get(), params, &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +std::string GetMockEpilogue(grpc_generator::File* file, + const Parameters& /*params*/) { + std::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + for (auto part = parts.rbegin(); part != parts.rend(); part++) { + vars["part"] = *part; + printer->Print(vars, "} // namespace $part$\n"); + } + printer->Print(vars, "\n"); + } + + printer->Print(vars, "\n"); + printer->Print(vars, + "#endif // GRPC_MOCK_$filename_identifier$__INCLUDED\n"); + } + return output; +} + +} // namespace grpc_cpp_generator diff --git a/plugin/src/compiler/cpp_generator.h b/plugin/src/compiler/cpp_generator.h new file mode 100644 index 0000000..47a555f --- /dev/null +++ b/plugin/src/compiler/cpp_generator.h @@ -0,0 +1,141 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H + +// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they +// can be used to generate code for other serialization systems, such as +// FlatBuffers. + +#include +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +#ifdef GRPC_CUSTOM_STRING +#warning GRPC_CUSTOM_STRING is no longer supported. Please use std::string. +#endif + +namespace grpc { + +// Using grpc::string and grpc::to_string is discouraged in favor of +// std::string and std::to_string. This is only for legacy code using +// them explicitly. +using std::string; // deprecated +using std::to_string; // deprecated + +} // namespace grpc + +namespace grpc_cpp_generator { + +// Contains all the parameters that are parsed from the command line. +struct Parameters { + // Puts the service into a namespace + std::string services_namespace; + // Use system includes (<>) or local includes ("") + bool use_system_headers; + // Prefix to any grpc include + std::string grpc_search_path; + // Generate Google Mock code to facilitate unit testing. + bool generate_mock_code; + // Google Mock search path, when non-empty, local includes will be used. + std::string gmock_search_path; + // *EXPERIMENTAL* Additional include files in grpc.pb.h + std::vector additional_header_includes; + // By default, use "pb.h" + std::string message_header_extension; + // Whether to include headers corresponding to imports in source file. + bool include_import_headers; + // Whether to expose synchronous server API. + bool allow_sync_server_api; + // Whether to generate completion queue API. + bool allow_cq_api; + // whether to add deprecated warning for services + bool allow_deprecated; +}; + +// Return the prologue of the generated header file. +std::string GetHeaderPrologue(grpc_generator::File* file, + const Parameters& params); + +// Return the includes needed for generated header file. +std::string GetHeaderIncludes(grpc_generator::File* file, + const Parameters& params); + +// Return the includes needed for generated source file. +std::string GetSourceIncludes(grpc_generator::File* file, + const Parameters& params); + +// Return the epilogue of the generated header file. +std::string GetHeaderEpilogue(grpc_generator::File* file, + const Parameters& params); + +// Return the prologue of the generated source file. +std::string GetSourcePrologue(grpc_generator::File* file, + const Parameters& params); + +// Return the services for generated header file. +std::string GetHeaderServices(grpc_generator::File* file, + const Parameters& params); + +// Return the services for generated source file. +std::string GetSourceServices(grpc_generator::File* file, + const Parameters& params); + +// Return the epilogue of the generated source file. +std::string GetSourceEpilogue(grpc_generator::File* file, + const Parameters& params); + +// Return the prologue of the generated mock file. +std::string GetMockPrologue(grpc_generator::File* file, + const Parameters& params); + +// Return the includes needed for generated mock file. +std::string GetMockIncludes(grpc_generator::File* file, + const Parameters& params); + +// Return the services for generated mock file. +std::string GetMockServices(grpc_generator::File* file, + const Parameters& params); + +// Return the epilogue of generated mock file. +std::string GetMockEpilogue(grpc_generator::File* file, + const Parameters& params); + +// Return the prologue of the generated mock file. +std::string GetMockPrologue(grpc_generator::File* file, + const Parameters& params); + +// Return the includes needed for generated mock file. +std::string GetMockIncludes(grpc_generator::File* file, + const Parameters& params); + +// Return the services for generated mock file. +std::string GetMockServices(grpc_generator::File* file, + const Parameters& params); + +// Return the epilogue of generated mock file. +std::string GetMockEpilogue(grpc_generator::File* file, + const Parameters& params); + +} // namespace grpc_cpp_generator + +#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H diff --git a/plugin/src/compiler/cpp_generator_helpers.h b/plugin/src/compiler/cpp_generator_helpers.h new file mode 100644 index 0000000..1658ee6 --- /dev/null +++ b/plugin/src/compiler/cpp_generator_helpers.h @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_cpp_generator { + +inline std::string DotsToColons(const std::string& name) { + return grpc_generator::StringReplace(name, ".", "::"); +} + +inline std::string DotsToUnderscores(const std::string& name) { + return grpc_generator::StringReplace(name, ".", "_"); +} + +inline std::string ClassName(const grpc::protobuf::Descriptor* descriptor, + bool qualified) { + // Find "outer", the descriptor of the top-level message in which + // "descriptor" is embedded. + const grpc::protobuf::Descriptor* outer = descriptor; + while (outer->containing_type() != NULL) outer = outer->containing_type(); + + std::string outer_name(outer->full_name()); + std::string inner_name(descriptor->full_name().substr(outer_name.size())); + + if (qualified) { + return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name); + } else { + return std::string(outer->name()) + DotsToUnderscores(inner_name); + } +} + +// Get leading or trailing comments in a string. Comment lines start with "// ". +// Leading detached comments are put in front of leading comments. +template +inline std::string GetCppComments(const DescriptorType* desc, bool leading) { + return grpc_generator::GetPrefixedComments(desc, leading, "//"); +} + +} // namespace grpc_cpp_generator + +#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/cpp_plugin.cc b/plugin/src/compiler/cpp_plugin.cc new file mode 100644 index 0000000..2de2745 --- /dev/null +++ b/plugin/src/compiler/cpp_plugin.cc @@ -0,0 +1,26 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Generates cpp gRPC service interface out of Protobuf IDL. +// +#include "src/compiler/cpp_plugin.h" + +int main(int argc, char* argv[]) { + CppGrpcGenerator generator; + return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); +} diff --git a/plugin/src/compiler/cpp_plugin.h b/plugin/src/compiler/cpp_plugin.h new file mode 100644 index 0000000..2cccbe6 --- /dev/null +++ b/plugin/src/compiler/cpp_plugin.h @@ -0,0 +1,206 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H +#define GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H + +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/cpp_generator.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/protobuf_plugin.h" + +// Cpp Generator for Protobug IDL +class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { + public: + CppGrpcGenerator() {} + virtual ~CppGrpcGenerator() {} + + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT + | FEATURE_SUPPORTS_EDITIONS +#endif + ; + } +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT + grpc::protobuf::Edition GetMinimumEdition() const override { + return grpc::protobuf::Edition::EDITION_PROTO2; + } + grpc::protobuf::Edition GetMaximumEdition() const override { + // TODO(yuanweiz): Remove when the protobuf is updated to a version + // that supports edition 2024. +#if !defined(GOOGLE_PROTOBUF_VERSION) || GOOGLE_PROTOBUF_VERSION >= 6032000 + return grpc::protobuf::Edition::EDITION_2024; +#else + return grpc::protobuf::Edition::EDITION_2023; +#endif + } +#endif + + virtual bool Generate(const grpc::protobuf::FileDescriptor* file, + const std::string& parameter, + grpc::protobuf::compiler::GeneratorContext* context, + std::string* error) const override { + if (file->options().cc_generic_services()) { + *error = + "cpp grpc proto compiler plugin does not work with generic " + "services. To generate cpp grpc APIs, please set \"" + "cc_generic_service = false\"."; + return false; + } + + grpc_cpp_generator::Parameters generator_parameters; + generator_parameters.use_system_headers = true; + generator_parameters.generate_mock_code = false; + generator_parameters.include_import_headers = false; + generator_parameters.allow_sync_server_api = true; + generator_parameters.allow_cq_api = true; + generator_parameters.allow_deprecated = false; + + ProtoBufFile pbfile(file); + + if (!parameter.empty()) { + std::vector parameters_list = + grpc_generator::tokenize(parameter, ","); + for (auto parameter_string = parameters_list.begin(); + parameter_string != parameters_list.end(); parameter_string++) { + std::vector param = + grpc_generator::tokenize(*parameter_string, "="); + if (param[0] == "services_namespace") { + generator_parameters.services_namespace = param[1]; + } else if (param[0] == "use_system_headers") { + if (param[1] == "true") { + generator_parameters.use_system_headers = true; + } else if (param[1] == "false") { + generator_parameters.use_system_headers = false; + } else { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "grpc_search_path") { + generator_parameters.grpc_search_path = param[1]; + } else if (param[0] == "generate_mock_code") { + if (param[1] == "true") { + generator_parameters.generate_mock_code = true; + } else if (param[1] != "false") { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "allow_sync_server_api") { + if (param[1] == "true") { + generator_parameters.allow_sync_server_api = true; + } else if (param[1] == "false") { + generator_parameters.allow_sync_server_api = false; + } else { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "allow_cq_api") { + if (param[1] == "true") { + generator_parameters.allow_cq_api = true; + } else if (param[1] == "false") { + generator_parameters.allow_cq_api = false; + } else { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "gmock_search_path") { + generator_parameters.gmock_search_path = param[1]; + } else if (param[0] == "additional_header_includes") { + generator_parameters.additional_header_includes = + grpc_generator::tokenize(param[1], ":"); + } else if (param[0] == "message_header_extension") { + generator_parameters.message_header_extension = param[1]; + } else if (param[0] == "include_import_headers") { + if (param[1] == "true") { + generator_parameters.include_import_headers = true; + } else if (param[1] != "false") { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "allow_deprecated") { + if (param[1] == "true") { + generator_parameters.allow_deprecated = true; + } else if (param[1] == "false") { + generator_parameters.allow_deprecated = false; + } else { + *error = std::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else { + *error = std::string("Unknown parameter: ") + *parameter_string; + return false; + } + } + } + + std::string file_name = + grpc_generator::StripProto(std::string(file->name())); + + std::string header_code = + grpc_cpp_generator::GetHeaderPrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters); + std::unique_ptr header_output( + context->Open(file_name + ".grpc.pb.h")); + grpc::protobuf::io::CodedOutputStream header_coded_out(header_output.get()); + header_coded_out.WriteRaw(header_code.data(), header_code.size()); + + std::string source_code = + grpc_cpp_generator::GetSourcePrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters); + std::unique_ptr source_output( + context->Open(file_name + ".grpc.pb.cc")); + grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); + source_coded_out.WriteRaw(source_code.data(), source_code.size()); + + if (!generator_parameters.generate_mock_code) { + return true; + } + std::string mock_code = + grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters); + std::unique_ptr mock_output( + context->Open(file_name + "_mock.grpc.pb.h")); + grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get()); + mock_coded_out.WriteRaw(mock_code.data(), mock_code.size()); + + return true; + } + + private: + // Insert the given code into the given file at the given insertion point. + void Insert(grpc::protobuf::compiler::GeneratorContext* context, + const std::string& filename, const std::string& insertion_point, + const std::string& code) const { + std::unique_ptr output( + context->OpenForInsert(filename, insertion_point)); + grpc::protobuf::io::CodedOutputStream coded_out(output.get()); + coded_out.WriteRaw(code.data(), code.size()); + } +}; + +#endif // GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H diff --git a/plugin/src/compiler/csharp_generator.h b/plugin/src/compiler/csharp_generator.h new file mode 100644 index 0000000..f2a6cf2 --- /dev/null +++ b/plugin/src/compiler/csharp_generator.h @@ -0,0 +1,32 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_csharp_generator { + +std::string GetServices(const grpc::protobuf::FileDescriptor* file, + bool generate_client, bool generate_server, + bool internal_access, bool append_async_suffix); + +} // namespace grpc_csharp_generator + +#endif // GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_H diff --git a/plugin/src/compiler/csharp_generator_helpers.h b/plugin/src/compiler/csharp_generator_helpers.h new file mode 100644 index 0000000..6d98099 --- /dev/null +++ b/plugin/src/compiler/csharp_generator_helpers.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_HELPERS_H + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_csharp_generator { + +inline bool ServicesFilename(const grpc::protobuf::FileDescriptor* file, + const std::string& file_suffix, + const bool base_namespace_present, + const std::string& base_namespace, + std::string& out_file, std::string* error) { + // Support for base_namespace option is **experimental**. + // + // If base_namespace is provided then slightly different name mangling + // is used to generate the service file name. This is because this + // uses common code with protoc. For most file names this will not + // make a difference (only files with punctuation or numbers in the + // name.) + // Otherwise the behavior remains the same as before. + if (!base_namespace_present) { + out_file = grpc_generator::FileNameInUpperCamel(file, false) + file_suffix; + } else { + out_file = GRPC_CUSTOM_CSHARP_GETOUTPUTFILE(file, file_suffix, true, + base_namespace, error); + if (out_file.empty()) { + return false; + } + } + return true; +} + +// Get leading or trailing comments in a string. Comment lines start with "// ". +// Leading detached comments are put in front of leading comments. +template +inline std::string GetCsharpComments(const DescriptorType* desc, bool leading) { + return grpc_generator::GetPrefixedComments(desc, leading, "//"); +} + +} // namespace grpc_csharp_generator + +#endif // GRPC_INTERNAL_COMPILER_CSHARP_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/generator_helpers.h b/plugin/src/compiler/generator_helpers.h new file mode 100644 index 0000000..8839c04 --- /dev/null +++ b/plugin/src/compiler/generator_helpers.h @@ -0,0 +1,286 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H + +#include +#include +#include +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/proto_parser_helper.h" + +namespace grpc_generator { + +inline std::string ToLower(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::tolower(c); }); + return s; +} + +inline bool StripSuffix(std::string* filename, const std::string& suffix) { + if (filename->length() >= suffix.length()) { + size_t suffix_pos = filename->length() - suffix.length(); + std::string filename_suffix = filename->substr(suffix_pos); + + if (ToLower(filename_suffix) == ToLower(suffix)) { + filename->resize(filename->size() - suffix.size()); + return true; + } + } + + return false; +} + +inline bool StripPrefix(std::string* name, const std::string& prefix) { + if (name->length() >= prefix.length()) { + if (name->substr(0, prefix.size()) == prefix) { + *name = name->substr(prefix.size()); + return true; + } + } + return false; +} + +inline std::string StripProto(std::string filename) { + if (!StripSuffix(&filename, ".protodevel")) { + StripSuffix(&filename, ".proto"); + } + return filename; +} + +inline std::string StringReplace(std::string str, const std::string& from, + const std::string& to, bool replace_all) { + size_t pos = 0; + + do { + pos = str.find(from, pos); + if (pos == std::string::npos) { + break; + } + str.replace(pos, from.length(), to); + pos += to.length(); + } while (replace_all); + + return str; +} + +inline std::string StringReplace(std::string str, const std::string& from, + const std::string& to) { + return StringReplace(str, from, to, true); +} + +inline std::vector tokenize(const std::string& input, + const std::string& delimiters) { + std::vector tokens; + size_t pos, last_pos = 0; + + for (;;) { + bool done = false; + pos = input.find_first_of(delimiters, last_pos); + if (pos == std::string::npos) { + done = true; + pos = input.length(); + } + + tokens.push_back(input.substr(last_pos, pos - last_pos)); + if (done) return tokens; + + last_pos = pos + 1; + } +} + +inline std::string CapitalizeFirstLetter(std::string s) { + if (s.empty()) { + return s; + } + s[0] = ::toupper(s[0]); + return s; +} + +inline std::string LowercaseFirstLetter(std::string s) { + if (s.empty()) { + return s; + } + s[0] = ::tolower(s[0]); + return s; +} + +inline std::string LowerUnderscoreToUpperCamel(std::string str) { + std::vector tokens = tokenize(str, "_"); + std::string result = ""; + for (unsigned int i = 0; i < tokens.size(); i++) { + result += CapitalizeFirstLetter(tokens[i]); + } + return result; +} + +inline std::string FileNameInUpperCamel( + const grpc::protobuf::FileDescriptor* file, bool include_package_path) { + std::vector tokens = + tokenize(StripProto(std::string(file->name())), "/"); + std::string result = ""; + if (include_package_path) { + for (unsigned int i = 0; i < tokens.size() - 1; i++) { + result += tokens[i] + "/"; + } + } + result += LowerUnderscoreToUpperCamel(tokens.back()); + return result; +} + +inline std::string FileNameInUpperCamel( + const grpc::protobuf::FileDescriptor* file) { + return FileNameInUpperCamel(file, true); +} + +enum MethodType { + METHODTYPE_NO_STREAMING, + METHODTYPE_CLIENT_STREAMING, + METHODTYPE_SERVER_STREAMING, + METHODTYPE_BIDI_STREAMING +}; + +inline MethodType GetMethodType( + const grpc::protobuf::MethodDescriptor* method) { + if (method->client_streaming()) { + if (method->server_streaming()) { + return METHODTYPE_BIDI_STREAMING; + } else { + return METHODTYPE_CLIENT_STREAMING; + } + } else { + if (method->server_streaming()) { + return METHODTYPE_SERVER_STREAMING; + } else { + return METHODTYPE_NO_STREAMING; + } + } +} + +inline void Split(const std::string& s, char /*delim*/, + std::vector* append_to) { + std::istringstream iss(s); + std::string piece; + while (std::getline(iss, piece)) { + append_to->push_back(piece); + } +} + +enum CommentType { + COMMENTTYPE_LEADING, + COMMENTTYPE_TRAILING, + COMMENTTYPE_LEADING_DETACHED +}; + +// Get all the raw comments and append each line without newline to out. +template +inline void GetComment(const DescriptorType* desc, CommentType type, + std::vector* out) { + grpc::protobuf::SourceLocation location; + if (!desc->GetSourceLocation(&location)) { + return; + } + if (type == COMMENTTYPE_LEADING || type == COMMENTTYPE_TRAILING) { + const std::string& comments = type == COMMENTTYPE_LEADING + ? location.leading_comments + : location.trailing_comments; + Split(comments, '\n', out); + } else if (type == COMMENTTYPE_LEADING_DETACHED) { + for (unsigned int i = 0; i < location.leading_detached_comments.size(); + i++) { + Split(location.leading_detached_comments[i], '\n', out); + out->push_back(""); + } + } else { + std::cerr << "Unknown comment type " << type << std::endl; + abort(); + } +} + +// Each raw comment line without newline is appended to out. +// For file level leading and detached leading comments, we return comments +// above syntax line. Return nothing for trailing comments. +template <> +inline void GetComment(const grpc::protobuf::FileDescriptor* desc, + CommentType type, std::vector* out) { + if (type == COMMENTTYPE_TRAILING) { + return; + } + grpc::protobuf::SourceLocation location; + std::vector path; + path.push_back(grpc::protobuf::FileDescriptorProto::kSyntaxFieldNumber); + if (!desc->GetSourceLocation(path, &location)) { + return; + } + if (type == COMMENTTYPE_LEADING) { + Split(location.leading_comments, '\n', out); + } else if (type == COMMENTTYPE_LEADING_DETACHED) { + for (unsigned int i = 0; i < location.leading_detached_comments.size(); + i++) { + Split(location.leading_detached_comments[i], '\n', out); + out->push_back(""); + } + } else { + std::cerr << "Unknown comment type " << type << std::endl; + abort(); + } +} + +// Add prefix and newline to each comment line and concatenate them together. +// Make sure there is a space after the prefix unless the line is empty. +inline std::string GenerateCommentsWithPrefix( + const std::vector& in, const std::string& prefix) { + std::ostringstream oss; + for (auto it = in.begin(); it != in.end(); it++) { + const std::string& elem = *it; + if (elem.empty()) { + oss << prefix << "\n"; + } else if (elem[0] == ' ') { + oss << prefix << EscapeVariableDelimiters(elem) << "\n"; + } else { + oss << prefix << " " << EscapeVariableDelimiters(elem) << "\n"; + } + } + return oss.str(); +} + +template +inline std::string GetPrefixedComments(const DescriptorType* desc, bool leading, + const std::string& prefix) { + std::vector out; + if (leading) { + grpc_generator::GetComment( + desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &out); + std::vector leading; + grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING, + &leading); + out.insert(out.end(), leading.begin(), leading.end()); + } else { + grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING, + &out); + } + return GenerateCommentsWithPrefix(out, prefix); +} + +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/node_generator.h b/plugin/src/compiler/node_generator.h new file mode 100644 index 0000000..48709ba --- /dev/null +++ b/plugin/src/compiler/node_generator.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_node_generator { + +// Contains all the parameters that are parsed from the command line. +struct Parameters { + // Sets the earliest version of nodejs that needs to be supported. + int minimum_node_version; +}; + +std::string GenerateFile(const grpc::protobuf::FileDescriptor* file, + const Parameters& params); + +} // namespace grpc_node_generator + +#endif // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H diff --git a/plugin/src/compiler/node_generator_helpers.h b/plugin/src/compiler/node_generator_helpers.h new file mode 100644 index 0000000..65fc0a0 --- /dev/null +++ b/plugin/src/compiler/node_generator_helpers.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_node_generator { + +inline std::string GetJSServiceFilename(const std::string& filename) { + return grpc_generator::StripProto(filename) + "_grpc_pb.js"; +} + +// Get leading or trailing comments in a string. Comment lines start with "// ". +// Leading detached comments are put in front of leading comments. +template +inline std::string GetNodeComments(const DescriptorType* desc, bool leading) { + return grpc_generator::GetPrefixedComments(desc, leading, "//"); +} + +} // namespace grpc_node_generator + +#endif // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/objective_c_generator.h b/plugin/src/compiler/objective_c_generator.h new file mode 100644 index 0000000..e010d9a --- /dev/null +++ b/plugin/src/compiler/objective_c_generator.h @@ -0,0 +1,59 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_objective_c_generator { + +struct Parameters { + // Do not generate V1 interface and implementation + bool no_v1_compatibility; +}; + +using ::grpc::protobuf::FileDescriptor; +using ::grpc::protobuf::ServiceDescriptor; + +// Returns forward declaration of classes in the generated header file. +std::string GetAllMessageClasses(const FileDescriptor* file); + +// Returns the content to be included defining the @protocol segment at the +// insertion point of the generated implementation file. This interface is +// legacy and for backwards compatibility. +std::string GetProtocol(const ServiceDescriptor* service, + const Parameters& generator_params); + +// Returns the content to be included defining the @protocol segment at the +// insertion point of the generated implementation file. +std::string GetV2Protocol(const ServiceDescriptor* service); + +// Returns the content to be included defining the @interface segment at the +// insertion point of the generated implementation file. +std::string GetInterface(const ServiceDescriptor* service, + const Parameters& generator_params); + +// Returns the content to be included in the "global_scope" insertion point of +// the generated implementation file. +std::string GetSource(const ServiceDescriptor* service, + const Parameters& generator_params); + +} // namespace grpc_objective_c_generator + +#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H diff --git a/plugin/src/compiler/objective_c_generator_helpers.h b/plugin/src/compiler/objective_c_generator_helpers.h new file mode 100644 index 0000000..0b390b5 --- /dev/null +++ b/plugin/src/compiler/objective_c_generator_helpers.h @@ -0,0 +1,125 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H + +#include + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_objective_c_generator { + +using ::grpc::protobuf::FileDescriptor; +using ::grpc::protobuf::MethodDescriptor; +using ::grpc::protobuf::ServiceDescriptor; + +inline std::string MessageHeaderName(const FileDescriptor* file) { + return google::protobuf::compiler::objectivec::FilePath(file) + ".pbobjc.h"; +} + +inline bool AsciiIsUpper(char c) { return c >= 'A' && c <= 'Z'; } + +inline ::std::string ServiceClassName(const ServiceDescriptor* service) { + const FileDescriptor* file = service->file(); + ::std::string prefix = + google::protobuf::compiler::objectivec::FileClassPrefix(file); + ::std::string class_name(service->name()); + // We add the prefix in the cases where the string is missing a prefix. + // We define "missing a prefix" as where 'input': + // a) Doesn't start with the prefix or + // b) Isn't equivalent to the prefix or + // c) Has the prefix, but the letter after the prefix is lowercase + // This is the same semantics as the Objective-C protoc. + // https://github.com/protocolbuffers/protobuf/blob/c160ae52a91ca4c76936531d68cc846f8230dbb1/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc#L389 + if (class_name.rfind(prefix, 0) == 0) { + if (class_name.length() == prefix.length() || + !AsciiIsUpper(class_name[prefix.length()])) { + return prefix + class_name; + } else { + return class_name; + } + } else { + return prefix + class_name; + } +} + +inline ::std::string LocalImport(const ::std::string& import) { + return ::std::string("#import \"" + import + "\"\n"); +} + +inline ::std::string FrameworkImport(const ::std::string& import, + const ::std::string& framework) { + // Flattens the directory structure: grab the file name only + std::size_t pos = import.rfind("/"); + // If pos is npos, pos + 1 is 0, which gives us the entire string, + // so there's no need to check that + ::std::string filename = import.substr(pos + 1, import.size() - (pos + 1)); + return ::std::string("#import <" + framework + "/" + filename + ">\n"); +} + +inline ::std::string SystemImport(const ::std::string& import) { + return ::std::string("#import <" + import + ">\n"); +} + +inline ::std::string PreprocConditional(::std::string symbol, bool invert) { + return invert ? "!defined(" + symbol + ") || !" + symbol + : "defined(" + symbol + ") && " + symbol; +} + +inline ::std::string PreprocIf(const ::std::string& symbol, + const ::std::string& if_true) { + return ::std::string("#if " + PreprocConditional(symbol, false) + "\n" + + if_true + "#endif\n"); +} + +inline ::std::string PreprocIfNot(const ::std::string& symbol, + const ::std::string& if_true) { + return ::std::string("#if " + PreprocConditional(symbol, true) + "\n" + + if_true + "#endif\n"); +} + +inline ::std::string PreprocIfElse(const ::std::string& symbol, + const ::std::string& if_true, + const ::std::string& if_false) { + return ::std::string("#if " + PreprocConditional(symbol, false) + "\n" + + if_true + "#else\n" + if_false + "#endif\n"); +} + +inline ::std::string PreprocIfNotElse(const ::std::string& symbol, + const ::std::string& if_true, + const ::std::string& if_false) { + return ::std::string("#if " + PreprocConditional(symbol, true) + "\n" + + if_true + "#else\n" + if_false + "#endif\n"); +} + +inline bool ShouldIncludeMethod(const MethodDescriptor* method) { +#ifdef OBJC_SKIP_METHODS_WITHOUT_MESSAGE_PREFIX + return (method->input_type()->file()->options().has_objc_class_prefix() && + method->output_type()->file()->options().has_objc_class_prefix()); +#else + (void)method; // to silence the unused warning for method. + return true; +#endif +} + +} // namespace grpc_objective_c_generator +#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/php_generator.h b/plugin/src/compiler/php_generator.h new file mode 100644 index 0000000..f775c8f --- /dev/null +++ b/plugin/src/compiler/php_generator.h @@ -0,0 +1,33 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PHP_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PHP_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_php_generator { + +std::string GenerateFile(const grpc::protobuf::FileDescriptor* file, + const grpc::protobuf::ServiceDescriptor* service, + const std::string& class_suffix, + bool is_server = false); + +} // namespace grpc_php_generator + +#endif // GRPC_INTERNAL_COMPILER_PHP_GENERATOR_H diff --git a/plugin/src/compiler/php_generator_helpers.h b/plugin/src/compiler/php_generator_helpers.h new file mode 100644 index 0000000..937e729 --- /dev/null +++ b/plugin/src/compiler/php_generator_helpers.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PHP_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_PHP_GENERATOR_HELPERS_H + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_php_generator { + +inline std::string GetPHPServiceClassname( + const grpc::protobuf::ServiceDescriptor* service, + const std::string& class_suffix, bool is_server) { + return std::string(service->name()) + + (class_suffix == "" ? (is_server ? "" : "Client") : class_suffix) + + (is_server ? "Stub" : ""); +} + +// ReplaceAll replaces all instances of search with replace in s. +inline std::string ReplaceAll(std::string s, const std::string& search, + const std::string& replace) { + size_t pos = 0; + while ((pos = s.find(search, pos)) != std::string::npos) { + s.replace(pos, search.length(), replace); + pos += replace.length(); + } + return s; +} + +inline std::string GetPHPServiceFilename( + const grpc::protobuf::FileDescriptor* file, + const grpc::protobuf::ServiceDescriptor* service, + const std::string& class_suffix, bool is_server) { + std::ostringstream oss; + if (file->options().has_php_namespace()) { + oss << ReplaceAll(file->options().php_namespace(), "\\", "/"); + } else { + std::vector tokens = + grpc_generator::tokenize(std::string(file->package()), "."); + for (unsigned int i = 0; i < tokens.size(); i++) { + oss << (i == 0 ? "" : "/") + << grpc_generator::CapitalizeFirstLetter(tokens[i]); + } + } + std::string path = oss.str(); + if (!path.empty()) path += "/"; + path += GetPHPServiceClassname(service, class_suffix, is_server) + ".php"; + return path; +} + +// Get leading or trailing comments in a string. Comment lines start with "// ". +// Leading detached comments are put in front of leading comments. +template +inline std::string GetPHPComments(const DescriptorType* desc, + std::string prefix) { + return ReplaceAll(grpc_generator::GetPrefixedComments(desc, true, prefix), + "*/", "*/"); +} + +} // namespace grpc_php_generator + +#endif // GRPC_INTERNAL_COMPILER_PHP_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/proto_parser_helper.cc b/plugin/src/compiler/proto_parser_helper.cc new file mode 100644 index 0000000..b094339 --- /dev/null +++ b/plugin/src/compiler/proto_parser_helper.cc @@ -0,0 +1,29 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +namespace grpc_generator { + +std::string EscapeVariableDelimiters(const std::string& original) { + std::string mut_str = original; + size_t index = 0; + while ((index = mut_str.find('$', index)) != std::string::npos) { + mut_str.replace(index, 1, "$$"); + index += 2; + } + return mut_str; +} + +} // namespace grpc_generator diff --git a/plugin/src/compiler/proto_parser_helper.h b/plugin/src/compiler/proto_parser_helper.h new file mode 100644 index 0000000..8177546 --- /dev/null +++ b/plugin/src/compiler/proto_parser_helper.h @@ -0,0 +1,22 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +namespace grpc_generator { + +// Replaces '$' with "$$", useful in proto comments. +std::string EscapeVariableDelimiters(const std::string& original); + +} // namespace grpc_generator diff --git a/plugin/src/compiler/protobuf_plugin.h b/plugin/src/compiler/protobuf_plugin.h new file mode 100644 index 0000000..6d26143 --- /dev/null +++ b/plugin/src/compiler/protobuf_plugin.h @@ -0,0 +1,207 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H +#define GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H + +#include + +#include "src/compiler/config.h" +#include "src/compiler/cpp_generator_helpers.h" +#include "src/compiler/python_generator_helpers.h" +#include "src/compiler/python_private_generator.h" +#include "src/compiler/schema_interface.h" + +// Get leading or trailing comments in a string. +template +inline std::string GetCommentsHelper(const DescriptorType* desc, bool leading, + const std::string& prefix) { + return grpc_generator::GetPrefixedComments(desc, leading, prefix); +} + +class ProtoBufMethod : public grpc_generator::Method { + public: + ProtoBufMethod(const grpc::protobuf::MethodDescriptor* method) + : method_(method) {} + + std::string name() const { return std::string(method_->name()); } + + std::string input_type_name() const { + return grpc_cpp_generator::ClassName(method_->input_type(), true); + } + std::string output_type_name() const { + return grpc_cpp_generator::ClassName(method_->output_type(), true); + } + + std::string get_input_type_name() const { + return std::string(method_->input_type()->file()->name()); + } + std::string get_output_type_name() const { + return std::string(method_->output_type()->file()->name()); + } + + // TODO(https://github.com/grpc/grpc/issues/18800): Clean this up. + bool get_module_and_message_path_input( + std::string* str, std::string generator_file_name, + bool generate_in_pb2_grpc, std::string import_prefix, + const std::vector& prefixes_to_filter) const final { + return grpc_python_generator::GetModuleAndMessagePath( + method_->input_type(), str, generator_file_name, generate_in_pb2_grpc, + import_prefix, prefixes_to_filter); + } + + bool get_module_and_message_path_output( + std::string* str, std::string generator_file_name, + bool generate_in_pb2_grpc, std::string import_prefix, + const std::vector& prefixes_to_filter) const final { + return grpc_python_generator::GetModuleAndMessagePath( + method_->output_type(), str, generator_file_name, generate_in_pb2_grpc, + import_prefix, prefixes_to_filter); + } + + bool NoStreaming() const { + return !method_->client_streaming() && !method_->server_streaming(); + } + + bool ClientStreaming() const { return method_->client_streaming(); } + + bool ServerStreaming() const { return method_->server_streaming(); } + + bool BidiStreaming() const { + return method_->client_streaming() && method_->server_streaming(); + } + + std::string GetLeadingComments(const std::string prefix) const { + return GetCommentsHelper(method_, true, prefix); + } + + std::string GetTrailingComments(const std::string prefix) const { + return GetCommentsHelper(method_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(method_); + } + + private: + const grpc::protobuf::MethodDescriptor* method_; +}; + +class ProtoBufService : public grpc_generator::Service { + public: + ProtoBufService(const grpc::protobuf::ServiceDescriptor* service) + : service_(service) {} + + std::string name() const { return std::string(service_->name()); } + bool is_deprecated() const { return service_->options().deprecated(); } + + int method_count() const { return service_->method_count(); } + std::unique_ptr method(int i) const { + return std::unique_ptr( + new ProtoBufMethod(service_->method(i))); + } + + std::string GetLeadingComments(const std::string prefix) const { + return GetCommentsHelper(service_, true, prefix); + } + + std::string GetTrailingComments(const std::string prefix) const { + return GetCommentsHelper(service_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(service_); + } + + private: + const grpc::protobuf::ServiceDescriptor* service_; +}; + +class ProtoBufPrinter : public grpc_generator::Printer { + public: + ProtoBufPrinter(std::string* str) + : output_stream_(str), printer_(&output_stream_, '$') {} + + void Print(const std::map& vars, + const char* string_template) { + printer_.Print(vars, string_template); + } + + void Print(const char* string) { printer_.Print(string); } + void PrintRaw(const char* string) { printer_.PrintRaw(string); } + void Indent() { printer_.Indent(); } + void Outdent() { printer_.Outdent(); } + + private: + grpc::protobuf::io::StringOutputStream output_stream_; + grpc::protobuf::io::Printer printer_; +}; + +class ProtoBufFile : public grpc_generator::File { + public: + ProtoBufFile(const grpc::protobuf::FileDescriptor* file) : file_(file) {} + + std::string filename() const { return std::string(file_->name()); } + std::string filename_without_ext() const { + return grpc_generator::StripProto(filename()); + } + + std::string package() const { return std::string(file_->package()); } + std::vector package_parts() const { + return grpc_generator::tokenize(package(), "."); + } + + std::string additional_headers() const { return ""; } + + int service_count() const { return file_->service_count(); } + std::unique_ptr service(int i) const { + return std::unique_ptr( + new ProtoBufService(file_->service(i))); + } + + std::unique_ptr CreatePrinter( + std::string* str) const { + return std::unique_ptr(new ProtoBufPrinter(str)); + } + + std::string GetLeadingComments(const std::string prefix) const { + return GetCommentsHelper(file_, true, prefix); + } + + std::string GetTrailingComments(const std::string prefix) const { + return GetCommentsHelper(file_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(file_); + } + + vector GetImportNames() const { + vector proto_names; + for (int i = 0; i < file_->dependency_count(); ++i) { + const auto& dep = *file_->dependency(i); + proto_names.emplace_back(dep.name()); + } + return proto_names; + } + + private: + const grpc::protobuf::FileDescriptor* file_; +}; + +#endif // GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H diff --git a/plugin/src/compiler/python_generator.h b/plugin/src/compiler/python_generator.h new file mode 100644 index 0000000..10ac03b --- /dev/null +++ b/plugin/src/compiler/python_generator.h @@ -0,0 +1,83 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H + +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +// Data pertaining to configuration of the generator with respect to anything +// that may be used internally at Google. +struct GeneratorConfiguration { + GeneratorConfiguration(); + GeneratorConfiguration(std::string version); + std::string grpc_package_root; + // TODO(https://github.com/grpc/grpc/issues/8622): Drop this. + std::string beta_package_root; + // TODO(https://github.com/protocolbuffers/protobuf/issues/888): Drop this. + std::string import_prefix; + std::string grpc_tools_version; + std::vector prefixes_to_filter; +}; + +class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { + public: + PythonGrpcGenerator(const GeneratorConfiguration& config); + ~PythonGrpcGenerator(); + + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT + | FEATURE_SUPPORTS_EDITIONS +#endif + ; + } + +#ifdef GRPC_PROTOBUF_EDITION_SUPPORT + grpc::protobuf::Edition GetMinimumEdition() const override { + return grpc::protobuf::Edition::EDITION_PROTO2; + } + grpc::protobuf::Edition GetMaximumEdition() const override { + // TODO(yuanweiz): Remove when the protobuf is updated to a version + // that supports edition 2024. +#if !defined(GOOGLE_PROTOBUF_VERSION) || GOOGLE_PROTOBUF_VERSION >= 6032000 + return grpc::protobuf::Edition::EDITION_2024; +#else + return grpc::protobuf::Edition::EDITION_2023; +#endif + } +#endif + + bool Generate(const grpc::protobuf::FileDescriptor* file, + const std::string& parameter, + grpc::protobuf::compiler::GeneratorContext* context, + std::string* error) const override; + + private: + GeneratorConfiguration config_; +}; + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H diff --git a/plugin/src/compiler/python_generator_helpers.h b/plugin/src/compiler/python_generator_helpers.h new file mode 100644 index 0000000..6162fdc --- /dev/null +++ b/plugin/src/compiler/python_generator_helpers.h @@ -0,0 +1,162 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H + +#include +#include +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/python_generator.h" +#include "src/compiler/python_private_generator.h" + +using grpc::protobuf::Descriptor; +using grpc::protobuf::FileDescriptor; +using grpc::protobuf::MethodDescriptor; +using grpc::protobuf::ServiceDescriptor; +using grpc::protobuf::compiler::GeneratorContext; +using grpc::protobuf::io::CodedOutputStream; +using grpc::protobuf::io::Printer; +using grpc::protobuf::io::StringOutputStream; +using grpc::protobuf::io::ZeroCopyOutputStream; +using grpc_generator::StringReplace; +using grpc_generator::StripProto; +using std::vector; + +namespace grpc_python_generator { + +namespace { + +typedef vector DescriptorVector; +typedef vector StringVector; + +static std::string StripModulePrefixes( + const std::string& raw_module_name, + const std::vector& prefixes_to_filter) { + for (const auto& prefix : prefixes_to_filter) { + if (raw_module_name.rfind(prefix, 0) == 0) { + return raw_module_name.substr(prefix.size(), + raw_module_name.size() - prefix.size()); + } + } + return raw_module_name; +} + +// TODO(https://github.com/protocolbuffers/protobuf/issues/888): +// Export `ModuleName` from protobuf's +// `src/google/protobuf/compiler/python/python_generator.cc` file. +std::string ModuleName(const std::string& filename, + const std::string& import_prefix, + const std::vector& prefixes_to_filter) { + std::string basename = StripProto(filename); + basename = StringReplace(basename, "-", "_"); + basename = StringReplace(basename, "/", "."); + return StripModulePrefixes(import_prefix + basename + "_pb2", + prefixes_to_filter); +} + +// TODO(https://github.com/protocolbuffers/protobuf/issues/888): +// Export `ModuleAlias` from protobuf's +// `src/google/protobuf/compiler/python/python_generator.cc` file. +std::string ModuleAlias(const std::string& filename, + const std::string& import_prefix, + const std::vector& prefixes_to_filter) { + std::string module_name = + ModuleName(filename, import_prefix, prefixes_to_filter); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + module_name = StringReplace(module_name, "_", "__"); + module_name = StringReplace(module_name, ".", "_dot_"); + return module_name; +} + +bool GetModuleAndMessagePath( + const Descriptor* type, std::string* out, std::string generator_file_name, + bool generate_in_pb2_grpc, std::string& import_prefix, + const std::vector& prefixes_to_filter) { + const Descriptor* path_elem_type = type; + DescriptorVector message_path; + do { + message_path.push_back(path_elem_type); + path_elem_type = path_elem_type->containing_type(); + } while (path_elem_type); // implicit nullptr comparison; don't be explicit + std::string file_name(type->file()->name()); + static const int proto_suffix_length = strlen(".proto"); + if (!(file_name.size() > static_cast(proto_suffix_length) && + file_name.find_last_of(".proto") == file_name.size() - 1)) { + return false; + } + + std::string module; + if (generator_file_name != file_name || generate_in_pb2_grpc) { + module = ModuleAlias(file_name, import_prefix, prefixes_to_filter) + "."; + } else { + module = ""; + } + std::string message_type; + for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin(); + path_iter != message_path.rend(); ++path_iter) { + message_type += std::string((*path_iter)->name()) + "."; + } + // no pop_back prior to C++11 + message_type.resize(message_type.size() - 1); + *out = module + message_type; + return true; +} + +template +StringVector get_all_comments(const DescriptorType* descriptor) { + StringVector comments; + grpc_generator::GetComment( + descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments); + grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING, + &comments); + grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING, + &comments); + return comments; +} + +inline void Split(const std::string& s, char delim, + std::vector* append_to) { + if (s.empty()) { + // splitting an empty string logically produces a single-element list + append_to->emplace_back(); + } else { + auto current = s.begin(); + while (current < s.end()) { + const auto next = std::find(current, s.end(), delim); + append_to->emplace_back(current, next); + current = next; + if (current != s.end()) { + // it was the delimiter - need to be at the start of the next entry + ++current; + } + } + } +} + +} // namespace + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H diff --git a/plugin/src/compiler/python_private_generator.h b/plugin/src/compiler/python_private_generator.h new file mode 100644 index 0000000..62f9250 --- /dev/null +++ b/plugin/src/compiler/python_private_generator.h @@ -0,0 +1,87 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H + +#include +#include + +#include "src/compiler/python_generator.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +namespace { + +// Tucks all generator state in an anonymous namespace away from +// PythonGrpcGenerator and the header file, mostly to encourage future changes +// to not require updates to the grpcio-tools C++ code part. Assumes that it is +// only ever used from a single thread. +struct PrivateGenerator { + const GeneratorConfiguration& config; + const grpc_generator::File* file; + + bool generate_in_pb2_grpc; + + PrivateGenerator(const GeneratorConfiguration& config, + const grpc_generator::File* file); + + std::pair GetGrpcServices(); + + private: + bool PrintPreamble(grpc_generator::Printer* out); + bool PrintBetaPreamble(grpc_generator::Printer* out); + bool PrintGAServices(grpc_generator::Printer* out); + bool PrintBetaServices(grpc_generator::Printer* out); + + bool PrintAddServicerToServer( + const std::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out); + bool PrintServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintStub(const std::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + + bool PrintServiceClass(const std::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaServerFactory(const std::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaStub(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaStubFactory(const std::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + + // Get all comments (leading, leading_detached, trailing) and print them as a + // docstring. Any leading space of a line will be removed, but the line + // wrapping will not be changed. + void PrintAllComments(std::vector comments, + grpc_generator::Printer* out); +}; + +} // namespace + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H diff --git a/plugin/src/compiler/ruby_generator.h b/plugin/src/compiler/ruby_generator.h new file mode 100644 index 0000000..939b245 --- /dev/null +++ b/plugin/src/compiler/ruby_generator.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_ruby_generator { + +std::string GetServices(const grpc::protobuf::FileDescriptor* file); + +} // namespace grpc_ruby_generator + +#endif // GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H diff --git a/plugin/src/compiler/ruby_generator_helpers-inl.h b/plugin/src/compiler/ruby_generator_helpers-inl.h new file mode 100644 index 0000000..3d2d9bc --- /dev/null +++ b/plugin/src/compiler/ruby_generator_helpers-inl.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H +#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/ruby_generator_string-inl.h" + +namespace grpc_ruby_generator { + +inline bool ServicesFilename(const grpc::protobuf::FileDescriptor* file, + std::string* file_name_or_error) { + // Get output file name. + static const unsigned proto_suffix_length = 6; // length of ".proto" + if (file->name().size() > proto_suffix_length && + file->name().find_last_of(".proto") == file->name().size() - 1) { + *file_name_or_error = std::string(file->name().substr( + 0, file->name().size() - proto_suffix_length)) + + "_services_pb.rb"; + return true; + } else { + *file_name_or_error = "Invalid proto file name: must end with .proto"; + return false; + } +} + +inline std::string MessagesRequireName( + const grpc::protobuf::FileDescriptor* file) { + return Replace(std::string(file->name()), ".proto", "_pb"); +} + +// Get leading or trailing comments in a string. Comment lines start with "# ". +// Leading detached comments are put in front of leading comments. +template +inline std::string GetRubyComments(const DescriptorType* desc, bool leading) { + return grpc_generator::GetPrefixedComments(desc, leading, "#"); +} + +} // namespace grpc_ruby_generator + +#endif // GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H diff --git a/plugin/src/compiler/ruby_generator_map-inl.h b/plugin/src/compiler/ruby_generator_map-inl.h new file mode 100644 index 0000000..8951552 --- /dev/null +++ b/plugin/src/compiler/ruby_generator_map-inl.h @@ -0,0 +1,57 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H +#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H + +#include +#include +#include +#include // NOLINT +#include + +#include "src/compiler/config.h" + +using std::initializer_list; +using std::map; +using std::vector; + +namespace grpc_ruby_generator { + +// Converts an initializer list of the form { key0, value0, key1, value1, ... } +// into a map of key* to value*. Is merely a readability helper for later code. +inline std::map ListToDict( + const initializer_list& values) { + if (values.size() % 2 != 0) { + std::cerr << "Not every 'key' has a value in `values`." << std::endl; + } + std::map value_map; + auto value_iter = values.begin(); + for (unsigned i = 0; i < values.size() / 2; ++i) { + std::string key = *value_iter; + ++value_iter; + std::string value = *value_iter; + value_map[key] = value; + ++value_iter; + } + return value_map; +} + +} // namespace grpc_ruby_generator + +#endif // GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H diff --git a/plugin/src/compiler/ruby_generator_string-inl.h b/plugin/src/compiler/ruby_generator_string-inl.h new file mode 100644 index 0000000..ee7794a --- /dev/null +++ b/plugin/src/compiler/ruby_generator_string-inl.h @@ -0,0 +1,151 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H +#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H + +#include +#include +#include + +#include "src/compiler/config.h" + +using std::getline; +using std::transform; + +namespace grpc_ruby_generator { + +std::string RubifyConstant(const std::string& name); + +// Split splits a string using char into elems. +inline std::vector& Split(const std::string& s, char delim, + std::vector* elems) { + std::stringstream ss(s); + std::string item; + while (getline(ss, item, delim)) { + elems->push_back(item); + } + return *elems; +} + +// Split splits a string using char, returning the result in a vector. +inline std::vector Split(const std::string& s, char delim) { + std::vector elems; + Split(s, delim, &elems); + return elems; +} + +// Replace replaces from with to in s. +inline std::string Replace(std::string s, const std::string& from, + const std::string& to) { + size_t start_pos = s.find(from); + if (start_pos == std::string::npos) { + return s; + } + s.replace(start_pos, from.length(), to); + return s; +} + +// ReplaceAll replaces all instances of search with replace in s. +inline std::string ReplaceAll(std::string s, const std::string& search, + const std::string& replace) { + size_t pos = 0; + while ((pos = s.find(search, pos)) != std::string::npos) { + s.replace(pos, search.length(), replace); + pos += replace.length(); + } + return s; +} + +// ReplacePrefix replaces from with to in s if search is a prefix of s. +inline bool ReplacePrefix(std::string* s, const std::string& from, + const std::string& to) { + size_t start_pos = s->find(from); + if (start_pos == std::string::npos || start_pos != 0) { + return false; + } + s->replace(start_pos, from.length(), to); + return true; +} + +// Modularize converts a string into a ruby module compatible name +inline std::string Modularize(std::string s) { + if (s.empty()) { + return s; + } + std::string new_string = ""; + bool was_last_underscore = false; + new_string.append(1, ::toupper(s[0])); + for (std::string::size_type i = 1; i < s.size(); ++i) { + if (was_last_underscore && s[i] != '_') { + new_string.append(1, ::toupper(s[i])); + } else if (s[i] != '_') { + new_string.append(1, s[i]); + } + was_last_underscore = s[i] == '_'; + } + return new_string; +} + +// RubyPackage gets the ruby package in either proto or ruby_package format +inline std::string RubyPackage(const grpc::protobuf::FileDescriptor* file) { + std::string package_name(file->package()); + if (file->options().has_ruby_package()) { + package_name = file->options().ruby_package(); + + // If :: is in the package convert the Ruby formatted name + // -> A::B::C + // to use the dot separator notation + // -> A.B.C + package_name = ReplaceAll(package_name, "::", "."); + } + return package_name; +} + +// RubyTypeOf updates a proto type to the required ruby equivalent. +inline std::string RubyTypeOf(const grpc::protobuf::Descriptor* descriptor) { + std::string proto_type(descriptor->full_name()); + if (descriptor->file()->options().has_ruby_package()) { + // remove the leading package if present + ReplacePrefix(&proto_type, std::string(descriptor->file()->package()), ""); + ReplacePrefix(&proto_type, ".", ""); // remove the leading . (no package) + proto_type = RubyPackage(descriptor->file()) + "." + proto_type; + } + std::string res("." + proto_type); + if (res.find('.') == std::string::npos) { + return res; + } else { + std::vector prefixes_and_type = Split(res, '.'); + res.clear(); + for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) { + if (i != 0) { + res += "::"; // switch '.' to the ruby module delim + } + if (i < prefixes_and_type.size() - 1) { + res += Modularize(prefixes_and_type[i]); // capitalize pkgs + } else { + res += RubifyConstant(prefixes_and_type[i]); + } + } + return res; + } +} + +} // namespace grpc_ruby_generator + +#endif // GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H diff --git a/plugin/src/compiler/schema_interface.h b/plugin/src/compiler/schema_interface.h new file mode 100644 index 0000000..c9aa6f6 --- /dev/null +++ b/plugin/src/compiler/schema_interface.h @@ -0,0 +1,120 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H +#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H + +#include +#include +#include + +#include "src/compiler/config.h" + +#ifdef GRPC_CUSTOM_STRING +#warning GRPC_CUSTOM_STRING is no longer supported. Please use std::string. +#endif + +namespace grpc { + +// Using grpc::string and grpc::to_string is discouraged in favor of +// std::string and std::to_string. This is only for legacy code using +// them explicitly. +using std::string; // deprecated +using std::to_string; // deprecated + +} // namespace grpc + +namespace grpc_generator { + +// A common interface for objects having comments in the source. +// Return formatted comments to be inserted in generated code. +struct CommentHolder { + virtual ~CommentHolder() {} + virtual std::string GetLeadingComments(const std::string prefix) const = 0; + virtual std::string GetTrailingComments(const std::string prefix) const = 0; + virtual std::vector GetAllComments() const = 0; +}; + +// An abstract interface representing a method. +struct Method : public CommentHolder { + virtual ~Method() {} + + virtual std::string name() const = 0; + + virtual std::string input_type_name() const = 0; + virtual std::string output_type_name() const = 0; + + virtual bool get_module_and_message_path_input( + std::string* str, std::string generator_file_name, + bool generate_in_pb2_grpc, std::string import_prefix, + const std::vector& prefixes_to_filter) const = 0; + virtual bool get_module_and_message_path_output( + std::string* str, std::string generator_file_name, + bool generate_in_pb2_grpc, std::string import_prefix, + const std::vector& prefixes_to_filter) const = 0; + + virtual std::string get_input_type_name() const = 0; + virtual std::string get_output_type_name() const = 0; + virtual bool NoStreaming() const = 0; + virtual bool ClientStreaming() const = 0; + virtual bool ServerStreaming() const = 0; + virtual bool BidiStreaming() const = 0; +}; + +// An abstract interface representing a service. +struct Service : public CommentHolder { + virtual ~Service() {} + + virtual std::string name() const = 0; + virtual bool is_deprecated() const = 0; + + virtual int method_count() const = 0; + virtual std::unique_ptr method(int i) const = 0; +}; + +struct Printer { + virtual ~Printer() {} + + virtual void Print(const std::map& vars, + const char* template_string) = 0; + virtual void Print(const char* string) = 0; + virtual void PrintRaw(const char* string) = 0; + virtual void Indent() = 0; + virtual void Outdent() = 0; +}; + +// An interface that allows the source generated to be output using various +// libraries/idls/serializers. +struct File : public CommentHolder { + virtual ~File() {} + + virtual std::string filename() const = 0; + virtual std::string filename_without_ext() const = 0; + virtual std::string package() const = 0; + virtual std::vector package_parts() const = 0; + virtual std::string additional_headers() const = 0; + virtual std::vector GetImportNames() const { return {}; } + + virtual int service_count() const = 0; + virtual std::unique_ptr service(int i) const = 0; + + virtual std::unique_ptr CreatePrinter(std::string* str) const = 0; +}; +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H diff --git a/templates/greeter/build.mcpp.in b/templates/greeter/build.mcpp.in new file mode 100644 index 0000000..e2cb31c --- /dev/null +++ b/templates/greeter/build.mcpp.in @@ -0,0 +1,70 @@ +// gRPC codegen, as build-graph nodes. +// +// The two tools come from the dependency graph — `mcpp::dep_bin()` reads the +// path mcpp published after building them for THIS machine. Nothing here knows +// or cares whether they were built from source, taken from the global store, or +// pointed at by a `[tools.overrides]` escape hatch. +// +// The work is DECLARED, not done. Running protoc here would be the easy path +// and the wrong one: it would re-run on every prepare, for every .proto at +// once, serially, and a failure would surface as "build.mcpp exited 1". +// Declared as an action it becomes an edge in the build graph — it re-runs +// exactly when its .proto changes, in parallel with everything else, and a +// failure is attributed to the edge that produced it. +// +// Design notes: mcpplibs/grpc-m, +// .agents/docs/2026-08-05-codegen-ecosystem-design.md +#include +#include +import mcpp; + +int main() { + const std::string root = mcpp::manifest_dir(); + const std::string out = mcpp::out_dir(); + + const char* protoc = mcpp::dep_bin("protobuf", "protoc"); + const char* plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); + if (!protoc || !*protoc) { + std::fprintf(stderr, + "no protoc: declare compat.protobuf = { version = \"35.1\", " + "tools = [\"protoc\"] }\n"); + return 1; + } + if (!plugin || !*plugin) { + std::fprintf(stderr, + "no grpc_cpp_plugin: declare grpc-plugin = { ..., " + "tools = [\"grpc_cpp_plugin\"] }\n"); + return 1; + } + + const std::string proto = root + "/proto/helloworld.proto"; + + // ONE action, four declared outputs. protoc emits the message code and the + // service stubs in a single invocation, so splitting it would run protoc + // twice for no reason. + // + // The .pb.h / .grpc.pb.h are declared too: they must be PRODUCED by this + // edge (main.cpp and the generated .cc include them), but mcpp knows a + // header is not a translation unit and keeps them out of the compile set. + mcpp::action gen; + gen.id = "protoc:helloworld"; + gen.role = "source"; + gen.description = "protoc + grpc_cpp_plugin -> helloworld"; + gen.arg(protoc) + .arg(("-I" + root + "/proto").c_str()) + .arg(("--cpp_out=" + out).c_str()) + .arg(("--grpc_out=" + out).c_str()) + .arg((std::string("--plugin=protoc-gen-grpc=") + plugin).c_str()) + .arg(proto.c_str()) + .input(proto.c_str()) + .output((out + "/helloworld.pb.cc").c_str()) + .output((out + "/helloworld.pb.h").c_str()) + .output((out + "/helloworld.grpc.pb.cc").c_str()) + .output((out + "/helloworld.grpc.pb.h").c_str()) + .submit(); + + // Where the generated headers live. PRIVATE to this package by design — + // an include dir a consumer must see belongs in the manifest, not in a + // build program. + mcpp::include_dir(out.c_str()); +} diff --git a/templates/greeter/gen/helloworld.grpc.pb.cc b/templates/greeter/gen/helloworld.grpc.pb.cc deleted file mode 100644 index 9c4c819..0000000 --- a/templates/greeter/gen/helloworld.grpc.pb.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto - -#include "helloworld.pb.h" -#include "helloworld.grpc.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace helloworld { - -static const char* Greeter_method_names[] = { - "/helloworld.Greeter/SayHello", -}; - -std::unique_ptr< Greeter::Stub> Greeter::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) { - (void)options; - std::unique_ptr< Greeter::Stub> stub(new Greeter::Stub(channel, options)); - return stub; -} - -Greeter::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) - : channel_(channel), rpcmethod_SayHello_(Greeter_method_names[0], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - {} - -::grpc::Status Greeter::Stub::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) { - return ::grpc::internal::BlockingUnaryCall< ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_SayHello_, context, request, response); -} - -void Greeter::Stub::async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function f) { - ::grpc::internal::CallbackUnaryCall< ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, std::move(f)); -} - -void Greeter::Stub::async::SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) { - ::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SayHello_, context, request, response, reactor); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::helloworld::HelloReply, ::helloworld::HelloRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_SayHello_, context, request); -} - -::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* Greeter::Stub::AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - auto* result = - this->PrepareAsyncSayHelloRaw(context, request, cq); - result->StartCall(); - return result; -} - -Greeter::Service::Service() { - AddMethod(new ::grpc::internal::RpcServiceMethod( - Greeter_method_names[0], - ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Greeter::Service, ::helloworld::HelloRequest, ::helloworld::HelloReply, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( - [](Greeter::Service* service, - ::grpc::ServerContext* ctx, - const ::helloworld::HelloRequest* req, - ::helloworld::HelloReply* resp) { - return service->SayHello(ctx, req, resp); - }, this))); -} - -Greeter::Service::~Service() { -} - -::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { - (void) context; - (void) request; - (void) response; - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); -} - - -} // namespace helloworld -#include - diff --git a/templates/greeter/gen/helloworld.grpc.pb.h b/templates/greeter/gen/helloworld.grpc.pb.h deleted file mode 100644 index 551fa9c..0000000 --- a/templates/greeter/gen/helloworld.grpc.pb.h +++ /dev/null @@ -1,248 +0,0 @@ -// Generated by the gRPC C++ plugin. -// If you make any local change, they will be lost. -// source: helloworld.proto -// Original file comments: -// The canonical gRPC "hello world" service, matching -// https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld -#ifndef GRPC_helloworld_2eproto__INCLUDED -#define GRPC_helloworld_2eproto__INCLUDED - -#include "helloworld.pb.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace helloworld { - -class Greeter final { - public: - static constexpr char const* service_full_name() { - return "helloworld.Greeter"; - } - class StubInterface { - public: - virtual ~StubInterface() {} - // Sends a greeting. - virtual ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) = 0; - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class async_interface { - public: - virtual ~async_interface() {} - // Sends a greeting. - virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) = 0; - virtual void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) = 0; - }; - typedef class async_interface experimental_async_interface; - virtual class async_interface* async() { return nullptr; } - class async_interface* experimental_async() { return async(); } - private: - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - virtual ::grpc::ClientAsyncResponseReaderInterface< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) = 0; - }; - class Stub final : public StubInterface { - public: - Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); - ::grpc::Status SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::helloworld::HelloReply* response) override; - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> AsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(AsyncSayHelloRaw(context, request, cq)); - } - std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>> PrepareAsyncSayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) { - return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>>(PrepareAsyncSayHelloRaw(context, request, cq)); - } - class async final : - public StubInterface::async_interface { - public: - void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, std::function) override; - void SayHello(::grpc::ClientContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response, ::grpc::ClientUnaryReactor* reactor) override; - private: - friend class Stub; - explicit async(Stub* stub): stub_(stub) { } - Stub* stub() { return stub_; } - Stub* stub_; - }; - class async* async() override { return &async_stub_; } - - private: - std::shared_ptr< ::grpc::ChannelInterface> channel_; - class async async_stub_{this}; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* AsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - ::grpc::ClientAsyncResponseReader< ::helloworld::HelloReply>* PrepareAsyncSayHelloRaw(::grpc::ClientContext* context, const ::helloworld::HelloRequest& request, ::grpc::CompletionQueue* cq) override; - const ::grpc::internal::RpcMethod rpcmethod_SayHello_; - }; - static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); - - class Service : public ::grpc::Service { - public: - Service(); - virtual ~Service(); - // Sends a greeting. - virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response); - }; - template - class WithAsyncMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithAsyncMethod_SayHello() { - ::grpc::Service::MarkMethodAsync(0); - } - ~WithAsyncMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::helloworld::HelloRequest* request, ::grpc::ServerAsyncResponseWriter< ::helloworld::HelloReply>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - typedef WithAsyncMethod_SayHello AsyncService; - template - class WithCallbackMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithCallbackMethod_SayHello() { - ::grpc::Service::MarkMethodCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>( - [this]( - ::grpc::CallbackServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) { return this->SayHello(context, request, response); }));} - void SetMessageAllocatorFor_SayHello( - ::grpc::MessageAllocator< ::helloworld::HelloRequest, ::helloworld::HelloReply>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(0); - static_cast<::grpc::internal::CallbackUnaryHandler< ::helloworld::HelloRequest, ::helloworld::HelloReply>*>(handler) - ->SetMessageAllocator(allocator); - } - ~WithCallbackMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - virtual ::grpc::ServerUnaryReactor* SayHello( - ::grpc::CallbackServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) { return nullptr; } - }; - typedef WithCallbackMethod_SayHello CallbackService; - typedef CallbackService ExperimentalCallbackService; - template - class WithGenericMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithGenericMethod_SayHello() { - ::grpc::Service::MarkMethodGeneric(0); - } - ~WithGenericMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - }; - template - class WithRawMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithRawMethod_SayHello() { - ::grpc::Service::MarkMethodRaw(0); - } - ~WithRawMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - void RequestSayHello(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag); - } - }; - template - class WithRawCallbackMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithRawCallbackMethod_SayHello() { - ::grpc::Service::MarkMethodRawCallback(0, - new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( - [this]( - ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SayHello(context, request, response); })); - } - ~WithRawCallbackMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable synchronous version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - virtual ::grpc::ServerUnaryReactor* SayHello( - ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; } - }; - template - class WithStreamedUnaryMethod_SayHello : public BaseClass { - private: - void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} - public: - WithStreamedUnaryMethod_SayHello() { - ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::internal::StreamedUnaryHandler< - ::helloworld::HelloRequest, ::helloworld::HelloReply>( - [this](::grpc::ServerContext* context, - ::grpc::ServerUnaryStreamer< - ::helloworld::HelloRequest, ::helloworld::HelloReply>* streamer) { - return this->StreamedSayHello(context, - streamer); - })); - } - ~WithStreamedUnaryMethod_SayHello() override { - BaseClassMustBeDerivedFromService(this); - } - // disable regular version of this method - ::grpc::Status SayHello(::grpc::ServerContext* /*context*/, const ::helloworld::HelloRequest* /*request*/, ::helloworld::HelloReply* /*response*/) override { - abort(); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); - } - // replace default version of method with streamed unary - virtual ::grpc::Status StreamedSayHello(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::helloworld::HelloRequest,::helloworld::HelloReply>* server_unary_streamer) = 0; - }; - typedef WithStreamedUnaryMethod_SayHello StreamedUnaryService; - typedef Service SplitStreamedService; - typedef WithStreamedUnaryMethod_SayHello StreamedService; -}; - -} // namespace helloworld - - -#include -#endif // GRPC_helloworld_2eproto__INCLUDED diff --git a/templates/greeter/gen/helloworld.pb.cc b/templates/greeter/gen/helloworld.pb.cc deleted file mode 100644 index df83265..0000000 --- a/templates/greeter/gen/helloworld.pb.cc +++ /dev/null @@ -1,827 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: helloworld.proto -// Protobuf C++ Version: 7.35.1 - -#include "helloworld.pb.h" - -#include -#include -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/generated_message_tctable_impl.h" -#include "google/protobuf/internal_visibility.h" -#include "google/protobuf/extension_set.h" -#include "google/protobuf/generated_message_util.h" -#include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/generated_message_reflection.h" -#include "google/protobuf/reflection_ops.h" -#include "google/protobuf/wire_format.h" -// @@protoc_insertion_point(includes) - -// Must be included last. -#include "google/protobuf/port_def.inc" -PROTOBUF_PRAGMA_INIT_SEG -namespace _pb = ::google::protobuf; -namespace _pbi = ::google::protobuf::internal; -namespace _fl = ::google::protobuf::internal::field_layout; -#ifdef PROTOBUF_MESSAGE_GLOBALS -namespace { -PROTOBUF_CONSTINIT ::google::protobuf::internal::ReflectionData - file_reflection_data[] = { - // ::helloworld::HelloRequest - {&::_pbi::kDescriptorMethods, &::descriptor_table_helloworld_2eproto, /* tracker*/ nullptr,}, - // ::helloworld::HelloReply - {&::_pbi::kDescriptorMethods, &::descriptor_table_helloworld_2eproto, /* tracker*/ nullptr,}, -}; -} // namespace -#endif -namespace helloworld { -class HelloRequest::_Internal { - public: - using HasBits = decltype(::std::declval()._impl_._has_bits_); - static constexpr ::int32_t kHasBitsOffset = - 8 * PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._has_bits_); -}; - -constexpr HelloRequest::ParseTableT_ HelloRequest::InternalGenerateParseTable_(const ::_pbi::ClassData* class_data) { - return ParseTableT_{ - { - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._has_bits_), - 0, // no _extensions_ - 1, 0, // max_field_number, fast_idx_mask - offsetof(ParseTableT_, field_lookup_table), - 4294967294, // skipmap - offsetof(ParseTableT_, field_entries), - 1, // num_field_entries - 0, // num_aux_entries - offsetof(ParseTableT_, field_names), // no aux_entries - class_data, - nullptr, // post_loop_handler - ::_pbi::TcParser::GenericFallback, // fallback - #ifdef PROTOBUF_PREFETCH_PARSE_TABLE - ::_pbi::TcParser::GetTable<::helloworld::HelloRequest>(), // to_prefetch - #endif // PROTOBUF_PREFETCH_PARSE_TABLE - }, {{ - // string name = 1; - {::_pbi::TcParser::FastUS1, - {10, 0, 0, - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_.name_)}}, - }}, {{ - 65535, 65535 - }}, {{ - // string name = 1; - {PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_.name_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kUtf8String | ::_fl::kRepAString)}, - }}, - // no aux_entries - {{ - "\27\4\0\0\0\0\0\0" - "helloworld.HelloRequest" - "name" - }}, - }; -} - - -inline constexpr HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - ::_pbi::ConstantInitialized) noexcept - : _cached_size_{0}, - name_( - &::google::protobuf::internal::fixed_address_empty_string, - ::_pbi::ConstantInitialized()) {} - -template -constexpr HelloRequest::HelloRequest(::_pbi::ConstantInitialized, - const ::_pbi::ClassData* PROTOBUF_NONNULL class_data) - : ::google::protobuf::Message( -#if defined(PROTOBUF_CUSTOM_VTABLE) - class_data -#endif // PROTOBUF_CUSTOM_VTABLE - ), - _impl_(internal_visibility(), ::_pbi::ConstantInitialized()) { -} -inline void* PROTOBUF_NONNULL HelloRequest::PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) { - return ::new (mem) HelloRequest(arena); -} -constexpr auto HelloRequest::InternalNewImpl_() { - return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(HelloRequest), alignof(HelloRequest)); -} -constexpr auto HelloRequest::InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* tc_table) { - return ::google::protobuf::internal::ClassDataFull{ - ::google::protobuf::internal::ClassData{ - &prototype, -#ifndef PROTOBUF_MESSAGE_GLOBALS - &_table_.header, -#else - tc_table, -#endif - nullptr, // IsInitialized - &HelloRequest::MergeImpl, - ::google::protobuf::Message::GetNewImpl(), -#if defined(PROTOBUF_CUSTOM_VTABLE) - &HelloRequest::SharedDtor, - ::google::protobuf::Message::GetClearImpl(), &HelloRequest::ByteSizeLong, - &HelloRequest::_InternalSerialize, -#endif // PROTOBUF_CUSTOM_VTABLE - PROTOBUF_FIELD_OFFSET(HelloRequest, _impl_._cached_size_), - false, - }, -#ifdef PROTOBUF_MESSAGE_GLOBALS - &file_reflection_data[0], -#else // !PROTOBUF_MESSAGE_GLOBALS - &::_pbi::kDescriptorMethods, - &descriptor_table_helloworld_2eproto, - nullptr, // tracker -#endif // PROTOBUF_MESSAGE_GLOBALS - }; -} -struct HelloRequestGlobalsTypeInternal : ::_pbi::MessageGlobalsBase { - constexpr HelloRequestGlobalsTypeInternal() - : -#ifndef PROTOBUF_MESSAGE_GLOBALS - _default(::_pbi::ConstantInitialized{}, - HelloRequest_class_data_.base()) -#else // !PROTOBUF_MESSAGE_GLOBALS - MessageGlobalsBase(HelloRequest::InternalGenerateClassData_( - _default, &HelloRequest_globals_._table.header)), - _default(::_pbi::ConstantInitialized{}, GetClassData()), - _table(::_pbi::PrivateAccess::GenerateParseTable( - GetClassData())) -#endif // PROTOBUF_MESSAGE_GLOBALS - { - } - ~HelloRequestGlobalsTypeInternal() {} - union { - alignas(::_pbi::kMaxMessageAlignment) HelloRequest _default; - }; -#ifdef PROTOBUF_MESSAGE_GLOBALS - decltype(::_pbi::PrivateAccess::GenerateParseTable( - ::std::declval())) _table; -#endif -}; -#ifdef PROTOBUF_MESSAGE_GLOBALS -static_assert(PROTOBUF_FIELD_OFFSET(HelloRequestGlobalsTypeInternal, _default) == - ::_pbi::MessageGlobalsBase::OffsetToDefault()); -#endif // PROTOBUF_MESSAGE_GLOBALS - -PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT - PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PROTOBUF_MESSAGE_GLOBALS_CONST HelloRequestGlobalsTypeInternal HelloRequest_globals_ - PROTOBUF_MESSAGE_GLOBALS_SECTION(.data.rel.ro); -#if defined(PROTOBUF_CUSTOM_VTABLE) -namespace { -const ::_pbi::ClassData* HelloRequest_get_class_data() { -#ifdef PROTOBUF_MESSAGE_GLOBALS - return HelloRequest_globals_.GetClassData(); -#else - return HelloRequest_class_data_.base(); -#endif // PROTOBUF_MESSAGE_GLOBALS -} -} // namespace -#endif // PROTOBUF_CUSTOM_VTABLE -class HelloReply::_Internal { - public: - using HasBits = decltype(::std::declval()._impl_._has_bits_); - static constexpr ::int32_t kHasBitsOffset = - 8 * PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._has_bits_); -}; - -constexpr HelloReply::ParseTableT_ HelloReply::InternalGenerateParseTable_(const ::_pbi::ClassData* class_data) { - return ParseTableT_{ - { - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._has_bits_), - 0, // no _extensions_ - 1, 0, // max_field_number, fast_idx_mask - offsetof(ParseTableT_, field_lookup_table), - 4294967294, // skipmap - offsetof(ParseTableT_, field_entries), - 1, // num_field_entries - 0, // num_aux_entries - offsetof(ParseTableT_, field_names), // no aux_entries - class_data, - nullptr, // post_loop_handler - ::_pbi::TcParser::GenericFallback, // fallback - #ifdef PROTOBUF_PREFETCH_PARSE_TABLE - ::_pbi::TcParser::GetTable<::helloworld::HelloReply>(), // to_prefetch - #endif // PROTOBUF_PREFETCH_PARSE_TABLE - }, {{ - // string message = 1; - {::_pbi::TcParser::FastUS1, - {10, 0, 0, - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_.message_)}}, - }}, {{ - 65535, 65535 - }}, {{ - // string message = 1; - {PROTOBUF_FIELD_OFFSET(HelloReply, _impl_.message_), _Internal::kHasBitsOffset + 0, 0, (0 | ::_fl::kFcOptional | ::_fl::kUtf8String | ::_fl::kRepAString)}, - }}, - // no aux_entries - {{ - "\25\7\0\0\0\0\0\0" - "helloworld.HelloReply" - "message" - }}, - }; -} - - -inline constexpr HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - ::_pbi::ConstantInitialized) noexcept - : _cached_size_{0}, - message_( - &::google::protobuf::internal::fixed_address_empty_string, - ::_pbi::ConstantInitialized()) {} - -template -constexpr HelloReply::HelloReply(::_pbi::ConstantInitialized, - const ::_pbi::ClassData* PROTOBUF_NONNULL class_data) - : ::google::protobuf::Message( -#if defined(PROTOBUF_CUSTOM_VTABLE) - class_data -#endif // PROTOBUF_CUSTOM_VTABLE - ), - _impl_(internal_visibility(), ::_pbi::ConstantInitialized()) { -} -inline void* PROTOBUF_NONNULL HelloReply::PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) { - return ::new (mem) HelloReply(arena); -} -constexpr auto HelloReply::InternalNewImpl_() { - return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(HelloReply), alignof(HelloReply)); -} -constexpr auto HelloReply::InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* tc_table) { - return ::google::protobuf::internal::ClassDataFull{ - ::google::protobuf::internal::ClassData{ - &prototype, -#ifndef PROTOBUF_MESSAGE_GLOBALS - &_table_.header, -#else - tc_table, -#endif - nullptr, // IsInitialized - &HelloReply::MergeImpl, - ::google::protobuf::Message::GetNewImpl(), -#if defined(PROTOBUF_CUSTOM_VTABLE) - &HelloReply::SharedDtor, - ::google::protobuf::Message::GetClearImpl(), &HelloReply::ByteSizeLong, - &HelloReply::_InternalSerialize, -#endif // PROTOBUF_CUSTOM_VTABLE - PROTOBUF_FIELD_OFFSET(HelloReply, _impl_._cached_size_), - false, - }, -#ifdef PROTOBUF_MESSAGE_GLOBALS - &file_reflection_data[1], -#else // !PROTOBUF_MESSAGE_GLOBALS - &::_pbi::kDescriptorMethods, - &descriptor_table_helloworld_2eproto, - nullptr, // tracker -#endif // PROTOBUF_MESSAGE_GLOBALS - }; -} -struct HelloReplyGlobalsTypeInternal : ::_pbi::MessageGlobalsBase { - constexpr HelloReplyGlobalsTypeInternal() - : -#ifndef PROTOBUF_MESSAGE_GLOBALS - _default(::_pbi::ConstantInitialized{}, - HelloReply_class_data_.base()) -#else // !PROTOBUF_MESSAGE_GLOBALS - MessageGlobalsBase(HelloReply::InternalGenerateClassData_( - _default, &HelloReply_globals_._table.header)), - _default(::_pbi::ConstantInitialized{}, GetClassData()), - _table(::_pbi::PrivateAccess::GenerateParseTable( - GetClassData())) -#endif // PROTOBUF_MESSAGE_GLOBALS - { - } - ~HelloReplyGlobalsTypeInternal() {} - union { - alignas(::_pbi::kMaxMessageAlignment) HelloReply _default; - }; -#ifdef PROTOBUF_MESSAGE_GLOBALS - decltype(::_pbi::PrivateAccess::GenerateParseTable( - ::std::declval())) _table; -#endif -}; -#ifdef PROTOBUF_MESSAGE_GLOBALS -static_assert(PROTOBUF_FIELD_OFFSET(HelloReplyGlobalsTypeInternal, _default) == - ::_pbi::MessageGlobalsBase::OffsetToDefault()); -#endif // PROTOBUF_MESSAGE_GLOBALS - -PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT - PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 PROTOBUF_MESSAGE_GLOBALS_CONST HelloReplyGlobalsTypeInternal HelloReply_globals_ - PROTOBUF_MESSAGE_GLOBALS_SECTION(.data.rel.ro); -#if defined(PROTOBUF_CUSTOM_VTABLE) -namespace { -const ::_pbi::ClassData* HelloReply_get_class_data() { -#ifdef PROTOBUF_MESSAGE_GLOBALS - return HelloReply_globals_.GetClassData(); -#else - return HelloReply_class_data_.base(); -#endif // PROTOBUF_MESSAGE_GLOBALS -} -} // namespace -#endif // PROTOBUF_CUSTOM_VTABLE -} // namespace helloworld -static constexpr const ::_pb::EnumDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE - file_level_enum_descriptors_helloworld_2eproto = nullptr; -static constexpr const ::_pb::ServiceDescriptor* PROTOBUF_NONNULL* PROTOBUF_NULLABLE - file_level_service_descriptors_helloworld_2eproto = nullptr; -const ::uint32_t - TableStruct_helloworld_2eproto::offsets[] ABSL_ATTRIBUTE_SECTION_VARIABLE( - protodesc_cold) = { - 0x081, // bitmap - PROTOBUF_FIELD_OFFSET(::helloworld::HelloRequest, _impl_._has_bits_), - 4, // hasbit index offset - PROTOBUF_FIELD_OFFSET(::helloworld::HelloRequest, _impl_.name_), - 0, - 0x081, // bitmap - PROTOBUF_FIELD_OFFSET(::helloworld::HelloReply, _impl_._has_bits_), - 4, // hasbit index offset - PROTOBUF_FIELD_OFFSET(::helloworld::HelloReply, _impl_.message_), - 0, -}; - -static const ::_pbi::MigrationSchema - schemas[] ABSL_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { - {0, sizeof(::helloworld::HelloRequest)}, - {5, sizeof(::helloworld::HelloReply)}, -}; -static const ::_pbi::MessageGlobalsBase* PROTOBUF_NONNULL const - file_message_globals[] = { - &::helloworld::HelloRequest_globals_, - &::helloworld::HelloReply_globals_, -}; -const char descriptor_table_protodef_helloworld_2eproto[] ABSL_ATTRIBUTE_SECTION_VARIABLE( - protodesc_cold) = { - "\n\020helloworld.proto\022\nhelloworld\"\034\n\014HelloR" - "equest\022\014\n\004name\030\001 \001(\t\"\035\n\nHelloReply\022\017\n\007me" - "ssage\030\001 \001(\t2I\n\007Greeter\022>\n\010SayHello\022\030.hel" - "loworld.HelloRequest\032\026.helloworld.HelloR" - "eply\"\000b\006proto3" -}; -static ::absl::once_flag descriptor_table_helloworld_2eproto_once; -PROTOBUF_CONSTINIT const ::_pbi::DescriptorTable descriptor_table_helloworld_2eproto = { - false, - false, - 174, - descriptor_table_protodef_helloworld_2eproto, - "helloworld.proto", - &descriptor_table_helloworld_2eproto_once, - nullptr, - 0, - 2, - schemas, - file_message_globals, - TableStruct_helloworld_2eproto::offsets, - file_level_enum_descriptors_helloworld_2eproto, - file_level_service_descriptors_helloworld_2eproto, -}; -namespace helloworld { -// =================================================================== - -HelloRequest::HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloRequest_get_class_data()) { -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:helloworld.HelloRequest) -} -PROTOBUF_NDEBUG_INLINE HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - [[maybe_unused]] const ::helloworld::HelloRequest& from_msg) - : _has_bits_{from._has_bits_}, - _cached_size_{0}, - name_(arena, from.name_) {} - -HelloRequest::HelloRequest( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, - const HelloRequest& from) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloRequest_get_class_data()) { - -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - HelloRequest* const _this = this; - (void)_this; - _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); - new (&_impl_) Impl_(internal_visibility(), arena, from._impl_, from); - - // @@protoc_insertion_point(copy_constructor:helloworld.HelloRequest) -} -PROTOBUF_NDEBUG_INLINE HelloRequest::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) - : _cached_size_{0}, - name_(arena) {} - -inline void HelloRequest::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) { - new (&_impl_) Impl_(internal_visibility(), arena); -} -HelloRequest::~HelloRequest() { - // @@protoc_insertion_point(destructor:helloworld.HelloRequest) - SharedDtor(*this); -} -inline void HelloRequest::SharedDtor(MessageLite& self) { - HelloRequest& this_ = static_cast(self); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - this_._internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); - ABSL_DCHECK(this_.GetArena() == nullptr); - this_._impl_.name_.Destroy(); - this_._impl_.~Impl_(); -} - -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const - ::google::protobuf::internal::ClassDataFull HelloRequest_class_data_ = - HelloRequest::InternalGenerateClassData_(HelloRequest_globals_._default); - -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloRequest::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloRequest_class_data_); - ::google::protobuf::internal::PrefetchToLocalCache(HelloRequest_class_data_.tc_table); - return HelloRequest_class_data_.base(); -} -#else -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloRequest::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloRequest_globals_); - ::google::protobuf::internal::PrefetchToLocalCache( - ::google::protobuf::internal::MessageGlobalsBase::ToParseTableBase(&HelloRequest_globals_)); - return HelloRequest_globals_.GetClassData(); -} -#endif // !PROTOBUF_MESSAGE_GLOBALS -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT -PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const HelloRequest::ParseTableT_ - HelloRequest::_table_ = - HelloRequest::InternalGenerateParseTable_(HelloRequest_class_data_.base()); -#endif // !PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_NOINLINE void HelloRequest::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloRequest) - ::google::protobuf::internal::TSanWrite(&_impl_); - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - cached_has_bits = _impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - _impl_.name_.ClearNonDefaultToEmpty(); - } - _impl_._has_bits_.Clear(); - _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::uint8_t* PROTOBUF_NONNULL HelloRequest::_InternalSerialize( - const ::google::protobuf::MessageLite& base, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) { - const HelloRequest& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::uint8_t* PROTOBUF_NONNULL HelloRequest::_InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - const HelloRequest& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloRequest) - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = this_._impl_._has_bits_[0]; - // string name = 1; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_name().empty()) { - const ::std::string& _s = this_._internal_name(); - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "helloworld.HelloRequest.name"); - target = stream->WriteStringMaybeAliased(1, _s, target); - } - } - - if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) { - target = - ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( - this_._internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloRequest) - return target; -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::size_t HelloRequest::ByteSizeLong(const MessageLite& base) { - const HelloRequest& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::size_t HelloRequest::ByteSizeLong() const { - const HelloRequest& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - // @@protoc_insertion_point(message_byte_size_start:helloworld.HelloRequest) - ::size_t total_size = 0; - - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void)cached_has_bits; - - { - // string name = 1; - cached_has_bits = this_._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_name().empty()) { - total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( - this_._internal_name()); - } - } - } - return this_.MaybeComputeUnknownFieldsSize(total_size, - &this_._impl_._cached_size_); -} - -void HelloRequest::MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg) { - auto* const _this = static_cast(&to_msg); - auto& from = static_cast(from_msg); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - from.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloRequest) - ABSL_DCHECK_NE(&from, _this); - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = from._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!from._internal_name().empty()) { - _this->_internal_set_name(from._internal_name()); - } else { - if (_this->_impl_.name_.IsDefault()) { - _this->_internal_set_name(""); - } - } - } - _this->_impl_._has_bits_[0] |= cached_has_bits; - _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); -} - -void HelloRequest::CopyFrom(const HelloRequest& from) { - // @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloRequest) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - - -void HelloRequest::InternalSwap(HelloRequest* PROTOBUF_RESTRICT PROTOBUF_NONNULL other) { - using ::std::swap; - auto* arena = GetArena(); - ABSL_DCHECK_EQ(arena, other->GetArena()); - _internal_metadata_.InternalSwap(&other->_internal_metadata_); - swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); - ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, &other->_impl_.name_, arena); -} - -::google::protobuf::Metadata HelloRequest::GetMetadata() const { - return ::google::protobuf::Message::GetMetadataImpl(GetClassData()->full()); -} -// =================================================================== - -HelloReply::HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloReply_get_class_data()) { -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - SharedCtor(arena); - // @@protoc_insertion_point(arena_constructor:helloworld.HelloReply) -} -PROTOBUF_NDEBUG_INLINE HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - [[maybe_unused]] const ::helloworld::HelloReply& from_msg) - : _has_bits_{from._has_bits_}, - _cached_size_{0}, - message_(arena, from.message_) {} - -HelloReply::HelloReply( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, - const HelloReply& from) -#if defined(PROTOBUF_CUSTOM_VTABLE) - : ::google::protobuf::Message(arena, HelloReply_get_class_data()) { - -#else // PROTOBUF_CUSTOM_VTABLE - : ::google::protobuf::Message(arena) { -#endif // PROTOBUF_CUSTOM_VTABLE - HelloReply* const _this = this; - (void)_this; - _internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); - new (&_impl_) Impl_(internal_visibility(), arena, from._impl_, from); - - // @@protoc_insertion_point(copy_constructor:helloworld.HelloReply) -} -PROTOBUF_NDEBUG_INLINE HelloReply::Impl_::Impl_( - [[maybe_unused]] ::google::protobuf::internal::InternalVisibility visibility, - [[maybe_unused]] ::google::protobuf::Arena* PROTOBUF_NULLABLE arena) - : _cached_size_{0}, - message_(arena) {} - -inline void HelloReply::SharedCtor(::_pb::Arena* PROTOBUF_NULLABLE arena) { - new (&_impl_) Impl_(internal_visibility(), arena); -} -HelloReply::~HelloReply() { - // @@protoc_insertion_point(destructor:helloworld.HelloReply) - SharedDtor(*this); -} -inline void HelloReply::SharedDtor(MessageLite& self) { - HelloReply& this_ = static_cast(self); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - this_._internal_metadata_.Delete<::google::protobuf::UnknownFieldSet>(); - ABSL_DCHECK(this_.GetArena() == nullptr); - this_._impl_.message_.Destroy(); - this_._impl_.~Impl_(); -} - -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const - ::google::protobuf::internal::ClassDataFull HelloReply_class_data_ = - HelloReply::InternalGenerateClassData_(HelloReply_globals_._default); - -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloReply::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloReply_class_data_); - ::google::protobuf::internal::PrefetchToLocalCache(HelloReply_class_data_.tc_table); - return HelloReply_class_data_.base(); -} -#else -PROTOBUF_ATTRIBUTE_WEAK const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL -HelloReply::GetClassData() const { - ::google::protobuf::internal::PrefetchToLocalCache(&HelloReply_globals_); - ::google::protobuf::internal::PrefetchToLocalCache( - ::google::protobuf::internal::MessageGlobalsBase::ToParseTableBase(&HelloReply_globals_)); - return HelloReply_globals_.GetClassData(); -} -#endif // !PROTOBUF_MESSAGE_GLOBALS -#ifndef PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_CONSTINIT -PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const HelloReply::ParseTableT_ - HelloReply::_table_ = - HelloReply::InternalGenerateParseTable_(HelloReply_class_data_.base()); -#endif // !PROTOBUF_MESSAGE_GLOBALS -PROTOBUF_NOINLINE void HelloReply::Clear() { -// @@protoc_insertion_point(message_clear_start:helloworld.HelloReply) - ::google::protobuf::internal::TSanWrite(&_impl_); - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void) cached_has_bits; - - cached_has_bits = _impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - _impl_.message_.ClearNonDefaultToEmpty(); - } - _impl_._has_bits_.Clear(); - _internal_metadata_.Clear<::google::protobuf::UnknownFieldSet>(); -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::uint8_t* PROTOBUF_NONNULL HelloReply::_InternalSerialize( - const ::google::protobuf::MessageLite& base, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) { - const HelloReply& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::uint8_t* PROTOBUF_NONNULL HelloReply::_InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - const HelloReply& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - this_.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(serialize_to_array_start:helloworld.HelloReply) - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = this_._impl_._has_bits_[0]; - // string message = 1; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_message().empty()) { - const ::std::string& _s = this_._internal_message(); - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - _s.data(), static_cast(_s.length()), ::google::protobuf::internal::WireFormatLite::SERIALIZE, "helloworld.HelloReply.message"); - target = stream->WriteStringMaybeAliased(1, _s, target); - } - } - - if (ABSL_PREDICT_FALSE(this_._internal_metadata_.have_unknown_fields())) { - target = - ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( - this_._internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance), target, stream); - } - // @@protoc_insertion_point(serialize_to_array_end:helloworld.HelloReply) - return target; -} - -#if defined(PROTOBUF_CUSTOM_VTABLE) -::size_t HelloReply::ByteSizeLong(const MessageLite& base) { - const HelloReply& this_ = static_cast(base); -#else // PROTOBUF_CUSTOM_VTABLE -::size_t HelloReply::ByteSizeLong() const { - const HelloReply& this_ = *this; -#endif // PROTOBUF_CUSTOM_VTABLE - // @@protoc_insertion_point(message_byte_size_start:helloworld.HelloReply) - ::size_t total_size = 0; - - ::uint32_t cached_has_bits = 0; - // Prevent compiler warnings about cached_has_bits being unused - (void)cached_has_bits; - - { - // string message = 1; - cached_has_bits = this_._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!this_._internal_message().empty()) { - total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize( - this_._internal_message()); - } - } - } - return this_.MaybeComputeUnknownFieldsSize(total_size, - &this_._impl_._cached_size_); -} - -void HelloReply::MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg) { - auto* const _this = static_cast(&to_msg); - auto& from = static_cast(from_msg); - if constexpr (::_pbi::DebugHardenCheckHasBitConsistency()) { - from.CheckHasBitConsistency(); - } - // @@protoc_insertion_point(class_specific_merge_from_start:helloworld.HelloReply) - ABSL_DCHECK_NE(&from, _this); - ::uint32_t cached_has_bits = 0; - (void)cached_has_bits; - - cached_has_bits = from._impl_._has_bits_[0]; - if (CheckHasBit(cached_has_bits, 0x00000001U)) { - if (!from._internal_message().empty()) { - _this->_internal_set_message(from._internal_message()); - } else { - if (_this->_impl_.message_.IsDefault()) { - _this->_internal_set_message(""); - } - } - } - _this->_impl_._has_bits_[0] |= cached_has_bits; - _this->_internal_metadata_.MergeFrom<::google::protobuf::UnknownFieldSet>( - from._internal_metadata_); -} - -void HelloReply::CopyFrom(const HelloReply& from) { - // @@protoc_insertion_point(class_specific_copy_from_start:helloworld.HelloReply) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - - -void HelloReply::InternalSwap(HelloReply* PROTOBUF_RESTRICT PROTOBUF_NONNULL other) { - using ::std::swap; - auto* arena = GetArena(); - ABSL_DCHECK_EQ(arena, other->GetArena()); - _internal_metadata_.InternalSwap(&other->_internal_metadata_); - swap(_impl_._has_bits_[0], other->_impl_._has_bits_[0]); - ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.message_, &other->_impl_.message_, arena); -} - -::google::protobuf::Metadata HelloReply::GetMetadata() const { - return ::google::protobuf::Message::GetMetadataImpl(GetClassData()->full()); -} -// @@protoc_insertion_point(namespace_scope) -} // namespace helloworld -namespace google { -namespace protobuf { -} // namespace protobuf -} // namespace google -// @@protoc_insertion_point(global_scope) -PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 static ::std::false_type - _static_init2_ [[maybe_unused]] = - (::_pbi::AddDescriptors(&descriptor_table_helloworld_2eproto), - ::std::false_type{}); -#include "google/protobuf/port_undef.inc" diff --git a/templates/greeter/gen/helloworld.pb.h b/templates/greeter/gen/helloworld.pb.h deleted file mode 100644 index 19c8c15..0000000 --- a/templates/greeter/gen/helloworld.pb.h +++ /dev/null @@ -1,658 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// NO CHECKED-IN PROTOBUF GENCODE -// source: helloworld.proto -// Protobuf C++ Version: 7.35.1 - -#ifndef helloworld_2eproto_2epb_2eh -#define helloworld_2eproto_2epb_2eh - -#include -#include -#include -#include - -// clang-format off -#include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 7035001 -#error "Protobuf C++ gencode is built with an incompatible version of" -#error "Protobuf C++ headers/runtime. See" -#error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" -#endif -#include "google/protobuf/io/coded_stream.h" -#include "google/protobuf/arena.h" -#include "google/protobuf/arenastring.h" -#include "google/protobuf/generated_message_tctable_decl.h" -#include "google/protobuf/generated_message_util.h" -#include "google/protobuf/metadata_lite.h" -#include "google/protobuf/generated_message_reflection.h" -#include "google/protobuf/message.h" -#include "google/protobuf/message_lite.h" -#include "google/protobuf/repeated_field.h" // IWYU pragma: export -#include "google/protobuf/extension_set.h" // IWYU pragma: export -#include "google/protobuf/unknown_field_set.h" -// @@protoc_insertion_point(includes) - -// Must be included last. -#include "google/protobuf/port_def.inc" - -#define PROTOBUF_INTERNAL_EXPORT_helloworld_2eproto - -namespace google { -namespace protobuf { -namespace internal { -template -::absl::string_view GetAnyMessageName(); -} // namespace internal -} // namespace protobuf -} // namespace google - -// Internal implementation detail -- do not use these members. -struct TableStruct_helloworld_2eproto { - static const ::uint32_t offsets[]; -}; -extern "C" { -extern const ::google::protobuf::internal::DescriptorTable descriptor_table_helloworld_2eproto; -} // extern "C" -namespace helloworld { -class HelloReply; -struct HelloReplyGlobalsTypeInternal; -#ifndef PROTOBUF_MESSAGE_GLOBALS -extern HelloReplyGlobalsTypeInternal HelloReply_globals_; -extern const ::google::protobuf::internal::ClassDataFull HelloReply_class_data_; -#else -extern const HelloReplyGlobalsTypeInternal HelloReply_globals_; -#endif // PROTOBUF_MESSAGE_GLOBALS -class HelloRequest; -struct HelloRequestGlobalsTypeInternal; -#ifndef PROTOBUF_MESSAGE_GLOBALS -extern HelloRequestGlobalsTypeInternal HelloRequest_globals_; -extern const ::google::protobuf::internal::ClassDataFull HelloRequest_class_data_; -#else -extern const HelloRequestGlobalsTypeInternal HelloRequest_globals_; -#endif // PROTOBUF_MESSAGE_GLOBALS -} // namespace helloworld -namespace google { -namespace protobuf { -} // namespace protobuf -} // namespace google - -namespace helloworld { - -// =================================================================== - - -// ------------------------------------------------------------------- - -class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED HelloRequest final : public ::google::protobuf::Message -/* @@protoc_insertion_point(class_definition:helloworld.HelloRequest) */ { - public: - inline HelloRequest() : HelloRequest(nullptr) {} - ~HelloRequest() PROTOBUF_FINAL; - -#if defined(PROTOBUF_CUSTOM_VTABLE) - void operator delete(HelloRequest* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) { - SharedDtor(*msg); - ::google::protobuf::internal::SizedDelete(msg, sizeof(HelloRequest)); - } -#endif - - template - explicit constexpr HelloRequest(::google::protobuf::internal::ConstantInitialized, - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL - class_data); - - inline HelloRequest(const HelloRequest& from) : HelloRequest(nullptr, from) {} - inline HelloRequest(HelloRequest&& from) noexcept : HelloRequest(nullptr, ::std::move(from)) {} - inline HelloRequest& operator=(const HelloRequest& from) { - CopyFrom(from); - return *this; - } - inline HelloRequest& operator=(HelloRequest&& from) noexcept { - if (this == &from) return *this; - if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) { - InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - - [[nodiscard]] inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); - } - [[nodiscard]] inline ::google::protobuf::UnknownFieldSet* PROTOBUF_NONNULL - mutable_unknown_fields() ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); - } - - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL descriptor() { - return GetDescriptor(); - } - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL - GetDescriptor() { - return default_instance().GetMetadata().descriptor; - } - [[nodiscard]] static const ::google::protobuf::Reflection* PROTOBUF_NONNULL GetReflection() { - return default_instance().GetMetadata().reflection; - } - [[nodiscard]] static const HelloRequest& default_instance() { - return *::google::protobuf::internal::MessageGlobalsBase::ToDefaultInstance(&HelloRequest_globals_); - } - static constexpr int kIndexInFileMessages = 0; - friend void swap(HelloRequest& a, HelloRequest& b) { a.Swap(&b); } - inline void Swap(HelloRequest* PROTOBUF_NONNULL other) { - if (other == this) return; - if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) { - InternalSwap(other); - } else { - ::google::protobuf::internal::GenericSwap(this, other); - } - } - void UnsafeArenaSwap(HelloRequest* PROTOBUF_NONNULL other) { - if (other == this) return; - ABSL_DCHECK(GetArena() == other->GetArena()); - InternalSwap(other); - } - - // implements Message ---------------------------------------------- - - [[nodiscard]] HelloRequest* PROTOBUF_NONNULL - New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const { - return ::google::protobuf::Message::DefaultConstruct(arena); - } - using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const HelloRequest& from); - using ::google::protobuf::Message::MergeFrom; - void MergeFrom(const HelloRequest& from) { HelloRequest::MergeImpl(*this, from); } - - private: - static void MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg); - - public: - [[nodiscard]] bool IsInitialized() const { - return true; - } - ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL; - #if defined(PROTOBUF_CUSTOM_VTABLE) - private: - [[nodiscard]] static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg); - [[nodiscard]] static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream); - - public: - [[nodiscard]] ::size_t ByteSizeLong() const { return ByteSizeLong(*this); } - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - return _InternalSerialize(*this, target, stream); - } - #else // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] ::size_t ByteSizeLong() const final; - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final; - #endif // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] int GetCachedSize() const { - return _impl_._cached_size_.Get(); - } - - private: - void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static void SharedDtor(MessageLite& self); - void InternalSwap(HelloRequest* PROTOBUF_NONNULL other); - private: - template - friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)(); - static ::absl::string_view FullMessageName() { return "helloworld.HelloRequest"; } - - explicit HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - HelloRequest(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const HelloRequest& from); - HelloRequest( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, HelloRequest&& from) noexcept - : HelloRequest(arena) { - *this = ::std::move(from); - } - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL; - static void* PROTOBUF_NONNULL PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static constexpr auto InternalNewImpl_(); - - public: - static constexpr auto InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* PROTOBUF_NULLABLE tc_table = nullptr); - - [[nodiscard]] ::google::protobuf::Metadata GetMetadata() const; - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - enum : int { - kNameFieldNumber = 1, - }; - // string name = 1; - void clear_name() ; - [[nodiscard]] const ::std::string& name() const; - template - void set_name(Arg_&& arg, Args_... args); - ::std::string* PROTOBUF_NONNULL mutable_name(); - [[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_name(); - void set_allocated_name(::std::string* PROTOBUF_NULLABLE value); - - private: - const ::std::string& _internal_name() const; - PROTOBUF_ALWAYS_INLINE void _internal_set_name(const ::std::string& value); - ::std::string* PROTOBUF_NONNULL _internal_mutable_name(); - - public: - // @@protoc_insertion_point(class_scope:helloworld.HelloRequest) - private: - class _Internal; - using ParseTableT_ = - ::google::protobuf::internal::TcParseTable<0, 1, - 0, 36, - 2>; - static constexpr ParseTableT_ InternalGenerateParseTable_( - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL class_data); - friend class ::google::protobuf::internal::TcParser; - #ifndef PROTOBUF_MESSAGE_GLOBALS - static const ParseTableT_ _table_; - #endif - - friend class ::google::protobuf::MessageLite; - friend class ::google::protobuf::Arena; - friend ::google::protobuf::internal::PrivateAccess; - template - friend class ::google::protobuf::Arena::InternalHelper; - using InternalArenaConstructable_ = void; - using DestructorSkippable_ = void; - struct Impl_ { - inline explicit constexpr Impl_(::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::internal::ConstantInitialized) noexcept; - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - const HelloRequest& from_msg); - ::google::protobuf::internal::HasBits<1> _has_bits_; - ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr name_; - PROTOBUF_TSAN_DECLARE_MEMBER - }; - union { Impl_ _impl_; }; - friend struct ::TableStruct_helloworld_2eproto; -}; -// ------------------------------------------------------------------- - -class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED HelloReply final : public ::google::protobuf::Message -/* @@protoc_insertion_point(class_definition:helloworld.HelloReply) */ { - public: - inline HelloReply() : HelloReply(nullptr) {} - ~HelloReply() PROTOBUF_FINAL; - -#if defined(PROTOBUF_CUSTOM_VTABLE) - void operator delete(HelloReply* PROTOBUF_NONNULL msg, ::std::destroying_delete_t) { - SharedDtor(*msg); - ::google::protobuf::internal::SizedDelete(msg, sizeof(HelloReply)); - } -#endif - - template - explicit constexpr HelloReply(::google::protobuf::internal::ConstantInitialized, - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL - class_data); - - inline HelloReply(const HelloReply& from) : HelloReply(nullptr, from) {} - inline HelloReply(HelloReply&& from) noexcept : HelloReply(nullptr, ::std::move(from)) {} - inline HelloReply& operator=(const HelloReply& from) { - CopyFrom(from); - return *this; - } - inline HelloReply& operator=(HelloReply&& from) noexcept { - if (this == &from) return *this; - if (::google::protobuf::internal::CanMoveWithInternalSwap(GetArena(), from.GetArena())) { - InternalSwap(&from); - } else { - CopyFrom(from); - } - return *this; - } - - [[nodiscard]] inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.unknown_fields<::google::protobuf::UnknownFieldSet>(::google::protobuf::UnknownFieldSet::default_instance); - } - [[nodiscard]] inline ::google::protobuf::UnknownFieldSet* PROTOBUF_NONNULL - mutable_unknown_fields() ABSL_ATTRIBUTE_LIFETIME_BOUND { - return _internal_metadata_.mutable_unknown_fields<::google::protobuf::UnknownFieldSet>(); - } - - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL descriptor() { - return GetDescriptor(); - } - [[nodiscard]] static const ::google::protobuf::Descriptor* PROTOBUF_NONNULL - GetDescriptor() { - return default_instance().GetMetadata().descriptor; - } - [[nodiscard]] static const ::google::protobuf::Reflection* PROTOBUF_NONNULL GetReflection() { - return default_instance().GetMetadata().reflection; - } - [[nodiscard]] static const HelloReply& default_instance() { - return *::google::protobuf::internal::MessageGlobalsBase::ToDefaultInstance(&HelloReply_globals_); - } - static constexpr int kIndexInFileMessages = 1; - friend void swap(HelloReply& a, HelloReply& b) { a.Swap(&b); } - inline void Swap(HelloReply* PROTOBUF_NONNULL other) { - if (other == this) return; - if (::google::protobuf::internal::CanUseInternalSwap(GetArena(), other->GetArena())) { - InternalSwap(other); - } else { - ::google::protobuf::internal::GenericSwap(this, other); - } - } - void UnsafeArenaSwap(HelloReply* PROTOBUF_NONNULL other) { - if (other == this) return; - ABSL_DCHECK(GetArena() == other->GetArena()); - InternalSwap(other); - } - - // implements Message ---------------------------------------------- - - [[nodiscard]] HelloReply* PROTOBUF_NONNULL - New(::google::protobuf::Arena* PROTOBUF_NULLABLE arena = nullptr) const { - return ::google::protobuf::Message::DefaultConstruct(arena); - } - using ::google::protobuf::Message::CopyFrom; - void CopyFrom(const HelloReply& from); - using ::google::protobuf::Message::MergeFrom; - void MergeFrom(const HelloReply& from) { HelloReply::MergeImpl(*this, from); } - - private: - static void MergeImpl(::google::protobuf::MessageLite& to_msg, - const ::google::protobuf::MessageLite& from_msg); - - public: - [[nodiscard]] bool IsInitialized() const { - return true; - } - ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL; - #if defined(PROTOBUF_CUSTOM_VTABLE) - private: - [[nodiscard]] static ::size_t ByteSizeLong(const ::google::protobuf::MessageLite& msg); - [[nodiscard]] static ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - const ::google::protobuf::MessageLite& msg, ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream); - - public: - [[nodiscard]] ::size_t ByteSizeLong() const { return ByteSizeLong(*this); } - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const { - return _InternalSerialize(*this, target, stream); - } - #else // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] ::size_t ByteSizeLong() const final; - [[nodiscard]] ::uint8_t* PROTOBUF_NONNULL _InternalSerialize( - ::uint8_t* PROTOBUF_NONNULL target, - ::google::protobuf::io::EpsCopyOutputStream* PROTOBUF_NONNULL stream) const final; - #endif // PROTOBUF_CUSTOM_VTABLE - [[nodiscard]] int GetCachedSize() const { - return _impl_._cached_size_.Get(); - } - - private: - void SharedCtor(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static void SharedDtor(MessageLite& self); - void InternalSwap(HelloReply* PROTOBUF_NONNULL other); - private: - template - friend ::absl::string_view(::google::protobuf::internal::GetAnyMessageName)(); - static ::absl::string_view FullMessageName() { return "helloworld.HelloReply"; } - - explicit HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - HelloReply(::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const HelloReply& from); - HelloReply( - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, HelloReply&& from) noexcept - : HelloReply(arena) { - *this = ::std::move(from); - } - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL GetClassData() const PROTOBUF_FINAL; - static void* PROTOBUF_NONNULL PlacementNew_( - const void* PROTOBUF_NONNULL, void* PROTOBUF_NONNULL mem, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - static constexpr auto InternalNewImpl_(); - - public: - static constexpr auto InternalGenerateClassData_( - const MessageLite& prototype, - const ::google::protobuf::internal::TcParseTableBase* PROTOBUF_NULLABLE tc_table = nullptr); - - [[nodiscard]] ::google::protobuf::Metadata GetMetadata() const; - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - enum : int { - kMessageFieldNumber = 1, - }; - // string message = 1; - void clear_message() ; - [[nodiscard]] const ::std::string& message() const; - template - void set_message(Arg_&& arg, Args_... args); - ::std::string* PROTOBUF_NONNULL mutable_message(); - [[nodiscard]] ::std::string* PROTOBUF_NULLABLE release_message(); - void set_allocated_message(::std::string* PROTOBUF_NULLABLE value); - - private: - const ::std::string& _internal_message() const; - PROTOBUF_ALWAYS_INLINE void _internal_set_message(const ::std::string& value); - ::std::string* PROTOBUF_NONNULL _internal_mutable_message(); - - public: - // @@protoc_insertion_point(class_scope:helloworld.HelloReply) - private: - class _Internal; - using ParseTableT_ = - ::google::protobuf::internal::TcParseTable<0, 1, - 0, 37, - 2>; - static constexpr ParseTableT_ InternalGenerateParseTable_( - const ::google::protobuf::internal::ClassData* PROTOBUF_NONNULL class_data); - friend class ::google::protobuf::internal::TcParser; - #ifndef PROTOBUF_MESSAGE_GLOBALS - static const ParseTableT_ _table_; - #endif - - friend class ::google::protobuf::MessageLite; - friend class ::google::protobuf::Arena; - friend ::google::protobuf::internal::PrivateAccess; - template - friend class ::google::protobuf::Arena::InternalHelper; - using InternalArenaConstructable_ = void; - using DestructorSkippable_ = void; - struct Impl_ { - inline explicit constexpr Impl_(::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::internal::ConstantInitialized) noexcept; - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena); - inline explicit Impl_( - ::google::protobuf::internal::InternalVisibility visibility, - ::google::protobuf::Arena* PROTOBUF_NULLABLE arena, const Impl_& from, - const HelloReply& from_msg); - ::google::protobuf::internal::HasBits<1> _has_bits_; - ::google::protobuf::internal::CachedSize _cached_size_; - ::google::protobuf::internal::ArenaStringPtr message_; - PROTOBUF_TSAN_DECLARE_MEMBER - }; - union { Impl_ _impl_; }; - friend struct ::TableStruct_helloworld_2eproto; -}; - -// =================================================================== - - - - -// =================================================================== - - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif // __GNUC__ -// ------------------------------------------------------------------- - -// HelloRequest - -// string name = 1; -inline void HelloRequest::clear_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.name_.ClearToEmpty(); - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); -} -inline const ::std::string& HelloRequest::name() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:helloworld.HelloRequest.name) - return _internal_name(); -} -template -PROTOBUF_ALWAYS_INLINE void HelloRequest::set_name(Arg_&& arg, Args_... args) { - ::google::protobuf::internal::TSanWrite(&_impl_); - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - _impl_.name_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:helloworld.HelloRequest.name) -} -inline ::std::string* PROTOBUF_NONNULL HelloRequest::mutable_name() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - ::std::string* _s = _internal_mutable_name(); - // @@protoc_insertion_point(field_mutable:helloworld.HelloRequest.name) - return _s; -} -inline const ::std::string& HelloRequest::_internal_name() const { - ::google::protobuf::internal::TSanRead(&_impl_); - return _impl_.name_.Get(); -} -inline void HelloRequest::_internal_set_name(const ::std::string& value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.name_.Set(value, GetArena()); -} -inline ::std::string* PROTOBUF_NONNULL HelloRequest::_internal_mutable_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - return _impl_.name_.Mutable( GetArena()); -} -inline ::std::string* PROTOBUF_NULLABLE HelloRequest::release_name() { - ::google::protobuf::internal::TSanWrite(&_impl_); - // @@protoc_insertion_point(field_release:helloworld.HelloRequest.name) - if (!CheckHasBit(_impl_._has_bits_[0], 0x00000001U)) { - return nullptr; - } - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - auto* released = _impl_.name_.Release(); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) { - _impl_.name_.Set("", GetArena()); - } - return released; -} -inline void HelloRequest::set_allocated_name(::std::string* PROTOBUF_NULLABLE value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - if (value != nullptr) { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - } else { - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - } - _impl_.name_.SetAllocated(value, GetArena()); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.name_.IsDefault()) { - _impl_.name_.Set("", GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloRequest.name) -} - -// ------------------------------------------------------------------- - -// HelloReply - -// string message = 1; -inline void HelloReply::clear_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.message_.ClearToEmpty(); - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); -} -inline const ::std::string& HelloReply::message() const - ABSL_ATTRIBUTE_LIFETIME_BOUND { - // @@protoc_insertion_point(field_get:helloworld.HelloReply.message) - return _internal_message(); -} -template -PROTOBUF_ALWAYS_INLINE void HelloReply::set_message(Arg_&& arg, Args_... args) { - ::google::protobuf::internal::TSanWrite(&_impl_); - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - _impl_.message_.Set(static_cast(arg), args..., GetArena()); - // @@protoc_insertion_point(field_set:helloworld.HelloReply.message) -} -inline ::std::string* PROTOBUF_NONNULL HelloReply::mutable_message() - ABSL_ATTRIBUTE_LIFETIME_BOUND { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - ::std::string* _s = _internal_mutable_message(); - // @@protoc_insertion_point(field_mutable:helloworld.HelloReply.message) - return _s; -} -inline const ::std::string& HelloReply::_internal_message() const { - ::google::protobuf::internal::TSanRead(&_impl_); - return _impl_.message_.Get(); -} -inline void HelloReply::_internal_set_message(const ::std::string& value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - _impl_.message_.Set(value, GetArena()); -} -inline ::std::string* PROTOBUF_NONNULL HelloReply::_internal_mutable_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - return _impl_.message_.Mutable( GetArena()); -} -inline ::std::string* PROTOBUF_NULLABLE HelloReply::release_message() { - ::google::protobuf::internal::TSanWrite(&_impl_); - // @@protoc_insertion_point(field_release:helloworld.HelloReply.message) - if (!CheckHasBit(_impl_._has_bits_[0], 0x00000001U)) { - return nullptr; - } - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - auto* released = _impl_.message_.Release(); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString()) { - _impl_.message_.Set("", GetArena()); - } - return released; -} -inline void HelloReply::set_allocated_message(::std::string* PROTOBUF_NULLABLE value) { - ::google::protobuf::internal::TSanWrite(&_impl_); - if (value != nullptr) { - SetHasBit(_impl_._has_bits_[0], 0x00000001U); - } else { - ClearHasBit(_impl_._has_bits_[0], 0x00000001U); - } - _impl_.message_.SetAllocated(value, GetArena()); - if (::google::protobuf::internal::DebugHardenForceCopyDefaultString() && _impl_.message_.IsDefault()) { - _impl_.message_.Set("", GetArena()); - } - // @@protoc_insertion_point(field_set_allocated:helloworld.HelloReply.message) -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif // __GNUC__ - -// @@protoc_insertion_point(namespace_scope) -} // namespace helloworld - - -// @@protoc_insertion_point(global_scope) - -#include "google/protobuf/port_undef.inc" -// clang-format on - -#endif // helloworld_2eproto_2epb_2eh diff --git a/templates/greeter/mcpp.toml.in b/templates/greeter/mcpp.toml.in index d51a679..07244b0 100644 --- a/templates/greeter/mcpp.toml.in +++ b/templates/greeter/mcpp.toml.in @@ -1,23 +1,21 @@ # {{project.name}} — generated from {{self.name}}@{{self.version}}:greeter # -# gen/ holds protoc output, checked in so this project builds with nothing but -# mcpp. After editing proto/helloworld.proto, regenerate with: +# The protobuf/gRPC stubs are NOT checked in. They are generated during the +# build by protoc and grpc_cpp_plugin, which mcpp builds for this machine out of +# the same packages this project links against — so the generator and the +# runtime cannot be different versions. Edit proto/helloworld.proto and build; +# that is the whole workflow. # -# protoc -I proto --cpp_out=gen --grpc_out=gen \ -# --plugin=protoc-gen-grpc=$(which grpc_cpp_plugin) \ -# proto/helloworld.proto -# -# protoc must match the protobuf compat.protobuf pins (35.1 — upstream ships -# prebuilt protoc for every platform) and grpc_cpp_plugin must come from the -# same gRPC release as this dependency. +# Under `mcpp build --target ` both tools are still built for the BUILD +# machine, because a code generator has to run here. You do not have to do +# anything for that. [package] name = "{{project.name}}" version = "0.1.0" standard = "c++23" [build] -sources = ["src/main.cpp", "gen/helloworld.pb.cc", "gen/helloworld.grpc.pb.cc"] -include_dirs = ["gen"] +sources = ["src/main.cpp"] [targets.{{project.name}}] kind = "bin" @@ -25,3 +23,11 @@ main = "src/main.cpp" [dependencies.mcpplibs] {{self.name}} = "{{self.version}}" +# The gRPC C++ codegen plugin — a package of its own rather than a target +# inside gRPC, because a code generator needs a .proto parser and a C++ +# emitter, not TLS, DNS and a regex engine. +grpc-plugin = { version = "{{self.version}}", tools = ["grpc_cpp_plugin"] } + +[dependencies.compat] +# protoc, pinned to the same protobuf this project links. +protobuf = { version = "35.1", tools = ["protoc"] } diff --git a/templates/greeter/src/main.cpp.in b/templates/greeter/src/main.cpp.in index 768ce3c..1c4cb0e 100644 --- a/templates/greeter/src/main.cpp.in +++ b/templates/greeter/src/main.cpp.in @@ -9,8 +9,8 @@ // exercising the same stack the two-binary version does: // // ServerBuilder / Server -> src/cpp/server/** -// Greeter::Service (generated) -> gen/helloworld.grpc.pb.cc -// HelloRequest / HelloReply -> gen/helloworld.pb.cc (protobuf runtime) +// Greeter::Service (generated) -> helloworld.grpc.pb.cc (generated at build time) +// HelloRequest / HelloReply -> helloworld.pb.cc (protobuf runtime) // CreateChannel / Stub -> src/cpp/client/** // the wire itself -> src/core/** (HTTP/2, transport, iomgr) // diff --git a/templates/greeter/template.toml b/templates/greeter/template.toml index e7fd459..6ef7d13 100644 --- a/templates/greeter/template.toml +++ b/templates/greeter/template.toml @@ -1,3 +1,3 @@ [template] description = "Greeter service + client in one program — a real gRPC round trip over loopback" -post_message = "cd into the project and `mcpp run`. The generated stubs in gen/ are protoc output for proto/helloworld.proto; the header comment in mcpp.toml shows how to regenerate them after you edit the .proto." +post_message = "cd into the project and `mcpp run`. The protobuf/gRPC stubs are NOT checked in: mcpp builds protoc and grpc_cpp_plugin from the same packages you link against, then generates the stubs during the build. Edit proto/helloworld.proto and rebuild — that is the whole workflow, and the generator can never be a different version from the runtime." From a2b059ab3ce7b1c51f2347c8e73e55183ac59105 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 5 Aug 2026 17:47:49 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(codegen):=20=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=8C=85=20grpcgen=20=E2=80=94=E2=80=94=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=9A=84=20build.mcpp=20=E4=BB=8E=2060=20=E8=A1=8C=E9=99=8D?= =?UTF-8?q?=E5=88=B0=203=20=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一个 commit 让 codegen 不再签入仓库,代价是每个工程都要抄一份约 60 行的 build.mcpp。抄一份就是**复制一份将来要各自修的 bug**,而其中至少有一处是所有人 都会踩的:protoc **不内嵌 well-known types**,`import "google/protobuf/timestamp.proto"` 是从磁盘读的,真实服务几乎必用 Timestamp / Duration / Any —— 用户写第二个 .proto 时必然撞墙,而路径要从 `mcpp::dep_dir("protobuf")` 里探出来。 那 60 行现在装进 `rules/`,以普通 mcpp 包 `grpcgen` 发布。用户侧: [dependencies] grpcgen = { version = "1.83.0", host-module = true } // build.mcpp —— 全文如此 import mcpp; import grpcgen; int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } 规则有版本、能测试、能发布,而且是 C++ 写的 —— 不像 xmake 的 Lua rule 与 Bazel 的 Starlark,这里没有第二门语言。 ── 落地时改掉的三处判断 ───────────────────────────────────────────────────── 1. **设计文档说规则包「带不动自己的 tools」,那条理由不成立。** 消费者本来就要在 自己的 manifest 里声明 grpc / grpc-plugin / protobuf,`tools = [...]` 写在同一处, 环境变量本来就在消费者进程里,规则直接 `mcpp::dep_bin()` 就读到了。 2. **真正挡路的是另外两个缺口**,都在 mcpp 2026.8.5.1:规则里 `import std;` 与 `import mcpp;` 都编不过(host module 在 std 建好前就编译;`host-module = true` 没把包移出普通依赖图,于是又被当普通库编一遍)。已在 mcpp 2026.8.5.2 修掉 (mcpp#357),所以 CI floor 抬到 2026.8.5.2。 3. **包名必须是合法 C++ 模块名。** mcpp 用裸 `package.name` 注册 host 模块,所以 包名就是模块名 —— `grpc-rules` 不行(连字符),故名 `grpcgen`。 ── 两个示例,是刻意的 ─────────────────────────────────────────────────────── - `examples/greeter`(新)= `templates/greeter` 的实例化,三行 build.mcpp。 CI 构建它**就是**在测试模板 —— 否则模板坏了只有用户 `mcpp new` 时才发现。 新增 job `template-matches-example` 机器校验两者的 build.mcpp 逐字节相同。 - `examples/helloworld` 保留手写版本,把规则摊开写,让机制保持可读。 `package-versions-match`(原 plugin-version-matches)扩到三个包:grpc / grpc-plugin / grpcgen 同 tag 同版本,版本漂开正是本方案要消灭的那类错配。 --- .../2026-08-05-codegen-ecosystem-design.md | 69 ++++++-- .github/workflows/ci.yml | 62 +++++-- README.md | 43 +++-- README.zh.md | 40 +++-- examples/greeter/build.mcpp | 22 +++ examples/greeter/mcpp.toml | 44 +++++ examples/greeter/proto/helloworld.proto | 18 ++ examples/greeter/src/main.cpp | 111 ++++++++++++ examples/helloworld/build.mcpp | 138 ++++++++++----- rules/mcpp.toml | 39 +++++ rules/src/grpcgen.cppm | 163 ++++++++++++++++++ templates/greeter/build.mcpp.in | 78 ++------- templates/greeter/mcpp.toml.in | 4 + templates/greeter/template.toml | 2 +- 14 files changed, 669 insertions(+), 164 deletions(-) create mode 100644 examples/greeter/build.mcpp create mode 100644 examples/greeter/mcpp.toml create mode 100644 examples/greeter/proto/helloworld.proto create mode 100644 examples/greeter/src/main.cpp create mode 100644 rules/mcpp.toml create mode 100644 rules/src/grpcgen.cppm diff --git a/.agents/docs/2026-08-05-codegen-ecosystem-design.md b/.agents/docs/2026-08-05-codegen-ecosystem-design.md index f9bf37c..299ed41 100644 --- a/.agents/docs/2026-08-05-codegen-ecosystem-design.md +++ b/.agents/docs/2026-08-05-codegen-ecosystem-design.md @@ -1,10 +1,11 @@ # grpc-m 全生态打通:让 codegen 不再签入仓库 > 状态:**已验证,实施中** -> 依赖:mcpp **2026.8.5.1**(#355 依赖产出的 host 工具、`mcpp:action=` 构建图节点、 -> `host-module = true` 规则包) -> 涉及:本仓库的 `plugin/`(新)、`templates/`、`examples/`、`.github/workflows/ci.yml`; -> `mcpp-index` 的 `compat.protobuf` 与新条目 `mcpplibs.grpc-plugin` +> 依赖:mcpp **2026.8.5.2**(.5.1 给出 #355 依赖产出的 host 工具与 `mcpp:action=` 构建图节点; +> .5.2 才让 `host-module = true` 规则包真正可用 —— 规则里能 `import std;` 与 `import mcpp;`) +> 涉及:本仓库的 `plugin/`(新)、`rules/`(新)、`templates/`、`examples/`、 +> `.github/workflows/ci.yml`;`mcpp-index` 的 `compat.protobuf` 与新条目 +> `mcpplibs.grpc-plugin` / `mcpplibs.grpcgen` --- @@ -162,23 +163,60 @@ compat.protobuf = { version = "35.1", tools = ["protoc"] } 模板直接给出可用的 `build.mcpp`,用户 `mcpp new --template greeter` 之后改 `.proto` 即可,**不需要理解 action 的细节**。 -### 5.2 下一步:规则包(不在本次范围,设计在此) +### 5.2 规则包(**已实施** —— `rules/` 包 `grpcgen`) | | 用户要写 | |---|---| | CMake + vcpkg/Conan | `protobuf_generate(TARGET app)` ≈ 1 行(交叉时要自己处理 host protoc) | | xmake | `add_rules("protobuf.cpp")` ≈ 1 行(交叉下 protoc **没接通**) | -| **mcpp 本方案** | 约 20 行 build.mcpp | -| mcpp + 规则包 | **约 3 行** | +| mcpp,手写 build.mcpp | 约 60 行(= `examples/helloworld`) | +| **mcpp + 规则包** | **3 行**(= `templates/greeter` 与 `examples/greeter`) | -`host-module = true` 就是为这一步做的:规则以**普通 mcpp 包**分发,消费者 -`import mcpp.rules.grpc;`。规则因此有版本、能测试、能发布,而且是 **C++** 写的 —— +```cpp +import mcpp; +import grpcgen; +int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } +``` + +规则以**普通 mcpp 包**分发:有版本、能测试、能发布,而且是 **C++** 写的 —— 不引入第二门语言(xmake 用 Lua rule、Bazel 用 Starlark)。 -**为什么不在本次做**:规则包要有自己的发布节奏;而且有一个**已知的引擎缺口**要先补 —— -一个 `host-module` 规则包**带不动自己的 tools**:工具的环境变量按「请求它的那个包」 -记账,而规则代码是在**消费者**的 build.mcpp 里执行的,于是消费者看不到那个变量。 -补法是让 host-module 依赖的 tools 转发给消费者,是一处小改动,但要单独做。 +> 初版设计把这一步推迟了,理由是「规则包带不动自己的 tools」。**那条理由不成立**: +> 消费者本来就要在自己的 manifest 里声明 grpc / grpc-plugin / protobuf,`tools = [...]` +> 写在同一处,于是环境变量本来就在消费者进程里,规则直接 `mcpp::dep_bin()` 就能读到。 +> +> 真正挡路的是**另外两个**缺口,都是 2026.8.5.1 引入的,已在 **mcpp 2026.8.5.2** 修掉 +> (mcpp PR #357),因此本仓库的 CI floor 是 2026.8.5.2: +> +> 1. **规则里 `import std;` 编不过。** host module 在 std 模块建好之前就被编译, +> `stdFlags` 是空的;而且「是否需要 std」只扫 `build.mcpp`,规则说了不算。 +> 2. **规则里 `import mcpp;` 编不过。** `host-module = true` 只注册模块,没把这个包 +> 移出消费者的普通依赖图 —— 同一个 `.cppm` 又被当普通库编一遍,那次编译里 +> `mcpp` 模块并不存在,报 `fatal error: module 'mcpp' not found`。 +> +> 换句话说:规则包机制发布时,**只能承载「手工 printf 指令」的玩具规则**。 +> grpc-m 是它的第一个真实使用者,一次撞上两个。 + +**命名是承重的**:mcpp 用依赖的裸 `package.name` 注册 host 模块,所以包名**就是** +模块名,必须是合法 C++ 模块名。`grpc-rules` 不行(连字符),`grpcgen` 可以 —— +而且报错是 `module 'grpc_rules' not found`,不会提示你名字有问题。 + +**为什么规则里那段 well-known types 探测不能省**:protoc 不内嵌 WKT, +`import "google/protobuf/timestamp.proto"` 是从磁盘读的。真实服务几乎必用 +Timestamp / Duration / Any,所以这不是边角情况 —— 它是**用户写第二个 .proto 时 +必然撞上的墙**。路径可以从 `mcpp::dep_dir("protobuf")` 推出来,代价是规则里多 8 行; +把这 8 行放进规则包,正是规则包存在的意义。 + +### 5.3 三个包,一个 tag + +| 包 | 是什么 | 消费者怎么写 | +|---|---|---| +| `mcpplibs.grpc` | gRPC 运行时 | `grpc = "1.83.0"` | +| `mcpplibs.grpc-plugin` | `grpc_cpp_plugin`(codegen 工具) | `{ version = "1.83.0", tools = ["grpc_cpp_plugin"] }` | +| `mcpplibs.grpcgen` | 构建规则(host module) | `{ version = "1.83.0", host-module = true }` | + +三者同 tag、同版本号,CI 的 `package-versions-match` 机器校验 —— 版本漂开正是本 +方案要消灭的那类错配。 ## 6. 已知缺口(都不阻塞本方案) @@ -197,8 +235,9 @@ compat.protobuf = { version = "35.1", tools = ["protoc"] } | ✓ grpc_cpp_plugin 可构建 | 3 TU + libprotoc,**2.19s**(protobuf 命中全局缓存) | | ✓ 两者生成的桩子正确 | 四个文件与仓库签入的**逐字节相同** | | ✓ 工具进全局 store 并跨工程复用 | 二次构建不重建 | -| 生成的桩子能编能跑 | example 去签入 gen/ 后 `mcpp run` 完成真实 RPC | -| 改 `.proto` 触发重新生成 | 且不相关的重建不触发 | +| 生成的桩子能编能跑 | **本地未验证** —— 本沙箱装不上 compat.openssl(gRPC 的硬依赖),由 CI 的 linux + macOS 两条腿验证 | +| ✓ 改 `.proto` 触发重新生成 | 实测 1.38s vs 空转 0.02s;跨 proto import 也重跑 | +| ✓ 规则包把 build.mcpp 降到 3 行 | 已用 protobuf-only 工程实测跑通全链路(生成→编译→链接→运行);`examples/greeter` = 模板实例化,CI 构建它即测试模板 | ## 8. 明确不做 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91b45ea..9c964c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,10 +8,13 @@ on: env: # Keep in step with the mcpp-index CI pin: this package's dependencies are # index packages, and they are validated against that same mcpp. - # 2026.8.5.1 is the FLOOR, not a routine pin: `tools = [...]` host tools and - # `mcpp:action=` build-graph nodes — what the codegen in templates/ and - # examples/ is built on — do not exist before it. - MCPP_VERSION: "2026.8.5.1" + # 2026.8.5.2 is the FLOOR, not a routine pin. Three things the codegen in + # templates/ and examples/ is built on do not exist before it: + # 2026.8.5.1 `tools = [...]` host tools; `mcpp:action=` build-graph nodes + # 2026.8.5.2 a `host-module = true` rule package may use `import std;` and + # `import mcpp;` — rules/ needs both, and before .5.2 it failed + # with `module 'std' not found` / `module 'mcpp' not found` + MCPP_VERSION: "2026.8.5.2" jobs: build: @@ -73,6 +76,7 @@ jobs: "$MCPP" --version "$MCPP" test + # The long form: codegen spelled out by hand in build.mcpp. - name: helloworld example — a real RPC over loopback shell: bash working-directory: examples/helloworld @@ -82,25 +86,61 @@ jobs: run: | "$MCPP" run - plugin-version-matches: - name: grpc-plugin version == grpc version + # The short form: the same program, with codegen from the `grpcgen` rule + # package and a three-line build.mcpp. This example IS templates/greeter + # instantiated, so building it is how the template gets tested — a broken + # template would otherwise only be discovered by a user running + # `mcpp new`. + - name: greeter example — the template, via the rule package + shell: bash + working-directory: examples/greeter + env: + MCPP_INDEX_MIRROR: GLOBAL + MCPP_BUILD_CACHE: local + run: | + "$MCPP" run + + package-versions-match: + name: all three packages share one version runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # The plugin generates code that calls gRPC internals, so a plugin built # from a different release than the runtime being linked is exactly the - # mismatch this whole design exists to make impossible. They ship as two - # index entries from one tag, so nothing but a check keeps them equal. + # mismatch this whole design exists to make impossible. The rule package + # names both of the others by version in what it tells users to write. + # All three ship as separate index entries from ONE tag, so nothing but a + # check keeps them equal. - name: versions must match shell: bash run: | lib=$(awk -F'"' '/^version/{print $2; exit}' mcpp.toml) plug=$(awk -F'"' '/^version/{print $2; exit}' plugin/mcpp.toml) - echo "grpc=$lib grpc-plugin=$plug" - if [ "$lib" != "$plug" ]; then - echo "FAIL: grpc-plugin version ($plug) must equal grpc version ($lib)" + rule=$(awk -F'"' '/^version/{print $2; exit}' rules/mcpp.toml) + echo "grpc=$lib grpc-plugin=$plug grpcgen=$rule" + rc=0 + [ "$lib" = "$plug" ] || { echo "FAIL: grpc-plugin ($plug) != grpc ($lib)"; rc=1; } + [ "$lib" = "$rule" ] || { echo "FAIL: grpcgen ($rule) != grpc ($lib)"; rc=1; } + exit $rc + + template-matches-example: + name: templates/greeter == examples/greeter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + # examples/greeter is the template instantiated; CI builds it, which is + # the only thing that tests the template at all. That only holds while + # the two do not drift, and build.mcpp is the file that matters — it is + # pure code with no substitutions, so it must be byte-identical. + - name: build.mcpp must be identical + shell: bash + run: | + if ! diff -u templates/greeter/build.mcpp.in examples/greeter/build.mcpp; then + echo "FAIL: the template and its example have drifted apart." + echo " cp templates/greeter/build.mcpp.in examples/greeter/build.mcpp" exit 1 fi + echo "template and example agree" manifest-matches-upstream: name: source list == upstream CMakeLists diff --git a/README.md b/README.md index 4320c22..99576cf 100644 --- a/README.md +++ b/README.md @@ -77,30 +77,39 @@ Prefer plain headers instead? That works too and needs no import at all: ## Code generation gRPC needs two host tools — `protoc` and `grpc_cpp_plugin` — and since **mcpp 2026.8.5.1** -you no longer supply them yourself. Declare them on the dependencies they belong to and -mcpp builds them for your machine: +you no longer supply them yourself. Declare them on the dependencies they belong to, add +the codegen rule, and that is the entire setup: ```toml [dependencies] grpc = "1.83.0" grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } +grpcgen = { version = "1.83.0", host-module = true } compat.protobuf = { version = "35.1", tools = ["protoc"] } ``` ```cpp -// build.mcpp — declare the generation as a build-graph edge -mcpp::action gen; -gen.role = "source"; -gen.arg(mcpp::dep_bin("protobuf", "protoc")) - .arg("--cpp_out=…").arg("--grpc_out=…") - .arg(std::string("--plugin=protoc-gen-grpc=") + mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin")) - .input("proto/helloworld.proto") - .output("…/helloworld.pb.cc").output("…/helloworld.grpc.pb.cc") - .submit(); +// build.mcpp — in full +import mcpp; +import grpcgen; +int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } ``` -`templates/greeter` and `examples/helloworld` both do exactly this — **no generated file -is checked in any more**. Edit the `.proto` and rebuild. +That is `templates/greeter`, and `mcpp new --template greeter` gives it to you ready to +build. **No generated file is checked in any more** — edit the `.proto` and rebuild. + +`grpcgen` is an ordinary mcpp package holding the rule, written in C++ and versioned +alongside gRPC. Rules ship through the package manager you already have, so there is no +second language here the way xmake has Lua rules and Bazel has Starlark. It needs +**mcpp 2026.8.5.2**, which is where a rule package first became able to use `import std;` +and `import mcpp;`. + +Two examples, on purpose: + +| | | +|---|---| +| `examples/greeter` | the template instantiated — 3-line `build.mcpp` via `grpcgen` | +| `examples/helloworld` | the same program with the rule written out by hand, so the mechanism stays legible | Three properties this buys, none of which hand-managed codegen can offer: @@ -146,7 +155,10 @@ third_party/grpc-1.83.0/ pinned upstream source, zero patches src/grpc.cppm the C++23 module interface (also the lib root) tools/gen_sources.py regenerates the source list from upstream CMakeLists.txt build.mcpp private include dirs + the `ares` off-state -examples/helloworld/ a real server, a real client, a real RPC +rules/ `grpcgen` — the codegen rule package (host module) +plugin/ `grpc_cpp_plugin` — the codegen tool, its own package +examples/greeter/ the template instantiated: 3-line build.mcpp +examples/helloworld/ the same program with the rule written out by hand ``` The 995-entry source list in `mcpp.toml` is **upstream's own** — the union of @@ -181,7 +193,8 @@ tarball is that artifact. ```bash mcpp test # builds the library, runs the module test -cd examples/helloworld && mcpp run +cd examples/greeter && mcpp run # 3-line build.mcpp (via grpcgen) +cd examples/helloworld && mcpp run # same program, rule written by hand ``` ## License diff --git a/README.zh.md b/README.zh.md index 9efee62..6ff733f 100644 --- a/README.zh.md +++ b/README.zh.md @@ -75,29 +75,37 @@ class Greeter final : public helloworld::Greeter::Service { ## 代码生成 gRPC 需要两个宿主工具 —— `protoc` 与 `grpc_cpp_plugin` —— 自 **mcpp 2026.8.5.1** 起 -你不再需要自己准备它们。把它们声明在各自所属的依赖上,mcpp 会为你的机器构建出来: +你不再需要自己准备它们。把它们声明在各自所属的依赖上、再加上 codegen 规则,配置就完了: ```toml [dependencies] grpc = "1.83.0" grpc-plugin = { version = "1.83.0", tools = ["grpc_cpp_plugin"] } +grpcgen = { version = "1.83.0", host-module = true } compat.protobuf = { version = "35.1", tools = ["protoc"] } ``` ```cpp -// build.mcpp —— 把生成声明成构建图的一条边 -mcpp::action gen; -gen.role = "source"; -gen.arg(mcpp::dep_bin("protobuf", "protoc")) - .arg("--cpp_out=…").arg("--grpc_out=…") - .arg(std::string("--plugin=protoc-gen-grpc=") + mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin")) - .input("proto/helloworld.proto") - .output("…/helloworld.pb.cc").output("…/helloworld.grpc.pb.cc") - .submit(); +// build.mcpp —— 全文如此 +import mcpp; +import grpcgen; +int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } ``` -`templates/greeter` 与 `examples/helloworld` 都是这么做的 —— **仓库里不再签入任何生成 -产物**。改 `.proto` 然后重新构建,就这样。 +这就是 `templates/greeter`,`mcpp new --template greeter` 直接给你一份能建的。 +**仓库里不再签入任何生成产物** —— 改 `.proto` 然后重新构建,就这样。 + +`grpcgen` 是一个普通的 mcpp 包,里面装着那条规则,用 C++ 写、与 gRPC 同版本发布。 +规则走你已经在用的包管理器分发,所以这里**没有第二门语言** —— 不像 xmake 用 Lua rule、 +Bazel 用 Starlark。它需要 **mcpp 2026.8.5.2**:规则包是从那一版起才真正能用 +`import std;` 与 `import mcpp;` 的。 + +两个示例,是刻意的: + +| | | +|---|---| +| `examples/greeter` | 模板的实例化 —— 经 `grpcgen`,`build.mcpp` 三行 | +| `examples/helloworld` | 同一个程序,但把规则手工摊开写,让机制保持可读 | 由此得到三个手工管理 codegen 给不了的性质: @@ -140,7 +148,10 @@ third_party/grpc-1.83.0/ 钉住的上游源码,零补丁 src/grpc.cppm C++23 模块接口(同时也是 lib root) tools/gen_sources.py 从上游 CMakeLists.txt 重新生成源码清单 build.mcpp 私有 include 目录 + `ares` 的关闭态 -examples/helloworld/ 真实服务端、真实客户端、真实 RPC +rules/ `grpcgen` —— codegen 规则包(host module) +plugin/ `grpc_cpp_plugin` —— 独立的 codegen 工具包 +examples/greeter/ 模板实例化:三行 build.mcpp +examples/helloworld/ 同一个程序,规则手工摊开写 ``` `mcpp.toml` 里那份 995 条的源码清单是**上游自己的** —— `add_library(gpr)`、 @@ -172,7 +183,8 @@ gRPC **不发布任何自包含的源码产物**。它的 tag 归档里 abseil ```bash mcpp test # 构建库并运行模块测试 -cd examples/helloworld && mcpp run +cd examples/greeter && mcpp run # 三行 build.mcpp(经 grpcgen) +cd examples/helloworld && mcpp run # 同一个程序,规则手写 ``` ## License diff --git a/examples/greeter/build.mcpp b/examples/greeter/build.mcpp new file mode 100644 index 0000000..b444f24 --- /dev/null +++ b/examples/greeter/build.mcpp @@ -0,0 +1,22 @@ +// gRPC codegen. +// +// To add a .proto: drop it in proto/ and add its name below. +// +// The rule lives in the `grpcgen` package rather than in this file, so it is +// versioned, tested and fixed in one place instead of copy-pasted into every +// project. It declares one build-graph edge per .proto — meaning protoc re-runs +// exactly when a .proto changes, in parallel with the rest of the build, and a +// failure is reported against the edge that produced it rather than as +// "build.mcpp exited 1". +// +// protoc and grpc_cpp_plugin are built by mcpp for THIS machine out of the same +// packages this project links, so they cannot be a different version from the +// runtime. Under `mcpp build --target ` they are still built for the +// build machine, because a code generator has to run here. You do not have to +// do anything for that. +import mcpp; +import grpcgen; + +int main() { + return grpcgen::generate({"helloworld"}) ? 0 : 1; +} diff --git a/examples/greeter/mcpp.toml b/examples/greeter/mcpp.toml new file mode 100644 index 0000000..cba4149 --- /dev/null +++ b/examples/greeter/mcpp.toml @@ -0,0 +1,44 @@ +# greeter — what `mcpp new --template greeter` produces. +# +# This example exists to keep the TEMPLATE honest: it is the template +# instantiated, so CI building it is CI testing what users are handed. The only +# deliberate difference is that the three grpc-m packages are taken by `path` +# rather than from the index, so the example tests the working tree. +# +# The sibling examples/helloworld does the same job with a hand-written +# build.mcpp instead of the rule package — that one demonstrates the mechanism, +# this one demonstrates the ergonomics. +# +# The protobuf/gRPC stubs are NOT checked in. They are generated during the +# build by protoc and grpc_cpp_plugin, which mcpp builds for this machine out of +# the same packages this project links against — so the generator and the +# runtime cannot be different versions. Edit proto/helloworld.proto and build; +# that is the whole workflow. +# +# Under `mcpp build --target ` both tools are still built for the BUILD +# machine, because a code generator has to run here. You do not have to do +# anything for that. +[package] +name = "greeter" +version = "0.1.0" +standard = "c++23" + +[build] +sources = ["src/main.cpp"] + +[targets.greeter] +kind = "bin" +main = "src/main.cpp" + +[dependencies] +grpc = { path = "../.." } +# The gRPC C++ codegen plugin — a package of its own rather than a target +# inside gRPC, because a code generator needs a .proto parser and a C++ +# emitter, not TLS, DNS and a regex engine. +grpc-plugin = { path = "../../plugin", tools = ["grpc_cpp_plugin"] } +# The codegen RULE. `host-module = true` makes its module importable from +# build.mcpp, which is why build.mcpp is three lines instead of sixty. It is +# build-time only — not compiled into or linked with this project. +grpcgen = { path = "../../rules", host-module = true } +# protoc, pinned to the same protobuf this project links. +compat.protobuf = { version = "35.1", tools = ["protoc"] } diff --git a/examples/greeter/proto/helloworld.proto b/examples/greeter/proto/helloworld.proto new file mode 100644 index 0000000..a855b87 --- /dev/null +++ b/examples/greeter/proto/helloworld.proto @@ -0,0 +1,18 @@ +// The canonical gRPC "hello world" service, matching +// https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld +syntax = "proto3"; + +package helloworld; + +service Greeter { + // Sends a greeting. + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +message HelloRequest { + string name = 1; +} + +message HelloReply { + string message = 1; +} diff --git a/examples/greeter/src/main.cpp b/examples/greeter/src/main.cpp new file mode 100644 index 0000000..ceadccf --- /dev/null +++ b/examples/greeter/src/main.cpp @@ -0,0 +1,111 @@ +// greeter — generated from grpc@1.83.0:greeter +// +// A gRPC greeter, end to end in ONE process. +// +// Upstream's example is two binaries (greeter_server / greeter_client) you run +// by hand. That shape cannot assert anything, so this collapses it into a +// single program that stands a real server on a real loopback port, dials it +// over a real HTTP/2 channel, makes a real unary RPC, and checks the answer — +// exercising the same stack the two-binary version does: +// +// ServerBuilder / Server -> src/cpp/server/** +// Greeter::Service (generated) -> helloworld.grpc.pb.cc (generated at build time) +// HelloRequest / HelloReply -> helloworld.pb.cc (protobuf runtime) +// CreateChannel / Stub -> src/cpp/client/** +// the wire itself -> src/core/** (HTTP/2, transport, iomgr) +// +// Returns non-zero on any mismatch, so `mcpp run` doubles as the test. +#include +#include +#include +#include + +#include + +#include "helloworld.grpc.pb.h" + +namespace { + +class GreeterService final : public helloworld::Greeter::Service { + grpc::Status SayHello(grpc::ServerContext* /*context*/, + const helloworld::HelloRequest* request, + helloworld::HelloReply* reply) override { + if (request->name().empty()) { + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "name must not be empty"); + } + reply->set_message("Hello " + request->name()); + return grpc::Status::OK; + } +}; + +} // namespace + +int main() { + GreeterService service; + + // Port 0 => the OS picks a free one and hands it back, so this never + // collides with whatever else is running on a CI machine. + int port = 0; + grpc::ServerBuilder builder; + builder.AddListeningPort("127.0.0.1:0", grpc::InsecureServerCredentials(), &port); + builder.RegisterService(&service); + + std::unique_ptr server = builder.BuildAndStart(); + if (!server || port == 0) { + std::puts("FAIL: server did not start"); + return 1; + } + const std::string target = "127.0.0.1:" + std::to_string(port); + std::printf("server listening on %s\n", target.c_str()); + + auto channel = grpc::CreateChannel(target, grpc::InsecureChannelCredentials()); + auto stub = helloworld::Greeter::NewStub(channel); + + int rc = 0; + + // 1. The happy path. + { + helloworld::HelloRequest request; + request.set_name("mcpp"); + helloworld::HelloReply reply; + grpc::ClientContext ctx; + ctx.set_deadline(std::chrono::system_clock::now() + std::chrono::seconds(10)); + + const grpc::Status status = stub->SayHello(&ctx, request, &reply); + if (!status.ok()) { + std::printf("FAIL: SayHello: %d %s\n", static_cast(status.error_code()), + status.error_message().c_str()); + rc = 1; + } else if (reply.message() != "Hello mcpp") { + std::printf("FAIL: got \"%s\", want \"Hello mcpp\"\n", reply.message().c_str()); + rc = 1; + } else { + std::printf("Greeter replied: %s\n", reply.message().c_str()); + } + } + + // 2. The error path must ALSO cross the wire: an empty name has to come + // back as INVALID_ARGUMENT from the server, not as a local success. + // Without this a stub that answered everything OK would pass. + if (rc == 0) { + helloworld::HelloRequest request; // name left empty on purpose + helloworld::HelloReply reply; + grpc::ClientContext ctx; + ctx.set_deadline(std::chrono::system_clock::now() + std::chrono::seconds(10)); + + const grpc::Status status = stub->SayHello(&ctx, request, &reply); + if (status.error_code() != grpc::StatusCode::INVALID_ARGUMENT) { + std::printf("FAIL: empty name gave %d, want INVALID_ARGUMENT\n", + static_cast(status.error_code())); + rc = 1; + } else { + std::printf("Greeter rejected the empty name: %s\n", status.error_message().c_str()); + } + } + + server->Shutdown(); + server->Wait(); + + std::puts(rc == 0 ? "helloworld: OK" : "helloworld: FAILED"); + return rc; +} diff --git a/examples/helloworld/build.mcpp b/examples/helloworld/build.mcpp index c1e653e..d64d4c2 100644 --- a/examples/helloworld/build.mcpp +++ b/examples/helloworld/build.mcpp @@ -1,69 +1,117 @@ -// gRPC codegen, as build-graph nodes. +// gRPC codegen, written out by hand. // -// The two tools come from the dependency graph — `mcpp::dep_bin()` reads the -// path mcpp published after building them for THIS machine. Nothing here knows -// or cares whether they were built from source, taken from the global store, or -// pointed at by a `[tools.overrides]` escape hatch. +// ── YOU PROBABLY WANT ../greeter INSTEAD ──────────────────────────────────── +// That example — and `mcpp new --template greeter`, which produces it — does +// exactly what this file does in THREE lines, by importing the `grpcgen` rule +// package: // -// The work is DECLARED, not done. Running protoc here would be the easy path -// and the wrong one: it would re-run on every prepare, for every .proto at -// once, serially, and a failure would surface as "build.mcpp exited 1". -// Declared as an action it becomes an edge in the build graph — it re-runs -// exactly when its .proto changes, in parallel with everything else, and a -// failure is attributed to the edge that produced it. +// import mcpp; +// import grpcgen; +// int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } +// +// This file is kept deliberately as the long form: it is the same work with +// nothing hidden, so the mechanism stays legible and the rule package has +// something to be checked against. Everything below is what grpcgen does for +// you. +// ──────────────────────────────────────────────────────────────────────────── +// +// To add a .proto: drop it in proto/ and add its name to kProtos below. +// +// protoc and grpc_cpp_plugin are built by mcpp for THIS machine, out of the +// same packages this project links — so they cannot be a different version +// than the runtime. Under `mcpp build --target ` they are still built +// for the build machine, because a code generator has to run here. You do not +// have to do anything for that. // // See ../../.agents/docs/2026-08-05-codegen-ecosystem-design.md. #include +#include #include + import mcpp; +// proto/.proto +static constexpr const char* kProtos[] = { + "helloworld", +}; + +// protoc does not embed the well-known types: `import +// "google/protobuf/timestamp.proto"` — and Duration, Any, Empty, Struct, which +// real services use constantly — is read from disk. They ship inside the +// protobuf package this project already depends on, so the path is derivable +// and you do not have to install anything. Found by looking for the directory +// that holds descriptor.proto rather than by assuming the tarball's layout. +static std::string well_known_types_dir() { + namespace fs = std::filesystem; + std::error_code ec; + for (const auto& e : fs::directory_iterator(mcpp::dep_dir("protobuf"), ec)) + if (fs::exists(e.path() / "src/google/protobuf/descriptor.proto", ec)) + return (e.path() / "src").generic_string(); + return {}; +} + int main() { const std::string root = mcpp::manifest_dir(); const std::string out = mcpp::out_dir(); const char* protoc = mcpp::dep_bin("protobuf", "protoc"); const char* plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); - if (!protoc || !*protoc) { + if (!protoc || !*protoc || !plugin || !*plugin) { std::fprintf(stderr, - "no protoc: declare compat.protobuf = { version = \"35.1\", " - "tools = [\"protoc\"] }\n"); + "missing a codegen tool. Both are declared in mcpp.toml:\n" + " compat.protobuf = { version = \"35.1\", tools = [\"protoc\"] }\n" + " grpc-plugin = { version = \"...\", tools = " + "[\"grpc_cpp_plugin\"] }\n"); return 1; } - if (!plugin || !*plugin) { - std::fprintf(stderr, - "no grpc_cpp_plugin: declare grpc-plugin = { ..., " - "tools = [\"grpc_cpp_plugin\"] }\n"); + + const std::string wkt = well_known_types_dir(); + if (wkt.empty()) { + std::fprintf(stderr, "no well-known .proto files in the protobuf " + "package\n"); return 1; } - const std::string proto = root + "/proto/helloworld.proto"; + for (const char* name : kProtos) { + const std::string proto = root + "/proto/" + name + ".proto"; + const std::string base = out + "/" + name; - // ONE action, four declared outputs. protoc emits the message code and the - // service stubs in a single invocation, so splitting it would run protoc - // twice for no reason. - // - // The .pb.h / .grpc.pb.h are declared too: they must be PRODUCED by this - // edge (main.cpp and the generated .cc include them), but mcpp knows a - // header is not a translation unit and keeps them out of the compile set. - mcpp::action gen; - gen.id = "protoc:helloworld"; - gen.role = "source"; - gen.description = "protoc + grpc_cpp_plugin -> helloworld"; - gen.arg(protoc) - .arg(("-I" + root + "/proto").c_str()) - .arg(("--cpp_out=" + out).c_str()) - .arg(("--grpc_out=" + out).c_str()) - .arg((std::string("--plugin=protoc-gen-grpc=") + plugin).c_str()) - .arg(proto.c_str()) - .input(proto.c_str()) - .output((out + "/helloworld.pb.cc").c_str()) - .output((out + "/helloworld.pb.h").c_str()) - .output((out + "/helloworld.grpc.pb.cc").c_str()) - .output((out + "/helloworld.grpc.pb.h").c_str()) - .submit(); + // The work is DECLARED, not done. Running protoc here would re-run it + // on every prepare, serially, and report a failure as "build.mcpp + // exited 1". As an action it is an edge in the build graph: it re-runs + // when its .proto changes, in parallel, and a failure is attributed to + // the edge that produced it. + // + // One action, four outputs — protoc emits the messages and the service + // stubs in a single invocation. The headers are declared because they + // must be PRODUCED by this edge; mcpp knows a header is not a + // translation unit and keeps it out of the compile set. + // + // Every .proto is an input of every action: a .proto that imports a + // sibling has a dependency this file does not parse, and regenerating + // a little too eagerly beats silently stale stubs. + mcpp::action gen; + const std::string id = std::string("protoc:") + name; + gen.id = id.c_str(); + gen.role = "source"; + gen.description = id.c_str(); + gen.arg(protoc) + .arg(("-I" + root + "/proto").c_str()) + .arg(("-I" + wkt).c_str()) + .arg(("--cpp_out=" + out).c_str()) + .arg(("--grpc_out=" + out).c_str()) + .arg((std::string("--plugin=protoc-gen-grpc=") + plugin).c_str()) + .arg(proto.c_str()); + for (const char* dep : kProtos) + gen.input((root + "/proto/" + dep + ".proto").c_str()); + gen.output((base + ".pb.cc").c_str()) + .output((base + ".pb.h").c_str()) + .output((base + ".grpc.pb.cc").c_str()) + .output((base + ".grpc.pb.h").c_str()) + .submit(); + } - // Where the generated headers live. PRIVATE to this package by design — - // an include dir a consumer must see belongs in the manifest, not in a - // build program. + // Where the generated headers live. PRIVATE to this package by design — an + // include dir a consumer must see belongs in the manifest, not here. mcpp::include_dir(out.c_str()); } diff --git a/rules/mcpp.toml b/rules/mcpp.toml new file mode 100644 index 0000000..3759b18 --- /dev/null +++ b/rules/mcpp.toml @@ -0,0 +1,39 @@ +# grpcgen — the gRPC/protobuf codegen rule, as a package. +# +# A rule ("run protoc and grpc_cpp_plugin over these .proto files") should be +# written once, not copy-pasted into every consumer's build.mcpp. mcpp ships it +# as an ordinary library package that the consumer imports from its build +# program: +# +# [dependencies] +# grpcgen = { version = "1.83.0", host-module = true } +# +# // build.mcpp +# import mcpp; +# import grpcgen; +# int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } +# +# Rules are therefore versioned, testable and distributed through the package +# manager that already exists — and written in C++, so the build does not grow +# a second language the way xmake's Lua rules or Bazel's Starlark do. +# +# The package name is load-bearing: mcpp registers a host module under the +# dependency's `package.name`, so the name here IS the module name and must be +# a legal C++ module name (no hyphens, no dots). +# +# Versioned in lock-step with grpc and grpc-plugin: all three ship from one +# tag, and .github/workflows/ci.yml checks that they never drift apart. +[package] +name = "grpcgen" +version = "1.83.0" +standard = "c++23" +description = "protoc + grpc_cpp_plugin codegen as an importable mcpp build rule" +license = "Apache-2.0" +repo = "https://github.com/mcpplibs/grpc-m" +platforms = ["linux", "macos", "windows"] + +# No dependencies on purpose. A host module is compiled alongside build.mcpp, +# where only `std` and the bundled `mcpp` module exist — see the note at the +# top of src/grpcgen.cppm for why this rule uses neither. +[targets.grpcgen] +kind = "lib" diff --git a/rules/src/grpcgen.cppm b/rules/src/grpcgen.cppm new file mode 100644 index 0000000..191e76f --- /dev/null +++ b/rules/src/grpcgen.cppm @@ -0,0 +1,163 @@ +// grpcgen — protoc + grpc_cpp_plugin as an importable build rule. +// +// Consumers write three lines and never see anything below: +// +// import mcpp; +// import grpcgen; +// int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } +// +// `host-module = true` makes mcpp compile this interface in the same command as +// the consumer's build.mcpp, which is what makes the BMI importable there and +// what lets this file use `import mcpp;` — the typed wrapper over the `mcpp:` +// directive protocol — rather than hand-printing JSON. +// +// Requires mcpp >= 2026.8.5.2. Both of those properties are fixes in that +// release: before it, a rule was compiled before the std module existed +// (`module 'std' not found`) and was ALSO compiled as an ordinary library of +// the consumer, where the `mcpp` module does not exist. +export module grpcgen; + +import std; +import mcpp; + +namespace grpcgen::detail { + +// protoc does not embed the well-known types: `import +// "google/protobuf/timestamp.proto"` — and Duration, Any, Empty, Struct, which +// real services use constantly — is read from disk. They ship inside the +// protobuf package the consumer already depends on, so the path is derivable +// and nobody has to install anything. +// +// Found by looking for the directory that actually holds descriptor.proto, +// rather than by assuming the tarball's wrap-directory name: that name is a +// packaging artifact and not part of any contract. +std::string well_known_types_dir() { + namespace fs = std::filesystem; + const std::string base = mcpp::dep_dir("protobuf"); + if (base.empty()) return {}; + std::error_code ec; + for (const auto& e : fs::directory_iterator(base, ec)) { + const fs::path src = e.path() / "src"; + if (fs::exists(src / "google" / "protobuf" / "descriptor.proto", ec)) + return src.generic_string(); + } + return {}; +} + +} // namespace grpcgen::detail + +export namespace grpcgen { + +struct options { + // Where the .proto files live, relative to the consumer's manifest. + std::string_view proto_dir = "proto"; + // Also run grpc_cpp_plugin. Set false for a protobuf-only project, which + // then needs neither the plugin dependency nor its tool. + bool grpc = true; +}; + +// Declare one codegen edge per .proto. Names are given WITHOUT the extension, +// relative to `opt.proto_dir` — "helloworld" means /helloworld.proto. +// +// Returns false after printing a diagnostic; a build program should propagate +// that as a non-zero exit. +bool generate(std::initializer_list protos, options opt = {}) { + const std::string root = mcpp::manifest_dir(); + const std::string out = mcpp::out_dir(); + if (root.empty() || out.empty()) { + std::println(std::cerr, + "grpcgen: no mcpp build context — this runs from build.mcpp"); + return false; + } + if (protos.size() == 0) { + std::println(std::cerr, "grpcgen::generate() called with no .proto files"); + return false; + } + + const char* protoc = mcpp::dep_bin("protobuf", "protoc"); + if (!protoc || !*protoc) { + std::println(std::cerr, + "grpcgen: no protoc. Declare it in mcpp.toml:\n" + " compat.protobuf = {{ version = \"35.1\", tools = [\"protoc\"] }}"); + return false; + } + + const char* plugin = ""; + if (opt.grpc) { + plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); + if (!plugin || !*plugin) { + std::println(std::cerr, + "grpcgen: no grpc_cpp_plugin. Declare it in mcpp.toml:\n" + " grpc-plugin = {{ version = \"...\", tools = " + "[\"grpc_cpp_plugin\"] }}\n" + " (or call grpcgen::generate(..., {{.grpc = false}}) for a " + "protobuf-only project)"); + return false; + } + } + + const std::string wkt = detail::well_known_types_dir(); + if (wkt.empty()) { + std::println(std::cerr, + "grpcgen: cannot locate the well-known .proto files inside the " + "protobuf package"); + return false; + } + + const std::string protoDir = root + "/" + std::string(opt.proto_dir); + + // Every .proto is an input of every action. A .proto that imports a sibling + // has a real dependency this rule does not parse, and regenerating a little + // too eagerly is far better than silently stale stubs. + std::vector inputs; + inputs.reserve(protos.size()); + for (const char* n : protos) + inputs.push_back(std::format("{}/{}.proto", protoDir, n)); + + for (const char* name : protos) { + const std::string src = std::format("{}/{}.proto", protoDir, name); + const std::string base = std::format("{}/{}", out, name); + + // The work is DECLARED, not done. Running protoc here would re-run it + // on every prepare, serially, and report failure as "build.mcpp exited + // 1". As an action it is an edge in the build graph: it re-runs when + // its inputs change, in parallel, and a failure is attributed to the + // edge that produced it. + // + // The headers are declared as outputs because they must be PRODUCED by + // this edge; mcpp knows a header is not a translation unit and keeps + // them out of the compile set. + mcpp::action gen; + const std::string id = std::format("protoc:{}", name); + gen.id = id.c_str(); + gen.role = "source"; + gen.description = id.c_str(); + + const std::string incProto = "-I" + protoDir; + const std::string incWkt = "-I" + wkt; + const std::string cppOut = "--cpp_out=" + out; + gen.arg(protoc).arg(incProto.c_str()).arg(incWkt.c_str()) + .arg(cppOut.c_str()); + + const std::string grpcOut = "--grpc_out=" + out; + const std::string pluginArg = std::string("--plugin=protoc-gen-grpc=") + plugin; + if (opt.grpc) gen.arg(grpcOut.c_str()).arg(pluginArg.c_str()); + gen.arg(src.c_str()); + + for (const auto& in : inputs) gen.input(in.c_str()); + + const std::string pbcc = base + ".pb.cc", pbh = base + ".pb.h"; + gen.output(pbcc.c_str()).output(pbh.c_str()); + const std::string gcc_ = base + ".grpc.pb.cc", gh = base + ".grpc.pb.h"; + if (opt.grpc) gen.output(gcc_.c_str()).output(gh.c_str()); + gen.submit(); + } + + // Where the generated headers live. PRIVATE to the consuming package by + // design — an include dir that a package's own consumers must see belongs + // in its manifest, not in a build program. + mcpp::include_dir(out.c_str()); + return true; +} + +} // namespace grpcgen diff --git a/templates/greeter/build.mcpp.in b/templates/greeter/build.mcpp.in index e2cb31c..b444f24 100644 --- a/templates/greeter/build.mcpp.in +++ b/templates/greeter/build.mcpp.in @@ -1,70 +1,22 @@ -// gRPC codegen, as build-graph nodes. +// gRPC codegen. // -// The two tools come from the dependency graph — `mcpp::dep_bin()` reads the -// path mcpp published after building them for THIS machine. Nothing here knows -// or cares whether they were built from source, taken from the global store, or -// pointed at by a `[tools.overrides]` escape hatch. +// To add a .proto: drop it in proto/ and add its name below. // -// The work is DECLARED, not done. Running protoc here would be the easy path -// and the wrong one: it would re-run on every prepare, for every .proto at -// once, serially, and a failure would surface as "build.mcpp exited 1". -// Declared as an action it becomes an edge in the build graph — it re-runs -// exactly when its .proto changes, in parallel with everything else, and a -// failure is attributed to the edge that produced it. +// The rule lives in the `grpcgen` package rather than in this file, so it is +// versioned, tested and fixed in one place instead of copy-pasted into every +// project. It declares one build-graph edge per .proto — meaning protoc re-runs +// exactly when a .proto changes, in parallel with the rest of the build, and a +// failure is reported against the edge that produced it rather than as +// "build.mcpp exited 1". // -// Design notes: mcpplibs/grpc-m, -// .agents/docs/2026-08-05-codegen-ecosystem-design.md -#include -#include +// protoc and grpc_cpp_plugin are built by mcpp for THIS machine out of the same +// packages this project links, so they cannot be a different version from the +// runtime. Under `mcpp build --target ` they are still built for the +// build machine, because a code generator has to run here. You do not have to +// do anything for that. import mcpp; +import grpcgen; int main() { - const std::string root = mcpp::manifest_dir(); - const std::string out = mcpp::out_dir(); - - const char* protoc = mcpp::dep_bin("protobuf", "protoc"); - const char* plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); - if (!protoc || !*protoc) { - std::fprintf(stderr, - "no protoc: declare compat.protobuf = { version = \"35.1\", " - "tools = [\"protoc\"] }\n"); - return 1; - } - if (!plugin || !*plugin) { - std::fprintf(stderr, - "no grpc_cpp_plugin: declare grpc-plugin = { ..., " - "tools = [\"grpc_cpp_plugin\"] }\n"); - return 1; - } - - const std::string proto = root + "/proto/helloworld.proto"; - - // ONE action, four declared outputs. protoc emits the message code and the - // service stubs in a single invocation, so splitting it would run protoc - // twice for no reason. - // - // The .pb.h / .grpc.pb.h are declared too: they must be PRODUCED by this - // edge (main.cpp and the generated .cc include them), but mcpp knows a - // header is not a translation unit and keeps them out of the compile set. - mcpp::action gen; - gen.id = "protoc:helloworld"; - gen.role = "source"; - gen.description = "protoc + grpc_cpp_plugin -> helloworld"; - gen.arg(protoc) - .arg(("-I" + root + "/proto").c_str()) - .arg(("--cpp_out=" + out).c_str()) - .arg(("--grpc_out=" + out).c_str()) - .arg((std::string("--plugin=protoc-gen-grpc=") + plugin).c_str()) - .arg(proto.c_str()) - .input(proto.c_str()) - .output((out + "/helloworld.pb.cc").c_str()) - .output((out + "/helloworld.pb.h").c_str()) - .output((out + "/helloworld.grpc.pb.cc").c_str()) - .output((out + "/helloworld.grpc.pb.h").c_str()) - .submit(); - - // Where the generated headers live. PRIVATE to this package by design — - // an include dir a consumer must see belongs in the manifest, not in a - // build program. - mcpp::include_dir(out.c_str()); + return grpcgen::generate({"helloworld"}) ? 0 : 1; } diff --git a/templates/greeter/mcpp.toml.in b/templates/greeter/mcpp.toml.in index 07244b0..37b651d 100644 --- a/templates/greeter/mcpp.toml.in +++ b/templates/greeter/mcpp.toml.in @@ -27,6 +27,10 @@ main = "src/main.cpp" # inside gRPC, because a code generator needs a .proto parser and a C++ # emitter, not TLS, DNS and a regex engine. grpc-plugin = { version = "{{self.version}}", tools = ["grpc_cpp_plugin"] } +# The codegen RULE. `host-module = true` makes its module importable from +# build.mcpp, which is why build.mcpp is three lines instead of sixty. It is +# build-time only — not compiled into or linked with this project. +grpcgen = { version = "{{self.version}}", host-module = true } [dependencies.compat] # protoc, pinned to the same protobuf this project links. diff --git a/templates/greeter/template.toml b/templates/greeter/template.toml index 6ef7d13..7d7a658 100644 --- a/templates/greeter/template.toml +++ b/templates/greeter/template.toml @@ -1,3 +1,3 @@ [template] description = "Greeter service + client in one program — a real gRPC round trip over loopback" -post_message = "cd into the project and `mcpp run`. The protobuf/gRPC stubs are NOT checked in: mcpp builds protoc and grpc_cpp_plugin from the same packages you link against, then generates the stubs during the build. Edit proto/helloworld.proto and rebuild — that is the whole workflow, and the generator can never be a different version from the runtime." +post_message = "cd into the project and `mcpp run`. The protobuf/gRPC stubs are NOT checked in: mcpp builds protoc and grpc_cpp_plugin from the same packages you link against, then generates the stubs during the build. Edit proto/helloworld.proto and rebuild — that is the whole workflow, and the generator can never be a different version from the runtime. To add a .proto, drop it in proto/ and add its name to the list in build.mcpp." From 19633a9005cb6c9fab2ad7f316d93e17dcbc719b Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 5 Aug 2026 17:55:42 +0800 Subject: [PATCH 3/5] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=E8=A7=84?= =?UTF-8?q?=E5=88=99=E5=8C=85=E4=B8=A4=E6=9D=A1=E8=B7=AF=E5=BE=84=E7=9A=84?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=E7=BB=93=E6=9E=9C=E4=B8=8E=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E6=AC=A1=E5=BA=8F=E7=BA=A6=E6=9D=9F=E7=9A=84=E8=AF=81=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `grpc = false` 全链路跑通;`grpc = true` 四个产物齐全。 - **规则产出与官方 protoc 35.1 + 官方插件的产物逐字节相同** —— 之前验证的是手写 build.mcpp 的产物,这次验证的是规则包的。 - §4.1 的「索引先合」不是推测:插件包在 `compat.protobuf` 没有 `protoc` feature 时 链接期报 `undefined symbol: typeinfo for google::protobuf::compiler::CodeGenerator`。 --- .agents/docs/2026-08-05-codegen-ecosystem-design.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.agents/docs/2026-08-05-codegen-ecosystem-design.md b/.agents/docs/2026-08-05-codegen-ecosystem-design.md index 299ed41..8ee1dfc 100644 --- a/.agents/docs/2026-08-05-codegen-ecosystem-design.md +++ b/.agents/docs/2026-08-05-codegen-ecosystem-design.md @@ -237,7 +237,9 @@ Timestamp / Duration / Any,所以这不是边角情况 —— 它是**用户 | ✓ 工具进全局 store 并跨工程复用 | 二次构建不重建 | | 生成的桩子能编能跑 | **本地未验证** —— 本沙箱装不上 compat.openssl(gRPC 的硬依赖),由 CI 的 linux + macOS 两条腿验证 | | ✓ 改 `.proto` 触发重新生成 | 实测 1.38s vs 空转 0.02s;跨 proto import 也重跑 | -| ✓ 规则包把 build.mcpp 降到 3 行 | 已用 protobuf-only 工程实测跑通全链路(生成→编译→链接→运行);`examples/greeter` = 模板实例化,CI 构建它即测试模板 | +| ✓ 规则包把 build.mcpp 降到 3 行 | `grpc = false` 路径全链路跑通(生成→编译→链接→运行);`grpc = true` 路径四个产物齐全 | +| ✓ **规则产出 ≡ 官方产出** | 规则生成的四个文件与官方 protoc 35.1 + 官方插件的产物**逐字节相同** | +| ✓ 插件包必须等索引先合 | 未开 `protoc` feature 时链接期报 `undefined symbol: typeinfo for CodeGenerator` —— §4.1 的次序约束是实测的,不是推测 | ## 8. 明确不做 From bb0d422fc569b1085664de75254e717ed525acd3 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 5 Aug 2026 22:15:47 +0800 Subject: [PATCH 4/5] =?UTF-8?q?refactor(build.mcpp):=20=E6=94=B9=E7=94=A8?= =?UTF-8?q?=20import=20std;,=E4=B8=8D=E5=86=8D=E5=9B=9E=E9=80=80=E5=88=B0?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=A4=B4=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 一个构建程序就是普通的 C++23,没有理由成为整个模块化工程里唯一退回 `#include` 的地方。mcpp 会为它构建 host 的 std 模块,复用的正是工程自己的 TU 所 import 的 那份 BMI;宿主工具链若没有 std 模块,mcpp 会明确报错并给出修法。 两处: - `build.mcpp`(库自身,设置私有 include 目录与 `ares` 的关闭态) - `examples/helloworld/build.mcpp`(手写长版本的 codegen 示例) `templates/greeter` 与 `examples/greeter` 只有三行,本来就不碰标准库; `rules/src/grpcgen.cppm` 一开始就是 `import std;`。 ── 一个会咬人的细节 ───────────────────────────────────────────────────────── `import std;` **不导出 C 的 `stderr`**:它是 `` 里的**宏**,不属于 `std::` 命名空间,没有模块会导出它。于是 std::fprintf(stderr, ...) // 编译不过 /usr/include/stdio.h:151:14: error: ... extern FILE *stderr; 改用 `std::println(std::cerr, ...)` —— `std::cerr` 在 `std::` 里,由 `import std;` 正常导出。库自身那份本来就只往 stdout 写(指令流的注释里写明了「诊断走 stdout, 绝不走 stderr,后者会插进被缓冲的指令流」),所以不受影响。 两种写法都用等价工程实测编译通过。 --- build.mcpp | 17 ++++++++++------- examples/helloworld/build.mcpp | 19 +++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/build.mcpp b/build.mcpp index 5f517b7..2cdb8ac 100644 --- a/build.mcpp +++ b/build.mcpp @@ -23,13 +23,16 @@ // feature is absent. The 7 resolver TUs are handled the other way round — // declaratively, by [features.ares].sources. // -// Style follows opencv-m: textual std includes first, then `import mcpp;` -// (the mcpp module is bundled in the mcpp binary, so it always matches the -// directive protocol). Diagnostics go to stdout as non-directive lines — -// never stderr, which can interleave into the buffered directive stream. -#include -#include - +// `import std;` rather than textual /: a build program is +// ordinary C++23 and there is no reason for it to be the one place in a +// modular project that falls back to headers. mcpp builds the host std module +// for it, reusing the very BMI the project's own TUs import. If a host +// toolchain ships no std module, mcpp says so and names the fix. +// +// The mcpp module is bundled in the mcpp binary, so it always matches the +// directive protocol. Diagnostics go to stdout as non-directive lines — never +// stderr, which can interleave into the buffered directive stream. +import std; import mcpp; int main() { diff --git a/examples/helloworld/build.mcpp b/examples/helloworld/build.mcpp index d64d4c2..5336273 100644 --- a/examples/helloworld/build.mcpp +++ b/examples/helloworld/build.mcpp @@ -24,10 +24,7 @@ // have to do anything for that. // // See ../../.agents/docs/2026-08-05-codegen-ecosystem-design.md. -#include -#include -#include - +import std; import mcpp; // proto/.proto @@ -57,18 +54,20 @@ int main() { const char* protoc = mcpp::dep_bin("protobuf", "protoc"); const char* plugin = mcpp::dep_bin("grpc-plugin", "grpc_cpp_plugin"); if (!protoc || !*protoc || !plugin || !*plugin) { - std::fprintf(stderr, + // std::cerr, not the C `stderr`: `import std;` exports the namespace, + // and `stderr` is a MACRO that no module exports. + std::println(std::cerr, "missing a codegen tool. Both are declared in mcpp.toml:\n" - " compat.protobuf = { version = \"35.1\", tools = [\"protoc\"] }\n" - " grpc-plugin = { version = \"...\", tools = " - "[\"grpc_cpp_plugin\"] }\n"); + " compat.protobuf = {{ version = \"35.1\", tools = [\"protoc\"] }}\n" + " grpc-plugin = {{ version = \"...\", tools = " + "[\"grpc_cpp_plugin\"] }}"); return 1; } const std::string wkt = well_known_types_dir(); if (wkt.empty()) { - std::fprintf(stderr, "no well-known .proto files in the protobuf " - "package\n"); + std::println(std::cerr, + "no well-known .proto files in the protobuf package"); return 1; } From 04bd11c7ec7c748dcffe7e459fdcd82fc81c5b0b Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 5 Aug 2026 23:03:11 +0800 Subject: [PATCH 5/5] =?UTF-8?q?docs:=20=E4=BF=AE=E6=AD=A3=20`mcpp=20new=20?= =?UTF-8?q?--template`=20=E7=9A=84=E7=94=A8=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 我在 codegen 那节写的是 `mcpp new --template greeter` —— **错的**,而且错在用户会 敲的第一条命令上。`--template` 的文法是 `pkg | pkg:tmpl | pkg@ver | pkg@ver:tmpl` (src/cli/cmd_new.cppm),接的是**包名**,不是模板目录名。`greeter` 会被当成一个 不存在的包。 同一篇 README 的 Quick Start 一直写的是 `--template grpc`,是对的 —— 两处自相 矛盾,现在统一,并写明一个包带多个模板时怎么显式指定(`grpc:greeter`)。中英同步。 --- README.md | 5 +++-- README.zh.md | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 99576cf..953c5fd 100644 --- a/README.md +++ b/README.md @@ -95,8 +95,9 @@ import grpcgen; int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } ``` -That is `templates/greeter`, and `mcpp new --template greeter` gives it to you ready to -build. **No generated file is checked in any more** — edit the `.proto` and rebuild. +That is `templates/greeter`, and `mcpp new --template grpc` gives it to you ready to +build (`--template` takes the PACKAGE; spell the template out as `grpc:greeter` when a +package ships more than one). **No generated file is checked in any more** — edit the `.proto` and rebuild. `grpcgen` is an ordinary mcpp package holding the rule, written in C++ and versioned alongside gRPC. Rules ship through the package manager you already have, so there is no diff --git a/README.zh.md b/README.zh.md index 6ff733f..cf53ef9 100644 --- a/README.zh.md +++ b/README.zh.md @@ -92,7 +92,8 @@ import grpcgen; int main() { return grpcgen::generate({"helloworld"}) ? 0 : 1; } ``` -这就是 `templates/greeter`,`mcpp new --template greeter` 直接给你一份能建的。 +这就是 `templates/greeter`,`mcpp new --template grpc` 直接给你一份能建的 +(`--template` 接的是**包名**;一个包带多个模板时写成 `grpc:greeter`)。 **仓库里不再签入任何生成产物** —— 改 `.proto` 然后重新构建,就这样。 `grpcgen` 是一个普通的 mcpp 包,里面装着那条规则,用 C++ 写、与 gRPC 同版本发布。