有没有办法定义 属性 在 settings.gradle.kts 和 projects/subprojects build.gradle.kts 中使用 gradle 6.0?
Is there a way to define property to be used in both settings.gradle.kts and projects/subprojects build.gradle.kts with gradle 6.0?
我们有多模块 android 应用程序,其构建逻辑是用 gradle kotlin dsl 编写的。我们使用 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
块中使用这些来避免 hardcoded/duplicated 值:
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 时,我在 settings.gradle.kts 文件中得到 Unresolved reference: Modules
。我发现它在 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 避免这种重复?
AFAIK - 不,这就是前面提到的迁移指南所说的:settings.gradle 是第一个被评估的,因此,在那个阶段,在 buildSrc 中定义的对象甚至还不存在。
我 可以 想象一些 hacky 解决方法 - 只是为了科学,但在实际项目中它会闻起来很难闻,IMO,不值得。
P. S.:我猜你可以反转它并尝试通过遍历 buildSrc 代码中的子模块来创建一些枚举的实例。但同样,实现这一目标的方法可能非常奇特,只能用于证明它可行的唯一目的)
参见 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:
- Settings plugins can influence buildSrc and main build (i.e. apply a build plugin to both)
- Build cache configuration is applied to buildSrc
- 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
解决方法
在上述post中,作者提出了一些解决方法:
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:
- Inline the logic into the settings file
- Move the logic to a shared script that can be used where it needs to
- 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 交朋友。话虽如此,让我们试一试。
在#3 中,作者可能正在谈论开发一个外部插件并将其应用到两个脚本中。我不太确定这是否可以实现(尽管它可以为您提供强类型)。
"#2 将逻辑移至可在需要的地方使用的共享脚本"
我认为这是关于有一个共同点 script plugin and including it in both settings.gradle
and build.gradle
files. The plugin would put the static information in the ExtraPropertiesExtension
of the ExtensionAware
in scope (Settings
in case of a settings.gradle
script plugin and Project
in case of build.gradle
). This is described in :
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")
}
--
我们有多模块 android 应用程序,其构建逻辑是用 gradle kotlin dsl 编写的。我们使用 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
块中使用这些来避免 hardcoded/duplicated 值:
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 时,我在 settings.gradle.kts 文件中得到 Unresolved reference: Modules
。我发现它在 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 避免这种重复?
AFAIK - 不,这就是前面提到的迁移指南所说的:settings.gradle 是第一个被评估的,因此,在那个阶段,在 buildSrc 中定义的对象甚至还不存在。
我 可以 想象一些 hacky 解决方法 - 只是为了科学,但在实际项目中它会闻起来很难闻,IMO,不值得。
P. S.:我猜你可以反转它并尝试通过遍历 buildSrc 代码中的子模块来创建一些枚举的实例。但同样,实现这一目标的方法可能非常奇特,只能用于证明它可行的唯一目的)
参见 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
andbuildSrc-then-settings
), and we opted for the former after considering.(...)
The pros that compelled us to make the change:
- Settings plugins can influence buildSrc and main build (i.e. apply a build plugin to both)
- Build cache configuration is applied to buildSrc
- 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
解决方法
在上述post中,作者提出了一些解决方法:
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:
- Inline the logic into the settings file
- Move the logic to a shared script that can be used where it needs to
- 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 交朋友。话虽如此,让我们试一试。
在#3 中,作者可能正在谈论开发一个外部插件并将其应用到两个脚本中。我不太确定这是否可以实现(尽管它可以为您提供强类型)。
"#2 将逻辑移至可在需要的地方使用的共享脚本"
我认为这是关于有一个共同点 script plugin and including it in both settings.gradle
and build.gradle
files. The plugin would put the static information in the ExtraPropertiesExtension
of the ExtensionAware
in scope (Settings
in case of a settings.gradle
script plugin and Project
in case of build.gradle
). This is described in
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") }
--