2012-08-28 8 views
35

Ich habe die folgende ProjektstrukturMehrere Einstellungen gradle Dateien für mehrere Projekte an

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

Idee von oben Projektstruktur ist, dass wir mehrere Projekte haben, die Teilprojekte enthält, jedes Projekt Abhängigkeiten zu anderen Projekten haben kann. Auch Teilprojekte innerhalb des Projekts können Abhängigkeiten zu anderen Teilprojekten innerhalb desselben Projekts haben. Projekte werden in den settings.gradle im root angegeben. Auch settings.gradle in jedem Projekt wird sagen, was die Teilprojekte des jeweiligen Projekts sind.

Mein settings.gradle in der Wurzel würde sieht aus wie

include 'Project1', 
     'Project2' 

und Project1 settings.gradle Willen wie

sieht
include 'SubProject11' 
     'SubProject12' 

andere depndecy Bestellungen werden in den jeweiligen build.gradle Dateien definiert Wenn Ich Rand Großansicht sauber Build installieren in der Root-Speicherort (Standar-Speicherort) scheint es keine Konfigurationen in der Project level settings.gradle-Datei verwenden.

Was mache ich hier falsch?

+0

Haben Sie das eine Abhilfe für herausgefunden? –

Antwort

8

Derzeit unterstützt Gradle nur eine einzige settings.gradle Dateien pro Build. Dies kann sich in Zukunft ändern.

+3

Wer weiß, ob sich das schon geändert hat? Die aktuelle Version ist 1.10. Ich sehe nichts, dass es sich geändert hat, aber ich hoffe es hat. –

+6

Es hat sich noch nicht geändert. –

+0

Obwohl es immer noch nicht unterstützt wird, konnte ich den gewünschten Effekt erzielen: http://stackoverflow.com/a/29664571/204480 –

4

Ich habe auch in das geschaut und Sie können es irgendwie tun, aber es ist sehr hässlich! Der Grund, warum dies für uns überhaupt funktioniert, ist, dass wir die meiste Zeit nur von der obersten Ebene aus bauen wollen.

Wenn es Ihnen überhaupt hilft, müssen Sie die oberste settings.gradle-Datei verwenden, um jedes Projekt-Unterprojekt direkt zu referenzieren. Lass das zuerst funktionieren.

Wenn Project1 und Project2 (usw.) unabhängig voneinander erstellt werden können, können Sie eine lokale settings.gradle-Datei für dieses Projekt erstellen. Da, wie ich oben sagte, dies nicht das ist, was wir normalerweise tun, nennen wir diese Datei settings.project1. Wenn wir diese Datei verwenden möchten, kopieren wir sie in settings.gradle. Ich weiß, hässlich.

Aber es wird tatsächlich schlimmer :) Sobald Sie diese settings.gradle Datei an Ort und Stelle, bauen Sie aus Project1 nicht mehr sehen die oberste Ebene build.gradle Datei, wo Sie wahrscheinlich Dinge definiert haben. So rufen Sie diese müssten Sie etwas zu jeder Projektebene build.gradle Datei hinzugefügt:

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

Dann können Sie den Build ausführen wie: gradle bauen -Plocal

hässlich, aber wenn Sie benötigen es funktioniert zumindest. Und im Interesse der vollständigen Offenlegung, nachdem dies vor ein paar Wochen eingeführt wurde, hat keiner der Entwickler es benötigt und/oder benutzt. Wird es wahrscheinlich in ein paar Wochen entfernen, wenn es weiterhin nicht verwendet wird.

Denken Sie daran, dass, wenn Sie aus dem Unterprojekt selbst erstellen, nur dieses Unterprojekt (und alle abhängigen Projekte) erstellt werden (obwohl alle Skripts für Skripts kompiliert/ausgewertet werden).

+0

Denken Sie daran, dass Einstellungsdateien nicht kopiert werden müssen. Wahrscheinlich helfen die weniger gut gewählten Antworten hier. Unterstützen Sie es auf diese Weise in Ihrem Projekt, was Sie vorgeschlagen haben? –

+0

@BenSteinert wie in meiner Antwort erwähnt, obwohl wir es in, niemand benutzt es und ich weiß nicht wann, aber innerhalb einer oder zwei wurde es entfernt. – JoeG

13

Ich konnte dieses Problem relativ sauber lösen. Verbesserungen sind sicherlich willkommen!

Obwohl Gradle nicht mehrere settings.gradle Skripte standardmäßig unterstützt, ist es möglich, einzelne Unterprojekte mit jeweils eigenen settings.gradle Dateien zu erstellen. Nehmen wir an, Sie haben Multiprojekt A, das von Multiprojekt B abhängt, jedes mit eigenen Unterprojekten. Verzeichnisstruktur könnte wie folgt aussehen:

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

Out of the box, Gradle A/settings.gradle etwas wie folgt aussehen erwartet:

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

