はじめに
Gradleで依存関係の解決を行っていると、こんな問題に直面することがあります。
- 依存関係の解決に失敗する
- 思ってるのと違うバージョンが取得されている
- ビルドスクリプトに書いたのと違うバージョンが取得されている
こういう問題が起こる背景には、「間接依存」や「バージョン競合」など、Gradleでの依存解決の仕組みが関係していることがあります。
この記事では、そういった依存関係のトラブルへ直面した時に使っているGradleの標準タスク dependencies
とdependencyInsight
について整理します。
Gradle公式の、関連するページも貼っておきます↓
タスク概要
dependencies
dependencies
タスクは、依存関係の全体像を把握するためのタスクです。
./gradlew dependencies
よく使うオプションとして、--configuration
で「構成」を指定します。
たとえばコンパイル時に必要な依存関係を表示したければcompileClasspath
を使う、実行時の依存関係が見たければruntimeClasspath
などです。
他にも testCompileClasspath
や testRuntimeClasspath
といったテスト用の構成もあります。
./gradlew dependencies --configuration runtimeClasspath
タスクを実行すると、依存関係の親子関係がツリーで表示されるので、「どのライブラリがどのライブラリを引き込んでいるのか」などを把握することが出来ます。
ただ、大きなプロジェクトでは解決している依存関係も多いので、出力が膨大で把握するのが大変なときもあります。その際はgrepするなどして適宜絞り込みましょう。
./gradlew dependencies --configuration runtimeClasspath | grep <ライブラリ名など>
dependencyInsight
dependencyInsight
は、特定の依存関係について詳細を把握するためのタスクです。
./gradlew dependencyInsight --dependency <ライブラリ名>
指定されたライブラリの詳細、つまり「どこから来たのか」「なぜそのバージョンが選ばれたのか」などが出力されます。
ちなみにライブラリ名の指定は部分一致もOKなのですが、基本的には最初にマッチしたものを表示する仕様のようなので、できるだけ正確に(違うものがマッチしないように)指定しましょう。
なおdependencyInsight
も、--configuration
オプションで構成を指定できます。
./gradlew dependencyInsight --dependency <ライブラリ名> --configuration compileClasspath
サンプル
例えば私の手元にあるプロジェクトで、quarkus-hibernate-orm
について出力させると下記の出力が得られました。
./gradlew dependencyInsight --dependency io.quarkus:quarkus-hibernate-orm
> Task :master-service:dependencyInsight
io.quarkus:quarkus-hibernate-orm:3.4.1
Variant compile:
| Attribute Name | Provided | Requested |
|------------------------------------|----------|--------------|
| org.gradle.status | release | |
| org.gradle.category | library | library |
| org.gradle.libraryelements | jar | classes |
| org.gradle.usage | java-api | java-api |
| org.gradle.dependency.bundling | | external |
| org.gradle.jvm.environment | | standard-jvm |
| org.gradle.jvm.version | | 21 |
| org.jetbrains.kotlin.platform.type | | jvm |
Selection reasons:
- By constraint
- Forced
io.quarkus:quarkus-hibernate-orm:3.4.1
\--- io.quarkus:quarkus-bom:3.4.1
\--- compileClasspath (requested io.quarkus:quarkus-bom:{strictly 3.4.1})
io.quarkus:quarkus-hibernate-orm -> 3.4.1
\--- compileClasspath
この出力で、たとえばSelection reasons
を見れば、By constraint
Forced
と出ているので、それぞれ「制約があって選ばれた」「特定のバージョンに固定されている」のが分かります。
また、そのあとを見ていくと、requested io.quarkus:quarkus-bom:{strictly 3.4.1}
とあるので、quarkus-bom
からquarkus-hibernate-orm
が引き込まれており、しかも3.4.1
をstrictly
指定で要求していることが分かります。
依存関係の調査方法
簡単な例ですが、依存関係の解決について調べるときのよくある流れを。
- まず構成ごとの全体像を出す
./gradlew dependencies --configuration runtimeClasspath
-
grep
で絞り込んでアタリをつける。ここではquarkus
で絞ってみる
./gradlew dependencies --configuration runtimeClasspath | grep quarkus
- 絞り込んだ出力からフルネームを取得して、
dependencyInsight
で依存関係について深堀りする
./gradlew dependencyInsight --dependency io.quarkus:quarkus-hibernate-orm --configuration runtimeClasspath
この流れを、依存関係を追いかける時の基本セットみたいな感じで使っています。
dependencyInsight
で、例えば依存関係の解決に失敗しているならその理由、思ってるのと違うバージョンが取得されているならそれが引き込まれている理由が分かるはずです。
あとはそれを手がかりに、依存関係の指定を見直すなど、具体的な改善のアクションに繋げられます。