kdnakt blog

hello there.

KotlinでHTTPサーバーを作るアドベントカレンダー(5日目:パッケージ分割)

この記事はkdnaktの1人 Advent Calendar 2020の5日目の記事です。

 

2020年は会社でKotlin dojoを主催して週1回30分Kotlinと戯れていました。12月はその集大成ということで、KotlinでHTTPサーバーを作ってみたいと思います。どこまでできるか、お楽しみ……。

 

 

[パッケージを分割する]

現在のソースコードは、ビルドされたバイナリファイルを覗くとこのようになっています。

$ tree -I build
.
├── build.gradle.kts
├── settings.gradle.kts
└── src
    └── nativeMain
        └── kotlin
            └── hello.kt

 

現時点ではhello.ktの1ファイルしかソースコードがありませんが、プロダクトバックログに記載したとおり、設定ファイルの読み込みやTLS対応など、複数の機能を追加する予定があります。しかし、このままではすべてのソースコードsrc/nativeMain/kotlinディレクトリの直下に配置せざるをえません。数年Javaをやっている身としては、やはり各ファイルの責務に応じて、パッケージに分割したくなります。

 

Kotlinでも、Javaと同様にpackage <パッケージ名>という形でパッケージ名を宣言することができるので、hello.ktファイルをcom.kdnakt.httpdパッケージに配置します。

Packages and Imports - Kotlin Programming Language

 

まず、必要なディレクトリを作成し、hello.ktファイルを移動させます。

$ cd src/nativeMain/kotlin
$ mkdir -p com/kdnakt/kttpd
$ mv hello.kt com/kdnakt/kttpd/

 

この時点で、プロジェクトのディレクトリ構成は次のようになっています。

$ tree -I build
.
├── build.gradle.kts
├── settings.gradle.kts
└── src
    └── nativeMain
        └── kotlin
            └── com
                └── kdnakt
                    └── kttpd
                        └── hello.kt

 

つぎに、hello.ktを編集してパッケージ名を宣言します。

package com.kdnakt.kttpd // この行を追加

fun main() {
  println("Hello Kotlin/Native!")
}

 

プロジェクトのトップディレクトリに戻り、ビルドを実行してみます。

$ cd ../../../
$ gradle nativeBinaries
Starting a Gradle Daemon (subsequent builds will be faster)

> Configure project :
Kotlin Multiplatform Projects are an Alpha feature. See: https://kotlinlang.org/docs/reference/evolution/components-stability.html. To hide this message, add 'kotlin.mpp.stability.nowarn=true' to the Gradle properties.


> Task :linkDebugExecutableNative FAILED
e: Could not find 'main' in '<root>' package.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':linkDebugExecutableNative'.
> Compilation finished with errors

* Try:
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

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.7.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 26s
2 actionable tasks: 2 executed

 

エラーが出てビルドが失敗してしまいました。e: Could not find 'main' in '<root>' package.とあるので、エントリーポイントとなるmain()関数をルートパッケージから別の場所へ移動してしまったことが原因のようです。

 

Introduction to Kotlin/Nativeというハンズオンを確認すると、build.gradleファイルのexecutableタスク部分にentryPointが記載されています。この点が現在のプロジェクトで利用しているbuild.gradle.ktsファイルと異なるので、以下のようにentryPointを追加します。executable()の丸カッコ()が波カッコ{}になっている点に注意が必要です。

// 修正前
kotlin {
  macosX64("native") {
    binaries {
      executable()
    }
  }
}

// 修正後
kotlin {
  macosX64("native") {
    binaries {
      executable {
        entryPoint = "com.kdnakt.kttpd.main"
      }
    }
  }
}

 

改めてコマンドを実行すると、今度はgradle nativeBinariesコマンドが成功しました。

$ gradle nativeBinaries

> Configure project :
Kotlin Multiplatform Projects are an Alpha feature. See: https://kotlinlang.org/docs/reference/evolution/components-stability.html. To hide this message, add 'kotlin.mpp.stability.nowarn=true' to the Gradle properties.


Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.7.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 39s
3 actionable tasks: 3 executed

 

これでパッケージを分割しながらKotlin/Nativeの開発がすすめられそうです。

 

[まとめ]

  • Kotlin/Nativeでmain()関数をルートパッケージから移動した場合は、ビルドスクリプトentryPointの追加が必要
  • 実装中のコードは以下のリポジトリにまとめてある

github.com