gradle - 有没有办法使用 gradle 6.0 定义要在 settings.gradle.kts 和项目/子项目 build.gradle.kts 中使用的属性?

标签 gradle gradle-kotlin-dsl

我们有用 gradle kotlin dsl 编写的带有构建逻辑的多模块 android 应用程序。我们使用 buildSrc 来提取常见的逻辑,比如依赖版本。我们有类似的东西:
buildSrc/src/main/kotlin/Dependencies.kt :

object Versions {
    const val fooVersion = "1.2.3"
    const val barVersion = "4.5.6"
}

object Libraries {
    val foo = "com.example.foo:foo:$fooVersion"
    val bar = "com.example.bar:bar:$barVersion"
}

object Modules {
    const val app = ":app"
    const val base = ":base"
    const val baz = ":baz"
}

然后我们可以在模块的 dependencies 中使用它们 block 以避免硬编码/重复值:
app/build.gradle.kts :
dependencies {
    implementation(Libs.foo)
    implementation(Libs.bar)

    implementation(project(Modules.base))
    implementation(project(Modules.baz))
}

我们也在 settings.gradle.kts 中使用它:
settings.gradle.kts :
include(
    Modules.app,
    Modules.base,
    Modules.baz
)

这适用于 gradle 5.6。当我升级到 6.0 时,我得到 Unresolved reference: Modules在 settings.gradle.kts 文件中。我发现它在 migration guide 中提到过:

Previously, the buildSrc project was built before applying the project’s settings script and its classes were visible within the script. Now, buildSrc is built after the settings script and its classes are not visible to it. The buildSrc classes remain visible to project build scripts and script plugins.

Custom logic can be used from a settings script by declaring external dependencies.



所以我知道是什么破坏了构建,我可以通过使用 settings.gradle.kts 中的硬编码值来修复构建:
include(
    ":app",
    ":base",
    ":baz"
)

gradle 6.0 是否可以避免这种重复?

最佳答案

ticket #11090 "Definitions from buildSrc/ not found in settings.gradle.kts using gradle 6.0-rc-1"

正如您已经注意到的那样,这最近发生了变化:

This has changed in 6.0, and was deprecated in 5.6. Please see: https://docs.gradle.org/current/userguide/upgrading_version_5.html#buildsrc_usage_in_gradle_settings

-- https://github.com/gradle/gradle/issues/11090#issuecomment-544473179



One of the maintainers 描述了该决定背后的原因:

Unfortunately, there are pros and cons to both arrangements (settings-then-buildSrc and buildSrc-then-settings), and we opted for the former after considering.

(...)

The pros that compelled us to make the change:

  1. Settings plugins can influence buildSrc and main build (i.e. apply a build plugin to both)
  2. Build cache configuration is applied to buildSrc
  3. buildSrc behaves more like a regular included build

-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268



最后是一些坏消息:

We won't be changing the behaviour back to the pre Gradle 6 arrangement. Please let us know if you would like more detail on how to use one of the alternative mechanisms for using complex logic in a settings script.

-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268



解决方法

在上述帖子中,作者提出了一些解决方法:

The con of this is exactly what you have hit. It's now less convenient to use complex logic in your settings script. Now, you have to either:

  1. Inline the logic into the settings file
  2. Move the logic to a shared script that can be used where it needs to
  3. Move the logic to a pre-built binary that you load in the settings file (i.e. a settings plugin)

-- https://github.com/gradle/gradle/issues/11090#issuecomment-545697268



#1 非常简单,但我只能假设 #2 和 #3 是什么意思。我来自 Groovy 世界,最近才开始与 Kotlin DSL 交 friend 。话虽如此,让我们试一试。

在#3 中,作者可能正在谈论开发一个外部插件并将其应用到两个脚本中。我不确定这是否是有意义的实现(虽然它给你强类型)。

“#2 将逻辑移动到可以在需要的地方使用的共享脚本”

我认为这是关于拥有一个通用的 script plugin 并将其包含在 settings.gradlebuild.gradle 文件中。该插件会将静态信息放在 ExtraPropertiesExtension 范围内的 ExtensionAware 中( Settings settings.gradle 脚本插件的情况下, Project build.gradle 的情况下)。这在 this answer to "Include scripts with Gradle Kotlin DSL" 中有描述:

How can I put all common constants (such as dependency versions) to the separate file to include them just by using something like springBootVersion or Constants.springBootVersion with compile-time checks?



目前没有好的方法可以做到这一点。您可以使用额外的属性,但它不能保证编译时检查。像这样的东西:
// $rootDir/dependencies.gradle.kts

// this will try to take configuration from existing ones
val compile by configurations
val api by configurations
dependencies {
  compile("commons-io:commons-io:1.2.3")
  api("some.dep")
}

// This will put your version into extra extension
extra["springBootVersion"] = "1.2.3"

你可以像这样使用它:
// $rootDir/build.gradle.kts
subprojects {
  apply {
    plugin<JavaLibraryPlugin>()
    from("$rootDir/dependencies.gradle.kts")
  }

在你的模块中:
// $rootDir/module/build.gradle.kts
// This will take existing dependency from extra
val springBootVersion: String by extra
dependencies {
  compile("org.spring:boot:$springBootVersion")
}

-- Include scripts with Gradle Kotlin DSL

关于gradle - 有没有办法使用 gradle 6.0 定义要在 settings.gradle.kts 和项目/子项目 build.gradle.kts 中使用的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59066869/

相关文章:

java - Gradle 5 Kotlin DSL : Common Tasks & Maven Artifacts in multi-modules projects

Gradle kotlin dsl - 如何指定重复任务?

android - gradlew 安装包 R 不存在

android - 使用 com.google.gms.google-services gradle 插件时出现 NoSuchMethodError。

android - 无法访问 'kotlin.collections.Collection',它是 'org.gradle.api.artifacts.dsl.RepositoryHandler' 的父类(super class)型

android - 将 Android 项目转换为使用 Gradle Script Kotlin

android - react-native run-android 错误 : Unable to upload some APKs

android - Maven 依赖与 Android Studio/Gradle

android - 与 Android Studio 相关的 build.gradle 文件中无法访问的几个任务

kotlin 原生 gradle Hello World