【问题标题】:Gradle Kotlin DSL: Define Kotlin version in unique placeGradle Kotlin DSL:在独特的地方定义 Kotlin 版本
【发布时间】:2018-05-15 06:13:14
【问题描述】:

为了描述 Gradle 构建脚本,我们可以通过 build.gradle.kts 文件使用 Kotlin。在dependencies 和构建plugin 部分中全局定义要使用的 Kotlin 版本是一个常见问题(在给定情况下使用不同版本是相当罕见的)。

考虑以下代码(Gradle 4.3.1):

plugins {
    var pluginVersion = "1.2.30"
    kotlin("jvm").version(kotlinVersion)
    // more
}

var dependencyVersion = "1.2.30"
dependencies {
    compile(kotlin("stdlib", kotlinVersion))
    compile(kotlin("reflect", kotlinVersion))
    testCompile(kotlin("test", kotlinVersion))
    // more
}

如您所见,kotlin version(在本例中为 1.2.30)被定义两次dependencyVersionpluginVersion,通常没有区别。由于DSL限制,无法从plugins块外访问pluginVersion或从plugins块内访问dependencyVersion

如何将版本字符串"1.2.30" 提取到一个地方?

【问题讨论】:

  • kotlin 版本常量是 gradle-kotlin-DSL 的一部分。使用示例:implementation(embeddedKotlin("stdlib-jdk7"))classpath(embeddedKotlin("gradle-plugin"))

标签: gradle kotlin build.gradle gradle-kotlin-dsl


【解决方案1】:

有一种可用的解决方法,它搜索为 kotlin 插件 定义的版本并将其分配给外部变量。下面证明了这一点:

val kotlinVersion: String? by extra {
    buildscript.configurations["classpath"]
            .resolvedConfiguration.firstLevelModuleDependencies
            .find { it.moduleName == "kotlin-gradle-plugin" }?.moduleVersion
}

plugins {
    kotlin("jvm").version("1.2.30")
    //more
}

然后可以在dependencies 中使用变量kotlinVersion,而无需进一步的麻烦。

