首页 文章

多个设置为多个项目构建gradle文件

提问于
浏览
37

我有以下项目结构

-->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

上述项目结构的想法是我们有多个包含子项目的项目,每个项目都可以与其他项目有依赖关系 . 项目内的子项目也可以与同一项目中的其他子项目具有依赖关系 . 项目将在根目录中的settings.gradle中指定 . 此外,每个项目中的settings.gradle将说明该特定项目的子项目是什么 .

我在根目录中的settings.gradle看起来像

include 'Project1',
         'Project2'

和Project1 settings.gradle看起来像

include 'SubProject11'
         'SubProject12'

其他depndecy命令在相应的build.gradle文件中定义如果我在根位置(Standar位置)内进行gradle clean build install,它似乎不使用Project level settings.gradle文件中的配置 .

我在这做错了什么?

6 回答

  • 4

    我能够以相对干净的方式解决这个问题 . 当然欢迎改进!

    尽管Gradle不支持多个开箱即用的 settings.gradle 脚本,但可以创建各个子项目,每个子项目都有自己的 settings.gradle 文件 . 假设您有多项目A,它依赖于多项目B,每个项目都有自己的子项目 . 您的目录结构可能如下所示:

    A
    - settings.gradle
    - foo
    - faz
    \ B
      - settings.gradle
      - bar
      - bap
    

    开箱即用,Gradle希望 A/settings.gradle 看起来像这样:

    include ':foo', ':faz', 'B:bar', 'B:bap'
    

    这个问题是,每次B添加一个新项目时,即使新项目仅由B使用, A/settings.gradle 也必须改变 . 为了避免这种情况,你可以尝试 A/settings.gradle 中的 apply B/settings.gradle 而不是添加冗余声明:

    apply from: 'B/settings.gradle'
    include ':foo', ':faz'
    

    如果你试试这个,你会发现Gradle失败了,因为它为 :bar:bap 生成了错误的 projectDir . 它错误地假设B的包含是相对于 settingsDir ,当从该项目根调用Gradle时恰好是 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")
    }
    

    这会剥离 settingsDir.path 并使用 B/ 作为路径的前缀 . 通过让每个图层将自身添加到路径上,可以将其扩展到多个 settings[-parent].gradle 文件层 . 现在,您将此脚本应用于 A/settings.gradle

    apply from: 'B/settings-parent.gradle'
    include ':foo', ':faz'
    

    使用此方案,新的B项目不会不必要地破坏 A/settings.gradle ,并且可以在不明确引用B子项目的情况下使用所有项目 . 例如,如果 ':foo' 想要使用 'B:bap' ,它可能只是声明:

    compile project(':bap')
    
  • 5

    目前,Gradle仅支持每个版本的单个 settings.gradle 文件 . 这可能在将来发生变化 .

  • 4

    如果您使用的是Gradle 3.x,请尝试使用includeBuild():https://docs.gradle.org/current/userguide/composite_builds.html

    // settings.gradle
    includeBuild './Project1'
    includeBuild './Project2'
    

    如果您使用的是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
            }
        }
    }
    
  • 13

    我也研究了这个,你可以做到这一点,但它非常难看!这对我们起作用的原因是,绝大多数时候,我们只想从最顶层 Build .

    如果它对您有所帮助,您需要做的是让最顶层的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'
    }
    

    然后你可以运行build as:gradle -Plocal build

    丑陋,但如果你需要它,它至少可以工作 . 并且为了全面披露,几周前已经实现了这一点,没有一个开发人员需要和/或使用它 . 如果继续不使用,可能会在几周内将其删除 .

    请记住,如果您从子项目本身构建,则只构建该子项目(以及任何相关项目)(尽管将编译/评估所有gradle脚本) .

  • 2

    因为这个话题现在经常超越我的日常工作,而且它的改进(GRADLE-803)仍然存在打开,我也想分享我的方法:

    乍一看,它看起来与James Wald的_1868910相似,但有一点不同 . 您不需要在子项目中以某种方式拆分设置文件 . 如果您可以接受,那么在超级项目中有一个干净的方法来完成所有事情 . 通常,您的小子项目不应该关心周围的超级项目 . 它们包括它们的子依赖项以及模块本身需要知道其目录名称('B')的方法:

    project.projectDir =新文件(“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
    

    在super project 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')
    

    它仍然看起来相当冗长(并且仍然没有添加真正的分层行为),但是在超级项目中保留额外的工作量,通常您需要知道有关所包含模块的所有信息 .

    其余的再次非常直接 .

    如果你想在实践中看到我的方法,请阅读blog post的第5.)节,其中我明确要求模块之间的这种独立性,或者只是在cross-language benchmarks上查看我的github项目 . 但请注意,您需要一个运行本机编译器工具链,如gcc或Clang来执行它;)

    希望这可以帮助!干杯本

  • 8

    Build 早期的答案,这就是我提出的 .

    interface Includer {
      def include(String... args)
    }
    
    def applyFrom(String folder) {
      apply from: folder + '/settings.gradle'
      def includer = [
        include: { args ->
              args.each {
                project(it.startsWith(':') ? it : ':' + it).projectDir =
                    new File(rootDir, folder + "/" + (it.startsWith(':') ? it.substring(1) : it).replace(':', '/'))
              }
        }] as Includer
    
      apply from: folder + '/settings.gradle', to: includer
    }
    
    applyFrom('A')
    applyFrom('B')
    

    优点是没有重复 .

相关问题