我对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
被传递给任务,而在修改版本中,'正常'闭包被传递给'doLast'方法。
首先,我的假设是正确的吗?
其次,为什么我在第一个实例中无法访问'sub2'项目?
最后,是否可以在第一个实例中访问'sub2'项目(即在配置闭包中)?
鉴于“Invisible Arrow”提供了接受的答案,我想问一个关于引用另一个项目配置的最佳实践的进一步问题(即sub1中的任务需要使用sub2项目生成的存档) 。
我应该在两个项目之间声明评估依赖关系吗?
或者我应该只在执行时引用sub2的配置(例如在doLast()中)?
或者,我应该在两个项目之间创建依赖关系配置吗?
答案 0 :(得分:3)
是的,两者之间存在差异。 构建基本上有3个阶段,分别是初始化,配置和执行。这在Gradle文档的Build Lifecycle章节中详细描述。
在您的情况下,第一个实例属于配置阶段,无论任务是否执行,都会始终评估该阶段。这意味着在开始构建时,将执行闭包内的所有语句。
task testConfiguration {
// This always runs during a build,
// irrespective of whether the task is executed or not
println project(':sub2').configurations.sub2FooConfiguration
}
第二个实例属于执行阶段。请注意<<
是doLast
的简写,执行任务时会调用此闭包。
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
项目的配置阶段尚未评估。因此,sub2FooConfiguration
尚未创建。
为什么呢?因为sub1
和sub2
之间没有明确的评估依赖关系。在您的情况下,sub1
需要sub2
作为评估依赖项,因此我们可以在任务声明之前在sub1
的{{1}}中添加该依赖项,如下所示:
build.gradle
这将确保始终在evaluationDependsOn(':sub2')
task testConfiguration {
println project(':sub2').configurations.sub2FooConfiguration
}
之前评估sub2
(评估意味着项目的配置阶段)。 sub1
现在可以在任务声明关闭中访问sub1
。这在Multi-project Builds章节中有详细解释。
在第二个实例中,configurations.sub2FooConfiguration
是可访问的,因为调用是在任务的执行块中(在两个项目的配置阶段之后)。
PS :请注意,如果您颠倒了项目的名称,那么第一个实例可能确实有效,因为如果没有显式依赖项,Gradle会按字母顺序配置项目。但是,当然,您不应该依赖于此并确保明确声明项目之间的依赖关系。