Jeff Lockhart
05/12/2023, 7:11 PMcompileOnly dependency that allows the consumer to use one of a couple variations of a dependency by explicitly declaring which implementation to use. I'd like to test my project against both variations though. What's the best way to configure gradle to do this?
kotlin {
...
sourceSets {
val commonMain by getting {
dependencies {
compileOnly("variantA")
}
}
val commonTest by getting {
dependencies {
implementation("variantA") // would also like the same tests to run with "variantB" too
}
}
}
}ephemient
05/13/2023, 10:31 AMcompileOnly, but rather model it properly with https://docs.gradle.org/current/userguide/feature_variants.htmlephemient
05/13/2023, 10:31 AMephemient
05/13/2023, 10:35 AMcompileOnly isn't supported on KMP anyway, https://youtrack.jetbrains.com/issue/KT-46760Jeff Lockhart
05/16/2023, 3:43 PMcompileOnly working with Kotlin/Native. This issue implies it should work if the consumer disables gradle caches. I've been finding it definitely doesn't work like with the JVM though. Most recently I'm finding the compileOnly dependency is actually available at runtime (at least in tests even after I remove the test implementation). So yes, I think I'm going to have to avoid this route and publish separate variants explicitly.
What I'm trying to do is prevent the need for cascading variants with combinations of my base library, which has two variants, and supplemental extensions to the libraries. I'd prefer not to bundle all of them into the same library because some of the features in the extensions are optional and bring in other dependencies. But if this can be done with a slight modification to a project build.gradle.kts by creating another variant publication with a different dependency, this would work better. Do you know of a good example of doing this manually in a KMP project?
And what about cocoapods dependencies for iOS/macOS? Is it possible to use a different cocoapods dependency for a variant in the same way as Kotlin dependencies? My base library variants each require a different cocoapods dependency.ephemient
05/17/2023, 7:40 PMkotlin {
for (target in listOf(macosArm64("macosarm64basic"), macosX64("macosx64basic"), macosArm64("macosarm64extra"), macosX64("macosx64extra"))) {
configurations.matching { it.name.startsWith(target.name) }.configureEach {
outgoing {
// Register the same capability in all variants so that downstream consumers will reject using multiple different variants at the same time
capability("$group:${project.name}:$version")
// Add a unique capability to each variant so that they can be published distinctly
capability("$group:${project.name}-${target.name}:$version")
consumer
kotlin {
macosArm64()
sourceSets {
getByName("macosArm64Main") {
dependencies {
// Choose one or the other; Gradle will fail if both are used
implementation("my.group:name-macosarm64basic:version")
implementation("my.group:name-macosarm64extra:version")
it doesn't really seem to play well with other stuff that the Kotlin Gradle Plugin wants to do thoughephemient
05/17/2023, 7:44 PMephemient
05/17/2023, 7:45 PMJeff Lockhart
05/17/2023, 8:11 PMsrcDir for the supplemental code. The supplemental code needs access to internal APIs, which is why I have to symlink the base variant's source files, rather than just depending on the module.
If I could create both variants within the same module, where one uses the base srcDir and the other uses both `srcDir`s, as well as changing the dependencies for each, this would work better. The symlinked `srcDir`s are only a problem in that all the files are indexed twice and occasionally experience false merge conflicts from find/replace changes.ephemient
05/17/2023, 8:13 PMinternal code across modules with @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") but a better option would be to use your own @RequiresOptIn annotationJeff Lockhart
05/17/2023, 8:18 PMinternal is public).Jeff Lockhart
05/17/2023, 8:30 PMephemient
05/17/2023, 8:33 PMephemient
05/17/2023, 8:34 PMJeff Lockhart
05/17/2023, 8:34 PMJeff Lockhart
05/17/2023, 8:36 PMsrc again. I might be able to rework these extension library modules with similar code to what you tried above, assuming I publish exclusive capabilities for the base library variants.Jeff Lockhart
05/17/2023, 8:36 PMephemient
05/17/2023, 8:36 PMephemient
05/17/2023, 8:37 PMephemient
05/17/2023, 8:38 PMwrapper-api that your public code builds against, and wrapper-ce and wrapper-ee libraries that are only needed at runtime to implement wrapper-apiephemient
05/17/2023, 8:40 PMJeff Lockhart
05/17/2023, 8:55 PMJeff Lockhart
05/18/2023, 9:42 PM