使用 Kotlin Gradle DSL 从 ktor Kotlin 多平台项目创建 fat jar
Create fat jar from ktor Kotlin multiplatform project with Kotlin Gradle DSL
尝试为包含 ktor 服务器组件的 kotlin 多平台项目创建一个 运行nable jar,使用 Kotlin Gradle DSL 构建。
我看到了几个问题,包括 ,它询问并回答了如何在 Groovy 中创建 gradle 构建文件,但是你如何在 kotlin dsl 中创建它?
报告有效的 groovy 代码是:
kotlin {
jvm() {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'sample.MainKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
...
}
这将如何转化为 Kotlin DSL?我尝试了很多变体,其中一些变体可以编译 运行,但没有创建所需的输出... 运行nable jar。
你的groovydsl可以用kotlin写成如下
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) })
}
}
}
@andylamax 的答案非常接近,但导致了@cfnz 看到的错误
要解决此问题,您需要添加 doFirst
,如本例所示:
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) })
}
}
}
它在 here 和 gradle jvmJar && java -jar build/libs/laguna-jvm.jar
中按预期工作
我花了 3 天时间试图让 fat jar 工作,下面是解决方案以及解决方案澄清之前的内容:
我早先犯的错误
- 不应该冲进 docker,应该先让 fat jar 在本地工作。
- withJava() 被遗漏了,这是 36 个工时的主要浪费...WTF 是这个函数的重点?
- dependsOn(build): 为什么 jar 任务类型不知道这个我不明白。
- main.compileDependencyFiles:我曾用它代替下面参数中的地图。
- main.output.classesDirs:其他解决方案中缺少,似乎包含您的实际代码。
注意:不需要影子插件,这太棒了(gradle 恕我直言,插件往往不能很好地协同工作)。
注意:版本控制很重要,因为在某些情况下,此堆栈的更改速度似乎比文档快大约 50 倍,以下用于此解决方案:
- 科特林 1.3.72
- Gradle6.5
- Ktor 1.3.2
代码:
//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 }
}
我希望这可以节省 3 天的时间,如果您发现改进请告诉我(我也在学习)。 Kotlin、gradle、多平台、docker...都很难处理,他们需要并行更新文档恕我直言,否则 jetbrains 就完蛋了。
潜在改进:
- 生成的 jar 看起来比应有的大很多,包含大量不必要的东西,怀疑更改为编译路径而不是运行时路径将解决这个问题(已确认大小减少 30%)。
- 也许有更多清单属性。
- 同样值得注意的是,我读到一篇文章恰当地建议不应将 fatJars 部署到 docker,java 依赖项应构建为图像的一部分。
这个对我有用 gradle 多平台 (mpp) 项目
编辑:
tasks {
named<JavaExec>("run") {
standardInput = System.`in`
classpath += objects.fileCollection().from(
named("compileKotlinJvm"),
configurations.named("jvmRuntimeClasspath")
)
}
shadowJar {
manifest { attributes["Main-Class"] = theMainClass }
val jvmJar = named<org.gradle.jvm.tasks.Jar>("jvmJar").get()
from(jvmJar.archiveFile)
configurations.add(project.configurations.named("jvmRuntimeClasspath").get())
}
}
---
旧版:
plugins {
kotlin("multiplatform") version Deps.JetBrains.Kotlin.VERSION
application
id("com.github.johnrengelman.shadow") version Deps.Plugins.Shadow.VERSION
}
application {
mainClass.set(theMainClass)
}
tasks {
val shadowCreate by creating(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
manifest { attributes["Main-Class"] = theMainClass }
archiveClassifier.set("fat")
mergeServiceFiles()
from(kotlin.jvm().compilations.getByName("main").output)
configurations = mutableListOf(kotlin.jvm().compilations.getByName("main").compileDependencyFiles as Configuration)
}
val build by existing {
dependsOn(shadowCreate)
}
}
tasks.named<JavaExec>("run") {
classpath += objects.fileCollection().from(
tasks.named("compileKotlinJvm"),
configurations.named("jvmRuntimeClasspath")
)
}
尝试为包含 ktor 服务器组件的 kotlin 多平台项目创建一个 运行nable jar,使用 Kotlin Gradle DSL 构建。
我看到了几个问题,包括
报告有效的 groovy 代码是:
kotlin {
jvm() {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'sample.MainKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
...
}
这将如何转化为 Kotlin DSL?我尝试了很多变体,其中一些变体可以编译 运行,但没有创建所需的输出... 运行nable jar。
你的groovydsl可以用kotlin写成如下
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) })
}
}
}
@andylamax 的答案非常接近,但导致了@cfnz 看到的错误
要解决此问题,您需要添加 doFirst
,如本例所示:
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) })
}
}
}
它在 here 和 gradle jvmJar && java -jar build/libs/laguna-jvm.jar
我花了 3 天时间试图让 fat jar 工作,下面是解决方案以及解决方案澄清之前的内容:
我早先犯的错误
- 不应该冲进 docker,应该先让 fat jar 在本地工作。
- withJava() 被遗漏了,这是 36 个工时的主要浪费...WTF 是这个函数的重点?
- dependsOn(build): 为什么 jar 任务类型不知道这个我不明白。
- main.compileDependencyFiles:我曾用它代替下面参数中的地图。
- main.output.classesDirs:其他解决方案中缺少,似乎包含您的实际代码。
注意:不需要影子插件,这太棒了(gradle 恕我直言,插件往往不能很好地协同工作)。
注意:版本控制很重要,因为在某些情况下,此堆栈的更改速度似乎比文档快大约 50 倍,以下用于此解决方案:
- 科特林 1.3.72
- Gradle6.5
- Ktor 1.3.2
代码:
//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 }
}
我希望这可以节省 3 天的时间,如果您发现改进请告诉我(我也在学习)。 Kotlin、gradle、多平台、docker...都很难处理,他们需要并行更新文档恕我直言,否则 jetbrains 就完蛋了。
潜在改进:
- 生成的 jar 看起来比应有的大很多,包含大量不必要的东西,怀疑更改为编译路径而不是运行时路径将解决这个问题(已确认大小减少 30%)。
- 也许有更多清单属性。
- 同样值得注意的是,我读到一篇文章恰当地建议不应将 fatJars 部署到 docker,java 依赖项应构建为图像的一部分。
这个对我有用 gradle 多平台 (mpp) 项目
编辑:
tasks {
named<JavaExec>("run") {
standardInput = System.`in`
classpath += objects.fileCollection().from(
named("compileKotlinJvm"),
configurations.named("jvmRuntimeClasspath")
)
}
shadowJar {
manifest { attributes["Main-Class"] = theMainClass }
val jvmJar = named<org.gradle.jvm.tasks.Jar>("jvmJar").get()
from(jvmJar.archiveFile)
configurations.add(project.configurations.named("jvmRuntimeClasspath").get())
}
}
---
旧版:
plugins {
kotlin("multiplatform") version Deps.JetBrains.Kotlin.VERSION
application
id("com.github.johnrengelman.shadow") version Deps.Plugins.Shadow.VERSION
}
application {
mainClass.set(theMainClass)
}
tasks {
val shadowCreate by creating(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
manifest { attributes["Main-Class"] = theMainClass }
archiveClassifier.set("fat")
mergeServiceFiles()
from(kotlin.jvm().compilations.getByName("main").output)
configurations = mutableListOf(kotlin.jvm().compilations.getByName("main").compileDependencyFiles as Configuration)
}
val build by existing {
dependsOn(shadowCreate)
}
}
tasks.named<JavaExec>("run") {
classpath += objects.fileCollection().from(
tasks.named("compileKotlinJvm"),
configurations.named("jvmRuntimeClasspath")
)
}