使用 Gradle 和 Kotlin 构建一个自执行的 jar
Posted
技术标签:
【中文标题】使用 Gradle 和 Kotlin 构建一个自执行的 jar【英文标题】:Building a self-executable JAR with Gradle and Kotlin 【发布时间】:2014-12-15 15:42:49 【问题描述】:为了入门,我编写了一个简单的 kotlin 源文件,以及一个 gradle 脚本文件。 但我不知道如何将 main func 添加到清单中,以便 jar 可以自执行。
这是我的 build.gradle 脚本:
buildscript
repositories
mavenCentral()
dependencies
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.9.66'
apply plugin: "kotlin"
repositories
mavenCentral()
dependencies
compile 'org.jetbrains.kotlin:kotlin-stdlib:0.9.66'
jar
manifest
attributes 'Main-Class': 'com.loloof64.kotlin.exps.ExpsPackage'
这是我的 com.loloof64.kotlin.exps.Multideclarations.kt
package com.loloof64.kotlin.exps
class Person(val firstName: String, val lastName: String)
fun component1(): String
return firstName
fun component2(): String
return lastName
fun main(args: Array < String > )
val(first, last) = Person("Laurent", "Bernabé")
println("First name : $first - Last name : $last")
当我从终端(java -jar MYJar.jar)启动 jar 时,我得到以下堆栈跟踪,说我缺少 kotlin 反射库类,实际上它们还没有添加到 jar 中。看来我缺少最终 jar 中的 kotlin-compiler 工件类以及 kotlin-stdlib 源,但我不知道如何调整 gradle 构建。
$> java -jar build/libs/kotlin_exps.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/reflect/jvm/internal/InternalPackage
at com.loloof64.kotlin.exps.ExpsPackage.<clinit>(MultiDeclarations.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.reflect.jvm.internal.InternalPackage
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
我正在使用 Kotlin 0.9.66 和 gradle 2.1
【问题讨论】:
请注意,Kotlin 为诸如main
之类的***函数生成的类名是在同一个文件中定义的包,加上附加了KT
的文件名。在您的情况下,这将是com.loloof64.kotlin.exps.MultideclarationsKT
。您可以通过在文件顶部添加 @file:JvmName("OtherName")
来更改此行为,以便为文件中的所有***函数定义新的类名。
您附加两个字符 Kt
而不是 KT
... 即大写 K 和小写 t。这是一个容易犯的错误,但会导致 jar 执行失败。由于打字不完善,我自己有时也会遇到这个问题。
见this rather comprehensive answer。
【参考方案1】:
添加插件application
,然后设置mainClassName
为
mainClassName = '[your_namespace].[your_arctifact]Kt'
例如,假设您已将以下代码放在名为main.kt
的文件中:
package net.mydomain.kotlinlearn
import kotlin
import java.util.ArrayList
fun main(args: Array<String>)
println("Hello!")
您的build.gradle
应该是:
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = "net.mydomain.kotlinlearn.MainKt"
事实上,Kotlin 正在构建一个类来封装你的主函数,该函数与你的文件同名 - 使用标题大小写。
【讨论】:
您能否更新您对 Kotlin 如何为***函数创建类的新命名约定的答案。在他的示例中,现在将是:com.loloof64.kotlin.exps.MultideclarationsKT
作为类名。 Kotlin 1.0 beta 及更高版本也是如此。
针对 Kotlin 1.0 Beta 和更新版本进行了更新。谢谢杰森。
这不应该是公认的答案;这是正确的,但不是全貌:需要“收集” Kotlin 运行时文件以制作完整的可执行 jar,如下面@loloof64 的示例所示。
这不再起作用了。如果你修复它,我会删除我的反对票。
@AdamArold 我用 1.1.51 进行了测试,它可以工作。你指的是哪个版本?谢谢【参考方案2】:
我找到了解决方法(感谢MkYong website)
-
gradle 脚本需要 kotlin-compiler 工件作为依赖项
gradle 脚本需要一种方法来收集所有 kotlin 文件并将它们放入 jar 中。
所以我得到了以下 gradle 脚本:
buildscript
repositories
mavenCentral()
dependencies
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.1-2'
apply plugin: "kotlin"
repositories
mavenCentral()
dependencies
compile 'org.jetbrains.kotlin:kotlin-stdlib:1.0.1-2'
jar
manifest
attributes 'Main-Class': 'com.loloof64.kotlin.exps.MultideclarationsKT'
// NEW LINE HERE !!!
from configurations.compile.collect it.isDirectory() ? it : zipTree(it)
【讨论】:
对我来说它在没有编译器依赖的情况下工作,收集 jar 的文件就足够了 可以确认不需要编译器依赖,收集文件就够了。 执行任务后的jar在哪里? jar 文件的位置取决于构建 jar 的方法。如果您执行 gradle jar 任务,它将被放入目录build/libs
。构建目录与build.gradle
文件处于同一级别。如果您在 IntelliJ IDE 中将 jar 映射构建为工件并使用 IntelliJ 构建工件,则将其放置在 IntelliJ 项目级别的 out/artifacts
目录中
具体来说,我发现将这个jar_block添加到build.gradle文件后,我可以使用IntelliJ神器机制或者使用gradle任务机制构建jar文件来创建一个成功的jar。跨度>
【参考方案3】:
在构建 Artifact 时,上述解决方案都不适合我。
IDE 版本IntelliJ IDEA 2019.1.1
。
要解决此问题,请执行以下操作
步骤
第 1 步 - 创建工件
转到文件 -> 项目结构 -> 工件
点击+
-> JAR
-> From modules with dependencies
-
选择您的程序的
Main Class
第 2 步 - 更改清单路径
将Directory for META-INF/MANIFEST.MF
的值更改为您的项目根目录。
例如,从/your/project/directory/src/main/kotlin
到/your/project/directory
-
按
OK
,然后按Apply
和OK
。
第 3 步 - 构建工件
-
最后,转到
Build
-> Build Artifacts
-> [your-artifact-name]
-> Build
。
生成的JAR
文件可以在out/artifact/[your-artifact-name]
目录下找到。 (y)
【讨论】:
非常感谢!!!经过几次尝试,这是唯一对我有用的东西!【参考方案4】:谢谢,对我来说,添加 jar 部分很有效
jar
manifest
attributes 'Main-Class': 'com.photofiles.Application'
from configurations.compile.collect it.isDirectory() ? it : zipTree(it)
不需要应用程序插件。
【讨论】:
主类名需要以Kt
结尾。所以上面应该是ApplicationKt
。【参考方案5】:
如果使用Gradle
和Kotlin
DSL
,那么我的duplicate 问题的答案是:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins
kotlin("jvm") version "1.2.51"
id("com.github.johnrengelman.shadow") version "2.0.4"
group = "xxx.yyy"
version = "1.0-SNAPSHOT"
repositories
mavenCentral()
dependencies
implementation(kotlin("stdlib-jdk8"))
tasks.withType<KotlinCompile>
kotlinOptions.jvmTarget = "1.8"
tasks.withType<ShadowJar>
manifest.attributes.apply
put("Implementation-Title", "Gradle Jar File Example")
//put("Implementation-Version" version)
put("Main-Class", "HelloKotlinWorld.App")
我认为这是最简单的解决方案。哦,也许您只使用Kotlin
本身而不是DSL
。
【讨论】:
【参考方案6】:如果你碰巧像我一样愚蠢:
不要将 IntelliJ 运行配置创建为应用程序。 IntelliJ 将假定它是 Java 并且它永远不会工作。相反,请使用“Kotlin”条目。
【讨论】:
【参考方案7】:对于任何使用 Kotlin MP 插件的人,这里是您的代码
jvm
jvmJar
manifest
attributes 'Main-Class':'Class path here'
【讨论】:
以上是关于使用 Gradle 和 Kotlin 构建一个自执行的 jar的主要内容,如果未能解决你的问题,请参考以下文章
如何解析和修改build.gradle.kts Kotlin Gradle构建脚本?
为啥 kotlin gradle 插件无法使用 1.8 目标构建?