androidgradleandroid-gradle-plugingradle-kotlin-dslgradle-task

How to run a main class in gradle task in android multi-module project?


In my android multi-module project, I want to execute a Kotlin file to generare code.

My need is:

I have a multi-module project with one app module and lots of library modules.

There is a module named offlinedb. In that I have a main function file in it's package com.framework.offlinedb.generator. It's a simple main function that just calls a code gen kotlin class.

For that I used a gradle task. But the gradle task unable identify the main sourceset. I tried setting sourcesets etc.

gradle task:

tasks.register<JavaExec>("runCodeGenerator") {
    group = "code generation"
    description = "Runs the code generator in the offlinedb module"

    // Set the classpath to include the compiled classes of the offlinedb module
    classpath = project(":offlinedb").sourceSets["main"].runtimeClasspath
    // Set the main class to be executed
    mainClass.set("com.framework.offlinedb.generator.MainKt")

    // Pass any arguments if needed
    args = listOf("arg1", "arg2") // Replace with actual arguments if any
}

When i try to run the task I got this error:

* What went wrong:
A problem occurred configuring project ':offlinedb'.
> Could not create task ':offlinedb:runCodeGenerator'.
   > SourceSet with name 'main' not found.

When I try to list all sourceset, it returns empty list like no sourcesets at all.

How to fix this issue. Why I can't find the "main" source set?.

I tried giving android.sourcesets["main"], but I get "unable to locate the main class"

Please help me


Solution

  • JVM project

    You can access the classpath of the other project like this if it is a Kotlin JVM project:

    classpath = files(
        project(":offlinedb")
            .the<KotlinJvmProjectExtension>()
            .target
            .compilations
            .named("main")
            .map { it.output.allOutputs + it.runtimeDependencyFiles }
    )
    

    Edit: Android project

    If your other project is an Android project (as I now see is the case), you can do this:

    classpath = files(
        project(":offlinedb")
            .the<KotlinAndroidProjectExtension>()
            .target
            .compilations
            .named("debug") // Or whatever the build variant name is
            .map { it.output.allOutputs + it.runtimeDependencyFiles }
    )
    

    In testing this solution, I had to add a Java toolchain to the Android project to make it work, as there was a Java bytecode compatibility issue. In my case I used:

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }
    

    Best practice

    It's worth being aware, though, that these are not best practice. Ideally you only want to depend on other projects' outputs to keep relationships clear and manageable. More discussion of this is in the documentation.