Search code examples
gradlekotlinprotocol-buffers

How to build Google protocol buffers and Kotlin using Gradle?


I'm trying to build a project that uses both Google protocol buffers and Kotlin using Gradle. I want the proto files to compile into Java source, which is then called from my Kotlin code.

My source files are arranged like this:

src/main/proto/*.proto
src/main/kotlin/*.kt
src/test/kotlin/*.kt

Here's my build.gradle file:

version '1.0-SNAPSHOT'

apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'com.google.protobuf'

repositories {
    mavenCentral()
    maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}


buildscript {
    ext.kotlin_version = '1.1-M02'

    repositories {
        mavenCentral()
        maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
    }

    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.0.0'
    }
}

dependencies {
    compile 'com.google.protobuf:protobuf-java:3.0.0'
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    testCompile 'junit:junit:4.12'
}

When I run ./gradlew assemble I get a bunch of "Unresolved reference" errors during :compileKotlin. Afterwards I can see that there are no Java source files generated, so it appears that the proto compiler is not being invoked at all.

If I remove the apply plugin: 'kotlin' line, then ./gradlew assemble successfully generates the Java source, but of course my Kotlin source is never compiled.

How do I fix my build.gradle so that I can call my protobuf code from Kotlin?


Solution

  • To get protobuf-gradle-plugin and kotlin-gradle-plugin to cooperate, you need to ensure that the Java code is (re)generated before invoking the Kotlin compiler.

    For Gradle's default source sets, main and test, you can do that like this:

    compileKotlin.dependsOn ':generateProto'
    compileTestKotlin.dependsOn ':generateTestProto'
    

    If you are using other source sets, you'll need to make adjustments.

    Older versions of protobuf-gradle-plugin also required updating sourceSets, but newer versions do not seem to require this.

    // Don't do this with protobuf-gradle-plugin 0.9.0 or higher
    sourceSets.main.java.srcDirs += "${protobuf.generatedFilesBaseDir}/main/java"
    sourceSets.test.java.srcDirs += "${protobuf.generatedFilesBaseDir}/test/java"