Das Problem dabei ist, dass jedes Mal, B ein neues Projekt fügt hinzu: A/settings.gradle auch selbst muss sich ändern, wenn das neue Projekt nur durch B. verwendet wird, um diese Situation zu vermeiden, die Sie applyB/settings.gradle in A/settings.gradle statt mit redundanten Erklärungen könnten versuchen:

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

Wenn Sie dies versuchen, werden Sie feststellen, dass Gradle fehlschlägt, weil es projectDir für :bar und :bap erzeugt. Es nimmt irrtümlicherweise an, dass die Includes von B relativ zu settingsDir sind, was zufällig A/ ist, wenn Gradle von diesem Projektstamm aufgerufen wird. Um dies zu beheben können Sie ein anderes Skript hinzufügen, wie B/settings-parent.gradle (der genaue Name ist nicht signifikant):

apply from: 'settings.gradle' 

rootProject.children.each { project -> 
    String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, "") 
    project.projectDir = new File("B/$relativeProjectPath") 
} 

Dieser Streifen settingsDir.path und Präfixe den Pfad mit B/. Dies kann auf mehrere Schichten von settings[-parent].gradle Dateien erweitert werden, indem jede Schicht sich selbst auf den Pfad aufaddiert. Nun werden Sie dieses Skript A/settings.gradle gelten:

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

Mit diesem Schema neue B-Projekte nicht unnötig brechen A/settings.gradle und alle Projekte können ohne explizit Referenzierung der B Teilprojekt verwendet werden. Zum Beispiel, wenn ':foo' verwenden 'B:bap' wollte, kann es einfach erklären:

compile project(':bap') 
+0

Ist es erforderlich, die build.gradle-Datei jedes Unterprojekts zusammenzuführen. Ich folgte der Anweisung hier, aber ich bekomme ein Problem mit fehlenden Plugin. Details in meiner Frage hier http://stackoverflow.com/questions/37330659/gradle-multi-project-build-plugin-not-found – prashant

4

wie dieses Thema überquerten meine tägliche Arbeit sehr oft jetzt und die Verbesserung (GRADLE-803) auf es ist noch offen, ich möchte meine teilen Ansatz auch:

Auf den ersten Blick ähnelt es James Wald answer, aber hat einen Unterschied. Sie müssen Ihre Einstellungsdateien nicht irgendwie im Unterprojekt aufteilen. Es gibt einen sauberen Weg, alles im Super-Projekt zu tun, wenn das für Sie akzeptabel ist. Normalerweise sollten sich Ihre kleinen Unterprojekte nicht um die umgebenden Superprojekte kümmern. Sie enthalten ihre Subabhängigkeiten und das war's. Es sollte auch nicht relevant sein, wie das Modulverzeichnis genannt wird, in Wald Ansatz einerseits das Modul seine Verzeichnisnamen muss wissen (‚B‘) hier:

project.projectDir = new File("B/$relativeProjectPath")

Im Gegensatz dazu in der Regel eines super project kennt seine Unterprojekte und Verzeichnisse gut, weil es zum Beispiel git Submodule sein können, die fest definierte Namen haben, die aus der Superprojektperspektive sicher referenziert werden können.

Das ist mein Setup (mit 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 

Im Super-Projekt settings.gradle Sie nun der folgende Code:

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

Es sieht immer noch ziemlich ausführliche (und immer noch nicht wirklich hierarchische Verhalten) hinzufügt, sondern hält die zusätzlicher Aufwand im Super-Projekt, wo Sie normalerweise sowieso alles über Ihre enthaltenen Module wissen müssen.

Der Rest ist wieder ziemlich einfach.

Wenn Sie meinen Ansatz in der Praxis sehen wollen, lesen Sie Abschnitt 5.) dieser blog post, wo ich explizit diese Unabhängigkeit zwischen den Modulen oder einfach mein github Projekt auf cross-language benchmarks überprüfen. Aber beachten Sie, Sie brauchen eine laufende native Compiler Toolchain wie gcc oder Clang, um es auszuführen;)

Hope this hilft! Cheers Ben

+0

Das ist ein guter Punkt über den Verzeichnisnamen wird hart codiert. Es sollte ziemlich einfach sein, diesen Code zu ändern, so dass er den Namen mit File.getName() oder etwas Ähnlichem erhält. –

2

Aufbauend auf früheren Antworten ist das, was ich herauskam.

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

Der Vorteil ist keine Vervielfältigung.

4

Wenn Sie Gradle 3.x verwenden, versuchen includeBuild(): https://docs.gradle.org/current/userguide/composite_builds.html

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

Wenn Sie Gradle 2.x verwenden, habe ich eine Demo für diese Funktion geschrieben. Hoffe, es wird Ihnen helfen: 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 
     } 
    } 
} 
+0

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/15429483) –

+0

@JimGarrison Danke für deinen Rat, ich habe meine Antwort aktualisiert. –