Search code examples
gradleprotocol-buffersgrpcgrpc-javagrpc-go

How to generate Go gRPC code with the protobuf-gradle-plugin?


This question is the same as this one, How do I use gradle to generate go grpc code?, but since that hasn't been answered yet I'm asking it again. I've made a simplified Gradle project with a structure similar to the following:

├── build.gradle
└── src
    └── main
        └── proto
            └── helloworld.proto

where build.gradle reads

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.14'
    }
}

plugins {
    id "com.google.protobuf" version "0.8.14"
    id "java"
}

dependencies {
    compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0'
    implementation group: 'io.grpc', name: 'grpc-protobuf', version: '1.35.0'
    implementation group: 'io.grpc', name: 'grpc-stub', version: '1.35.0'
    compileOnly group: 'org.apache.tomcat', name: 'annotations-api', version: '6.0.53'
}

protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.0.0'
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0-pre2'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
        all().each { task ->
            task.builtins {
                go {}
            }
        }
    }
}

and helloworld.proto is taken from a gRPC tutorial:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

If I run ./gradlew build, I get the following generated source code:

build/generated/source/
└── proto
    └── main
        ├── go
        │   └── helloworld.pb.go
        ├── grpc
        │   └── io
        │       └── grpc
        │           └── examples
        │               └── helloworld
        │                   └── GreeterGrpc.java
        └── java
            └── io
                └── grpc
                    └── examples
                        └── helloworld
                            ├── HelloReply.java
                            ├── HelloReplyOrBuilder.java
                            ├── HelloRequest.java
                            ├── HelloRequestOrBuilder.java
                            └── HelloWorldProto.java

I've done something similarly using protoc directly and would expect there to also be a helloworld_grpc.pb.go generated by the Go Protobuf plugin with gRPC server and client stubs. How can I get Gradle to generate this code?


Solution

  • gRPC-Go's codegen (https://github.com/grpc/grpc-go/tree/master/cmd/protoc-gen-go-grpc) is picked up by protoc automatically instead of specified in the --plugin flag (maybe there is a way, but I've never tried).

    First you need to install protoc-gen-go-grpc plugin following the gRPC quickstart. Make sure the plugin is in PATH.

    Then use the protoc-gen-go-grpc plugin in the same way for protoc builtins:

    protobuf {
        protoc {
            artifact = 'com.google.protobuf:protoc:3.0.0'
        }
        plugins {
            grpc {
                artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0-pre2'
            }
        }
        generateProtoTasks {
            all()*.plugins {
                grpc {}
            }
            all().each { task ->
                task.builtins {
                    go {}
                    'go-grpc' {}
                }
            }
        }
    }
    

    (Note you need the quote for 'go-grpc' due to the dash).

    Also note, the generated Go code won't be picked up by Gradle compilation tasks automatically, you would need to hook things up by yourself (something similar to srcDirs 'build/generated/source/proto/main/grpc' in the sourceSets block for Java, but I don't know how Gradle is used for building Go projects).