streem / pbandk

Kotlin Code Generator and Runtime for Protocol Buffers
MIT License
271 stars 37 forks source link

How to get the generated code to work within a KMM project? #164

Closed todorus closed 3 years ago

todorus commented 3 years ago

Hi there,

We are starting on a project with KMM and Protobuf, and we are looking into PBandK, as it looks like a very promising project to use for Kotlin Native code generation.

We've managed to install protoc and the plugin just fine, and have generated the code. However in our KMM project, the generated ble_commands.kt file is full of unresolved references. We figure it is something to do with the runtime library not being imported correctly, but cannot find out what is causing it.

I've attached our .kts build file to this issue, and we would be much obliged if someone could point out our mistake(s). If needed, I can also create a public repo with our full project setup.

protoc v3.17.3 pbandk-protoc-gen v0.10.0

import com.android.build.gradle.internal.tasks.factory.dependsOn
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("multiplatform") version "1.5.20"
    id("com.android.library")
    id("kotlin-android-extensions")
}

group = "com.redacted.project"
version = "0.1-SNAPSHOT"

val pbandkVersion by extra("0.10.0")

repositories {
    google()
    mavenCentral()
}

kotlin {
    android()

    // Commented out the iOS builds for now, as we are depending on the PBandK runtime library for iOS. Currently
    // they do not build and iOS version of their runtime, and the workaround would be to build it ourselves and
    // host it internally.
    // See https://github.com/streem/pbandk/issues/97
    //
    // However. There is an active PR as the time of writing for this exact issue, and it is likely to be resolved,
    // by the time we start development on iOS.
    // See https://github.com/streem/pbandk/pull/163

//    iosX64("ios") {
//        binaries {
//            framework {
//                baseName = "library"
//            }
//        }
//    }
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("pro.streem.pbandk:pbandk-runtime:$pbandkVersion")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("com.google.android.material:material:1.2.1")
            }
        }
        val androidTest by getting {
            dependencies {
                implementation("junit:junit:4.13")
            }
        }

        // val iosMain by getting
        // val iosTest by getting
    }
}

android {
    compileSdkVersion(29)
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    defaultConfig {
        minSdkVersion(24)
        targetSdkVersion(29)
    }
}

tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}

val compileProtobuf = tasks.register("compileProtobuf") {
    print("* Compiling protobuf *\n")
    project.exec {
        commandLine = "mkdir -p build/proto/java".split(" ")
    }
    project.exec {
        commandLine = "mkdir -p ./src/commonMain/kotlin/com/redacted/project/proto".split(" ")
    }
    project.exec {
        commandLine = "rm -f ./src/commonMain/kotlin/com/redacted/project/proto/*".split(" ")
    }
    project.exec {
        commandLine = "protoc --pbandk_out=./src/commonMain/kotlin/com/redacted/project/proto --proto_path=./src/commonMain/proto ./src/commonMain/proto/ble_commands.proto".split(" ")
    }
}

beforeEvaluate {
    tasks.build.dependsOn(compileProtobuf)
}
garyp commented 3 years ago

Hi @todorus. Can you please provide an example of the compiler errors you're seeing when you try to build the project and a snippet of the Kotlin code at the place where the error is being reported?

todorus commented 3 years ago

Thanks for the quick reply @garyp!

I was preparing a sample for you using the addressbook.proto, to avoid NDA issues, and noticed that did work. I compared the two and noticed our proto file had no package defined.

I am sorry to bother you with something this silly. Perhaps it can be documented as a requirement in a future release?

garyp commented 3 years ago

I'm glad you figured it out! Declaring a package in your proto file is considered best-practice when defining protobuf messages and that is the route I would recommend.

However, you are technically allowed to have a proto file with no package declaration. If you have a proto file like that for some reason, you'll just need to provide a kotlin_package option when running protoc to tell pbandk a valid package name to use in the generated code. For example:

protoc \
  --pbandk_out=kotlin_package=my.package.name:./src/commonMain/kotlin/com/redacted/project/proto \
  --proto_path=./src/commonMain/proto \
  ./src/commonMain/proto/ble_commands.proto

There's also an example at https://github.com/streem/pbandk#generating-code.