Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1f78401
protobuf codec, codegen, interop test
arjan-bal Jul 2, 2025
6a379ea
CI fixes
arjan-bal Jul 2, 2025
f3f9446
Enforce c++17
arjan-bal Jul 4, 2025
05f4d7d
Cache plugin
arjan-bal Jul 4, 2025
805cf79
Feature gate protobuf dependency
arjan-bal Jul 6, 2025
da8873f
Rename compiler directory
arjan-bal Jul 6, 2025
1a66195
Fix external types check
arjan-bal Jul 6, 2025
9c25329
Rename interop client biary
arjan-bal Jul 6, 2025
15e1519
Add liscenses
arjan-bal Jul 6, 2025
202411c
Docs and comments
arjan-bal Jul 6, 2025
fe31b76
Fix test
arjan-bal Jul 6, 2025
89d7331
Avoid using protobuf rust's context
arjan-bal Jul 8, 2025
9305da7
create a seperate module for the protobuf codec
arjan-bal Jul 9, 2025
ca8d638
Add readme for codegen
arjan-bal Jul 9, 2025
08c6be1
Apply suggestions from code review
arjan-bal Jul 11, 2025
4431e83
copyright in build files, clippy fixes and typos in README
arjan-bal Jul 11, 2025
8a8e4e6
mostly C++ readability fixes
arjan-bal Jul 14, 2025
cd77988
Format generated code during build
arjan-bal Jul 14, 2025
9f06a59
Address review
arjan-bal Jul 17, 2025
5cd495c
Apply suggestions from code review
arjan-bal Jul 17, 2025
c3e03f9
Combine client binaries, use flag for codec
arjan-bal Jul 17, 2025
e8aaa51
Merge remote-tracking branch 'source/master' into grpc-codegen
arjan-bal Jul 21, 2025
726d227
Fix cpp function name casing
arjan-bal Jul 21, 2025
d13eed5
Address review
arjan-bal Jul 23, 2025
c33f380
Align tonic-* crate versions in README
arjan-bal Jul 23, 2025
00b6d63
Use include! instead of path
arjan-bal Jul 25, 2025
e35ddb9
Merge remote-tracking branch 'source/master' into grpc-codegen
arjan-bal Jul 29, 2025
4b150c1
Export protobuf from tonic-protobuf
arjan-bal Jul 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,74 @@ jobs:
components: rustfmt
- run: cargo fmt --all --check

build-protoc-plugin:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
outputs:
cache-hit: ${{ steps.cache-plugin.outputs.cache-hit }}
steps:
- uses: actions/checkout@v4
- name: Cache protoc plugin
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
# The key changes only when plugin source files change
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Install Bazel
if: steps.cache-plugin.outputs.cache-hit != 'true'
uses: bazel-contrib/setup-bazel@0.15.0
with:
# Avoid downloading Bazel every time.
bazelisk-cache: true
# Store build cache per workflow.
disk-cache: ${{ github.workflow }}
# Share repository cache between workflows.
repository-cache: true
module-root: ./protoc-gen-rust-grpc
# Building the protoc plugin from scratch takes 6–14 minutes, depending on
# the OS. This delays the execution of workflows that use the plugin in
# build.rs files. We try to avoid rebuilding the plugin if it hasn't
# changed.
- name: Build protoc plugin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this step take a long time? Generally, speaking I would rather that we build the plugin in each test job to ensure we are building the latest code and there is no caching issues. Could you explain the reasoning for breaking it up like this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment in the yaml. Building the protoc plugin from scratch takes 6–14 minutes, depending on the OS. This delays the execution of workflows that use the plugin in build.rs files.

Example workflow execution: https://github.com/hyperium/tonic/actions/runs/16217230891/job/45789317103

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay yeah if this works its fine for now, we probably want to improve this in the future..

if: steps.cache-plugin.outputs.cache-hit != 'true'
working-directory: ./protoc-gen-rust-grpc
shell: bash
run: |
set -e
# On windows, the "//src" gets converted to "/". Disable this path
# conversion.
export MSYS_NO_PATHCONV=1
export MSYS2_ARG_CONV_EXCL="*"

