Gradleで非標準のSourceSetsを使う

GradleのいわゆるConvention(規約)に抵抗して、好みのプロジェクト構成にしたい。ここでの目標としては、複数の異なるSourceSetsを作り、別々にコンパイルすることである。正直なところ基本がわからないので(いくらマニュアル等を読んでみてもわからない)、ここでは一歩一歩試していく。

標準的な構成

以下が標準的なファイル構成だという(Eclipseを使っているので余計なファイルもある)。

コンパイルするためのbuild.gradleとしては、一行だ。

apply plugin: 'java'

コンパイルのみをしたいので、タスクとしては、「classes」で事足りる。
以下の結果が作成される。

Eclipseの標準配置に合わせる

これをEclipseのJavaプロジェクトの標準配置に合わせたい。この場合は以下に変更する。

※Eclipseのクラス出力先(bin)にgradleの出力を上書きする人はいないだろうが、一応やってみる。

apply plugin: 'java'

sourceSets {
  main {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

Javaとリソースで書き方が違うのかわからないが、とりあえずこれで何とかなる。

※ただし、一時ファイル出力用にbuildというディレクトリは使われてしまうようだ。

別のSourceSetにする

mainのソースセットであればcompileJavaやらclassesやらというタスクが使えるが、名前を変えるとそうはいかなくなる。それぞれcompileFoobarJava、foobarClassesという名前になる。もう少し名前を統一的にできなかったものだろうか?

apply plugin: 'java'

sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

ライブラリ依存を追加してみる

適当に小さめライブラリを依存指定し、それをJavaソースで使う。

apply plugin: 'java'
sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}
repositories {
  mavenCentral()
}
dependencies {
  compile group: 'javax.inject', name: 'javax.inject', version: '1'
}
import javax.inject.*;
public class Sample {
  @Inject
  public Sample() {
  }
}

見つけ出せないようだ。

Root project 'sample' executing foobarClasses 
:compileFoobarJavaC:\devel\workspace\sample\src\Sample.java:1: error: package javax.inject does not exist
import javax.inject.*;
^
C:\devel\workspace\sample\src\Sample.java:5: error: cannot find symbol
  @Inject
   ^
  symbol:   class Inject
  location: class Sample

foobarのコンフィギュレーションをcompileから継承させる

以下のようにすれば良いようだ。つまり、compileというコンフィギュレーションは、あくまでもmainというソースセットのものであって、他のソースセットには適用されないため、foobar用のcompileコンフィギュレーションをそこから派生させなければならない。

apply plugin: 'java'

sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

configurations {
  foobarCompile.extendsFrom compile
}

repositories {
  mavenCentral()
}

dependencies {
  compile group: 'javax.inject', name: 'javax.inject', version: '1'
}

foobar専用のコンフィギュレーションに依存ライブラリを記述する

そもそも、このライブラリをfoobarにしか使わないものとすればどう書けば良いのか?

依存ライブラリをfoobarCompileコンフィギュレーションに書けばよい。configurations定義は不要になる。

apply plugin: 'java'
apply plugin: 'eclipse'

sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

repositories {
  mavenCentral()
}

dependencies {
  // ここを変更
  foobarCompile group: 'javax.inject', name: 'javax.inject', version: '1'
}

つまり、本当にfoobarだけにしか使わないライブラリであれば、foobarCompileコンフィギュレーションに依存を書けばよいし、他との共通ライブラリであれば、compileを継承すればよい。

eclipseプラグインはどう対応しているのか?

当方では常にEclipseを使用しているので、ソースセットやコンフィギュレーションが標準で無い場合にどう対応しているのか気になる。

以下のようにeclipseプラグインを追加し、「cleanEclipse eclipse」を実行する。

apply plugin: 'java'
apply plugin: 'eclipse' // 追加

sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

repositories {
  mavenCentral()
}

dependencies {
  foobarCompile group: 'javax.inject', name: 'javax.inject', version: '1'
}

もともと、このプラグインには問題がある。ソースや出力先が以下のように設定されてしまうのである。

この対策については、既にGradleのEclipseプラグインの処理結果を変更に記述した。

もう一つの問題は、依存ライブラリが入って来ないことだ。どうもcompileやtestCompileぐらいしか入れてくれないらしい(他のコンフィギュレーションは試したことがない)。

以下のように、コンフィギュレーションを追加してやればよい。

apply plugin: 'java'
apply plugin: 'eclipse'

sourceSets {
  foobar {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }
    java.outputDir = file('bin')
    output.resourcesDir = file('bin')
  }
}

repositories {
  mavenCentral()
}

dependencies {
  foobarCompile group: 'javax.inject', name: 'javax.inject', version: '1'
}

/* これを追加 */
eclipse {
  classpath {
    plusConfigurations += [configurations.foobarCompile]
  }
}

この件の詳細説明はEclipseClasspathにある。