Подтвердить что ты не робот

Несколько настроек 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

Идея структуры выше проекта состоит в том, что у нас есть несколько проектов, которые содержат подпроекты, каждый проект может иметь зависимости от других проектов. Также подпроекты внутри проекта могут иметь зависимости от других подпроектов в рамках одного и того же проекта. Проекты будут указаны в настройках .gradle в корне. Также settings.gradle внутри каждого проекта скажет, какие подпроекты этого конкретного проекта.

Мои настройки .gradle в корневом каталоге будут выглядеть как

include 'Project1',
         'Project2'

и Project1 settings.gradle будет выглядеть как

include 'SubProject11'
         'SubProject12'

другие заказы depndecy определяются в соответствующих файлах build.gradle Если я установил rand gradle clean build install внутри корневого местоположения (положение Standar), похоже, что он не использует конфигурации в файле настроек уровня проекта.

Что я здесь делаю неправильно?

4b9b3361

Ответ 1

Я смог решить эту проблему относительно чистым способом. Усовершенствования, безусловно, приветствуются!

Хотя Gradle не поддерживает несколько сценариев settings.gradle из коробки, можно создавать отдельные подпроекты, каждый со своим собственным файлом settings.gradle. Скажем, у вас есть мультипроект А, который зависит от многопроектного Б, каждый со своими собственными подпроектами. Структура вашего каталога может выглядеть так:

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

Из коробки Gradle ожидает, что A/settings.gradle будет выглядеть примерно так:

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

Проблема заключается в том, что каждый раз, когда B добавляет новый проект, A/settings.gradle также должен меняться, даже если новый проект используется только B. Чтобы избежать этой ситуации, вы можете попробовать apply B/settings.gradle в A/settings.gradle вместо добавления избыточных объявлений:

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

Если вы попробуете это, вы обнаружите, что Gradle терпит неудачу, потому что он генерирует неправильный projectDir для :bar и :bap. Ошибочно полагает, что B включает в себя settingsDir, который оказывается A/, когда Gradle вызывается из этого корня проекта. Чтобы исправить это, вы можете добавить еще один script, например 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, добавив каждый слой на путь. Теперь вы примените этот script к A/settings.gradle:

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

С этой схемой новые B-проекты не излишне ломаются A/settings.gradle, и все проекты могут использоваться без явного ссылки на под-проект B. Например, если ':foo' хотел использовать 'B:bap', он может просто объявить:

compile project(':bap')

Ответ 2

В настоящее время Gradle поддерживает только один файл settings.gradle для каждой сборки. Это может измениться в будущем.

Ответ 3

Если вы используете 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
        }
    }
}

Ответ 4

Я также изучил это, и вы можете это сделать, но это очень уродливо! Причина, по которой это работает для нас, заключается в том, что подавляющее большинство времени мы просто хотим построить с самого верхнего уровня.

Если вам это вообще помогает, вам нужно сделать, чтобы файл самых лучших настроек .gradle правильно ссылался на каждый проект-подпроект напрямую. Сначала сделайте это.

Затем, если Project1 и Project2 (и т.д.) могут быть независимо построены друг от друга, вы можете создать локальный файл settings.gradle для этого проекта. Поскольку, как я сказал выше, это не то, что мы обычно делаем, мы вызываем этот файл settings.project1. Если мы хотим использовать этот файл, мы скопируем его в settings.gradle. Я знаю уродство.

Но это на самом деле становится хуже:) После того, как вы установили этот файл settings.gradle на место, вы создаете из Project1, больше не увидите файл build.gradle верхнего уровня, где вам, вероятно, нужны определенные вещи. Чтобы вызвать это, вам понадобится что-то подобное, добавленное к каждому файлу build.gradle на уровне проекта:

if (project.hasProperty('local')) {
    apply from: '../build.gradle'
}

Затем вы можете запустить сборку как: gradle -Plocal build

Уродливый, но если вам это нужно, он, по крайней мере, работает. И в интересах полного раскрытия информации, поставив это на место пару недель назад, ни один из разработчиков не нуждался и/или не использовал его. Вероятно, удалите его еще через пару недель, если он по-прежнему не будет использоваться.

Помните, что если вы создадите из самого подпроекта, будет создан только этот подпроект (и любые зависимые проекты) (хотя все скрипты gradle будут скомпилированы/оценены).

Ответ 5

поскольку эта тема довольно часто пересекалась с моей повседневной работой, и ее усовершенствование (GRADLE-803) все еще открыто, я хотел бы также поделиться своим подходом:

На первый взгляд, это похоже на ответ Джеймса Уолда, но имеет одно отличие. Вам не нужно как-то разбивать файлы настроек в подпроекте. В супер-проекте есть чистый способ сделать все, если это приемлемо для вас. Обычно ваши небольшие суб-проекты не должны заботиться об окружающих супер-проектах. Они включают свои подчиненные зависимости и что это. Также должно быть неважно, как называется каталог модуля, в подходе 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

В супер-проекте 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')

Это все еще выглядит довольно многословно (и все же не добавляет реального иерархического поведения), но сохраняет дополнительные усилия в супер-проекте, где вам все равно обычно нужно знать все о ваших содержащихся модулях.

Остальное снова довольно просто.

Если вы хотите увидеть мой подход на практике, прочитайте раздел 5.) этого сообщения в блоге, где я явно требует такой независимости между модулями или просто проверить мой GitHub проект по кросс-языковых тестов. Но имейте в виду, вам нужен работающий нативный набор инструментов компилятора, такой как gcc или Clang для его выполнения;)

Надеюсь это поможет! Приветствия Бен

Ответ 6

На основе более ранних ответов это то, с чем я вышел.

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

Преимущество - это не дублирование.