bazel build //src:protoc-gen-rust-grpc --enable_platform_specific_config

# The target path needs to match the cache config.
TARGET_PATH="${{ runner.temp }}/protoc-plugin"
mkdir -p "${TARGET_PATH}"
cp bazel-bin/src/protoc-gen-rust-grpc "${TARGET_PATH}"

clippy:
runs-on: ubuntu-latest
needs: build-protoc-plugin
steps:
- uses: actions/checkout@v4
- uses: hecrj/setup-rust-action@v2
with:
components: clippy
- uses: taiki-e/install-action@protoc
- name: Restore protoc plugin from cache
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Add protoc plugin to PATH
shell: bash
run: |
echo "${{ runner.temp }}/protoc-plugin" >> $GITHUB_PATH
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --workspace --all-features --all-targets

Expand All @@ -47,6 +107,7 @@ jobs:

udeps:
runs-on: ubuntu-latest
needs: build-protoc-plugin
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
Expand All @@ -55,6 +116,16 @@ jobs:
- uses: taiki-e/install-action@cargo-hack
- uses: taiki-e/install-action@cargo-udeps
- uses: taiki-e/install-action@protoc
- name: Restore protoc plugin from cache
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Add protoc plugin to PATH
shell: bash
run: |
echo "${{ runner.temp }}/protoc-plugin" >> $GITHUB_PATH
- uses: Swatinem/rust-cache@v2
- run: cargo hack udeps --workspace --exclude-features=_tls-any,tls,tls-aws-lc,tls-ring --each-feature
- run: cargo udeps --package tonic --features tls-ring,transport
Expand All @@ -66,6 +137,7 @@ jobs:

check:
runs-on: ${{ matrix.os }}
needs: build-protoc-plugin
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
Expand All @@ -76,6 +148,16 @@ jobs:
- uses: hecrj/setup-rust-action@v2
- uses: taiki-e/install-action@cargo-hack
- uses: taiki-e/install-action@protoc
- name: Restore protoc plugin from cache
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Add protoc plugin to PATH
shell: bash
run: |
echo "${{ runner.temp }}/protoc-plugin" >> $GITHUB_PATH
- uses: Swatinem/rust-cache@v2
- name: Check features
run: cargo hack check --workspace --no-private --each-feature --no-dev-deps
Expand Down Expand Up @@ -108,13 +190,24 @@ jobs:

