如何使用Kotlin DSL将Gradle插件应用到插件项目自身?
我们有一个已有的Gradle插件项目,该项目可配置包括静态分析在内的各类能力,现在需要将项目自身开发的插件应用到本项目。
对于使用Java编写的Gradle插件,现有实现方案是将Java源码目录添加到buildSrc项目中,buildSrc编译生成的类即可在主项目中使用。现在需要为使用Kotlin脚本编写的插件实现相同的效果,但尝试构建时,buildSrc编译失败,报错如下:
e: C:\Users\Trejkaz\Documents\test\self-applying-gradle-plugin\src\main\kotlin\example.common.gradle.kts: (1, 1): Unresolved reference: allprojects > Task :buildSrc:compileKotlin FAILED
需要补充什么配置才能让该方案正常生效?
- 如果将插件文件复制到
buildSrc/src/main/kotlin目录下,可正常运行; - 如果将插件文件复制到
buildSrc/src/main/kotlin2目录,再通过srcDirs指定该目录,同样会编译失败,当前配置完全不支持重定位源码路径。
主项目build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { `java-gradle-plugin` `kotlin-dsl` // 与Gradle内置Kotlin版本对齐 kotlin("jvm") version "1.5.31" } apply(from = "common-build.gradle.kts") apply(plugin = "example.common") // 尝试在此处应用编译完成的插件 group = "org.example" version = "1.0-SNAPSHOT" tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "11" }
buildSrc/build.gradle.kts
当前配置已将主项目的源码路径添加为buildSrc的源码目录:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { `java-gradle-plugin` `kotlin-dsl` // 与Gradle内置Kotlin版本对齐 kotlin("jvm") version "1.5.31" } apply(from = "../common-build.gradle.kts") tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "11" } kotlin { sourceSets["main"].kotlin.srcDir("../src/main/kotlin") }
common-build.gradle.kts
存放两个构建脚本的公共配置(KotlinCompile相关配置暂未移入,后续会单独排查无法移入的原因):
repositories { mavenCentral() } dependencies { // 编译Kotlin脚本所需依赖,插件不会自动添加 "implementation"("org.jetbrains.kotlin:kotlin-scripting-jvm") }
插件脚本src/main/kotlin/example.common.gradle.kts
allprojects { // 各类通用配置 }
报错核心原因是kotlin-dsl插件的预编译脚本机制默认仅扫描buildSrc/src/main/kotlin路径下的.gradle.kts文件,自动为这类文件注入Gradle API上下文(包括allprojects、dependencies、tasks这类内置扩展)。手动通过Kotlin源码集srcDir添加的自定义路径,只会被识别为普通Kotlin源码目录,不会触发预编译脚本的上下文注入,因此会出现Unresolved reference报错。自定义kotlin2目录编译失败也是同一个原因。
按以下方式修改buildSrc/build.gradle.kts即可解决问题:
在原有配置基础上,新增预编译脚本扫描路径声明,完整配置如下:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { `java-gradle-plugin` `kotlin-dsl` kotlin("jvm") version "1.5.31" } apply(from = "../common-build.gradle.kts") tasks.withType<KotlinCompile> { kotlinOptions.jvmTarget = "11" } kotlin { sourceSets["main"].kotlin.srcDir("../src/main/kotlin") } // 新增以下配置,指定预编译Kotlin脚本的扫描范围 gradlePlugin { precompiledScriptPlugins { scriptFiles.from( fileTree("../src/main/kotlin") { include("**/*.gradle.kts") } ) } }
配置生效后,主项目src/main/kotlin下的.gradle.kts插件脚本就会被正常识别为预编译插件,和放在buildSrc/src/main/kotlin下的行为完全一致,主项目中可以直接通过插件ID引用。
提示:如果使用Gradle 8.0+版本,
precompiledScriptPlugins配置块已调整至kotlinDslPluginOptions作用域下,需要对应修改配置路径,其余逻辑不变。
内容的提问来源于stack exchange,提问作者Hakanai

