5 votes

Créer un fat jar à partir d'un projet Kotlin multiplateforme avec Kotlin Gradle DSL

J'essaie de créer un jar exécutable pour un projet multiplateforme kotlin qui inclut un composant serveur ktor, construit avec Kotlin Gradle DSL.

J'ai vu plusieurs questions, notamment Créer un fat jar à partir d'un projet multiplateforme kotlin qui demande et répond à la question de savoir comment créer le fichier de construction gradle en Groovy, mais comment le faire en kotlin dsl ?

Le code groovy qui est censé fonctionner est le suivant :

kotlin {
jvm() {
    withJava()
    jvmJar {
        manifest {
            attributes 'Main-Class': 'sample.MainKt'
        }
        from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}
...
}

Comment cela se traduirait-il pour le DSL Kotlin ? J'ai essayé de nombreuses variantes, dont certaines compilent et s'exécutent, mais ne créent pas le résultat souhaité... un jar exécutable.

3voto

gunslingor Points 583

J'ai passé 3 jours à essayer de faire fonctionner le pot de graisse, voici la solution et ce qui suit avant la clarification de la solution :

LES ERREURS QUE J'AI COMMISES AU DÉBUT

  • Je n'aurais pas dû me précipiter sur docker, j'aurais dû d'abord faire fonctionner le fat jar en local.
  • withJava() a été omis, ce qui a été le principal gaspillage de 36 heures de travail... Quel est l'intérêt de cette fonction ?
  • dependsOn(build) : je ne comprends pas pourquoi le type de tâche jar ne le sait pas déjà.
  • main.compileDependencyFiles : J'ai utilisé ceci pendant un certain temps à la place de la carte de l'argument ci-dessous.
  • main.output.classesDirs : manquait dans les autres solutions et c'est ce qui semble inclure votre code réel.

NOTE : Aucun plugin shadow n'est nécessaire, ce qui est fantastique (les plugins gradle ont tendance à ne pas bien fonctionner ensemble IMHO, jamais).

NOTE : La version est importante car cette pile semble changer environ 50 fois plus vite que la documentation dans certains cas, la version suivante a été utilisée pour cette solution :

  • Kotlin 1.3.72
  • Gradle 6.5
  • Ktor 1.3.2

CODE :

//Import variables from gradle.properties
val environment: String by project
val kotlinVersion: String by project
val ktorVersion: String by project

//Build File Configuration
plugins {
    java
    kotlin("multiplatform") version "1.3.72"
}

group = "com.app"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
    jcenter()
    jcenter {
        url = uri("https://kotlin.bintray.com/kotlin-js-wrappers")
    }
    maven {
        url = uri("https://jitpack.io")
    }
}

//Multiplatform Configuration
kotlin {
    jvm {
        withJava()
        compilations {
            val main = getByName("main")
            tasks {
                register<Jar>("buildFatJar2") {
                    group = "application"
                    dependsOn(build)
                    manifest {
                        attributes["Main-Class"] = "com.app.BackendAppKt"
                    }
                    from(configurations.getByName("runtimeClasspath").map { if (it.isDirectory) it else zipTree(it) }, main.output.classesDirs)
                    archiveBaseName.set("${project.name}-fat2")
                }
            }
        }
    }
    js {
        browser {

        }
    }
    sourceSets { SKIPPED FOR LENGTH }
}

J'espère que cela permettra à quelqu'un d'économiser 3 jours, faites-moi savoir si vous trouvez des améliorations (je suis toujours en train d'apprendre aussi). Kotlin, gradle, multiplateforme, docker... tout cela est très difficile à gérer, ils doivent mettre à jour la documentation en parallèle IMHO ou jetbrains est condamné.

AMÉLIORATIONS POTENTIELLES :

  • Le jar produit semble beaucoup plus gros qu'il ne devrait l'être avec des tonnes de choses inutiles, je soupçonne que le fait de changer le chemin de compilation au lieu du chemin d'exécution va corriger cela (CONFIRMÉ 30% de réduction de taille).
  • Des attributs plus manifestes peut-être.
  • A noter également que j'ai lu un article suggérant à juste titre que les fatJars ne devraient pas être déployés sur docker, que les dépendances java devraient être construites en tant que partie de l'image.

1voto

Javier Diaz Points 1244

La réponse de @andylamax est assez proche mais conduit à l'erreur que @cfnz voyait.

Pour y remédier, vous devez ajouter doFirst comme dans cet exemple :

val jvm = jvm() {
    withJava()
    val jvmJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) {
        doFirst {
            manifest {
                attributes["Main-Class"] = project.ext["mainClass"]
            }
            from(configurations.getByName("runtimeClasspath").map { if (it.isDirectory) it else zipTree(it) })
        }
    }
}

Il fonctionne comme prévu dans aquí con gradle jvmJar && java -jar build/libs/laguna-jvm.jar

0voto

andylamax Points 478

Votre dsl groovy peut être écrit en kotlin comme suit

kotlin {
  jvm {
    withJava()
    val jvmJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) {
        manifest {
            attributes["Main-Class"] = "sample.MainKt"
        }
        from(configurations.getByName("runtimeClasspath").map { if (it.isDirectory) it else zipTree(it) })
    }
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X