【问题标题】:Gradle, how to publish jdk8 variant with a Kotlin libraryGradle,如何使用 Kotlin 库发布 jdk8 变体
【发布时间】:2021-08-23 15:06:02
【问题描述】:

长话短说:我想为我的一个仅限 kotlin 的库发布 jdk8 复古兼容性的变体。

这是一个渴望已久的功能,我在很长一段时间以来一直在尝试解决它,但一直没有做好。然而,经过对 Gradle Slack 的多次尝试和帮助,我认为我已经很接近了,但我仍然有一个错误,我似乎无法摆脱。

想法是使用 jdk11 编译主版本(src/mainscr/jpms,后者仅包含 module-info.class),而 src/mainjdk8 变体当然只使用 jdk8 编译.

这是我目前的build.gradle.kts

import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.5.10"
    `java-library`
    `maven-publish`
}

group = "kotlin.graphics"
version = "3.3.1"

repositories {
    mavenCentral()
}

dependencies {

    implementation(kotlin("stdlib-jdk8"))

    testImplementation("io.kotest:kotest-runner-junit5:4.4.1")
    testImplementation("io.kotest:kotest-assertions-core:4.4.1")
}


val jdk8 = sourceSets.create("jdk8") {
    java.srcDir("src/main/java")
    kotlin.srcDir("src/main/kotlin")
}

val jdk11 = sourceSets["main"].apply {
    java.srcDir("src/jpms/java")
}

java.registerFeature("jdk8") {
    usingSourceSet(jdk8)
    capability("group", "name", "0.1")
}

configureCompileVersion(jdk8, 8)
configureCompileVersion(jdk11, 11)

val moduleName = "$group.$name"

fun configureCompileVersion(set: SourceSet, jdkVersion: Int) {
    val compiler = project.javaToolchains.compilerFor {
        languageVersion.set(JavaLanguageVersion.of(jdkVersion))
    }.get()
    val target = if (jdkVersion == 8) "1.8" else jdkVersion.toString()
    tasks {
        named<KotlinCompile>(set.compileKotlinTaskName) {
            kotlinOptions {
                jvmTarget = target
                jdkHome = compiler.metadata.installationPath.asFile.absolutePath
            }
            source = sourceSets.main.get().kotlin
        }
        named<JavaCompile>(set.compileJavaTaskName) {
            targetCompatibility = target
            sourceCompatibility = target
            modularity.inferModulePath.set(jdkVersion >= 9)
            javaCompiler.set(compiler)
            source = sourceSets.main.get().allJava + set.allJava
            if (jdkVersion >= 9)
                options.compilerArgs = listOf("--patch-module", "$moduleName=${set.output.asPath}")
        }
    }
}

val SourceSet.compileKotlinTaskName: String
    get() = getCompileTaskName("kotlin")

val SourceSet.kotlin: SourceDirectorySet
    get() = withConvention(KotlinSourceSet::class) { kotlin }

publishing {
    publications {
        create<MavenPublication>("maven") {
            groupId = "org.gradle.sample"
            artifactId = "library"
            version = "1.1"

            from(components["java"])
        }
    }
    repositories.maven {
        name = "prova"
        url = uri("repo")
    }
}

如果我运行:assemble,则生成的工件将使用 jdk11 正确编译。 直到一切都如预期的那样。 但如果我尝试发布,我会得到:

任务:compileJdk8Kotlin FAILED 5 个可操作的任务:1 个已执行,4 个是最新的 e: 在模块图中找不到模块 java.base

由于某些原因,Gradle 似乎尝试使用 jpms 编译 jdk8 变体,尽管它应该被自动禁用。我尝试手动打开和关闭它:

modularity.inferModulePath.set(jdkVersion &gt;= 9)

但它也没有工作。

项目是here

Gradle 7.1.1

【问题讨论】:

    标签: kotlin gradle build.gradle gradle-kotlin-dsl java-platform-module-system


    【解决方案1】:

    我想我明白了

    
    // these two are simple helpers
    
    val SourceSet.compileKotlinTaskName: String
        get() = getCompileTaskName("kotlin")
    
    val SourceSet.kotlin: SourceDirectorySet
        get() = project.extensions.getByType<KotlinJvmProjectExtension>().sourceSets.getByName(name).kotlin
    
    // pick the `main` sourceSet and use it for jdk11
    val jdk11 = sourceSets.main.get()
    
    // now we clone `main` into `jdk8`, with the only difference being the exclusion 
    // of `module-info.class`. We need to call `::create` to avoid getting the 
    // reference to the same sourceSet.
    val jdk8 = sourceSets.create("jdk8") {
        // this is superfluous, adding not-existing folders is harmless, but it's 
        // rather confusing when you need to debug two sourceSet java/kotlin
        java.setSrcDirs(emptySet<File>())
        kotlin.setSrcDirs(emptySet<File>())
        // assign the very same source directories
        java.setSrcDirs(jdk11.java.srcDirs)
        kotlin.setSrcDirs(jdk11.kotlin.srcDirs)
        // exclude the file from both, since kotlin includes always the java sources
        java.setExcludes(listOf("module-info.java"))
        kotlin.setExcludes(listOf("module-info.java"))
    }
    
    // this will create the `jdk8` variant using the given sourceSet at the given
    // capabilities
    java.registerFeature("jdk8") {
        usingSourceSet(jdk8)
        // I experienced `version` to be `null` if it's declared in the 
        // build.gradle.kts, then I moved it into `settings.gradle.kts to fix this
        capability(group.toString(), name, version.toString())
    }
    
    // set everything for each variant, jdk11 is the default/main one
    configureCompileVersion(jdk8, 8)
    configureCompileVersion(jdk11, 11)
    
    val moduleName = "$group.$name"
    
    fun configureCompileVersion(set: SourceSet, jdkVersion: Int) {
        tasks {
            val target = if (jdkVersion == 8) "1.8" else jdkVersion.toString()
            // we do need the task name because we have compileKotlin and
            // jdk8CompileKotlin and we want to set stuff accordingly
            named<KotlinCompile>(set.compileKotlinTaskName) {
                targetCompatibility = target
                sourceCompatibility = target
                kotlinOptions {
                    // jdkHome is deprecated in 1.5.30
                    jvmTarget = target
                    // this is outside the variant scope
                    freeCompilerArgs += listOf("-Xinline-classes", "-Xopt-in=kotlin.RequiresOptIn")
                }
                source = sourceSets.main.get().kotlin
            }
            named<JavaCompile>(set.compileJavaTaskName) {
                targetCompatibility = target
                sourceCompatibility = target
                // this is supposed to be set automatically, well with a jdk8 variant
                // you need to set it up explicitly
                modularity.inferModulePath.set(jdkVersion >= 9)
                javaCompiler.set(project.javaToolchains.compilerFor {
                    languageVersion.set(JavaLanguageVersion.of(jdkVersion))
                }.get())
                source = set.allJava
                if (jdkVersion >= 9)
                    options.compilerArgs = listOf("--patch-module", "$moduleName=${set.output.asPath}")
            }
            withType<Test> { useJUnitPlatform() }
        }
    }
    
    // We also want to automatically set all the jdk11 dependencies to jdk8 as well
    configurations {
        named("jdk8Implementation") {
            extendsFrom(implementation.get())
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      • 2022-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-25
      相关资源
      最近更新 更多