2

I'm trying to create a runnable jar with Kotlin.

My gradle.build is this:



plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.11'

}

group 'com.github.dynamik'
version '1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'kotlin'
mainClassName = "interpreter.Repl"





repositories {
    mavenCentral()
    maven { setUrl("https://dl.bintray.com/hotkeytlt/maven") }

}
configurations {
    ktlint
}
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    compile 'com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3'
    // https://mvnrepository.com/artifact/junit/junit
    testCompile group: 'junit', name: 'junit', version: '4.4'
    ktlint "com.github.shyiko:ktlint:0.31.0"




    implementation 'com.github.ajalt:clikt:1.7.0'


    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'



}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

run {
    standardInput = System.in
}

jar {
    manifest {
        attributes 'Main-Class': 'interpreter.Repl'
    }
}

(As it stands, when I do ./gradlew run, everything works as expected.)

I'm reading an article here on how to proceed, and it says to do: java -jar <MY_PROJECT_NAME>.jar.

I don't quite understand this -- where do we run this? I tried running it from my project root and I got an error:

Error: Unable to access jarfile <my_jarname>.jar

nz_21
  • 6,140
  • 7
  • 34
  • 80

3 Answers3

5

As of Gradle 5.4.1, a build.gradle.kts would need a section like this:

tasks.register<Jar>("uberJar") {
    archiveClassifier.set("uber")

    manifest {
        attributes(
                "Main-Class" to "mytest.AppKt",
                "Implementation-Title" to "Gradle",
                "Implementation-Version" to archiveVersion
        )
    }

    from(sourceSets.main.get().output)

    dependsOn(configurations.runtimeClasspath)
    from({
        configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
    })
}
EntangledLoops
  • 1,951
  • 1
  • 23
  • 36
1

Ok, I figured it out :)

So, the way to create a jar is to go: ./gradlew build. This creates a jar in build/libs.

The problem is, when running that jar, one would run into an exception about java.lang.intrinsics because the kotlin stdlib hasn't been packed into the jar.

While there is a way to manually accomplish that, I found the easiest solution is to simply use the shadowjar plugin.

My build.gradle ended up looking like this:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
    }
}

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.11'

}

group 'com.github.dynamik'
version '1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'kotlin'
apply plugin: 'java'


mainClassName = "interpreter.Repl"

repositories {
    mavenCentral()
    jcenter()
    maven { setUrl("https://dl.bintray.com/hotkeytlt/maven") }
    maven {
        url = uri("https://plugins.gradle.org/m2/")
    }

}
configurations {
    ktlint
}
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    compile 'com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3'
    // https://mvnrepository.com/artifact/junit/junit
    testCompile group: 'junit', name: 'junit', version: '4.4'
    ktlint "com.github.shyiko:ktlint:0.31.0"
    implementation 'com.github.ajalt:clikt:1.7.0'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'

}
apply plugin: 'com.github.johnrengelman.shadow'



compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

run {
    standardInput = System.in
}

jar {
    manifest {
        attributes 'Main-Class': 'interpreter.Repl'
    }
}

nz_21
  • 6,140
  • 7
  • 34
  • 80
-2

When using a Kotlin main class you need to add a Kt at the end of the class name while referencing it on MANIFEST. So, if your main class is called interpreter.Repl, use:

jar {
    manifest {
        attributes 'Main-Class': 'interpreter.ReplKt'
    }
}

instead of

jar {
    manifest {
        attributes 'Main-Class': 'interpreter.Repl'
    }
}
NathanPB
  • 685
  • 1
  • 7
  • 22
  • You would also need to pack kotlin sdtlib within your generated .jar. – NathanPB Apr 15 '19 at 21:21
  • thank you for the pointers! Just a quick question though: how is that ```java -jar .jar``` command supposed to be run? I'm looking here https://stackoverflow.com/questions/5258159/how-to-make-an-executable-jar-file and it seems like it has to point to .class files in java - is it the same with kotlin? – nz_21 Apr 15 '19 at 21:24
  • When using `-jar` you will need to point to a .jar file. In your case, your generated .jar. It's supposed to execute the jar exactly as your IDE do. If you don't print anything you will have no output on `java -jar xxx.jar` – NathanPB Apr 15 '19 at 21:26
  • cool, thanks! I guess I need to first figure out how to create the .jar file. – nz_21 Apr 15 '19 at 21:37