アプリ開発備忘録

PlayStationMobile、Android、UWPの開発備忘録

GraalVM + Kotlinでネイティブコンソールアプリを作る

GraalVM + Kotlinでネイティブコンソールアプリを作る

bashでshell scriptを書くのが大変。使い慣れた言語のKotlinを使ってスクリプトを実行したい。しかし、Java環境が入れられない制約がある場所で実行したいという状況になりました。

最初に思い浮かんだのはKotlin/Nativeですが、これはKotlin/JSと同じく、普段使っているKotlin/JVMとはとても差があります。
そこでどうしたものかと思った時に思い出したのはGraalVMでした。GrralVMならJVMな上に、ネイティブアプリが作れるはずです。なので、初めてGraalVMを使ってみましたが、なかなかちゃんと動いてくれて、実用性があると判断しました。

導入

導入方法は至って簡単です。
JavaをGrralVMのものに設定し、Gradle Pluginを入れるだけです。

後はプラグインが自動的に必要なものを検出してくれます。
build.gradle.kts

plugins {
    kotlin("jvm") version "1.7.20"
+    id("org.graalvm.buildtools.native") version "0.9.18"
    application
}

出力名は、普通はarchivesNameに設定すれば良いのですが、GraalVMではそれではだめで、imageNameに名前を設定してあげる必要がありました。

archivesName.set("example")

graalvmNative {
    binaries {
        named("main") {
            javaLauncher.set(javaToolchains.launcherFor {
                languageVersion.set(JavaLanguageVersion.of(17))
                vendor.set(JvmVendorSpec.matching("GraalVM Community"))
            })
            imageName.set(archivesName.get())
        }
    }
}

コンパイルは以下のコマンドになります。 build/native/nativeCompile にバイナリが出力されます。

./gradlew nativeCompile

コード例

sshしてみる

class Main {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val process = ProcessBuilder("ssh", "192.168.0.1")
                .inheritIO()
                .start()

            process.waitFor()
        }
    }
}

lsしてgrepしてみる

class Main {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val process = ProcessBuilder.startPipeline(
                listOf(
                    ProcessBuilder("ls", "-al"),
                    ProcessBuilder("grep", "gradle")
                        .redirectOutput(ProcessBuilder.Redirect.INHERIT)
                        .redirectError(ProcessBuilder.Redirect.INHERIT),
                )
            )

            process.last().waitFor()
        }
    }
}

おわりに

一部ライブラリは動かないものとかはあるそうですが、文字列を置換したりそういった処理がKotlinで書きやすくなるだけでもだいぶ便利です。