kaakaa Blog

この世は極楽 空にはとんぼ

Gradleでマルチプロジェクトビルド

Gradle Effective Implementation Guideの第7章を参考に。

ディレクトリ構成は以下。

flower/
tree/
master/
  settings.gradle
  build.gradle

flowerプロジェクトとtreeプロジェクトのビルドを統括するmasterプロジェクトを作る。

マルチプロジェクトの定義

settings.gradleでflowerとtreeとmasterがマルチプロジェクトであることをmasterディレクトリ配下のsettings.gradleに定義。

includeFlat 'tree', 'flower'

もし、masterとtree/flowerが以下のようなディレクトリ構成の場合

master/
  flower/
  tree/

settings.gradleの中身は以下のようになる。

include 'tree', 'flower'

マルチプロジェクトの処理

依存関係を定義してあげると、ひとつのbuild.gradleファイルにマルチプロジェクトすべての処理を書くことが出来る。

allprojects{
        task printInfo << {
                println "This is ${project.name}"
        }
}

subprojects{
        printInfo << {
                println "Can be planted"
        }
}

allprojectsブロックでマルチプロジェクト内のすべてのプロジェクトに対してタスクを定義出来る。
subprojectsブロックでは、マルチプロジェクトにおける自プロジェクト意外のプロジェクトに対してのみタスクを定義出来る。(この場合、flower/treeロジェクト)

もちろん、各プロジェクトにbuild.gradleを置いてあげてもOK。

マルチプロジェクトビルドの実行

上記ファイルを用意した後、masterディクレクトリで以下のprintInfoタスクを実行してみる。

kaakaa_hoe@[master]$ gradle printInfo
:printInfo
This is master
:flower:printInfo
This is flower
Can be planted
:tree:printInfo
This is tree
Can be planted

すると、masterプロジェクトを筆頭にすべてのプロジェクトのprintInfoタスクを実行する。
タスクが実行される順番は、親プロジェクトとなるmasterが一番最初に実行されて、その後はプロジェクト名のアルファベット順で実行される。
もちろんdependsOnを設定してあげることで実行順を制御することが出来る。

サブプロジェクトのタスクのみを実行したい場合は

kaakaa_hoe@[master]$ gradle :flower:printInfo
:flower:printInfo
This is flower
Can be planted

BUILD SUCCESSFUL

Total time: 2.533 secs

次にflowerディレクトリでタスクを実行してみる。

kaakaa_hoe@[flower]$ gradle printInfo
:flower:printInfo
This is flower
Can be planted

BUILD SUCCESSFUL

Total time: 2.508 secs

面白いのはflowerディレクトリ配下にはbuild.gradleファイルが存在しないのに、タスクが実行出来ること。
これはGradleが自動で対象プロジェクトがマルチプロジェクトに含まれているかを確認してくれるため。

なので、各プロジェクトにbuild.graldeを投げなくても、settings.gradleとbuild.gradleを含むディレクトリを各プロジェクトとフラットな場所に投げてあげれば、すべてのプロジェクトでgradleタスクを作成することが出来る。
ちょっとbuild.gradleファイルが長くなりそうだけど。

ビルドの依存関係とか成果物に関しても色々設定できるみたいなので、上手く使えれば便利そうですね。


ただ、flowerディレクトリを削除して、masterディレクトリでprintInfoタスクを実行しても同じ結果が得られる。

ディレクトリ構成

tree/
master/
  settings.gradle
  build.gradle

settings.gradle,build.gradleは上記のまま。

実行

kaakaa_hoe@[master]$ gradle printInfo
:printInfo
This is master
:flower:printInfo
This is flower
Can be planted
:tree:printInfo
This is tree
Can be planted

BUILD SUCCESSFUL

Total time: 2.53 secs

マルチプロジェクトで実行しても実際のディレクトリを見に行ってるわけではない?

ちょっと確認。

build.gradleファイルにのallprojectsブロックに以下のタスクを追加。

        task hasHoge << {
                def file = file(new File('hoge.txt'))
                println "${project.name} has hoge? => ${file.exists()}"
        }

まずは、flowerプロジェクトがある状態で実行。

flower/
  hoge.txt
tree/
  hoge.txt
master/
  hoge.txt
  settings.gradle
  build.gradle

結果

kaakaa_hoe@[master]$ gradle hasHoge
:hasHoge
master has hoge? => true
:flower:hasHoge
flower has hoge? => true
:tree:hasHoge
tree has hoge? => true

BUILD SUCCESSFUL

Total time: 3.344 secs

flowerディレクトリを削除して実行。

kaakaa_hoe@[master]$ gradle hasHoge
:hasHoge
master has hoge? => true
:flower:hasHoge
flower has hoge? => false
:tree:hasHoge
tree has hoge? => true

BUILD SUCCESSFUL

Total time: 2.496 secs

ほぅ。
ちゃんと見に行けてる。

ということは指定されたプロジェクトが存在しない場合でも、そのプロジェクトに対するタスクは定義できるってことか。ちょっと気持ち悪い気がする。