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に名前を設定してあげる必要がありました。
base.archivesName.set("example") graalvmNative { binaries { named("main") { javaLauncher.set(javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(17)) vendor.set(JvmVendorSpec.matching("GraalVM Community")) }) imageName.set(base.archivesName.get()) mainClass.set("Main") } } }
コンパイルは以下のコマンドになります。 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で書きやすくなるだけでもだいぶ便利です。