tonic: Client/Server /can be/ duplicated into their include files

Bug Report

Version

master: afa9d9d236b7ca96d70d696ab38aadac7cdf41ff

Platform

Linux RILEY-LT 4.19.43-microsoft-standard #1 SMP Mon May 20 19:35:22 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Crates

cargo-build

Description

When using includes it seems like the client/server are generated into the include file output. This only seems to happen under certain conditions, I believe related to compiling multiple protos at once via tonic_build::configure().compile(&["proto/health.proto", "proto/test.proto"], &["proto"]).unwrap();

Repro here:

https://github.com/rlabrecque/tonic_include_repro

Specifically see: https://github.com/rlabrecque/tonic_include_repro/blob/master/src/proto/google.protobuf.rs

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 18 (7 by maintainers)

Commits related to this issue

Most upvoted comments

There are a few different issues that I’ve found so far. First, take this set of proto files:

Proto files

proto/hello.proto

syntax = "proto3";

import "types.proto";

package helloworld;

service Greeting {
  rpc Hello (Message) returns (Response) {}
}

proto/goodbye.proto

syntax = "proto3";

import "types.proto";

package helloworld;

service Farewell {
  rpc Goodbye (Message) returns (Response) {}
}

proto/types.proto

syntax = "proto3";

package helloworld;

message Message {
  string say = 1;
}

message Response {
  string say = 1;
}

And the following build.rs:

fn main() {
    tonic_build::compile_protos("proto/hello.proto").unwrap();
    tonic_build::compile_protos("proto/goodbye.proto").unwrap();
    println!("cargo:rerun-if-changed=proto/hello.proto");
    println!("cargo:rerun-if-changed=proto/goodbye.proto");
    println!("cargo:rerun-if-changed=proto/types.proto");

This fails to work because building goodbye.proto completely overwrites the output file generated for hello.proto.

Ok, maybe the Builder type is smarter, since you can provide a list of paths to multiple proto files? Let’s update build.rs:

fn main() {
    tonic_build::configure()
        .compile(&["proto/hello.proto", "proto/goodbye.proto"], &["proto"])
        .unwrap();
    println!("cargo:rerun-if-changed=proto/hello.proto");
    println!("cargo:rerun-if-changed=proto/goodbye.proto");
    println!("cargo:rerun-if-changed=proto/types.proto");
}

And this also fails because now the generated output has duplicate client and server modules for the two different services defined in the helloworld package.

I’m curious why it worked fine on tower-grpc as well though. It seems like it’s possible and this is just a regression in the rewrite.

Using tower-grpc with the same build file (gathers all proto files with services in to the array) doesn’t have the same issue

I hit this problem with a different repro case. Compiling two proto files with the same package name defining unique services will output Rust source code like:

// services for first proto file in package "foo"
pub mod client {}
pub mod server {}

// services for second proto file in package "foo"
pub mod client {}
pub mod server {}

Which then leads to errors:

error[E0428]: the name `client` is defined multiple times
error[E0428]: the name `server` is defined multiple times

I have to merge all proto files for the single package into one file to workaround this issue.