Windows+Scoop+VSCode で Kotlin の開発環境を構築する

この記事は [【Java 環境構築】Windows+Scoop+VSCode で開発環境を構築する](https://qiita.com/nimzo6689/items/72898eb9dc3896a41269) のスピンオフ記事です。

Kotlin の IDE といえば Android Studio もしくは Intellij IDEA ですが、何もかも VSCode でコーディングしたい欲が最近強いので、あえて VSCode でコーディング環境を作ってみました。この記事では、その際の手順と操作感を紹介します。

PC は Windows 10 or 11 が前提です。

# Kotlin のインストール

Scoop でインストールします。

JDK は冒頭の記事と同様、 Eclipse Temurin JDK 21 LTS をインストールします。
Kotlin は執筆時点での最新版（2.1.0 / 2024-11-27 リリース）を使用します。
※ 2.1.0 自体は JDK 23 でも OK。

```powershell
# JDK をインストール
# 環境変数に JAVA_HOME が追加され、 .\bin\ に PATH が通ります。
scoop install java/temurin21-jdk

# Gradle をインストール
scoop install main/gradle

# Kotlin をインストール
# 環境変数に KOTLIN_HOME が追加され、 .\bin\ に PATH が通ります。
scoop install main/kotlin
```

# VSCode に Kotlin 拡張機能をインストール

Kotlin と検索し、 Kotlin という拡張機能をインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/9ee805c7-0d08-6a3b-aa66-e743e86e957e.png)

Kotlin Language という拡張機能もありますが、開発が滞っていて、かつ、機能面も Kotlin が充実しているので、インストールは Kotlin のみで支障はないと思います。

https://marketplace.visualstudio.com/items?itemName=fwcd.kotlin

こちらは JetBrains 公式の拡張機能ではないですが、 Microsoft が提唱している LSP や DAP といったプロトコルに沿って開発されていて、いい感じです。

また、「Extension Pack for Java」の拡張機能もインストールしておきます。

https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack

# Gradle プロジェクトの作成

では、早速 Kotlin で Hello, world! をしてみます。
Kotlin を実行＆デバッグするには、 Maven か Gradle のプロジェクトで開く必要があるそうなので、 Gradle で Kotlin がビルドできるプロジェクトを作成します。

VSCode の拡張機能でひな形を作るコマンドがありますが、言語で Kotlin を選択できるルートが用意されていなかったので、 `gradle` コマンドで作成します。

```powershell
mkdir demo && cd demo
gradle init --type=kotlin-application

# 全て Enter で default を選択。
#=> ...
#=> Enter target Java version (min: 7, default: 21):
#=>
#=> Project name (default: demo):
#=>
#=> Select application structure:
#=>   1: Single application project
#=>   2: Application and library project
#=> Enter selection (default: Single application project) [1..2]
#=>
#=> Select build script DSL:
#=>   1: Kotlin
#=>   2: Groovy
#=> Enter selection (default: Kotlin) [1..2]
#=>
#=> Select test framework:
#=>   1: kotlin.test
#=>   2: JUnit Jupiter
#=> Enter selection (default: kotlin.test) [1..2]
#=>
#=> Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) #=> [yes, no]

# VSCode でカレントディレクトリをワークスペースとして開く
code .
```

このようなディレクトリ構成が生成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/af058532-e8da-4a62-fbce-fdabc328d015.png)

# デバッガでステップ実行

Java では main メソッドにブレークポイントを設定し、F5 キーでデバッグ実行が可能です。一方、Kotlin ではデバッグを行うために tasks.json と launch.json の設定が必要となります。

```json:..vscode\tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "type": "shell",
      "command": "./gradlew build -x test",
      "problemMatcher": [],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}
```

```json:..vscode\launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "kotlin",
      "request": "launch",
      "name": "Kotlin Launch",
      "projectRoot": "${workspaceFolder}/app",
      "mainClass": "org/example/AppKt",
      "preLaunchTask": "build"
    }
  ]
}
```

これらの設定ファイルを追加すれば、デバッグ実行が可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/85fef009-d996-2dfd-1fbc-8285531a9f40.png)

tasks.json に `gradle run` や `gradle test` なども設定して実行しやすくすることもできますが、Gradle の拡張機能でその辺はカバーできるので、特に私は設定しませんでした。

# JUnit コードの実行

JUnit でテストコードの実行も試してみます。

```diff_kotlin:AppTest.kt
class AppTest {
    @Test fun appHasAGreeting() {
        val classUnderTest = App()
        assertNotNull(classUnderTest.greeting, "app should have a greeting")
    }

+    @Test
+    fun testSucceeded() = assertTrue(true)
}
```

Gradle のサイドバーを開き、 app -> verification -> test でテストコードを実行します。

Java ではエディタからクラス単位やメソッド単位で実行範囲を指定できましたが、 Kotlin はまだ対応されていないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/fe12503e-7d5f-1207-9d70-14404f0266c3.png)

test の実行ボタンの横に `Debug Task` がありますが、そこから実行すればテストコードでもステップ実行ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/fbff4cf3-858b-3ee3-eff2-a4c1d169b66f.png)

テスト結果はエディタで表示されないため、JUnit が生成したレポートファイルを見ないと詳細が確認できないようになっていました。以下、`app/build/reports/index.html` ファイルを [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) で開いた結果です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/442d4809-2e49-7e67-a3f2-0ce74b6837bd.png)

ちなみにテストが失敗になれば、どのテストで失敗したかはターミナルで確認できました。

```diff_kotlin:AppTest.kt
    @Test
+   fun testFailed() = assertTrue(false)
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/ffaa64f7-2c37-0076-e04c-e72310756e70.png)

必要最小限のテスト実行はできる、といった感じですね。

# jar ファイルのビルド

最後に jar ファイルをビルドできるようにしてみます。
jar ファイルは既に build ディレクトリ配下に作成されていますが、マニフェストファイルに main メソッドの定義が入っていないので、実行することはできません。

```powershell
# -jar オプションを指定しただけでは実行できない。
java -jar app/build/libs/app.jar
#=> app/build/libs/app.jarにメイン・マニフェスト属性がありません

# -cp オプションで jar 指定して、その後に main メソッドが入っているクラスを指定すれば OK
# App.kt の main メソッドは AppKt というクラスに入る
java -cp app/build/libs/app.jar org.example.AppKt
#=> Hello, world!
```

`-jar` オプションだけで実行できるようにするには、 Gradle に以下の設定を追加します。

```diff_kotlin:build.gradle.kts
    mainClass.set("demo.AppKt")
}

+tasks.jar {
+    manifest {
+        attributes["Main-Class"] = "demo.AppKt"
+    }
+
+    // 以降は、現状不要な設定ですが、安全のために追加してます。
+    // fat JAR（依存ライブラリを全て含めた jar ファイル） を生成するための処理
+    from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
+    // 同じ名前のファイルが複数の依存ライブラリに存在する場合、最初の1つだけを保持する
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+}
```

これで `-jar` だけで実行できるようになりました。

```powershell
java -jar app/build/libs/app.jar
#=> Hello, world!
```