如何在命令行上编译 kotlinx.serialization 个库?

how to compile kotlinx.serialization libraries on the command line?

这与我要实现的目标非常接近。

我真的很想学习如何编译和 运行 包含库的简单代码,但在包含 class 路径时有点迷茫。

我目前正在尝试编译 运行

import kotlinx.serialization.*
import kotlinx.serialization.json.*


@Serializable 
data class Project(val name: String, val language: String)

fun main() {
    // Serializing objects
    val data = Project("kotlinx.serialization", "Kotlin")
    val string = Json.encodeToString(data)  
    println(string) // {"name":"kotlinx.serialization","language":"Kotlin"} 
    // Deserializing back into objects
    val obj = Json.decodeFromString<Project>(string)
    println(obj) // Project(name=kotlinx.serialization, language=Kotlin)
}

使用

kotlinc -cp "C:\PROGRA~1\Kotlin\lib\kotlinx-serialization-runtime-1.0-M1-1.4.0-rc.jar" main.kt

用这个编译器编译

https://blog.jetbrains.com/kotlin/2020/07/kotlin-1-4-rc-released/

文章底部允许的库 这就是 kotlinx-serialization-运行time-1.0-M1-1.4.0-rc.jar 的来源。我选择这个 运行time jar 是因为当我使用新的 kotlin 4.0.21 编译器时它需要 kotlin-serialization-运行time-1.0.1.jar 你需要自己构建但是当我下载了源代码并 运行 gradle 构建它似乎没有生成(单独的问题但很想知道如何自己构建 运行time jar)

当我尝试 运行 我得到

Exception in thread "main" java.lang.NoClassDefFoundError: kotlinx/serialization/json/Json
        at MainKt.main(main.kt:12)
        at MainKt.main(main.kt)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at org.jetbrains.kotlin.runner.AbstractRunner.run(runners.kt:64)
        at org.jetbrains.kotlin.runner.Main.run(Main.kt:149)
        at org.jetbrains.kotlin.runner.Main.main(Main.kt:159)
Caused by: java.lang.ClassNotFoundException: kotlinx.serialization.json.Json
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:435)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        ... 9 more

我知道当我 运行

时我需要包含一个 class 路径
kotlin MainKt 

但尝试了所有方法都没有成功

我尝试了很多不同的组合,包括 编译有无 -Xplugin="C:\PROGRA~1\Kotlin\lib\kotlinx-serialization-compiler-plugin.jar 似乎没有什么区别所以我把它关掉了。

我试过编译成 java .jar 和 kotlin .class 文件似乎都需要 class 路径信息 运行 时间。我宁愿编译成 kotlin .class 并在我真正需要它之前将 java 排除在外。这样我就可以了解 java 在我的应用程序中真正做了什么。

我想我真正想知道的是如何确定 运行 时 运行 可执行文件需要什么。我发现这个网站有助于显示依赖关系,但适用于旧版本的 kotlin https://kotlin.binarydoc.org/org.jetbrains.kotlin/kotlin-compiler-dist/1.3.71/package?package=kotlinx.serialization

我也一直在使用 https://github.com/google/android-classyshark 进入 .class 文件 和 https://github.com/borisf/classyshark-bytecode-viewer

但是当人们在 Whosebug 上告诉其他人他们需要使用什么 class 路径来解决他们的问题时,这似乎很神奇。有人可以教我如何在没有 gradle 的情况下钓鱼吗?

p.s。如果有人有任何好的资源来学习 gradle 如何构建项目的内部结构。我在这里看了一点 https://docs.gradle.org/current/userguide/userguide.pdf but didn’t seem to help. maybe I missed something. Also, this page https://kotlinlang.org/docs/reference/serialization.html#example-json-serialization 似乎有我需要的东西,但似乎无法将其转换为命令行所需的东西。

dependencies {
     implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
 }

这是什么意思?我认为这是指这个 https://github.com/Kotlin/kotlinx.serialization

但是我如何从这个 repo 构建我需要的东西并使用它来让我的应用程序知道它的 运行 时间依赖项在哪里?啊。我真的很想自己解决这一切,但我必须为此向网络大神下跪。抱歉,我的 post 很乱。我爱学习。

花了一些时间,但我能够使用当前的 kotlinc 编译器和 kotlinx.serializtion.1.0 在命令行上 https://github.com/Kotlin/kotlinx.serialization 处构建和 运行 序列化示例。 1 个图书馆。

这里是编译器和库的直接链接

kotlinc 和 kotlinc-native v1.4.20 https://github.com/JetBrains/kotlin/releases/tag/v1.4.20

Kotlinx.serialization v1.0.1 https://github.com/Kotlin/kotlinx.serialization/releases/tag/v1.0.1

这些也可以在 1.4.20 版本博客 post 标题为“如何更新”的部分下找到: https://blog.jetbrains.com/kotlin/2020/11/kotlin-1-4-20-released/

设置 Katlin 的 .jar 库


更新我的路径以指向新的编译器后,我仍然需要构建序列化库。这就像 运行ning gradle 在解压缩的 kotlinx-serialization-1.0.1 文件夹的根目录中构建一样简单。确保在执行此操作之前设置 JAVA-HOME 系统变量,否则它将不起作用。

