kotlin编译失败_Kotlin使用GraalVM开发原生命令行应用
背景
之前用kotlin開(kāi)發(fā)過(guò)一款根據(jù)建表DDL語(yǔ)句生成plantuml ER圖的應(yīng)用。被問(wèn)如何使用,答曰"給你一個(gè)jar包,然后執(zhí)行java -jar ddl2plantuml.jar ./ddl.sql ./er.puml 就可以了。是不是so easy?"
結(jié)果被吐槽了一番,
這個(gè)吐槽帶來(lái)了一個(gè)思考: 為什么Java很少用于開(kāi)發(fā)原生命令行(CLI)應(yīng)用呢?我認(rèn)為主要問(wèn)題有2個(gè)
方案
為了解決上述問(wèn)題,引入2個(gè)名詞
Picocli
Picocli 致力于提供“最簡(jiǎn)便的方式來(lái)創(chuàng)建富命令行應(yīng)用,這種應(yīng)用可以在 JVM 上和 JVM 之外運(yùn)行”
使用起來(lái)非常簡(jiǎn)單
fun main(args: Array) { val cmd = CommandLine(Convert()) when { args.isEmpty() -> { cmd.usage(System.out) } else -> { val exitCode = cmd.execute(*args) exitProcess(exitCode) } }}@CommandLine.Command(name = "ddl2plantuml", version = ["軟件名稱(chēng):Ddl2plantuml版本:V1.1.0"], description = ["convert sql ddl to plantuml er"], mixinStandardHelpOptions = true)class Convert : Callable { @CommandLine.Parameters(index = "0", description = ["The sql ddl file that should be convert to plantuml er."]) lateinit var src: Path @CommandLine.Option(names = ["-o", "--output"], description = ["The file where the plantuml file to be saved. default is console "]) private var target: Path? = null override fun call(): Int { require(src.toFile().exists()) { "ddl file must be existed!" } when (target) { null -> { FileReader(src).read() .apply { ConsoleWriter(this).write() } } else -> { FileReader(src).read() .apply { FileWriter(target!!, this).write() } } } return 0 }}效果
這里介紹用到的幾個(gè)注解及概念
- @Parameters 和 @Options 都是用來(lái)定義參數(shù),區(qū)別在于 @Parameters根據(jù)位置區(qū)分,而@Options可以指定名稱(chēng)
- 退出碼。call()方法返回的0表示退出碼,用來(lái)描述命令行應(yīng)用的執(zhí)行結(jié)果。通常用0表示成功,其他數(shù)字為自定義異常。退出碼不會(huì)影響程序的執(zhí)行,但是有一個(gè)很實(shí)用的功能是當(dāng)你通過(guò)連接的方式同時(shí)執(zhí)行多個(gè)應(yīng)用時(shí),一個(gè)非零的退出碼會(huì)中斷這個(gè)組合。如: ./ddl2plantuml_mac ddl.sql |grep "table"
- 版本及幫助信息。可以自定義并指定樣式,version可以通過(guò)versionProvider自定義生成。
GraalVM
Go的一個(gè)宣傳點(diǎn)是可以將程序編譯為一個(gè)靜態(tài)可執(zhí)行文件,而Java也可以通過(guò)GraalVM做到這一點(diǎn)
GraalVM: Run Programs Faster Anywhere
這個(gè)slogan和Java的"Write Once, Run Anywhere"遙相呼應(yīng),同時(shí)又展示了極大的野心,準(zhǔn)備帶來(lái)下一個(gè)20年的輝煌。
GraalVM 是一個(gè)高性能的通用虛擬機(jī),可以運(yùn)行使用 JavaScript,Python 3,Ruby,R,基于 JVM 的語(yǔ)言以及基于 LLVM 的語(yǔ)言開(kāi)發(fā)的應(yīng)用。 GraalVM 消除了編程語(yǔ)言之間的隔離性,并且通過(guò)共享運(yùn)行時(shí)增強(qiáng)了他們的互操作性。它可以獨(dú)立運(yùn)行,也可以運(yùn)行在 OpenJDK,Node.js,Oracle,MySQL 等環(huán)境中。
可以看到GraalVM提供了非常強(qiáng)大的功能,這里我們不做展開(kāi)介紹,只看如何解決我們遇到的問(wèn)題。主要用到了2個(gè)功能特性
使用方式
編譯后的native image不運(yùn)行在Java VM上,但是包含了必要的組件,如內(nèi)存管理和線程調(diào)度,這些組件來(lái)自另一個(gè)Substrate VM。這個(gè)過(guò)程稱(chēng)為提前編譯
此時(shí)我們已經(jīng)得到了一個(gè)可以直接執(zhí)行的原生命令行應(yīng)用
./ddl2plantuml_mac ddl.sql注意:
native image不支持Java的所有特性,尤其是對(duì)reflection的限制。在這次改造過(guò)程中,原來(lái)通過(guò)阿里的druid進(jìn)行sql解析,但是druid使用了大量的reflection導(dǎo)致native image編譯失敗,所以改用jsqlparser。
其他
總結(jié)
以上是生活随笔為你收集整理的kotlin编译失败_Kotlin使用GraalVM开发原生命令行应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Web前端-html页面-网易注册表单,
- 下一篇: 第二次作业:软件分析之网易云音乐