Gradle公式ドキュメントを読む-Structuring Individual Builds(2)

#この記事について
Gradleをより理解するために公式ドキュメントを読んでメモ代わりとして私なりに訳していきます。
読んでいるドキュメントのバージョンは7.3.3です。
この記事で訳している章はAuthoring Gradle Builds>Structuring Individual Builds>Declaring Dependencies between Subprojectsとなります。
必要な章から読んでいるため、一連の記事は公式ドキュメントの章立て通りの順にはなっていません。

##Structuring Individual Builds>Declaring Dependencies between Subprojects
###[Declaring Dependencies between Subprojects](https://docs.gradle.org/current/userguide/declaring_dependencies_between_subprojects.html)
###[Project dependencies](https://docs.gradle.org/current/userguide/declaring_dependencies_between_subprojects.html#sec:project_jar_dependencies)

あるプロジェクトのコンパイルクラスパスに他のプロジェクトが提供するjarが必要な場合はどうしたらよいでしょう。また、他のプロジェクトへの過渡的な依存関係がある場合はどうでしょう。これは明らかにJavaのマルチプロジェクトで非常に一般的なユースケースです。[Project dependencies](https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:project_dependencies)で言及するように、Gradleはプロジェクトの依存関係を提供します。

####プロジェクトの依存関係の例
```:プロジェクトレイアウト
.
├── buildSrc
│   ...
├── api
│   ├── src
│   │   └──...
│   └── build.gradle
├── services
│   └── person-service
│       ├── src
│       │   └──...
│       └── build.gradle
├── shared
│   ├── src
│   │   └──...
│   └── build.gradle
└── settings.gradle
```

shared,api,person-serviceのプロジェクトを持っています。person-serviceプロジェクトは他の2つのプロジェクトに依存しています。apiプロジェクトはsharedプロジェクトに依存します。それは[^1]ビルドスクリプトを持たず他のビルドスクリプトからも何も注入されません。プロジェクトパスの区切りには`:`を使用します。プロジェクトパスについてのより詳細な情報はDSLドキュメントの<a href="https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html#org.gradle.api.initialization.Settings:include(java.lang.String[])">`Settings.include(java.lang.String[])`</a>を参照してください。

```gradle:setting.gradle
rootProject.name = 'dependencies-java'
include 'api', 'shared', 'services:person-service'
```
```gradle:buildSrc/src/main/groovy/myproject.java-conventions.gradle
plugins {
    id 'java'
}

group = 'com.example'
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation "junit:junit:4.13"
}
```
```gradle:api/build.gradle
plugins {
    id 'myproject.java-conventions'
}

dependencies {
    implementation project(':shared')
}
```
```gradle:shared/build.gradle
plugins {
    id 'myproject.java-conventions'
}
```
```gradle:services/person-service/build.gradle
plugins {
    id 'myproject.java-conventions'
}

dependencies {
    implementation project(':shared')
    implementation project(':api')
}
```
ビルドロジックの共有はプロジェクト依存も定義されたサブプロジェクトのビルドスクリプト内で適用されるconventionプラグインに抽出されます。プロジェクト依存は実行時依存の特殊な形式です。まず他のプロジェクトのビルドを行い、jarを他のプロジェクトのクラスパスに加える必要があるからです。また、他のプロジェクトの依存もクラスパスに追加されます。`gradle :api:compile`を起動すると、まずsharedプロジェクトがビルドされ、それからapiプロジェクトがビルドされます。プロジェクト依存が部分的なマルチプロジェクトのビルドを可能にします。

[^1]: この「それ」が何を指してるかが不明瞭。ビルドスクリプトがないのはルートプロジェクトなので「それ」かもしれない。

###[Depending on artifacts produced by another project](https://docs.gradle.org/current/userguide/declaring_dependencies_between_subprojects.html#sec:depending_on_output_of_another_project)
プロジェクト依存はモジュール間の依存関係をモデル化したものです。実質的に、他のプロジェクトの主な出力に依存している宣言となります。Javaベースのプロジェクトでは、それは通常jarファイルとなります。

他のタスクの出力に依存させたくなることがあるかもしれません。その場合、そのタスクが事前に実行され、正しく出力を行っていることを確認したくなるでしょう。タスク間で依存を宣言することはこの類の関係をモデリングするには悪手であり、不要な結合をもたらしてしまいます。このような依存性のモデリングに推奨される手法は出力を生成して"外向"アーティファクト[^2]としてマークするか、その出力を消費側プロジェクトが依存できるmainソースセットに追加することです。

producerとconsumerという2つのサブプロジェクトを持つマルチプロジェクトビルドで作業しているとします。producerサブプロジェクトはプロジェクトバージョンのようなビルド情報を含んだプロパティファイルを提供するbuildInfoというタスクを定義します。そしてタスクプロバイダにその出力ファイルをマップすれば、Gradleは自動的にタスク依存を確立します。

####ビルド情報を含んだプロパティファイルを出力するタスクの例
```gradle:build.gradle
plugins {
    id 'java-library'
}

version = '1.0'

def buildInfo = tasks.register("buildInfo", BuildInfo) {
    version = project.version
    outputFile = layout.buildDirectory.file('generated-resources/build-info.properties')
}

sourceSets {
    main {
        output.dir(buildInfo.map { it.outputFile.asFile.get().parentFile })
    }
}
```
```java:buildSrc/src/main/java/BuildInfo.java
public abstract class BuildInfo extends DefaultTask {

    @Input
    public abstract Property<String> getVersion();

    @OutputFile
    public abstract RegularFileProperty getOutputFile();

    @TaskAction
    public void create() throws IOException {
        Properties prop = new Properties();
        prop.setProperty("version", getVersion().get());
        try (OutputStream output = new FileOutputStream(getOutputFile().getAsFile().get())) {
            prop.store(output, null);
        }
    }
}
```
消費プロジェクト側は実行時にプロパティファイルを読み取れるようになっているはずです。produceプロジェクトへのプロジェクト依存を宣言することで、事前にプロパティを生成し、実行時のクラスパスで利用できるようにします。
####プロパティファイルを提供するプロジェクトへのプロジェクト依存を宣言する
```gradle:build.gradle
dependencies {
    runtimeOnly project(':producer')
}
```
上の例では、consumerはpuroducerプロジェクトの出力に依存することを宣言しました。

他のプロジェクトの主要な成果物に依存する事はひとつの例にすぎません。Gradleはプロジェクト間で任意の成果物を共有できる強力な依存関係管理エンジンを持っており、それを必要に応じてビルドできます。これについての詳細は[sharing outputs between projects](https://docs.gradle.org/current/userguide/cross_project_publications.html#cross_project_publications)を参照してください。
[^2]: Gradle独自の用語