构建完成后,您需要获取 kotlinx-serialization-json-jvm-SNAPSHOT-1.0.1.jar 和 kotlinx-serialization-core-jvm-SNAPSHOT -1.0.1.jar 文件并将它们移动到项目目录中。这绝对让我感到困惑,因为我在 MVN 存储库站点上找到了一个用于 kotlinx 序列化的 运行time 库,它是一个 jar 文件,但在构建 1.0.1 库后我没有看到它。一旦我提取了我在网上找到的 1.0.1 运行time jar,通过将 .jar 重命名为 .zip,很明显它包含核心和 json jar 的内容。不要使用 kotlinx-serialization-1.0.1-SNAPSHOT.jar。此 jar 仅包含一个空白 MANIFEST.ms 文件。您可以在 kotlinx.serialization-1.0.1\core\build\libs 文件夹和 kotlinx-serialization-[=119 中找到 kotlinx-serialization-core-jvm-1.0.1-SNAPSHOT.jar =]-jvm-1.0.1-SNAPSHOT.jar 在 kotlinx.serialization-1.0.1\formats\json\build\libs 文件夹中。无论如何。

编译您的 .jar 库


一旦你的项目文件夹中有了 jar,你就可以构建你的项目了 我在下面包含了我的 cleanbuildandrun.sh shell 脚本以便于参考。 我的第一次尝试 1) 是尝试构建项目而不将其编译为 .jar 库文件。这是一个彻底的失败。我得到它来编译,但 运行 事实证明这个项目要困难得多。在 运行 时间,我无法告诉 kotlin 库在哪里。我尝试了很多不同的方法,包括尝试将其指向我创建的清单文件,但似乎没有任何效果。看来您需要构建一个可执行的 jar 才能完成这项工作。这让我进行了第二次尝试 2)。这是我获得更多成功的地方。

尝试 2)

  • 首先,您需要使用“-Xplugin”编译器标志包含 kotlinx-serialization-compiler-plugin.jar。我的理解是插件是用来给编译器定义注解的,比如@Serializable。您可以在刚刚下载的编译器中的 lib 文件夹中找到此 jar 文件。我将其复制到其他 jar 文件旁边的项目 /lib 文件夹中,以制作 self-contained 和可移植的东西。

  • 接下来您需要使用“-classpath”或“-cp”编译器标志告诉编译器在哪里可以找到您要访问的库classes .

  • 确保使用“-include-runtime”编译器标志包含 kotlin 运行time 库。这会将 kotlin 标准 class 库捆绑在您的 jar 中,因此您无需在 运行 时间内指向它们。

  • 最后通过提供 -d 编译器标志以及您即将成为 .jar 文件的名称和扩展名来指示编译器构建 jar 文件。就是这样,你的关闭编译。

示例 Shell 脚本:
#!/bin/bash

sh clean.sh
case  in
    1) # Comming Soon
        kotlinc -verbose -Xplugin="lib\kotlinx-serialization-compiler-plugin.jar" \
                         -cp "lib\kotlinx-serialization-json-jvm-1.0.1.jar;lib\kotlinx-serialization-core-jvm-1.0.1.jar" \
                          main.kt
        ;;
    2) # Working
        kotlinc main.kt -Xplugin="lib\kotlinx-serialization-compiler-plugin.jar" \
                        -cp "lib\kotlinx-serialization-json-jvm-1.0.1.jar;lib\kotlinx-serialization-core-jvm-1.0.1.jar" \
                        -include-runtime -d main.jar
                         jar ufm Main.jar ManifestAdditions.txt lib
                         kotlin main.jar
        ;;
    3) # Comming Soon
        kotlinc-native main.kt -verbose -Xplugin="lib\kotlinx-serialization-compiler-plugin.jar" \
                        -cp "lib\kotlinx-serialization-json-jvm-1.0.1.jar;lib\kotlinx-serialization-core-jvm-1.0.1.jar" \
                        -manifest ManifestAddition.txt -o main
        ;;
esac

运行 你的 .jar 库


默认情况下,当您编译 jar 时,它会创建一个 MANIFEST.ms 文件,用于告诉您的 jar 库入口点在哪里。如果我们不在我们的应用程序中使用额外的库,这就足够了。所以接下来我们需要将这些库添加到我们编译的 jar 文件中,同时更新其 MANIFEST.ms 文件以告诉它这些库在该 jar 文件中的位置。我们可以使用 cli 工具 jar 来完成这个。使用命令:

jar ufm Main.jar ManifestAdditions.txt lib

我们可以更新当前的 jar 文件。

  • u - 告诉 jar 我们要更新现有的 jar 文件
  • f - 表示我们正在提供要在 cmd 行上更新的 jar 文件
  • m - 表示我们将提供清单文件

清单 .txt 文件应如下所示:

Main-Class: MainKt
Class-Path: lib\kotlinx-serialization-core-jvm-1.0.1.jar lib\kotlinx-serialization-json-jvm-1.0.1.jar

确保在文件末尾添加一个新行,否则它不会解析 Class-Path。

就是这样。现在我们有一个可执行的 jar 文件,我们可以使用它来 运行 我们在命令行上的序列化代码:

kotlin main.jar

应该输出:

{"name":"kotlinx.serialization","language":"Kotlin"}
Project(name=kotlinx.serialization, language=Kotlin)

Post马克


我真的很想把这个答案变成一个博客 post 来解释如何在命令行上使用带有库的 kotlin 编译器。信息在那里,但似乎是分散的。我想包括如何在不使用 jar 文件的情况下编译和 运行,如果可能的话以及如何使用本机编译器进行编译和 运行。如果有人可以帮助填补这些空白,我们将不胜感激。我认为这些信息可以帮助其他人学习如何设置简单的测试环境,这样他们就可以更好地理解这些库的功能,而无需设置构建脚本。这将是我第一次尝试创建教程类型的博客 post 所以任何信息都会很有帮助。