Isu*_*uru 42 build-automation multi-project gradle
我有以下项目结构
-->Starnderd Location
-->Project1
-->settings.gradle
-->build.gradle
-->Subproject11
-->build.gradle
-->Subproject12
-->build.gradle
-->Project2
-->settings.gradle
-->build.gradle
-->Subproject21
-->build.gradle
-->Subproject22
-->build.gradle
-->build.gradle
-->settings.gradle
Run Code Online (Sandbox Code Playgroud)
上述项目结构的想法是我们有多个包含子项目的项目,每个项目都可以与其他项目有依赖关系.项目内的子项目也可以与同一项目中的其他子项目具有依赖关系.项目将在根目录中的settings.gradle中指定.此外,每个项目中的settings.gradle将说明该特定项目的子项目是什么.
我在根目录中的settings.gradle看起来像
include 'Project1',
'Project2'
Run Code Online (Sandbox Code Playgroud)
和Project1 settings.gradle看起来像
include 'SubProject11'
'SubProject12'
Run Code Online (Sandbox Code Playgroud)
其他depndecy命令在相应的build.gradle文件中定义如果我在根位置(Standar位置)内进行gradle clean build install,它似乎不使用Project level settings.gradle文件中的配置.
我在这做错了什么?
Jam*_*ald 16
我能够以相对干净的方式解决这个问题.当然欢迎改进!
虽然Gradle不支持多个settings.gradle开箱即用的脚本,但可以创建各个子项目,每个子项目都有自己的settings.gradle文件.假设您有多项目A,它依赖于多项目B,每个项目都有自己的子项目.您的目录结构可能如下所示:
A
- settings.gradle
- foo
- faz
\ B
- settings.gradle
- bar
- bap
Run Code Online (Sandbox Code Playgroud)
开箱即用,Gradle希望A/settings.gradle看起来像这样:
include ':foo', ':faz', 'B:bar', 'B:bap'
Run Code Online (Sandbox Code Playgroud)
这里的问题是,每次B加上一个新的项目,A/settings.gradle也必须改变,即使新的项目仅用于B.为了避免这种情况,你可以尝试apply B/settings.gradle在A/settings.gradle不是增加冗余的声明:
apply from: 'B/settings.gradle'
include ':foo', ':faz'
Run Code Online (Sandbox Code Playgroud)
如果你试试这个,你会发现Gradle失败了因为它生成了错误projectDir的:bar和:bap.它错误地假定B的包括是相对于settingsDir这恰好是A/当摇篮从该项目根调用.要解决此问题,您可以添加其他脚本,例如B/settings-parent.gradle(确切的名称并不重要):
apply from: 'settings.gradle'
rootProject.children.each { project ->
String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, "")
project.projectDir = new File("B/$relativeProjectPath")
}
Run Code Online (Sandbox Code Playgroud)
这会剥离settingsDir.path路径并为其添加前缀B/.settings[-parent].gradle通过让每个层将自身添加到路径上,可以将其扩展到多个文件层.现在,您将此脚本应用于A/settings.gradle:
apply from: 'B/settings-parent.gradle'
include ':foo', ':faz'
Run Code Online (Sandbox Code Playgroud)
使用此方案,新的B项目不会不必要地中断,A/settings.gradle并且可以在不明确引用B子项目的情况下使用所有项目.例如,如果':foo'想要使用'B:bap',它可能只是声明:
compile project(':bap')
Run Code Online (Sandbox Code Playgroud)
目前,Gradle仅支持settings.gradle每个构建的单个文件.这可能在将来发生变化.
如果您使用的是Gradle 3.x,请尝试使用includeBuild():https://docs.gradle.org/current/userguide/composite_builds.html
// settings.gradle
includeBuild './Project1'
includeBuild './Project2'
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Gradle 2.x,我已经为此函数编写了一个演示.希望它能帮到你:https: //github.com/xujiaao/gradle-composite-build-demo
// settings.gradle
def includeProject(String path, Closure closure) {
...
apply {
from ...
to new SettingsProxy(...)
}
}
class SettingsProxy {
...
public getRootProject() { ... }
public void include(String... paths) {
for (String path : paths) {
if (!mProjectSpec.accept(path)) {
continue
}
def descendantPath = generateDescendantPath(path)
mSettings.include(descendantPath)
def descendantProjectDir = new File(mProject.projectDir, path.replace(':', '/'))
mSettings.project(descendantPath).projectDir = descendantProjectDir
}
}
}
Run Code Online (Sandbox Code Playgroud)
我也研究过这个,你可以这样做,但它非常丑陋!这对我们有用的原因是,绝大多数时候,我们只想从最顶层进行构建。
如果它对您有帮助,您需要做的就是让最顶层的 settings.gradle 文件直接正确引用每个项目子项目。首先让这个工作起来。
然后,如果 Project1 和 Project2(等等)能够彼此独立构建,您可以为该项目创建一个本地 settings.gradle 文件。正如我上面所说,这不是我们通常所做的,因此我们将此文件称为settings.project1。如果我们想使用这个文件,我们将其复制到settings.gradle。我知道丑。
但它实际上变得更糟:) 一旦你把这个 settings.gradle 文件放在适当的位置,你从 Project1 构建将不再看到你可能需要定义的东西的顶级 build.gradle 文件。要调用它,您需要将类似的内容添加到每个项目级 build.gradle 文件中:
if (project.hasProperty('local')) {
apply from: '../build.gradle'
}
Run Code Online (Sandbox Code Playgroud)
然后你可以运行构建: gradle -Plocal build
丑陋,但如果你需要它,它至少可以工作。出于充分披露的目的,几周前将其落实到位后,没有任何开发人员需要和/或使用它。如果继续不使用,可能会在几周后将其删除。
请记住,如果您从子项目本身构建,则只会构建该子项目(以及任何依赖项目)(尽管所有 gradle 脚本都将被编译/评估)。
由于这个主题现在已经很频繁地横扫了我的日常工作,并且该主题的改进(GRADLE-803)仍然是公开的,因此我也想分享一下我的方法:
乍一看,它看起来与詹姆斯·沃尔德(James Wald)的答案相似,但有一个不同。您无需在子项目中以某种方式拆分设置文件。如果您可以接受的话,有一种干净的方法可以在超级项目中完成所有工作。通常,您的小型子项目不必关心周围的超级项目。它们包括其子依赖关系,仅此而已。与模块目录的命名方式也无关紧要,在Wald的方法中,模块本身需要在此处知道其目录名称('B'):
project.projectDir = new File("B/$relativeProjectPath")
相反,通常,超级项目非常了解其子项目和目录,因为它们可以是git子模块,例如,它们具有定义明确的修复程序名称,从超级项目的角度来看,可以安全地引用它们。
那是我的设置(使用Gradle 2.4):
Super Project
??? build.gradle
??? settings.gradle (include 'A' include 'B')
??? <Subproject A>
??? build.gradle
??? settings.gradle (include 'subA')
??? <Subsubproject subA>
??? build.gradle
??? <Subproject B>
??? build.gradle
??? settings.gradle (include 'subB')
??? <Subsubproject subB>
??? build.gradle
Run Code Online (Sandbox Code Playgroud)
现在,您可以在超级项目settings.gradle中编写以下代码:
include 'A'
include 'B'
apply from: 'A/settings.gradle'
apply from: 'B/settings.gradle'
project(':subA').projectDir = new File(rootDir, 'A/subA')
project(':subB').projectDir = new File(rootDir, 'B/subB')
Run Code Online (Sandbox Code Playgroud)
它看起来仍然很冗长(并且仍然没有添加真正的层次结构行为),但是在超级项目中需要您付出额外的精力,在该项目中,您通常仍需要了解有关所包含模块的所有信息。
其余的又很简单。
如果您想在实践中看到我的方法,请阅读此博客文章的第5.)节,在该节中我明确要求模块之间具有这种独立性,或者只是查看有关跨语言基准测试的 github项目。但是请注意,您需要运行的本机编译器工具链(例如gcc或Clang)才能执行它;)
希望这可以帮助!干杯本
| 归档时间: |
|
| 查看次数: |
19302 次 |
| 最近记录: |