带空项目的Gradle多项目构建

带空项目的Gradle多项目构建,gradle,gradle-multi-project-build,Gradle,Gradle Multi Project Build,将多项目渐变结构应用于我们的项目时,我的设置.Gradle如下所示: 包括“来源:compA:api” 包括“来源:compA:core” 包括“来源:compB” gradle项目给了我 根项目“tmp” \---项目“:源” +---项目“:来源:compA” |+---项目“:来源:compA:api” |\---项目:来源:compA:core' \---项目“:来源:compB” 这正是目录结构 在我的根目录中,我有一个build.gradle,它将java插件应用于所有子项目:

将多项目渐变结构应用于我们的项目时,我的设置.Gradle如下所示:

包括“来源:compA:api”
包括“来源:compA:core”
包括“来源:compB”
gradle项目给了我

根项目“tmp”
\---项目“:源”
+---项目“:来源:compA”
|+---项目“:来源:compA:api”
|\---项目:来源:compA:core'
\---项目“:来源:compB”
这正是目录结构
在我的根目录中,我有一个build.gradle,它将java插件应用于所有子项目:

子项目{
应用插件:“java”
}
在构建时,我最终得到了:source:compA的工件,这些工件是空的,因为这实际上不是一个项目,只是子目录api和core是合适的Java项目


避免出现空工件的最佳方法是什么?

您可以尝试使用他们在文件中使用的技巧。请注意每个子项目如何位于
'subprojects/${projectName}
文件夹中,但
subprojects
文件夹本身不是一个项目

因此,在您的情况下,您可以执行以下操作:

包括“来源:compA api”
包括“来源:compA core”
包括“来源:compB”
project(':source:compA-api')。projectDir=新文件(setingsdir,'source/compA/api')
project(':source:compA-core')。projectDir=新文件(setingsdir,'source/compA/core')
我故意省略了
compA
api
之间的冒号,以确保
source:compA
不会作为项目容器进行评估

或者,您可以尝试将
source:compA
项目排除在
java
插件之外,方法如下:

def javaProjects(){
返回subprojects.findAll{it.name!='compA'}
} 
配置(javaProjects()){
应用插件:“java”
} 
编辑: 或者,您可以尝试类似的方法(根据您的喜好进行调整):

def javaProjects(){
返回subprojects.findAll{新文件(it.projectDir,“src”).exists()}
} 
配置(javaProjects()){
应用插件:“java”
} 

从Gradle 6.7开始,Gradle用户手册使用
子项目和
所有项目使用“跨项目配置”功能配置子项目:

另一种不鼓励在子项目之间共享构建逻辑的方法是通过
subprojects{}
allprojects{}
DSL构造进行跨项目配置。通过交叉配置,可以将构建逻辑注入子项目,这在查看子项目的构建脚本时并不明显,这使得理解特定子项目的逻辑变得更加困难。从长远来看,交叉配置通常会变得越来越复杂,有越来越多的条件逻辑和更高的维护负担。交叉配置也可能在项目之间引入,这可能会阻止优化(如)正常工作

建议的方法是使用定义共同特征:

Gradle推荐的组织构建逻辑的方法是使用其插件系统。插件应该定义子项目的类型。事实上,以相同的方式建模,例如,配置通用java项目,同时在内部应用和配置特定于java库的方面。类似地,应用并配置和

您可以通过应用和配置核心插件和外部插件,创建自定义插件,定义新的项目类型,并配置特定于您的项目或组织的约定,来组合自定义构建逻辑。对于本节开头的每个示例特征,我们可以编写一个插件,封装给定类型子项目的公共逻辑

我们建议将约定插件的源代码和测试放在项目根目录的特殊buildSrc目录中。有关buildSrc的更多信息,请参阅


在您的特殊情况下,您可以遵循Gradle的方法:

├── buildSrc
│   ├── 格雷德尔先生
│   ├── src
│   │   ├── 主要的
│   │   │   └── 棒极了
│   │   │       ├── source.java-conventions.gradle
buildSrc/build.gradle
文件只包含
groovy gradle插件

插件{
id“groovy gradle插件”
}
buildSrc/src/main/groovy/source.java conventions.gradle
将包含java项目的通用逻辑。在您的示例中,您刚刚使用了Java插件的应用程序,但您将添加任何其他不与非Java项目共享的Java插件的通用性:

插件{
id“groovy gradle插件”
}
然后,每个Java项目将包括约定插件:

插件{
id“source.java约定”
}

请注意,如果仅仅是
java
插件就很常见,那么这并不能买到很多东西;您正在用另一个插件替换一个插件。但是,一旦您得到更多的共享构建逻辑,就开始在跨项目一致性和减少重复代码方面获得回报。

我有第二种情况。空的父目录被视为项目。我们可以做一些检查来忽略这个项目

project.getBuildFile().exists()

为什么不在api和core各自的脚本中应用Java插件呢?我可以这样做,但我的实际项目结构要嵌套得多,有很多项目。我认为这是遗留项目结构的常见问题。我正在寻找一个灵活的解决方案,其中每个项目不需要了解它所在的构建过程。IMHO子模块应该明确知道它是一个Java项目。这将使它走得更远