Zoltan Demant
02/16/2023, 2:54 PMdependencies {}
block is now declared sourceSets { commonMain { dependencies { ... } } }
instead. Is there a way for me to rewrite my snippet to work in both situations automagically, or do I need to have 2 sets - one for regular modules, and one for multiplatform ones? Ive also toyed with allProjects
& subProjects
, but I think the issue is really the same. Snippet in 🧵Zoltan Demant
02/16/2023, 2:54 PMdependencies {
apply(projects.util.logger, project)
apply(projects.util.support, project)
}
private def apply(ProjectDependency dependency, Project project) {
def projectPath = project.path
def util = ":util"
if (!projectPath.startsWith(util)) {
project.dependencies {
implementation(dependency)
}
}
}
ephemient
02/16/2023, 2:59 PMCasey Brooks
02/16/2023, 3:00 PMallProjects
or subProjects
, as they break Gradle’s ability to isolate projects and improve build times. Likewise, applying ad-hoc scripts (apply from: "deps.gradle"
) is also discouraged.
Fortunately, Gradle has solutions to replace those mechanisms: buildSrc script plugins (though I think this is now being deprecated in favor of included builds), and version catalogsAdam S
02/16/2023, 3:00 PMdependencies {
if (!project.path.startsWith(":util")) {
implementation(projects.util.logger)
implementation(projects.util.support)
}
}
ephemient
02/16/2023, 3:00 PMZoltan Demant
02/16/2023, 3:10 PMephemient
02/16/2023, 3:12 PMpluginManager.withPlugin("org.jerbrains.kotlin.multiplatform") {
// ...
}
Adam S
02/16/2023, 3:16 PMkotlin {
sourceSets {
val commonMain by getting {
dependencies {
api(project(":util:logger"))
api(project(":util:support"))
}
}
}
}
You could even create an all-utils
project that just exposes all util projects as an API dependency, then use that in all non-util projects.Adam S
02/16/2023, 3:26 PMimplementation
is the name of a Gradle Configuration - which have a confusing name and perhaps a better name is ‘DependencyCollection’. They’re a collection of files that might fetch their content from Maven, or a local directory, or wherever. (They can also be used to provide files - but that’s another story).
implementation
is the name of a Configuration provided by the Java plugin. There are a lot more of them, and they’re listed here https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management
If you run ./gradlew resolvableConfigurations
then you’ll see all the Configurations.
Obviously, because Kotlin Multiplatform is more than just Java, it needs to keep dependencies separate. To do that, the Kotlin Multiplatform plugin makes more Configurations - and they have different names.
So if you want to add a dependency to the Kotlin/JS compile classpath, there’s a Configuration called jsCompileClasspath
. And, under the hood, that’s what the Kotlin DSL does
kotlin {
sourceSets {
val jsMain by getting {
dependencies {
implementation("example:foo:1.2.3")
}
}
}
}
That ^ adds example:foo:1.2.3
into the jsCompileClasspath
Configuration (and maybe also the jsRuntimeClasspath
? I’m not sure).
The Kotlin DSL is nice, but Gradle only really cares about the Configuration name. So you could also do it without the Kotlin DSL
dependencies {
"jsCompileClasspath"("example:foo:1.2.3")
}
but that’s a little more fragile, and not type-safe.
So if you’ve moved from kotlin("jvm")
to kotlin("multiplatform")
, there’s no more Configuration named implementation
. Instead, it’ll be called jvmCompileClasspath
or something.ephemient
02/16/2023, 3:32 PMkotlin {
jvm("one")
jvm("two")
Zoltan Demant
02/16/2023, 4:05 PMAdam S
02/16/2023, 4:13 PMimplementation(project(":kotest-runner:kotest-runner-junit5"))
to any subproject that applies the convention plugin
https://github.com/kotest/kotest/blob/master/buildSrc/src/main/kotlin/kotest-jvm-conventions.gradle.ktsephemient
02/16/2023, 4:14 PMplugins { id("kotest-jvm-conventions") }
I think it's fairephemient
02/16/2023, 4:15 PMif (!projectPath.startsWith(util))
ephemient
02/16/2023, 4:16 PMZoltan Demant
02/16/2023, 4:18 PM