为什么 Gradle 默认情况下按模块名称顺序解析依赖关系?

huangapple 未分类评论46阅读模式
英文:

Why gradle resolve dependencies in the module name order by default?

问题

我有三个模块:

  • amodule
  • bmodule
  • cmodule

这三个模块都有集成测试。bmodule 是基础模块,其中包含我想在 amodulecmodule 的集成测试中使用的 BaseClass

我项目的示例位于 GitHub 上:https://github.com/ljql/test-deps

我尝试在 amodulecmodule 的集成测试中添加对 bmodule 的依赖。
build.gradle 文件在 amodulecmodule 模块中看起来相同:

sourceSets {
    intTest {
        java {
            srcDir 'src/test-integration/java'
        }
        resources {
            srcDir 'src/test-integration/resources'
        }
        compileClasspath += rootProject.project(':bmodule').sourceSets.intTest.output
        runtimeClasspath += rootProject.project(':bmodule').sourceSets.intTest.output
    }
}

configurations {
    intTestCompile {
        extendsFrom compile
    }
    intTestRuntime {
        extendsFrom runtime
    }
}

dependencies {
    intTestCompile project(path: ':bmodule', configuration: 'intTestCompile')
}

但是当我尝试构建 amodule 时,我遇到了一个错误:

Build file '/test-deps/amodule/build.gradle' line: 10

A problem occurred evaluating project ':amodule'.
> Could not get unknown property 'intTest' for SourceSet container of type org.gradle.api.internal.tasks.DefaultSourceSetContainer.

cmodule 的构建(它是 amodule 的副本)成功完成。

amodulecmodule 之间唯一的区别是它们的名称。amodule 位于 bmodule 之前,而 cmodule 位于 bmodule 之后。

在我的情况下,我如何指定 Gradle 解析依赖项的顺序?我希望 Gradle 首先了解 bmodule,然后再了解 amodulecmodule

英文:

I've got three modules:

  • amodule
  • bmodule
  • cmodule

There are integration-tests in all of these three modules. The bmodule is the base - it contains BaseClass, which I want to use in integration-tests in amodule and cmodule

The example of my project is on github: https://github.com/ljql/test-deps

I try to add dependency to integration-tests of bmodule in amodule and cmodule.
File build.gradle looks the same in modules amodule and cmodule

sourceSets {
    intTest {
        java {
            srcDir 'src/test-integration/java'
        }
        resources {
            srcDir 'src/test-integration/resources'
        }
        compileClasspath += rootProject.project('bmodule').sourceSets.intTest.output
        runtimeClasspath += rootProject.project('bmodule').sourceSets.intTest.output
    }
}

configurations {
    intTestCompile {
        extendsFrom compile
    }
    intTestRuntime {
        extendsFrom runtime
    }
}

dependencies {
    intTestCompile project(path: ':bmodule', configuration:  'intTestCompile')
}

But when I try to build amodule I've got an error:

Build file '/test-deps/amodule/build.gradle' line: 10

A problem occurred evaluating project ':amodule'.
> Could not get unknown property 'intTest' for SourceSet container of type org.gradle.api.internal.tasks.DefaultSourceSetContainer.

The build of cmodule, which is the copy of amodule, is completed successfully.

The only difference between amodule and cmodule is in their names. The amodule precedes the bmodule and the cmodule followed by the bmodule

How can I specify a sequence of gradle resolve dependencies in my case? I want gradle to find out about the bmodule first and then about the amodule and the cmodule

答案1

得分: 0

尝试将以下内容放入您的 amdoule 模块的 build.gradle 文件中:

preBuild.dependsOn ":bmodule:build"
英文:

Try putting this in the your amdoule's build.gradle

preBuild.dependsOn ":bmodule:build"

答案2

得分: 0

你面临着一个项目评估排序的问题。由于amodulecmodule都期望找到bmodule的特定组件,你需要请求Gradle确保先评估bmodule

你可以在amodulecmodule的构建文件中添加以下内容:

evaluationDependsOn(':bmodule')

虽然Gradle提供了一个API来解决这个问题,但只有在没有循环依赖的情况下才能正常工作,也就是说bmodule不能依赖于amodulecmodule,否则你将无法通过这种方式找到解决方案。

另一种方法是利用适当的依赖解析,并声明你希望通过将它们暴露为测试固件来共享一些测试类,例如。

英文:

You have a project evaluation ordering problem. Since both amodule and cmodule expect to find specific components of bmodule, you need to ask Gradle to make sure bmodule has been evaluated first.

You can add in the build files of amodule and cmodule the following:

evaluationDependsOn(':bmodule')

While Gradle offers an API to resolve this, it will only work if you have no cycle, that is bmodule does not have dependencies on either amodule or cmodule, otherwise you will not be able to find a solution this way.

Another approach would be to leverage proper dependency resolution and declare that you want to share some test classes by having them exposed as test-fixtures for example.

答案3

得分: 0

Gradle有三个构建阶段:

  • 初始化
  • 配置
  • 执行

但只有当Gradle完成了这三个阶段时,才会显示解析所有依赖项的最终结果。

错误指示了sourceSets中的一个字符串 - 它来自配置阶段。在这个阶段开始时,Gradle对所有模块中的任何配置一无所知。Gradle会按顺序逐个模块地了解每个模块的内容。当Gradle首次考虑amodule的配置时,它对bmudule中的任何配置一无所知。

在问题中,我想要在配置:amodule:intTest中定义compileClasspathruntimeClasspath,但我也可以在自定义任务中定义它,没有什么可以阻止我这样做。Gradle将在第三阶段执行它,最终的compileClasspathruntimeClasspath将包含来自bmodule:intTest的信息。

amodulebuild.gradle结果:

sourceSets {
    intTest {
        java {
            srcDir 'src/test-integration/java'
        }
        resources {
            srcDir 'src/test-integration/resources'
        }
    }
}

configurations {
    intTestCompile {
        extendsFrom compile
    }
    intTestRuntime {
        extendsFrom runtime
    }
}

task intTest {
    sourceSets.intTest.compileClasspath += rootProject.project('bmodule').sourceSets.intTest.output
    sourceSets.intTest.runtimeClasspath += rootProject.project('bmodule').sourceSets.intTest.output
}
英文:

Gradle has three build phases:

  • Initialization
  • Configuration
  • Execution

But the final result of resolving all dependencies appears only when gradle completes all three phases.

The error indicates a string in sourceSets - it is from the phase Configuration. At the start of this phase gradle knows nothing about any configurations in all modules. And gradle learns about the content of each module sequentially module-by-module. Of course when gradle considers the configuration of the amodule for the first time, it doesn't know anything about any configurations in the bmudule.

In the question I want to define compileClasspath and runtimeClasspath in confuguration :amodule:intTest. But there is nothing to stop me to define it in a custom task. Gradle will execute it on the third phase and the final compileClasspath and runtimeClasspath will contain the information from the bmodule:intTest

The result build.gradle of amodule:

sourceSets {
    intTest {
        java {
            srcDir 'src/test-integration/java'
        }
        resources {
            srcDir 'src/test-integration/resources'
        }
    }
}

configurations {
    intTestCompile {
        extendsFrom compile
    }
    intTestRuntime {
        extendsFrom runtime
    }
}

task intTest {
    sourceSets.intTest.compileClasspath += rootProject.project('bmodule').sourceSets.intTest.output
    sourceSets.intTest.runtimeClasspath += rootProject.project('bmodule').sourceSets.intTest.output
}

huangapple
  • 本文由 发表于 2020年5月4日 17:34:45
  • 转载请务必保留本文链接:https://java.coder-hub.com/61589136.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定