In my plugin, I'd like to say "do this and that on...
# gradle
e
In my plugin, I'd like to say "do this and that only if the Kotlin Gradle plugin is present in the target project". Is that possible without making the Kotlin plugin a transitive dependency when my plugin is applied?
c
You can write:
Copy code
target.pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
	// …whatever you want…
}
The code block will be executed when the Kotlin Multiplatform plugin is applied. If it is never applied, the code is never executed.
gratitude thank you 4
You can also use
pluginManager.hasPlugin
, but I don't recommend it because it creates an ordering relationship (it will only return
true
if the Kotlin plugin is applied before yours, whereas with
withPlugin
the order makes no difference)
e
Thank you! I suppose tho that I won't ever be able to use classes from the KGP, correct?
Example, if I need to add a source dir for the common source set, I'd have to access the KGP definitions
c
If you don't add dependencies, yes, exactly.
If you want to access the classes, you can use a
compileOnly
dependency on KGP, this way the downstream project can still use whichever Kotlin version they want. However, if in the future a new KGP version has binary incompatibilities with the one you're compiling against, the user won't be warned, and the build will crash with a ClassNotFoundError (or similar)
e
But what if I declare a
compileOnly
and the user hasn't declared the Kotlin plugin? Won't that mean my plugin will throw as soon as it gets loaded for missing classes?
c
It will throw as soon as your plugin tries to access any class from KGP. If you only access symbols from KGP inside
pluginManager.withPlugin
, the KGP has already been applied for sure, so using KGP symbols is safe (assuming binary compatibility).
But the compiler can't check that, so it's on you to never use any symbol from KGP anywhere else. At this point, it's probably a good idea to set an example project up which doesn't use KGP but does use your plugin, and always recompile it in CI to ensure you never accidentally use any KGP class
If you're familiar with static initializers in Java, it's the exact same triggering rules (= if what you're doing would trigger the static initializer, then it counts as a usage and will throw if KGP is not on the classpath at that time) But well that pretty much means any usage.
e
Seems like a decent solution, I mean it doesn't look like there is anything better, so we're forced to play this risky game. Thanks for the advices!
c
In theory you could have an
implementation
dependency using rich versions with a lower bound but no preferred version? I haven't tested it. [EDIT. No you couldn't, since your goal is for KGP to be an optional dependency]
To my knowledge, this
compileOnly
+`pluginManager.withPlugin` is what the ecosystem uses. I'm not a fan of
compileOnly
either 😕
gratitude thank you 1
👌 1
e
I'd prefer
implementation
too just to not have to deal with missing classes, but then I'm forcing a KGP version on users, or at least I'm messing with the user's class path