使用Gradle和Kotlin构建一个可自我执行的jar

时间:2014-10-20 15:29:16

标签: gradle kotlin

我已经编写了一个简单的kotlin源文件以便开始使用,还有一个gradle脚本文件。 但我无法弄清楚如何将主要功能添加到清单中,以便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时,我得到以下stacktrace,告诉我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

7 个答案:

答案 0 :(得分:31)

添加插件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 正在构建一个类来封装您的主要函数,该函数使用与文件相同的名称命名 - 使用Title Case。

答案 1 :(得分:24)

我找到了解决方法(感谢MkYong website

  1. gradle脚本需要将kotlin-compiler工件作为依赖项
  2. gradle脚本需要一种方法来收集所有kotlin文件并将它们放入jar中。
  3. 所以我得到以下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) } }
    }
    

答案 2 :(得分:1)

谢谢,对我来说,它可以添加jar部分

jar {
    manifest {
        attributes 'Main-Class': 'com.photofiles.Application'
    }

    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

不需要应用程序插件。

答案 3 :(得分:0)

万一你碰巧像我一样愚蠢:

不要将IntelliJ运行配置创建为应用程序。 IntelliJ将假设它是Java&amp;它永远不会奏效。相反,请使用“Kotlin”条目。

答案 4 :(得分:0)

如果在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

答案 5 :(得分:0)

在构建Artifact时,以上解决方案均不适合我。

IDE版本IntelliJ IDEA 2019.1.1

要解决此问题,请执行以下操作

步骤

步骤1-创建工件

  1. 转到文件->项目结构->工件

  2. 单击 +-> JAR-> From modules with dependencies

enter image description here

  1. 选择程序的Main Class

enter image description here

第2步-更改清单路径

  1. Directory for META-INF/MANIFEST.MF的值更改为项目的根。

    例如,从/your/project/directory/src/main/kotlin/your/project/directory

enter image description here

  1. OK,然后按ApplyOK

第3步-构建工件

  1. 最后,转到 Build-> Build Artifacts-> [your-artifact-name]-> Build

生成的JAR文件可在out/artifact/[your-artifact-name]目录中找到。 (y)

答案 6 :(得分:0)

对于使用Kotlin MP插件的任何人,这里都是您的代码

jvm{
    jvmJar {
        manifest{
            attributes 'Main-Class':'Class path here'
        }
    }

}