Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BuildKonfig 0.9.0 -> 0.10.0 breaks Gradle Sync #56

Closed
chris-hatton opened this issue Sep 30, 2021 · 6 comments · Fixed by #58
Closed

BuildKonfig 0.9.0 -> 0.10.0 breaks Gradle Sync #56

chris-hatton opened this issue Sep 30, 2021 · 6 comments · Fixed by #58
Labels
bug Something isn't working

Comments

@chris-hatton
Copy link

chris-hatton commented Sep 30, 2021

Thanks for BuildKonfig, it continues to be an essential tool for KMP App Development! ❤️
I was happy to see continued maintenance with a 0.10.0 release:

Unfortunately, this new version has a bug for my project.
Gradle Sync fails with the error:

Duplicate content roots detected:
Path [/Users/me/project/client/build/buildkonfig/commonMain] of module 
[project.client.commonMain] was removed from modules [project.client.materialComposeMain]

(I've redacted my actual username and project name but the pattern is preserved)
This prevents working with the project.

If I change only the BuildKonfig dependency back to 0.9.0, everything works as expected.

My project has quite a nested module structure; perhaps you've changed some code related to adding source-set paths to modules that has caused it to add to multiple source-sets unnecessarily?

@yshrsmz
Copy link
Owner

yshrsmz commented Sep 30, 2021

Hi,

Indeed I changed the source-sets registration logic in 0.10.0.

v0.9.0...v0.10.1#diff-dd276d30d4

Previously the plugin explicitly obtained commonMain source-sets and registered common buildkonfig source-set, but now it adds the dependency when the target is KotlinMetadataTarget which is common code target.

I thought there's only one KotlinMetadataTarget in a single KMP module, but looks like it was wrong.

It seems like materialComposeMain is also a KotlinMetadataTarget, so we should also check target's name.

Can you provide your targets & sourceSets configuration in client module's build.gradle?
I'd like to see how each source-sets are depending to each other.

(Thanks for sponsoring me btw! It means a lot to me.)

@yshrsmz yshrsmz added the bug Something isn't working label Sep 30, 2021
@chris-hatton
Copy link
Author

chris-hatton commented Sep 30, 2021

Hi, thanks for your reply; my source sets dependencies (this is within a single module) look like this:

So far in KMP it has probably been less common to have these intermediary source-sets (here being materialComposeMain); but it will certainly become more common in the near future, as Compose/Multiplatform gains more use (this is what I am using now).

Also, JetBrains do show some examples of setting up source-sets like this in their KMP introductory material; just to show off the possibilities. See the source-set configurations discussed here.

@chris-hatton
Copy link
Author

chris-hatton commented Sep 30, 2021

I had a look at the relevant code change that you linked to; and see that your intent was to remove reliance on the exact name commonMain, which is of course a good idea 👍

Yes, now we see that commonMain isn't the only KotlinMetadataTarget. Probably an effective strategy would be to further filter the list of KotlinMetadataTargets to find the one which has no parent i.e. is the root (I'm not sure how easily that's modeled to filter on; but I think it should be trivial enough).

By the way, you might consider using a single operator in Kotlin to ensure we have one root. Pseudo-code like singleOrNull { it.hasNoParent() } ?: throw Exception("This source-set configuration is not supported yet.")

@yshrsmz
Copy link
Owner

yshrsmz commented Oct 1, 2021

Here's what I found so far.

Actually, there's only one KotlinMetadataTarget, but there are multiple main compilations in it.

When kotlin.mpp.enableGranularSourceSetsMetadata is set to true, KMP adds dedicated compilation for shared sourceset in KotlinMetadataTarget

so

kotlin {
    android()
    jvm {}
    js(IR) {
        browser()
    }
    js("node") {
        nodejs()
    }
    macosX64()
    linuxX64()
    mingwX64()

    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting

        val appMain by creating {
            dependsOn(commonMain)
        }

        val androidMain by getting {
            dependsOn(appMain)
        }

        val jsCommonMain by creating {
            dependsOn(commonMain)
        }
        val jsMain by getting {
            dependsOn(jsCommonMain)
        }
        val nodeMain by getting {
            dependsOn(jsCommonMain)
        }
        val jsTest by getting

        val desktopMain by creating {
            dependsOn(appMain)
        }
        val macosX64Main by getting {
            dependsOn(desktopMain)
        }
        val linuxX64Main by getting {
            dependsOn(desktopMain)
        }
        val mingwX64Main by getting {
            dependsOn(desktopMain)
        }
    }
}

so if we have a source set configuration above, KotlinMetadataTarget has compilations below

compilation: appMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileAppMainKotlinMetadata', metadataAppMainClasses
compilation: defaultSourceSet: source set appMain
compilation: allKotlinSourceSets: []
------
compilation: commonMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileCommonMainKotlinMetadata', metadataCommonMainClasses
compilation: defaultSourceSet: source set commonMain
compilation: allKotlinSourceSets: []
------
compilation: desktopMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation, task ':compileDesktopMainKotlinMetadata', metadataDesktopMainClasses
compilation: defaultSourceSet: source set desktopMain
compilation: allKotlinSourceSets: []
------
compilation: main, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileKotlinMetadata', metadataMainClasses
compilation: defaultSourceSet: source set commonMain
compilation: allKotlinSourceSets: [source set commonMain]

Looks like what we want is commonMain or main compilation, but I'm not sure which is the one.

But when I create a simple project without shared source set, there's one single main compilation

target: metadata, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget_Decorated
compilation: main, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':presentation:presentation-all:compileKotlinMetadata', metadataMainClasses
compilation: defaultSourceSet: source set commonMain
compilation: allKotlinSourceSets: [source set commonMain]

So for now I'm going to check the name of the compilation

@yshrsmz
Copy link
Owner

yshrsmz commented Oct 1, 2021

target: metadata, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget_Decorated
compilation: appMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileAppMainKotlinMetadata', metadataAppMainClasses
compilation: defaultSourceSet: source set appMain, dependsOn: [source set commonMain]
compilation: allKotlinSourceSets: []
------
compilation: commonMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileCommonMainKotlinMetadata', metadataCommonMainClasses
compilation: defaultSourceSet: source set commonMain, dependsOn: []
compilation: allKotlinSourceSets: []
------
compilation: desktopMain, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation, task ':compileDesktopMainKotlinMetadata', metadataDesktopMainClasses
compilation: defaultSourceSet: source set desktopMain, dependsOn: [source set appMain]
compilation: allKotlinSourceSets: []
------
compilation: main, class org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation, task ':compileKotlinMetadata', metadataMainClasses
compilation: defaultSourceSet: source set commonMain, dependsOn: []
compilation: allKotlinSourceSets: [source set commonMain]
------

Ok you are right.
I think we can just check defaultSourceSet dependency

commonMain and main has same SourceSet, but if it's the same it shouldn't be a problem

@yshrsmz
Copy link
Owner

yshrsmz commented Oct 1, 2021

@chris-hatton

Hi, I've just released v0.10.2 with a possible fix for this issue.
Please let me know if you find anything weird. thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants