Gradle の設定ファイルとライブラリ管理とビルドバージョン設定
はじめに
この記事は、次の記事に入れようとしたら長くなりすぎた部分を切り出した記事です。
Gradle の機能のうち、ライブラリ管理とビルドバージョンについてまとめました。
「普段の開発でメンテするのは主にこの辺りだろう」という経験と、「どうも似た設定が多くてよくわからないな」という経験をもとに整理対象を決めました。
なかなか複雑ですが、これくらい知って ( not 覚えて ) いればあまり困ることはなくなると思います。
設定ファイル
用途ごとにいくつかあるので、簡単にまとめます。
.gradle
というファイルは Groovy という言語で設定しますが、最近は .gradle.kts
というファイルを Kotlin で書けます。
settings.gradle.kts
プロジェクトの全体設定や構成設定を定義するファイルです。
とてもシンプルなプロジェクトだと、名前くらいしか書いてなかったりします。
rootProject.name = "my-awesome-app"
settings.gradle.kts
を読み書きすることは普段ほとんどありません。
この記事では取り上げませんが、Multi-Project [1] 構成にする場合は必須のファイルです。
gradle.properties
いわゆるプロパティファイルです。
プロジェクトルートの gradle.properties
ファイルと、ホームディレクトリの ~/.gradle/gradle.properties
ファイルがあります。
同じプロパティは ~/.gradle/gradle.properties
の値が使われます。
プロジェクト全体で使う共有していい値は gradle.properties
に書き、共有できない値は ~/.gradle/gradle.properties
に書きます。
fooCode=1234 # プロジェクトの設定
fooType=root # プロジェクトの設定 ( デフォルト値 )
fooSecret=abcd # 共有できないが必要な設定
fooType=home # プロジェクトの設定を個人調整
読み込まれたプロパティは properties
タスクで確認できます。
$ ./gradlew properties | grep foo | sort
fooCode: 1234 # プロジェクトの設定
fooSecret: abcd # 個人の設定
fooType: home # プロジェクトの設定を上書きした個人の設定
共有できない設定は、主に認証情報と性能設定です。
たとえば社内ライブラリをプライベートリポジトリに置いている場合は、GitHub の認証情報を設定する必要があります。
メモリの割当量などは秘匿情報ではないですが、ひとによって適切値が異なるため必要に応じて各個人で調整します。
設定した値は次のように build.gradle.kts
で参照できます。
val fooCode: String by project
println("foo_code = $fooCode")
所定のパラメータは設定するだけで効果があります。
org.gradle.jvmargs=-Xmx2048m -Xms512m
ほかのパラメータ名などは公式ドキュメントで確認できます。
settings.gradle.kts
はあくまで Gradle のプロパティファイルであり、プログラムで使うプロパティ管理は別の方法を使います。
たとえば Spring Boot で環境ごとにデータベースの接続先をわけたいなどのケースでは、Spring のお作法に則り application-{profile}.yml
を使います。
-P オプションと -D オプション
プロパティ設定は -P
オプションや -D
オプションでもできます。
$ ./gradlew properties -P fooType=p-option | grep foo | sort
fooType: p-option
$ ./gradlew properties -Dorg.gradle.project.fooType=d-option | grep foo | sort
fooType: d-option
-P
オプションは Gradle のプロパティを指定するオプションで、ふたつの gradle.properties
ファイルより優先されます。
-D
オプションは JVM の設定をするオプションで、org.gradle.project.
で始めると -P
オプションと同じ結果になります。
Gradle の設定をするときは素直に -P
オプションを使いましょう。
オプションによる指定は CI/CD で使ったりします。
環境変数
プロパティ設定は環境変数でもできます。
$ export ORG_GRADLE_PROJECT_fooType=env
$ ./gradlew properties | grep foo | sort
fooType: env
環境変数による指定は CI/CD で秘匿情報を渡すのに使ったりします。
build.gradle / build.gradle.kts
普段一番読み書きする設定ファイルです。
Gradle プロジェクトの基本的な設定や依存ライブラリの管理、テストやコンパイルの設定などほとんどのことを設定します。
gradle/libs.versions.toml
build.gradle.kts
に直接依存ライブラリのバージョンを書かず、Version Catalogs という機能で TOML ファイルにライブラリ情報を集約できます。
この記事では取り上げませんが、Multi-Project の際に特に便利 [2] です。
まとめ
- ✏️
.gradle
と.gradle.kts
は読み替え可能 - ✏️
settings.gradle.kts
は Multi-Project を使わないならあまり書くことはない - ✏️
gradle.properties
などで Gradle のプロパティ設定をする - ✏️
build.gradle.kts
がメインの設定ファイル - ✏️
gradle/libs.versions.toml
でライブラリ管理を一元化できる
依存ライブラリの設定
build.gradle.kts
はいろいろな設定ができますが、その中で一番触るとしたらライブラリ管理の項目でしょう。
プロジェクトが進めば増えることもありますし、バージョンアップ対応しないといけないですからね。
いくつかあるので簡単に見てみます。
plugins
いきなりライブラリではなくプラグインですが、plugins
ブロックについて確認します。
plugins {
kotlin("jvm") version "2.1.10"
id("org.springframework.boot") version "3.4.3"
id("io.spring.dependency-management") version "1.1.7"
}
Gradle プラグインには、特定のタスクを追加したりライブラリの依存関係を管理してくれたりするものがあります。
kotlin()
による指定は Kotlin 公式プラグインのための特別な文法で、それ以外のプラグインは id()
で指定します。
kotlin("jvm")
は id("org.jetbrains.kotlin.jvm")
のエイリアスです。
jvm
プラグインは Kotlin コードのコンパイルやテストをできるようにするものです。
org.springframework.boot
プラグインは Spring Boot の開発をサポートしてくれるもので、bootRun
タスクはこれが提供してくれています。
io.spring.dependency-management
プラグインは Spring 関係の依存ライブラリバージョンを統一的に管理してくれるプラグインです。
プラグインの情報は Gradle プラグインのページで確認できます。
文字通り Gradle のプラグインに関する設定で、プログラムではなく Gradle の挙動そのものに影響します。
dependencies
プロジェクトのコードが使う外部ライブラリを定義するブロックです。
ここに書かれたライブラリは、ビルドのタイミングで自動ダウンロードされます。
一番読み書きするのがここですね。
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.apache.commons:commons-lang3:3.17.0")
}
org.springframework.boot:spring-boot-starter-web
ライブラリのバージョンは、io.spring.dependency-management
プラグインがいい感じに決めてくれます。
org.springframework.boot
プラグインが 3.4.3
なので、Spring 関係のライブラリは 3.4.3
に対応するバージョンが自動選択されます。
spring-xxx
ライブラリはたくさんあるので、個別に手で書くより簡単だし安心です。
Spring 関係ではないライブラリは、当然自分でバージョンを指定します。
例に使った org.apache.commons:commons-lang3
ライブラリは、便利ユーティリティ集のよく使うライブラリです。
ライブラリの情報やバージョンは Maven Repository で確認できます。
mavenCentral()
の指定は、ライブラリを Maven Repository から探すという指定です。
「社内ライブラリがプライベートリポジトリにある」というようなケースでは、探してほしい場所を Maven Central の下に追記します。
buildscript
プロダクトコードではなくビルドスクリプト ( build.gradle.kts
) で使う依存ライブラリを定義するブロックです。
次の設定は、Gson ライブラリを使う foo
タスクを定義しています。
plugins {
// kotlin("jvm")
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.google.code.gson:gson:2.8.8")
}
}
tasks.register("foo") {
doLast {
val map = mapOf("id" to 2, "name" to "foo")
val s = com.google.gson.Gson().toJson(map)
println(s)
}
}
jvm
プラグインは Gson を使えるようにしてしまうので無効化しています。
buildscript
で Gson ライブラリを追加したので、foo
タスクの処理部で Gson()
を使えています。
import
を一番上に書くと buildscript
より先に評価されてエラーになってしまうため、完全修飾名で使うか import
を buildscript
より下に書きます。
$ ./gradlew foo
> Task :foo
{"id":2,"name":"foo"}
このように foo
タスクが動く状況でも、dependencies
ブロックに Gson が追加されていなければ次のコードはエラーになります。
import com.google.gson.Gson // Unresolved reference 'google'
fun main() {
val map = mapOf("id" to 1, "name" to "foo")
val s = Gson().toJson(map)
println(s)
}
ビルドスクリプトを書くのは、なんらかのチェック処理や CI/CD のための自作タスクを作るときです。
タスクを自作するほかだと、DB マイグレーション ( e.g. Flyway ) のタスクを動かすために DB 関係のライブラリが必要になるなどのケースがあります。
とはいえ、あまり buildscript
に大量の依存設定をすることはないです。
まとめ
- ✏️
plugins
で追加するプラグインとは、Gradle の挙動そのものに影響するもの - ✏️
dependencies
でプログラムが使うライブラリを管理する - ✏️
buildscript
ではbuild.gradle.kts
で使うライブラリを管理する
依存の構成
dependencies
ブロックでライブラリへの依存を設定する際、implementation
以外にもいくつかのキーワードがあります。
適切に使い分けることで無駄な依存が減り、ビルド結果が小さくなったりビルド時間が短くなったりという恩恵が得られます。
implementation
に対する testImplementation
のように、それぞれには test~
というテストコードのための依存設定もあります。
implementation
implementation
で依存したライブラリは、コンパイルに使われ JAR にも含まれます。
Spring Boot など、大体のライブラリは implementation
で設定します。
api
api
で依存したライブラリは、implementation
と同じくコンパイルに使われビルド結果にも含まれます。
implementation
と違うのは、再エクスポートされる点です。
implementation
で依存したライブラリは、再エクスポートされません。
たとえば Gradle プロジェクト MyApp とライブラリ Lib1 Lib2 があり、MyApp は Lib1 を依存追加しています。
このとき Lib1 が Lib2 に implementation
で依存していても、MyApp から Lib2 が使えるようにはなりません。
しかし Lib1 が Lib2 に api
で依存していると、MyApp から Lib2 が使えるようになります。
「Lib1 のメソッド引数が Lib2 のオブジェクト」みたいな状況では、Lib1 は Lib2 とセットで使える必要があるからです。
そういう意味で API ( Application Programming Interface ) と言うのでしょう。 [3]
セットで必要になるライブラリをまとめて得られる反面、管理が複雑化したりコンパイル時間が長くなったりします。
自分の Gradle プロジェクトが社内ライブラリや Gradle サブプロジェクトではなくただのスタンドアロンアプリケーションであれば、api
の利用を検討する必要はありません。
compile
挙動としては api
に近いですが、非推奨時代を経てもう使えなくなりました。
再エクスポートしたい場合は api
を使います。
かなり古い書き方なので、見かけたら ( api
ではなく ) implementation
に書き直して使いましょう。
runtimeOnly
runtimeOnly
で依存したライブラリは、コンパイルに使われず実行時にだけ使われます。
よくあるケースとしては、JDBC ドライバやログライブラリの依存設定に使います。
「自分のコード上では Logger
という interface
としてしか存在しないが、動くときはなんらかの具象クラスが必要」みたいなケースです。
わかりやすくいうと「import
はしないけど必要なライブラリ」は runtimeOnly
で指定するということです。
implementation
を使うよりコンパイル時間の短縮になります。
compileOnly
compileOnly
で依存したライブラリは、コンパイルにだけ使われビルド結果には含まれません。
よくあるケースとしては、Lombok のようなアノテーションプロセッサの依存設定に使います。
Lombok はクラス変数の String name
に @Getter
アノテーションをつけると、function String getName()
メソッドを生成してくれます。
仕組みとしてはコンパイル時にアノテーション部分を通常実装と同じ形になるようクラスファイルへねじ込んでおり、コンパイルすると Lombok はなくなります。
そのままですが「コンパイルにだけ使うライブラリ」は compileOnly
で指定するということです。
implementation
を使うよりビルド結果の縮小になります。
まとめ
- ✏️
implementation
で依存追加するのが基本 - ✏️
api
は必要になるまで気にしなくていい - ✏️
runtimeOnly
はimport
しないけど必要なライブラリの追加に使う - ✏️
compileOnly
は実行には不要なライブラリの追加に使う
依存ツリーの確認
Gradle で追加したライブラリは、dependencies
タスクで確認できます。
ツリーで子要素になっているものは、依存先の依存で入ったものです。
$ ./gradlew dependencies
> Task :dependencies
------------------------------------------------------------
Project 'xxxxxxxxxxxxxxxxxxxxxxxxxx'
------------------------------------------------------------
compileClasspath - Compile classpath for main.
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21
| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21
| | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21
| | \--- org.jetbrains:annotations:13.0
| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.21
| \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 (*)
+--- org.springframework.boot:spring-boot-starter-web -> 3.1.1
| +--- org.springframework.boot:spring-boot-starter:3.1.1
| | +--- org.springframework.boot:spring-boot:3.1.1
| | | +--- org.springframework:spring-core:6.0.10
| | | | \--- org.springframework:spring-jcl:6.0.10
| | | \--- org.springframework:spring-context:6.0.10
| | | +--- org.springframework:spring-aop:6.0.10
| | | | +--- org.springframework:spring-beans:6.0.10
| | | | | \--- org.springframework:spring-core:6.0.10 (*)
| | | | \--- org.springframework:spring-core:6.0.10 (*)
| | | +--- org.springframework:spring-beans:6.0.10 (*)
| | | +--- org.springframework:spring-core:6.0.10 (*)
| | | \--- org.springframework:spring-expression:6.0.10
| | | \--- org.springframework:spring-core:6.0.10 (*)
# 以下 5000 行ほど切り捨て
よく目にする記号の (*)
は、二度目の登場なのでサブツリーの表示を省略するというマークです。
もうひとつよく見る ->
は、Gradle がバージョンを決めたという意味です。
次の出力は「spring-boot-starter-web
は 3.1.1
にした」と伝えています。
+--- org.springframework.boot:spring-boot-starter-web -> 3.1.1
build.gradle.kts
が次のようになっているので、プラグインにより Gradle が決定したということです。
plugins {
id("org.springframework.boot") version "3.1.1"
id("io.spring.dependency-management") version "1.1.6"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
}
次のようにライブラリのバージョンをプラグインとずらしても、3.2.0
ではなく 3.1.1
が使われます。
plugins {
id("org.springframework.boot") version "3.1.1"
id("io.spring.dependency-management") version "1.1.6"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:3.2.0")
}
次の出力は「spring-boot-starter-web
は 3.2.0
って書いてあったけど 3.1.1
にした」と伝えています。
+--- org.springframework.boot:spring-boot-starter:3.2.0 -> 3.1.1
プラグインに限らず、複数ライブラリのバージョン衝突によりこのような自動解決が発生するのは珍しくありません。
次の出力は「flyway-mysql:9.22.1
が flyway-core:9.22.1
を使うはずが、ほかとの兼ね合いで 9.16.3
にした」と伝えています。
+--- org.flywaydb:flyway-mysql:9.22.1
\--- org.flywaydb:flyway-core:9.22.1 -> 9.16.3
これが問題になるかはケースバイケースです。
上のような形で内部ライブラリのバージョンが明らかにずれているケースは、問題になりやすいです。
ライブラリの更新を放置しているとライブラリ間の整合がどんどん取れなくなり、最悪のケースではコンパイルできなくなります。 [4] [5]
基本的には最新バージョンや公式が明言している対応バージョンでちゃんと統一しましょう。
たとえば Spring Boot だと Releases に情報があります。
plugins {
// 安定版最新
id("org.springframework.boot") version "3.4.3"
// 安定版最新
id("io.spring.dependency-management") version "1.1.7"
}
dependencies {
// プラグインにまかせる
implementation("org.springframework.boot:spring-boot-starter-web")
// Releases などを見て調べて書く
implementation("org.flywaydb:flyway-mysql:10.20.1")
}
こうやってメンテすると整います。
+--- org.springframework.boot:spring-boot-starter-web -> 3.4.3
# 略
+--- org.flywaydb:flyway-mysql:10.20.1
\--- org.flywaydb:flyway-core:10.20.1
さらに情報が必要になったら、そのときは公式サイトをどうぞ。
Java のバージョン設定
このセクションは Java のコンパイルや実行、Gradle Toolchain などを整理します。
コンパイル・実行や Toolchain の概要については、こちらの記事も参考にしてください。
Gradle ( Java コンパイル ) におけるバージョン指定には似たような設定があるため、それぞれ確認します。
sourceCompatibility, targetCompatibility
sourceCompatibility
では、どのバージョンの言語仕様としてコンパイルするか指定します。
これを 17 にすると、17 でリリースされた構文や機能がコンパイルできます。
端的に言えば、コーディングするときの言語バージョンです。
targetCompatibility
では、生成されるクラスファイルが動作する JVM のバージョンを指定します。
これを 17 にすると、JVM 17 以上で動くようになります。
端的に言えば、実行環境の JVM バージョンです。
それぞれ javac
コマンドの -source
オプションと -target
オプションに相当します。
次のメイン文を使いながら、確認します。
ローカルマシンの JDK は 17 で、まず Kotlin は抜きにして Java のプロジェクトで整理します。
public class Main {
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
System.out.println(System.getProperty("java.home"));
}
}
sourceCompatibility < targetCompatibility < JDK
java {
sourceCompatibility = JavaVersion.VERSION_15
targetCompatibility = JavaVersion.VERSION_16
}
実行結果は次のようになります。
$ ./gradlew run
17.0.6
/Users/xxx/xxx/corretto-17.0.6/Contents/Home
実行時の java.version
プロパティが 17.0.6
なので、JDK は 17 です。
JAVA_HOME
を見るとローカルマシンにインストールされている JDK が使われています。
クラスファイル ( JAR ) を作って、中の major version
を確認すると 60 になっています。
$ ./gradlew clean build
$ unzip build/libs/foo.jar -d /tmp/out
$ javap -v /tmp/out/foo/Main.class | grep major
major version: 60
これは targetCompatibility
が 16 だから [6] です。
「15 の文法で書かれているコードを」「16 の JVM で動くように」「17 の JDK でコンパイルした」ということになります。
この設定のまま Record Class のような新機能をコードで使うと、コンパイルエラーになります。
コンパイラが 17 でも、コードの言語仕様を 15 としているからです。
public record Foo() {
^
(レコードを有効にするには-source 16以上を使用してください)
targetCompatibility 省略
targetCompatibility
は、省略すると sourceCompatibility
と同じになります。
15 の言語仕様を使っているなら 15 の JVM で動かすだろう、ということです。
java {
sourceCompatibility = JavaVersion.VERSION_15
}
major version: 59
sourceCompatibility > targetCompatibility ( エラー )
sourceCompatibility
> targetCompatibility
はコンパイルエラーになります。
15 の機能を使っているのに 14 の JVM では動かせません。
java {
sourceCompatibility = JavaVersion.VERSION_15
targetCompatibility = JavaVersion.VERSION_14
}
警告:ソース・リリース15にはターゲット・リリース15が必要です
sourceCompatibility > JDK ( エラー )
sourceCompatibility
を JDK より高いバージョンにすることは当然できません。
コンパイラの知らない機能が使われているコードは、コンパイルできません。
java {
sourceCompatibility = JavaVersion.VERSION_21
}
エラー: 21は無効なソース・リリースです
まとめ
- ✏️
sourceCompatibility
はコーディングに使える言語機能のバージョン - ✏️
targetCompatibility
は実行環境のバージョン - ✏️
sourceCompatibility
とtargetCompatibility
は運用環境の JVM と同じでいい - ✏️ どちらも JDK より高いバージョンにはできない
- ✏️ どちらもコンパイラ (
javac
) のオプション
Toolchain
Toolchain はプロジェクトのビルドに使用する JDK を管理する Gradle の機能です。
プロジェクトで使えるインストール済み JDK の確認
javaToolchains
タスクで選択できる JDK を確認できます。
$ ./gradlew javaToolchains
+ Options
| Auto-detection: Enabled
| Auto-download: Enabled
+ Amazon Corretto JDK 17.0.6+10-LTS
| Location: /Users/xxx/xxx/corretto-17.0.6/Contents/Home
| Language Version: 17
| Vendor: Amazon Corretto
| Architecture: x86_64
| Is JDK: true
| Detected by: IntelliJ
+ Amazon Corretto JDK 21.0.5+11-LTS
| Location: /Users/xxx/xxx/corretto-21.0.5/Contents/Home
| Language Version: 21
| Vendor: Amazon Corretto
| Architecture: aarch64
| Is JDK: true
| Detected by: IntelliJ
+ Eclipse Temurin JDK 1.8.0_362-b09
| Location: /Library/xxx/xxx/temurin-8.jdk/Contents/Home
| Language Version: 8
| Vendor: Eclipse Temurin
| Architecture: x86_64
| Is JDK: true
| Detected by: MacOS java_home
プロジェクトで使う JDK の指定
さきほど確認したとおり、プロジェクトのバージョン指定がローカルマシンの JDK ( 17 ) より高いと、コンパイルできません。
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
エラー: 21は無効なソース・リリースです
build.gradle
に次のように書いておくと、そのプロジェクトは JDK 21 でビルドされるようになります。
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
実行にも JDK 21 が使われています。
$ ./gradlew run
21.0.5
/Users/xxx/xxx/corretto-21.0.5/Contents/Home
Gradle を実行する JDK さえあれば、プロジェクトのビルドはプロジェクトの定めた JDK で行われるようになります。
sourceCompatibility
, targetCompatibility
, toolchain
は基本的に必ず指定しましょう。
プロジェクトで使う JDK の自動インストール
Gradle 8.0 以前は、toolchain
で指定されたバージョンがローカルマシンになければ自動インストールされていました。
Gradle 8.0 からはベンダが増えたことや柔軟性を持たせるなどの理由で、ダウンロードリポジトリ ( Toolchain Resolver Plugins ) の指定が必須になりました。
今手元には 22
がないため、toolchain
で 22
を指定すると次のようなエラーが発生します。
$ ./gradlew run
> Task :compileJava FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Error while evaluating property 'javaCompiler' of task ':compileJava'.
> Failed to calculate the value of task ':compileJava' property 'javaCompiler'.
> Cannot find a Java installation on your machine matching this tasks requirements: {languageVersion=22, vendor=any vendor, implementation=vendor-specific} for MAC_OS on x86_64.
> No locally installed toolchains match and toolchain download repositories have not been configured.
* Try:
> Learn more about toolchain auto-detection at https://docs.gradle.org/8.10.2/userguide/toolchains.html#sec:auto_detection.
> Learn more about toolchain repositories at https://docs.gradle.org/8.10.2/userguide/toolchains.html#sub:download_repositories.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 2s
1 actionable task: 1 executed
自動ダウンロードもできるようにするには、settings.gradle
にプラグイン追加しておく必要があります。
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0'
}
こうすると JDK が ~/.gradle/jdks
に自動ダウンロードされます。
$ ./gradlew run
22.0.2
/Users/xxx/.gradle/jdks/eclipse_adoptium-22-x86_64-os_x.2/jdk-22.0.2+9/Contents/Home
まとめ
- ✏️
sourceCompatibility
とtargetCompatibility
を運用環境の JVM と同じにする - ✏️
toolchain
で同じバージョンの JDK を指定する - ✏️
settings.gradle.kts
で自動ダウンロードできるようにする
Kotlin のバージョン設定
このセクションは Kotlin のコンパイルや実行、Gradle Toolchain などを整理します。
Java と基本の部分は同じなので、簡単にまとめます。
compilerOptions
次の設定は、kotlinCompile
タスクにおける kotlin
のコンパイルでコンパイラ ( kotlinc
) の -jvm-target
オプションを指定しています。
kotlinCompile
タスクで 16 を指定するには、プロジェクト全体も java
ブロックで 16 に揃える必要があります。
java {
sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_16
}
tasks.withType<KotlinCompile> {
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_16
}
}
}
ビルドされたクラスファイルの major version
は 60 [7] になります。
要するに Java のコンパイラ ( javac
) における -target
オプションに相当するものです。
major version: 60
16 の JVM で動くようにコンパイルしただけで、JDK はローカルマシンの 17 が使われています。
$ ./gradlew run
17.0.6
/Users/xxx/xxx/corretto-17.0.6/Contents/Home
Toolchain
Kotlin のビルドに使用する JDK を管理するには、kotlin
ブロックで jvmToolchain
を指定します。
kotlin {
jvmToolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
$ ./gradlew run
21.0.5
/Users/xxx/xxx/corretto-21.0.5/Contents/Home
まとめ
- ✏️
sourceCompatibility
とtargetCompatibility
にあわせてcompilerOptions
も書く - ✏️
toolchain
や自動ダウンロードについては Java と同じ
おわりに
さっと書いてしまうつもりでしたが、細かいところをちゃんと確認したら思ったより大変でした。
それだけに細かいところまであらためて確認できたので、満足感は得られました。
Gradle の設定はすこし複雑なのと、前提となるコンパイルや JVM などの理解が必要なので大変ですね。
-
api
とcore
やweb
とbatch
のように、Gradle プロジェクトをいくつかの Gradle プロジェクトにわける仕組み。コンパイル範囲が局所化でき、プロジェクトを跨いだimport
のコントロールなどもできる。 ↩︎ -
複数のサブプロジェクトで使うライブラリのバージョンをひとつの TOML ファイルに書けるので、メンテがとても楽になる。 ↩︎
-
この記事は設計論の記事ではないので詳細は割愛しますが、Lib1 の引数に Lib2 を使うかはちゃんと検討するべきです。Lib1 が「Lib2 使うのやめるわ」と言って引数を Lib3 に変更したら、MyApp は Lib2 のコードをすべて Lib3 に書き換えなければいけないからです。 ↩︎
-
実際ときどき見ます。「Lib1 が内部で利用している Lib2 を 9.0 だと思って呼んでいるのに、実際には Lib2 が 8.0 だった。呼んでいるメソッドは 9.0 でできたものだった。」「Lib3 を追加したいのに Lib1 が古すぎて追加すらできなかった。」はありがちです。 ↩︎
-
ある意味、本当の最悪は「コンパイルできたけど実行エラーになった」かも。 ↩︎
-
60 - 44 = 16 ↩︎
-
60 - 44 = 16 ↩︎
Discussion