https://kotlinlang.org logo
Title
m

martmists

04/05/2023, 10:30 AM
Setting up a project with multiple JS targets, but getting a strange error. The gist of my setup:
kotlin {
    js("frontendPublic", IR) {
        browser {
            commonWebpackConfig {
                outputFileName = "index.js"
            }
        }
        binaries.executable()
    }
    js("frontendAdmin", IR) {
        browser {
            commonWebpackConfig {
                outputFileName = "index-admin.js"
            }
        }
        binaries.executable()
    }

    sourceSets {
        val frontendCommonMain by creating
        val frontendPublicMain by getting {
            dependsOn(frontendCommonMain)
        }

        val frontendAdminMain by getting {
            dependsOn(frontendCommonMain)
        }
    }
}
The error I'm getting:
Caused by: org.gradle.api.GradleException: Consumable configurations with identical capabilities within a project (other than the default configuration) must have unique attributes, but configuration ':frontendPublicApiElements' and [configuration ':frontendAdminApiElements'] contain identical attribute sets. Consider adding an additional attribute to one of the configurations to disambiguate them.  Run the 'outgoingVariants' task for more details. See <https://docs.gradle.org/8.0.1/userguide/upgrading_version_7.html#unique_attribute_sets> for more details.
a

Adam S

04/05/2023, 10:43 AM
you have multiple JS targets, and Gradle needs to be able to differentiate them https://kotlinlang.org/docs/multiplatform-set-up-targets.html#distinguish-several-targets-for-one-platform
if another project needs to depend on one or the other, then they’ll also need to set up the attribute so Gradle knows which version to grab. if you’re planning to publish these libraries to a Maven repo, then it might be easier to just make two separate subprojects, so they’ll have different Maven GAV coordinates
m

martmists

04/05/2023, 12:08 PM
Now I'm getting a different error:
A problem was found with the configuration of task ':compileProductionExecutableKotlinFrontendPublic' (type 'KotlinJsIrLink').
  - Gradle detected a problem with the following location: '/home/mart/git/sites/teamexr_wiki/build/compileSync/js/main/productionExecutable/kotlin'.
    
    Reason: Task ':frontendAdminProductionExecutableCompileSync' uses this output of task ':compileProductionExecutableKotlinFrontendPublic' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
How would I solve this?
a

Adam S

04/05/2023, 12:09 PM
is that an error or a warning?
m

martmists

04/05/2023, 12:30 PM
An error, gradle fails to build
a

Adam S

04/05/2023, 12:45 PM
this will have to be something you’ll need to investigate yourself, because it’s hard to figure out without having the whole project Basically, Gradle tasks need to declare their input files and output files. Gradle also needs to know in what order tasks should run. What has happened is that Gradle has noticed that one task is using the output of another task, but Gradle didn’t expect this, and so it doesn’t know what order to run the tasks in. So you’ll need to figure out why one task uses the input of another task, and either register the inputs/outputs correctly, or add a task dependency to make sure Gradle can run the tasks in the correct order I didn’t think that this would be an error, I thought this would just be a warning…
m

martmists

04/05/2023, 12:57 PM
I think this behavior became an error since gradle 8, but the main issue is that I can't seem to access the KotlinJsIrLink from a specific target easily to modify these (not to mention it'd likely involve multiple other tasks), and the JS compilation pipeline seems to use paths that are not dependent on the JS target's name in some places. (note the
main
in the path above rather than
frontendPublicMain
)
a

Adam S

04/05/2023, 1:01 PM
what you could try is a very wide shotgun approach, and add a task dependency for all tasks based on the name
val compileKotlinProductionExecTasks = tasks.matching {
  it.name.startsWith("compileProductionExecutable")
}

val compileSyncTasks = tasks.matching {
  it.name.endsWith("CompileSync")
}

compileSyncTasks.configureEach {
  dependsOn(compileKotlinProductionExecTasks)
}
it would be better to find out the task class type though, and do
dependsOn(tasks.withType<WhateverKotlinTaskType>())
m

martmists

04/05/2023, 1:22 PM
The issue is not the dependencies; The kotlin plugin does that just fine. The issue is that KotlinJsIrLink exists for both frontendAdmin and frontendPublic, but uses the same output directory for both; As result, tasks consuming only one of those tasks (which is desired behavior; public should not include code from admin), it does implicitly depend on both tasks' outputs, hence why it's throwing the error.