12

I have a multiproject gradle.kts setup and I would like to reuse a function, eg.

fun doSomethingWithString(string: String) { return string }

I then use the function within the dependencies {} block.

I would like to either:

  • define the fun within the root build.gradle.kts
  • define the fun within some other file which I could import within every subproject

Is this feasible?

Chriki
  • 15,638
  • 3
  • 51
  • 66
Vojtěch
  • 11,312
  • 31
  • 103
  • 173

1 Answers1

9

You can create your function in a buildSrc project.

There are various ways to approach this. Here are just two examples for how this could be done. Both use the same buildSrc/build.gradle.kts:

plugins {
    `kotlin-dsl`
}

repositories {
    jcenter()
}

Example: Shared Package-Level Function

You can create a package-level function, e.g., in buildSrc/src/main/kotlin/myconvention/myconventions.kt:

package myconvention

fun doSomethingWithString(string: String): String {
  return string + "321"
}

Then in your (sub)project build scripts, you can access the function as follows:

println(myconvention.doSomethingWithString("foo"))

Example: Precompiled Script Plugin

You can create the function as an extra property on the project in a precompiled script plugin, e.g., if you have buildSrc/src/main/kotlin/myproject.conventions.gradle.kts:

val doSomethingWithString by extra(
  fun(string: String): String {
    return string + "123"
  }
)

Then in your (sub)project build scripts, you can access the function as follows:

plugins {
    id("myproject.conventions")
}
val doSomethingWithString: (String) -> String by extra

println(doSomethingWithString("foo"))

Minimal Working Configuration for the First Example

Complete root project directory structure (excl. Gradle Wrapper files):

├── mysub
│   └── build.gradle.kts
├── buildSrc
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── kotlin
│               └── myconvention
│                   └── myconventions.kt
└── settings.gradle.kts
  • mysub/build.gradle.kts only contains println(myconvention.doSomethingWithString("foo"))
  • buildSrc/build.gradle.kts and buildSrc/src/main/kotlin/myconvention/myconventions.kt have the exact content described above
  • settings.gradle.kts:
rootProject.name = "my_test"
include("mysub")

When running ./gradlew projects (using Gradle 6.7.1), the output contains the following, as expected:

> Configure project :mysub
foo321
Chriki
  • 15,638
  • 3
  • 51
  • 66
  • 3
    The first way is what I would like to pursue. However it does not seem to work: Once I try to use the `myconvention.doSomethibg` within a subproject, it says "Unresolved reference" for the `myconvention`. I also tried `import myconvention.doSomething` with no luck. Note that the `buildSrc` project is not added within the `settings.gradle.kts` as that leads to an error too. – Vojtěch Jan 04 '21 at 13:48
  • Thanks for considering my answer, @Vojtěch! I have updated it with a minimal, working example build configuration; I hope that works for you, too? How does your configuration differ from it? Can you maybe add a [mcve] to your question? – Chriki Jan 05 '21 at 09:43
  • For me even when I just put the sample piece with `extra` into equivalent of `myconventions.kt`, extra is undefined – ror Jul 15 '22 at 08:00
  • Did anyone ever figure this out? The first example definitely doesn't work. Not sure why this answer is accepted – M Dapp May 24 '23 at 20:09