Search code examples
kotlingradlejavafxquarkusjavafx-gradle-plugin

How can I re-declare variants for a configuration using gradle kotlin dsl


I am trying to setup a basic app running quarkus 3.4.3 and javafx 21.0.1 using gradle 8.4 with kotlin dsl as the build tool. As soon as I apply the quarkus plugin, I get an error when the build tries to resolve the files for the configuration:

Execution failed for task ':jfxapp:quarkusGenerateCode'.
> Could not resolve all files for configuration ':jfxapp:quarkusProdBaseRuntimeClasspathConfiguration'.
   > Could not resolve org.openjfx:javafx-controls:21.0.1.
     Required by:
         project :jfxapp
      > Cannot choose between the following variants of org.openjfx:javafx-controls:21.0.1:
          - linux-aarch64Runtime
          - linuxRuntime
          - mac-aarch64Runtime
          - macRuntime
          - runtime
          - winRuntime
        All of them match the consumer attributes:
          - Variant 'linux-aarch64Runtime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.native.architecture 'aarch64' but the consumer didn't ask for it
                  - Provides org.gradle.native.operatingSystem 'linux' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'linuxRuntime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.native.architecture 'x86-64' but the consumer didn't ask for it
                  - Provides org.gradle.native.operatingSystem 'linux' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'mac-aarch64Runtime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.native.architecture 'aarch64' but the consumer didn't ask for it
                  - Provides org.gradle.native.operatingSystem 'macos' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'macRuntime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.native.architecture 'x86-64' but the consumer didn't ask for it
                  - Provides org.gradle.native.operatingSystem 'macos' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'runtime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'winRuntime' capability org.openjfx:javafx-controls:21.0.1:
              - Unmatched attributes:
                  - Provides org.gradle.category 'library' but the consumer didn't ask for it
                  - Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
                  - Provides org.gradle.native.architecture 'x86-64' but the consumer didn't ask for it
                  - Provides org.gradle.native.operatingSystem 'windows' but the consumer didn't ask for it
                  - Provides org.gradle.status 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it

The javafx-gradle-plugin readme page states the following regarding this specific problem:

Variants

If you encounter errors such as Cannot choose between the following variants of org.openjfx... it is possible that your build or another plugin is interacting with the classpath/module path in a way that "breaks" functionality provided by this plugin. In such cases, you may need to re-declare the variants yourself as described in Gradle docs on attribute matching/variants or reach out to the plugin author in an attempt to remediate the situation.

// Approach 1: Explicit Variant
// The following snippet will let you add attributes for linux and x86_64 to a configuration
configurations.someConfiguration {
    attributes {
        attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))
        attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, "linux"))
        attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, "x86-64"))
    }
}

// Approach 2: Copy existing configuration into another configuration
configurations.someConfiguration  {
    def runtimeAttributes = configurations.runtimeClasspath.attributes
    runtimeAttributes.keySet().each { key ->
        attributes.attribute(key, runtimeAttributes.getAttribute(key))
    }
}

How can that "fix" be done using kotlin dsl instead of groovy like the example shows?

The gradle documentation mentioned in the possible solution does talk about variants but everything I tried was in vain. Gradle documentation also talks about Attribute Disambiguation Rules (which make sense based on the type of error I get), but as in the Variants case, it does provide any examples and I was unable to find anything online that makes sense.

I filed a bug with Quarkus, and I attached to the sample app I am using in case anyone is interested.

Thanks!

Gradle docs here

Quarkus issue 36820 with sample app here


Solution

  • The answer to my question was provided by Vampire in the gradle forum questions:

    Gradle forum question 46919

    Gradle forum question 46940

    The first part of the answer includes the rewrite of the groovy dsl to kotlin:

    // Approach 1: Explicit Variant
    // The following snippet will let you add attributes for linux and x86_64 to a configuration
    configurations.someConfiguration {
        attributes {
            attribute(Usage.USAGE_ATTRIBUTE, objects.named<Usage>(Usage.JAVA_RUNTIME))
            attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named<OperatingSystemFamily>("linux"))
            attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named<MachineArchitecture>("x86-64"))
        }
    }
    
    // Approach 2: Copy existing configuration into another configuration
    configurations.someConfiguration {
        val runtimeAttributes = configurations.runtimeClasspath.get().attributes
        runtimeAttributes.keySet().forEach { key ->
            attributes.attribute(key as Attribute<Any>, runtimeAttributes.getAttribute(key))
        }
    }
    

    but this did not solve my problem, because some configurations were added later. His answer to my 2nd question was to match configurations of tasks that are resolvable:

    configurations
        .matching { it.isCanBeResolved && it.name.contains("quarkus") }
        .configureEach { ... }
    

    so the final solution that works is as follows:

    configurations.matching {
        it.isCanBeResolved && it.name.toString().contains("quarkus")
    }.configureEach {
        attributes {
            attribute(Usage.USAGE_ATTRIBUTE, objects.named<Usage>(Usage.JAVA_RUNTIME))
            attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named<OperatingSystemFamily>("linux"))
            attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named<MachineArchitecture>("x86-64"))
        }
    }