Gradle Kotlin DSL 的 accessors 生成问题

2020-02-20 13:19:31 浏览数 (1)

概要

如果你想用 gradle kotlin DSL,那么请注意,accessors 的支持从 0.8.0 开始(gradle 3.5),后续也做了一些完善和更新,目前已经默认开启了这一项功能。使用时由于 accessors 是动态生成的,因此要注意使用 plugins{...} 可以直接触发 accessors 的动态生成,其他情况下就比较麻烦了。

正文

昨天也是手欠,非要用 Gradle Kotlin DSL 构建工程,还看到现在连 settings.gradle 也支持用 kts 了,于是乎:

不过这个需要 Gradle 的版本在 4.4 以上,gradle-wrapper.properties 的版本修改为:

代码语言:javascript复制
...
distributionUrl=https://services.gradle.org/distributions/gradle-4.4-all.zip

看上去也没啥毛病啊,我的 build.gradle.kts 是这个样子:

代码语言:javascript复制
buildscript {
    var kotlin_version: String by extra
    kotlin_version = "1.2.10"

    repositories {
        mavenCentral()
    }

    dependencies {
        classpath(kotlin("gradle-plugin", kotlin_version))
    }
}

apply {
    plugin("java")
    plugin("kotlin")
}

val kotlin_version: String by extra

repositories {
    mavenCentral()
}

dependencies {
    compile(kotlin("stdlib"))
}

然而一运行,出事儿了,compile 不识别。。

代码语言:javascript复制
e: .../kotlinspecificsJvm/app/build.gradle.kts:42:5: Unresolved reference: compile

额,这就尴尬了,哪儿说理去。。由于 Kotlin 是静态语言,能够在这个地方写出来 compile 那么一定是定义了这个方法,就像:

代码语言:javascript复制
dependencies {
        classpath(kotlin("gradle-plugin", kotlin_version))
    }

这里的 classpath 就是一个方法:

代码语言:javascript复制
class ScriptHandlerScope(scriptHandler: ScriptHandler) : ScriptHandler by scriptHandler {
    ...
    fun DependencyHandler.classpath(dependencyNotation: Any): Dependency =
        add(CLASSPATH_CONFIGURATION, dependencyNotation)
}

那么 compile 的定义哪儿去了?其实,compile 和 classpath 不一样,前者是构建插件的 configuration,而 classpath 则是 gradle 本身的一个方法。

那么 compile 到底是什么,gradle 自己没有定义就不能用了吗?那倒也不是,gradle kotlin DSL 会帮我们根据插件的 configuration 定义生成这样的代码。这在 gradle kotlin dsl 0.8.0 中就做了支持,官方把他们称作:Type-safe accessors,这个版本也跟随 gradle 3.5 发版。

我本来用 4.0 用得好好的,非要因为 settings.gradle.kts 改用了 4.4 的版本,导致出现了这个问题,我就想难道新版本做了调整?于是我又换了 4.5、4.5.1,果然问题还是有。

后来查了一下官方 demo "hello-kotlin":

代码语言:javascript复制
plugins {
    application
    kotlin("jvm") version "1.2.0"
}

application {
    mainClassName = "samples.HelloWorldKt"
}

dependencies {
    compile(kotlin("stdlib"))
}

repositories {
    jcenter()
}

对比了一下才发现,原来人家用的 是 plugins{} 这种写法,而我的工程仍然用的是 apply plugin 的写法,就这么点儿区别。。难道真的是因为这个?

果然,我把我的配置修改了一下:

代码语言:javascript复制
- apply {
-    plugin("java")
-    plugin("kotlin")
- }

  plugins {
     java
     kotlin("jvm") version "1.2.10"
  }

这时候果然没问题了:

而且我们也能找到 compile 的定义:

代码语言:javascript复制
fun DependencyHandler.`compile`(dependencyNotation: Any): Dependency =
    add("compile", dependencyNotation)

原来,这些 gradle 帮我们动态生成的 accessors,生成的时机就是 plugins{} 调用之后。也就是说我们需要使用这种方式来应用插件才会生成上述的方法。

详细说明在 gradle kotlin DSL 0.8.0 的更新说明当中:https://github.com/gradle/kotlin-dsl/releases/tag/v0.8.0 ,不过其中提到的 gskGenerateAccessors 我在 gradle 4.5 当中已经找不到了。

小结

kotlin 和 groovy 也算是各有所长,如果我们对于 gradle 的语法非常熟悉,那么我个人认为用 groovy 写 DSL 倒也灵活,kotlin 的约束毕竟多一些——而这也正是 Kotlin DSL 的优点,静态类型安全有保障。。


0 人点赞