概要
如果你想用 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 的优点,静态类型安全有保障。。