我正在为JVM设置一个基于Kotlin的多模块Gradle项目。由于根项目不包含任何代码,Kotlin插件应该只应用于子项目。build.gradle.kts
(根项目)
plugins {
kotlin("jvm") version "1.6.20" apply false
}
subprojects {
apply(plugin = "kotlin")
group = "com.example"
repositories {
mavenCentral()
}
dependencies {}
kotlin {
jvmToolchain {
check(this is JavaToolchainSpec)
languageVersion.set(JavaLanguageVersion.of(11))
}
}
}
尝试设置工具链会导致构建在kotlin {...}
扩展名处失败:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun DependencyHandler.kotlin(module: String, version: String? = ...): Any defined in org.gradle.kotlin.dsl
public fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec defined in org.gradle.kotlin.dsl
如果我将扩展定义复制到每个子项目构建脚本中,它可以正常工作,但是为什么它在主脚本中不可用?
1条答案
按热度按时间mrphzbgm1#
这是我最喜欢在Gradle中修复的问题之一,并且真正展示了可能的灵活性(以及演示为什么Gradle会很复杂!)
首先,我将给予一些关于
subprojects {}
DSL的背景信息,然后我将展示如何修复您的脚本,最后我将展示与buildSrc约定插件共享构建逻辑的最佳方法。(尽管这是最后一部分,但我确实推荐使用buildSrc!)组合与继承
使用
allprojects {}
和subprojects {}
确实很常见,我经常看到这种情况。它更类似于Maven的工作方式,所有配置都在“父”构建文件中定义。[A]不鼓励在子项目之间共享构建逻辑的方法是通过
subprojects {}
和allprojects {}
DSL构造进行跨项目配置。(It的常见原因可能是它易于理解-它使Gradle的工作方式更像Maven,因此每个项目都继承自一个父项目。但Gradle是专为组合设计的。(第10页)
快速修复:'未解析引用'
你看到的错误基本上是因为你还没有应用Kotlin插件。
kotlin { }
配置块是一个非常有用的扩展函数,在应用Kotlin插件时加载。因此,如果我们没有扩展函数,我们可以直接调用
configure
,从而配置Kotlin扩展。但是,即使这样做是可行的,使用
subprojects {}
也有问题。buildSrc和惯例插件
buildSrc
基本上是一个独立的Gradle项目,我们可以在主项目的构建脚本中使用它的输出。因此,我们可以编写自己的自定义Gradle插件,定义约定,我们可以选择性地将其应用于'main'构建中的任何子项目。(This是Gradle和Maven之间的关键区别。在Gradle中,一个子项目可以由任意数量的插件配置。在Maven中,只有一个父项目。
Gradle文档提供了关于设置约定插件的完整指南,因此我在此仅简要总结一下解决方案。
1.设置
./buildSrc
在项目根目录中创建一个名为
buildSrc
的目录。因为
buildSrc
是独立项目,所以请像通常的项目一样,建立./buildSrc/build.gradle.kts
和./buildSrc/settings.gradle.kts
档案。在
./buildSrc/build.gradle.kts
中,1.应用
kotlin-dsl
插件1.添加您希望在项目中的任何位置使用的Gradle插件的依赖项
请注意,我使用的是Maven存储库KotlinGradle插件的坐标,而不是插件ID!
如果你愿意,你也可以在
./buildSrc/build.gradle.kts
中添加其他依赖项。如果你想在构建脚本中解析JSON,那么就在JSON解析器上添加一个依赖项,比如kotlinx-serialization
。2.创建约定插件
创建可应用于任何Kotlin JVM子项目的Kotlin JVM约定。
不要忘记添加
package
声明!我已经忘记了几次,它会导致很难弄清楚的错误。3.应用约定插件
就像Gradle插件有ID一样,我们的约定插件也有ID。它是包名称+
.gradle.kts
之前的位。因此,在我们的示例中,ID为my.project.convention.kotlin-jvm
我们可以像常规Gradle插件一样应用此功能...
(约定插件也可以导入其他约定插件,使用
id("...")
)此外,由于我们使用的是Kotlin,因此还有一种更好的方法。您知道Gradle插件中包含了
java
和java-library
。我们可以用同样的方法导入约定插件!请注意插件ID周围的反勾号-因为需要连字符,所以需要它们。
(警告:这种非
id("...")
方式在buildSrc
中不起作用,只在主项目中起作用)结果
现在,根
./build.gradle.kts
可以保持干净整洁--它只需要定义项目的组和版本。因为我们使用的是约定插件,而不是一揽子的
subprojects
,所以每个子项目都可以专门化,只导入它需要的约定插件,而不需要重复。站点注解:在
buildSrc
和主项目之间共享资源库通常您希望在
buildSrc
和主项目之间共享存储库。因为Gradle插件不是专门针对项目的,所以我们可以为任何项目编写插件,包括settings.gradle.kts
!我所做的就是创建一个文件,其中包含我想要使用的所有存储库...
(the名称
repositories.settings.gradle.kts
并不重要-但将其命名为*.settings.gradle.kts
应该意味着IntelliJ会提供建议,但目前这是错误的。)然后,我可以将其作为插件导入到其他
settings.gradle.kts
文件中,就像您将KotlinJVM插件应用到子项目中一样。