等级:无法从另一个项目访问一个项目中定义的配置

Grade: Can't access configuration defined in one project from another project

我对 gradle 和 groovy 都很陌生。

问题

我有一个非常简单的多项目结构,如下所示:

Root project 'gradle_test'
+--- Project ':sub1'
\--- Project ':sub2'

这是 sub1 项目的 'build.grade' 文件的样子:

// build.gradle of sub1 project
task testConfiguration {
    println project(':sub2').configurations.sub2FooConfiguration
}

最后,这是 sub2 项目的 'build.grade' 文件:

// build.gradle of sub2 project
configurations {
    sub2FooConfiguration
}

非常少。现在,如果我 运行 gradle :sub1:testConfiguration,我得到以下错误:

A problem occurred evaluating project ':sub1'.
> Could not find property 'sub2FooConfiguration' on configuration container.

但是,如果 sub1 项目中的 testConfiguration 任务修改如下:

// notice the "<<" (I believe this is calling the 'doLast' method on the task instance)
task testConfiguration << {
    println project(':sub2').configurations.sub2FooConfiguration
}

问题

我认为 'testConfiguration' 任务的两个版本之间的区别在于,在第一个实例中,configuration closure 被传递给任务,而在修改版本中 'normal' 闭包传递给 'doLast' 方法。

那么,首先,我的假设是否正确?

其次,为什么我一开始就无法访问'sub2'项目?

最后,是否可以在第一个实例中(即在配置闭包中)访问 'sub2' 项目?

[更新]进一步的问题

鉴于 "Invisible Arrow" 提供的公认答案,我想再问一个关于引用另一个项目配置的最佳实践的问题(即 sub1 中的任务需要使用由子 2 项目)。

我是否应该声明两个项目之间的评估依赖关系?

或者我应该只在执行时引用 sub2 的配置(例如在 doLast() 中)吗?

或者,我应该在两个项目之间创建依赖配置吗?

是的,两者是有区别的。 构建基本上有 3 个阶段,即 初始化配置执行。 Gradle 文档中的 Build Lifecycle 章节对此进行了详细描述。

在您的情况下,第一个实例属于 Configuration 阶段,无论任务是否执行,都会对其进行评估。这意味着闭包中的所有语句都会在您开始构建时执行。

task testConfiguration {
    // This always runs during a build,
    // irrespective of whether the task is executed or not
    println project(':sub2').configurations.sub2FooConfiguration
}

第二个实例属于执行阶段。注意<<doLast的shorthand,这个闭包是在任务执行的时候调用的

task testConfiguration << {
    // Called during actual execution of the task,
    // and called only if the task was scheduled to be executed.
    // Note that Configuration phase for both projects are complete at this point,
    // which is why :sub1 is able to access :sub2's configurations.sub2FooConfiguration
    println project(':sub2').configurations.sub2FooConfiguration
}

现在来谈谈为什么一审报错了。这是因为尚未评估 sub2 项目的 Configuration 阶段。因此 sub2FooConfiguration 尚未创建。

为什么?因为 sub1sub2 之间没有明确的求值依赖关系。在您的情况下,sub1 需要 sub2 作为评估依赖项,因此我们可以在任务声明之前在 sub1build.gradle 中添加该依赖项,如下所示:

evaluationDependsOn(':sub2')
task testConfiguration {
    println project(':sub2').configurations.sub2FooConfiguration
}

这将确保 sub2 始终在 sub1 之前评估(评估意味着项目的 配置 阶段)。 sub1 现在可以在任务声明闭包中访问 configurations.sub2FooConfiguration。这在 Multi-project Builds 章节中有详细解释。

在第二个实例中,configurations.sub2FooConfiguration 是可访问的,因为调用是在任务的执行块中(在两个项目的 配置 阶段之后) .

PS:请注意,如果您颠倒了项目名称,那么第一个实例实际上可能有效,因为 Gradle 按字母顺序配置项目,如果没有明确的依赖关系。但是,当然,你永远不应该依赖它并确保明确声明项目之间的依赖关系。