Gradle Kotlin DSL 的 accessors 生成问题

概要

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

正文

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

Gradle Kotlin DSL 的 accessors 生成问题_第1张图片

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

 
   
  1. ...

  2. distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

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

 
   
  1. buildscript {

  2.    var kotlin_version: String by extra

  3.    kotlin_version = "1.2.10"

  4.    repositories {

  5.        mavenCentral()

  6.    }

  7.    dependencies {

  8.        classpath(kotlin("gradle-plugin", kotlin_version))

  9.    }

  10. }

  11. apply {

  12.    plugin("java")

  13.    plugin("kotlin")

  14. }

  15. val kotlin_version: String by extra

  16. repositories {

  17.    mavenCentral()

  18. }

  19. dependencies {

  20.    compile(kotlin("stdlib"))

  21. }

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

 
   
  1. e: .../kotlinspecificsJvm/app/build.gradle.kts:42:5: Unresolved reference: compile

Gradle Kotlin DSL 的 accessors 生成问题_第2张图片

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

 
   
  1.    dependencies {

  2.        classpath(kotlin("gradle-plugin", kotlin_version))

  3.    }

这里的 classpath 就是一个方法:

 
   
  1. class ScriptHandlerScope(scriptHandler: ScriptHandler) : ScriptHandler by scriptHandler {

  2.    ...

  3.    fun DependencyHandler.classpath(dependencyNotation: Any): Dependency =

  4.        add(CLASSPATH_CONFIGURATION, dependencyNotation)

  5. }

那么 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":

 
   
  1. plugins {

  2.    application

  3.    kotlin("jvm") version "1.2.0"

  4. }

  5. application {

  6.    mainClassName = "samples.HelloWorldKt"

  7. }

  8. dependencies {

  9.    compile(kotlin("stdlib"))

  10. }

  11. repositories {

  12.    jcenter()

  13. }

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

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

 
   
  1. - apply {

  2. -    plugin("java")

  3. -    plugin("kotlin")

  4. - }

  5. + plugins {

  6. +    java

  7. +    kotlin("jvm") version "1.2.10"

  8. + }

这时候果然没问题了:

Gradle Kotlin DSL 的 accessors 生成问题_第3张图片

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

 
   
  1. fun DependencyHandler.`compile`(dependencyNotation: Any): Dependency =

  2.    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 的优点,静态类型安全有保障。。


欢迎关注微信公众号 Kotlin

Gradle Kotlin DSL 的 accessors 生成问题_第4张图片


你可能感兴趣的:(Gradle Kotlin DSL 的 accessors 生成问题)