test:
runs-on: ${{ matrix.os }}
needs: build-protoc-plugin
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: hecrj/setup-rust-action@v2
- uses: taiki-e/install-action@protoc
- name: Restore protoc plugin from cache
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Add protoc plugin to PATH
shell: bash
run: |
echo "${{ runner.temp }}/protoc-plugin" >> $GITHUB_PATH
- uses: taiki-e/install-action@cargo-hack
- uses: taiki-e/install-action@cargo-nextest
- uses: Swatinem/rust-cache@v2
Expand All @@ -134,13 +227,24 @@ jobs:
interop:
name: Interop Tests
runs-on: ${{ matrix.os }}
needs: build-protoc-plugin
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: hecrj/setup-rust-action@v2
- uses: taiki-e/install-action@protoc
- name: Restore protoc plugin from cache
id: cache-plugin
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/protoc-plugin
key: ${{ runner.os }}-protoc-plugin-${{ hashFiles('protoc-gen-rust-grpc/src/**', 'protoc-gen-rust-grpc/.bazelrc', 'protoc-gen-rust-grpc/MODULE.bazel') }}
- name: Add protoc plugin to PATH
shell: bash
run: |
echo "${{ runner.temp }}/protoc-plugin" >> $GITHUB_PATH
- uses: Swatinem/rust-cache@v2
- name: Run interop tests
run: ./interop/test.sh
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ members = [
"tonic",
"tonic-build",
"tonic-health",
"tonic-protobuf",
"tonic-protobuf-build",
"tonic-types",
"tonic-reflection",
"tonic-prost",
Expand Down
1 change: 1 addition & 0 deletions grpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
pub mod client;
pub mod credentials;
pub mod inmemory;
mod macros;
pub mod rt;
pub mod server;
pub mod service;
Expand Down
104 changes: 104 additions & 0 deletions grpc/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
*
* Copyright 2025 gRPC authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/

/// Includes generated proto message, client, and server code.
///
/// You must specify the path to the `.proto` file
/// **relative to the proto root directory**, without the `.proto` extension.
///
/// For example, if your proto directory is `path/to/protos` and it contains the
/// file `helloworld.proto`, you would write:
///
/// ```rust,ignore
/// mod pb {
/// grpc::include_proto!("path/to/protos", "helloworld");
/// }
/// ```
///
/// # Note
/// **This macro only works if the gRPC build output directory and message path
/// are unmodified.**
/// By default:
/// - The output directory is set to the [`OUT_DIR`] environment variable.
/// - The message path is set to `self`.
///
/// If your `.proto` files are not in a subdirectory, you can omit the first
/// parameter.
///
/// ```rust,ignore
/// mod pb {
/// grpc::include_proto!("helloworld");
/// }
/// ```
///
/// If you have modified the output directory or message path, you should
/// include the generated code manually instead of using this macro.
///
/// The following example assumes the message code is imported using `self`:
///
/// ```rust,ignore
/// mod protos {
/// // Include message code.
/// include!("relative/protobuf/directory/generated.rs");
///
/// // Include service code.
/// include!("relative/protobuf/directory/helloworld_grpc.pb.rs");
/// }
/// ```
///
/// If the message code and service code are in different modules, and the
/// message path specified during code generation is `super::protos`, use:
///
/// ```rust,ignore
/// mod protos {
/// // Include message code.
/// include!("relative/protobuf/directory/generated.rs");
/// }
///
/// mod grpc {
/// // Include service code.
/// include!("relative/protobuf/directory/helloworld_grpc.pb.rs");
/// }
/// ```
///
/// [`OUT_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
#[macro_export]
macro_rules! include_proto {
// Assume the generated output dir is OUT_DIR.
($proto_file:literal) => {
$crate::include_proto!("", $proto_file);
};

($parent_dir:literal, $proto_file:literal) => {
include!(concat!(env!("OUT_DIR"), "/", $parent_dir, "/generated.rs"));
include!(concat!(
env!("OUT_DIR"),
"/",
$parent_dir,
"/",
$proto_file,
"_grpc.pb.rs"
));
};
}
9 changes: 9 additions & 0 deletions interop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ tonic = {path = "../tonic", features = ["tls-ring"]}
tonic-prost = {path = "../tonic-prost"}
tower = "0.5"
tracing-subscriber = {version = "0.3"}
grpc = {path = "../grpc"}
# TODO: Remove the direct protobuf dependency after updating to version 4.32,
# which includes https://github.com/protocolbuffers/protobuf/pull/22764.
# We also need the protobuf-codegen crate to support configuring the path
# to the protobuf crate used in the generated message code, instead of
# defaulting to `::protobuf`.
protobuf = { version = "4.31.1-release" }
tonic-protobuf = {path = "../tonic-protobuf"}

[build-dependencies]
tonic-prost-build = {path = "../tonic-prost-build"}
tonic-protobuf-build = {path = "../tonic-protobuf-build"}
5 changes: 5 additions & 0 deletions interop/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ fn main() {
let proto = "proto/grpc/testing/test.proto";

tonic_prost_build::compile_protos(proto).unwrap();
tonic_protobuf_build::CodeGen::new()
.include("proto/grpc/testing")
.inputs(["test.proto", "empty.proto", "messages.proto"])
.compile()
.unwrap();

// prevent needing to rebuild if files (or deps) haven't changed
println!("cargo:rerun-if-changed={proto}");
Expand Down
Loading
Loading