【问题标题】:Gradle multi project build with empty projects使用空项目构建 Gradle 多项目
【发布时间】:2012-06-24 12:04:20
【问题描述】:

在我们的项目中应用多项目 Gradle 结构时,我的 settings.gradle 如下所示:

include "source:compA:api"
include "source:compA:core"
include "source:compB"

gradle 项目给我

Root project 'tmp'
\--- Project ':source'
     +--- Project ':source:compA'
     |    +--- Project ':source:compA:api'
     |    \--- Project ':source:compA:core'
     \--- Project ':source:compB'

这正是目录结构!
在我的根目录中,我有一个 build.gradle,它将 java 插件应用于所有子项目:

subprojects {
    apply plugin: 'java'
}

在构建时,我最终得到了 :source:compA 的工件,它们是空的,因为这实际上不是一个项目,只是子目录 apicore em> 是正确的 Java 项目。

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

【问题讨论】:

  • 为什么不直接将Java插件应用到各自脚本中的api和core呢?
  • 我可以这样做,但我的实际项目结构更加嵌套,有很多项目。我认为这是遗留项目结构的常见问题。而且我正在寻找一种灵活的解决方案,每个项目都不需要了解它所处的构建过程。
  • 恕我直言,子模块应该明确知道它是一个 Java 项目。与在根级别声明此信息相比,这对于任何查看它的人来说都更具表现力。

标签: gradle gradle-multi-project-build


【解决方案1】:

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

所以在你的情况下,你会做这样的事情:

include "source:compA-api"
include "source:compA-core"
include "source:compB"

project(':source:compA-api').projectDir = new File(settingsDir, 'source/compA/api')
project(':source:compA-core').projectDir = new File(settingsDir, 'source/compA/core')

我有意省略了compAapi 之间的冒号,以确保source:compA 不会被评估为项目容器。

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

def javaProjects() { 
  return subprojects.findAll { it.name != 'compA' }
} 

configure(javaProjects()) { 
  apply plugin: 'java' 
} 

编辑: 或者,您可以尝试这样的事情(根据自己的喜好调整):

def javaProjects() { 
  return subprojects.findAll { new File(it.projectDir, "src").exists() }
} 

configure(javaProjects()) { 
  apply plugin: 'java' 
} 

【讨论】:

  • 感谢您的回答。我希望有类似skipIfEmpty 的设置。
  • 您可以通过自定义findAll 子句来实现与此等价的功能。请参阅上面的编辑。
  • 这是一个很好的解决方案。我仍然必须习惯构建文件是 groovy 脚本这一事实;)
【解决方案2】:

从 Gradle 6.7 开始,Gradle 用户手册recommends against 使用“跨项目配置”功能使用subprojectsallprojects 配置子项目:

另一种不鼓励在子项目之间共享构建逻辑的方法是跨项目配置,通过subprojects {}allprojects {} DSL 构造。使用交叉配置,可以将构建逻辑注入到子项目中,这在查看子项目的构建脚本时并不明显,使得理解特定子项目的逻辑变得更加困难。从长远来看,交叉配置通常会随着越来越多的条件逻辑和越来越高的维护负担而变得复杂。交叉配置还可以在项目之间引入configuration-time coupling,这样可以防止configuration-on-demand之类的优化不能正常工作。

建议的方法是改用convention plugins 来定义共同特征:

Gradle 推荐的组织构建逻辑的方法是使用它的插件系统。插件应该定义子项目的 type。事实上,Gradle core plugins 以相同的方式建模 - 例如,Java Plugin 配置通用 Java 项目,而 Java Library Plugin 在内部应用 Java Plugin 并另外配置特定于 Java 库的方面。同样,Application Plugin 应用和配置Java PluginDistribution Plugin

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

我们建议将约定插件的源代码和测试放在项目根目录的特殊 buildSrc 目录中。有关 buildSrc 的更多信息,请咨询Using buildSrc to organize build logic


在您的特定情况下,您可以遵循 Gradle 的 sample 中给出的方法:

├── buildSrc
│   ├── build.gradle
│   ├── src
│   │   ├── main
│   │   │   └── groovy
│   │   │       ├── source.java-conventions.gradle

buildSrc/build.gradle 文件将仅包含 groovy-gradle-plugin

plugins {
    id 'groovy-gradle-plugin'
}

buildSrc/src/main/groovy/source.java-conventions.gradle 将包含 Java 项目的通用逻辑。在您的示例中,您只有 Java 插件的应用程序,但您将添加不会与非 Java 项目共享的 Java 插件的任何其他通用性:

plugins {
    id 'groovy-gradle-plugin'
}

然后每个 Java 项目都将包含约定插件:

plugins {
    id 'source.java-conventions'
}

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

【讨论】:

    【解决方案3】:

    我有两种情况。空的父目录被视为项目。我们可以进行一些检查以忽略该项目。

    project.getBuildFile().exists()
    

    【讨论】:

      猜你喜欢
      • 2015-04-26
      • 2011-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-13
      • 2017-02-11
      • 2012-08-01
      • 2014-05-16
      相关资源
      最近更新 更多