【讨论】:

    【解决方案2】:

    您可以从插件类中提取版本:

    import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
    
    plugins {
        kotlin("jvm") version "1.2.0"
    }
    
    val kotlinVersion = plugins.getPlugin(KotlinPluginWrapper::class.java).kotlinPluginVersion
    

    【讨论】:

    • 可以从 KotlinCompilerVersion.VERSION 获取版本
    【解决方案3】:

    在 Gradle 的更高版本中,您不再需要指定 kotlin(stdlib|reflect|test) 依赖项的版本,Kotlin 插件会自动为您配置它们。

    至于将依赖提取到一个地方,主要有两种模式:

    • buildSrc/src/main/kotlin/ 内的对象中定义要共享的常量并在构建脚本中使用该对象,来自buildSrc 的代码可用于包括plugins 块在内的整个脚本
    • 使用系统属性,您可以在gradle.properties中定义系统属性,方法是在其名称前加上systemProp.,您可以通过System.getProperties()访问系统属性,例如:

      // build.gradle.kts
      plugins {
        val kotlinVersion by System.getProperties()
        println("Kotlin version is $kotlinVersion")
      }
      
      // gradle.properties
      systemProp.kotlinVersion=1.2.20
      

    【讨论】:

    • buildSrc中定义常量时,是否也可以在buildSrc本身的build.gradle.kts中使用?
    • 注意:kotlin 版本常量是 gradle-kotlin-DSL 的一部分。使用示例:implementation(embeddedKotlin("stdlib-jdk7"))classpath(embeddedKotlin("gradle-plugin"))
    • buildSrc 真的是个好地方,Gradle 官方也支持这种方式。
    【解决方案4】:

    我刚刚偶然发现在我的build.gradle.kts 中使用 Kotlin 类。

    我不得不:

    • 创建一个名为buildSrc 的模块,在其根目录中包含src/main/kotlinbuild.gradle.kts
    • (已过时)include("buildSrc")settings.gradle.kts

    buildSrc/build.gradle.kts 非常小:

    plugins {
        `kotlin-dsl`
    }
    
    repositories {
        jcenter()
    }
    

    buildSrc/src/main/kotlin 我添加了一个Config.kt

    const val GROUP_ID = "my-company"
    const val VERSION = "0.1.0-SNAPSHOT"
    
    const val POM_NAME = "my-library-name"
    const val POM_DESCRIPTION = "A library doing stuff."
    const val POM_URL = "https://github.com/${GROUP_ID}/${POM_NAME}/"
    const val POM_SCM_URL = POM_URL
    const val POM_SCM_CONNECTION = "scm:git:git://github.com/${GROUP_ID}/${POM_NAME}.git"
    const val POM_SCM_DEV_CONNECTION = "scm:git:ssh://git@github.com/${GROUP_ID}/${POM_NAME}.git"
    const val POM_LICENCE_NAME = "The Apache Software License, Version 2.0"
    const val POM_LICENCE_URL = "http://www.apache.org/licenses/LICENSE-2.0.txt"
    const val POM_LICENCE_DIST = "repo"
    const val POM_DEVELOPER_ID = "me"
    const val POM_DEVELOPER_NAME = "meeee"
    const val POM_DEVELOPER_EMAIL = "me@foo.com"
    

    还有一个Dependencies.kt

    @file:Suppress("MemberVisibilityCanBePrivate")
    
    object Jvm {
        const val version = "1.8"
    }
    
    object Kotlin {
        const val version = "1.3.50"
        const val stdlibJdk8 = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
        const val jvmId = "jvm"
        const val kaptId = "kapt"
    }
    
    object MavenPublish {
        const val id = "maven-publish"
    }
    
    object Arrow {
        const val version = "0.10.1"
        const val core = "io.arrow-kt:arrow-core:$version"
        const val syntax = "io.arrow-kt:arrow-syntax:$version"
        const val optics = "io.arrow-kt:arrow-optics:$version"
        const val fx = "io.arrow-kt:arrow-fx:$version"
        const val meta = "io.arrow-kt:arrow-meta:$version"
    }
    
    object Versions {
        const val version = "0.27.0"
        const val versions = "com.github.ben-manes:gradle-versions-plugin:$version"
        const val id = "com.github.ben-manes.versions"
    }
    

    所以我可以在我的根 build.gradle.kts 中使用它

    import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
    
    plugins {
        kotlin(Kotlin.jvmId) version Kotlin.version
        kotlin(Kotlin.kaptId) version Kotlin.version
        id(Versions.id) version Versions.version
        id(MavenPublish.id)
    }
    
    group = GROUP_ID
    version = VERSION
    
    repositories {
        mavenCentral()
        jcenter()
    }
    
    dependencies {
        implementation(Kotlin.stdlibJdk8)
        implementation(Arrow.core)
        implementation(Arrow.syntax)
        kapt(Arrow.meta)
    }
    
    tasks.withType<KotlinCompile> {
        kotlinOptions.jvmTarget = Jvm.version
    }
    
    publishing {
        publications {
            create<MavenPublication>("mavenJava") {
                @Suppress("UnstableApiUsage")
                pom {
                    name.set(POM_NAME)
                    description.set(POM_DESCRIPTION)
                    url.set(POM_URL)
                    licenses {
                        license {
                            name.set(POM_LICENCE_NAME)
                            url.set(POM_LICENCE_URL)
                            distribution.set(POM_LICENCE_DIST)
                        }
                    }
                    developers {
                        developer {
                            id.set(POM_DEVELOPER_ID)
                            name.set(POM_DEVELOPER_NAME)
                            email.set(POM_DEVELOPER_EMAIL)
                        }
                    }
                    scm {
                        connection.set(POM_SCM_CONNECTION)
                        developerConnection.set(POM_SCM_DEV_CONNECTION)
                        url.set(POM_SCM_URL)
                    }
                }
            }
        }
    }
    

    我对此非常满意,但是当涉及到自动增加 version 时,我可能会退回到在 gradle.properties 中维护它。


    编辑: 不再需要(并且允许)将buildSrc 添加到settings.gradle.kts,而是会自动获取(如果存在)。

    【讨论】:

    • 'buildSrc' cannot be used as a project name as it is a reserved name in settings.gradle
    • 是的,这适用于最新版本。如果 BuildSrc 存在,也会自动获取。
    【解决方案5】:

    @s1m0nw1 评论的答案(评论太长): 不,你不能在 buildSrc/build.gradle 中使用 buildSrc/src 的东西。我在编写基于 android 的插件时遇到了这个问题,我需要 buildsSrc 中的 android gradle 插件依赖项,但我也在项目中声明了这个依赖项。所以我有两个不同的地方和两个版本要维护。

    我通过在 buildSrc 目录中创建 gradle.properties 文件解决了这个问题。 在其中我创建了道具androidGradlePluginVersion=3.6.0-rc02

    buildSrc/build.gradle:

    val androidGradlePluginVersion: String by project
    dependencies {
        implementation("com.android.tools.build:gradle:$androidGradlePluginVersion")
    

    buildSrc/src/.../Versions.kt:

    var ANDROID_PLUGIN = loadAndroidGradlePluginVersion()
    

    道具用处:

    val GRADLE_PROPERTIES = "buildSrc/gradle.properties"
    val ANDROID_PLUGIN_VERSION_PROP = "androidGradlePluginVersion"
    
    fun loadAndroidGradlePluginVersion(): String {
        Properties().apply { load(FileInputStream(GRADLE_PROPERTIES)) }.let {
            return it.getProperty(ANDROID_PLUGIN_VERSION_PROP)
        }
    
        error("Provide $ANDROID_PLUGIN_VERSION_PROP in $GRADLE_PROPERTIES")
    } 
    

    【讨论】:

    • 这样做,我仍然必须复制 buildSrc/gradle.properties 和 rootProject/gradle.properties 中的属性定义。否则,当尝试使用该属性时,例如在 buildSrc/src/main/kotlin/Versions.kt 中,它不会找到该属性。出于某种原因,它会尝试在 rootProject 的 buildSrc 中搜索属性,跳过 buildSrc 的。我已经尝试了几个小时以找到解决方案但无济于事。
    • 好的,所以我最终能够通过使用这个val gradlePropertiesFile: File = File("${System.getProperty("user.dir")}${if (project.name == "buildSrc") "" else "/buildSrc"}/$GRADLE_PROPERTIES") 作为从中加载输入流的文件来解决这个问题。 (使用 Kotlin DSL)
    • 我想这是有道理的,因为它是在运行时而不是编译时解决的。我的错,我忘了添加我的常量:GRADLE_PROPERTIES = "buildSrc/gradle.properties" ANDROID_PLUGIN_VERSION_PROP = "androidGradlePluginVersion"
    【解决方案6】:

    一旦您为 Kotlin 插件定义了一个版本,所有其他 Kotlin 库都将使用相同的版本,并且不需要特定的版本集。

    所以唯一需要设置版本的地方是定义插件的类路径时,例如:

    buildscript {
        repositories {
            google()
            mavenCentral()
            gradlePluginPortal()
        }
    
        dependencies {
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31")
        }
    }
    

    如果您出于其他目的需要该版本(例如在resolutionStrategy 中或仅作为参考),您可以从org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION 获得它

    例如:

    println("Kotlin version used is ${org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION}")
    

    【讨论】:

      猜你喜欢
      • 2019-09-15
      • 1970-01-01
      • 2022-11-01
      • 2019-03-22
      • 2018-11-05
      • 1970-01-01
      • 2020-01-18
      • 2019-04-29
      • 2022-01-06
      相关资源
      最近更新 更多