从 kotlin 多平台项目创建 fat jar
Create fat jar from kotlin multiplatform project
我最近从旧的 1.2 多平台切换到 1.3。不同之处在于,每个多平台模块有一个 build.gradle 文件(我有 5 个),因此配置要少得多。
但是,我似乎无法配置创建具有来自 jvm 平台的所有依赖项的可运行胖 jar。
我曾经在我的 jvm 项目和 jar 任务中使用标准 "application" 插件,但那不再起作用了。我发现有 "jvmJar" 任务并对其进行了修改(设置 Main-class),但是创建的 jar 不包含依赖项并且在 ClassNotFoundException 上崩溃。我该怎么做?
这是我现在拥有的:
jvm() {
jvmJar {
manifest {
attributes 'Main-Class': 'eu.xx.Runner'
}
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
我确实碰到了那个颠簸并使用了这个解决方法。
1。重组您的项目
我们称您的项目为 Project
。
创建另一个子模块,比如 subA
,它将具有 gradle 符号 Project:subA
现在,subA
在其 build.gradle
中包含了您的多平台代码(它是 gradle 应用了 :kotlin-multiplafrom 的项目)
2。添加另一个子模块
创建另一个仅针对 jvm 的子模块说 subB
,它将具有 gradle 符号 Project:subB
因此,subB
将有插件:'application'
和 'org.jetbrains.kotlin.jvm'
3。将您的模块添加为 gradle 依赖项(参见我的 build.gradle)
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.31'
id "application"
}
apply plugin: "kotlinx-serialization"
group 'tz.or.self'
version '0.0.0'
mainClassName = "com.example.MainKt"
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
dependencies {
implementation project(':subA')
}
您可以像常规 java 项目一样继续构建 subB,甚至可以使用现有的插件,它会起作用
在 kotlin 1.3.61 中使用多平台插件:
以下适用于 src/jvmMain/kotlin/com/example/Hello.kt
中的主文件
Hello.kt 还必须将其包指定为 package com.example
我是这样配置我的 jvm 目标的:
kotlin {
targets {
jvm()
configure([jvm]) {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'com.example.HelloKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
}
}
让它与 luca992 所做的稍微修改的版本一起工作:
kotlin {
jvm() {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'sample.MainKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
...
}
使 gradle/multiplatform 正常工作的唯一方法似乎是无休止的反复试验;这是一场噩梦,它不是作为“构建”系统构建的,而是作为“构建系统”构建的;换句话说,这两个工具(一起或单独)是一种仅实现插件制造商预期的单一软件开发生命周期的方法,但是,如果您已经设计了所需的软件生命周期并且 CI/CD系统,现在您尝试实施该工程,使用这些工具比使用脚本、代码或 Maven 更难。造成这种情况的原因有很多:
- 由于插件制造商只公开了最低限度的可配置性,编码约定发生了巨大变化,可能只允许访问他们自己的个人项目所需的东西。
- 文档更新非常糟糕; Kotlin、gradle 和插件变化如此之快,我开始严重质疑这些工具的实用性。
因此,在撰写本文时,这似乎是使用 kotlin 1.3.72、多平台 1.3.72、ktor 1.3.2 和 gradle 6.2.2(使用 kts格式)。
注意 fatJar 似乎 assemble 正确但不会 运行,它找不到 class,所以我包含了第二个 运行Locally 任务我一直在使用。
这不是一个完整的解决方案,所以我不想在这里发布它,但据我所知...这是我在任何地方都能找到的最完整和最新的解决方案。
//Import variables from gradle.properties
val environment: String by project
val kotlinVersion: String by project
val ktorVersion: String by project
val kotlinExposedVersion: String by project
val mySqlConnectorVersion: String by project
val logbackVersion: String by project
val romeToolsVersion: String by project
val klaxonVersion: String by project
val kotlinLoggingVersion: String by project
val skrapeItVersion: String by project
val jsoupVersion: String by project
val devWebApiServer: String by project
val devWebApiServerVersion: 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 {
compilations {
val main = getByName("main")
tasks {
register<Jar>("buildFatJar") {
group = "application"
manifest {
attributes["Implementation-Title"] = "Gradle Jar File Example"
attributes["Implementation-Version"] = archiveVersion
attributes["Main-Class"] = "com.app.BackendAppKt"
}
archiveBaseName.set("${project.name}-fat")
from(main.output.classesDirs, main.compileDependencyFiles)
with(jar.get() as CopySpec)
}
register<JavaExec>("runLocally") {
group = "application"
setMain("com.app.BackendAppKt")
classpath = main.output.classesDirs
classpath += main.compileDependencyFiles
}
}
}
}
js {
browser { EXCLUDED FOR LENGTH }
}
sourceSets { EXCLUDED FOR LENGTH }
}
我最近从旧的 1.2 多平台切换到 1.3。不同之处在于,每个多平台模块有一个 build.gradle 文件(我有 5 个),因此配置要少得多。 但是,我似乎无法配置创建具有来自 jvm 平台的所有依赖项的可运行胖 jar。 我曾经在我的 jvm 项目和 jar 任务中使用标准 "application" 插件,但那不再起作用了。我发现有 "jvmJar" 任务并对其进行了修改(设置 Main-class),但是创建的 jar 不包含依赖项并且在 ClassNotFoundException 上崩溃。我该怎么做?
这是我现在拥有的:
jvm() {
jvmJar {
manifest {
attributes 'Main-Class': 'eu.xx.Runner'
}
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
我确实碰到了那个颠簸并使用了这个解决方法。
1。重组您的项目
我们称您的项目为 Project
。
创建另一个子模块,比如 subA
,它将具有 gradle 符号 Project:subA
现在,subA
在其 build.gradle
2。添加另一个子模块
创建另一个仅针对 jvm 的子模块说 subB
,它将具有 gradle 符号 Project:subB
因此,subB
将有插件:'application'
和 'org.jetbrains.kotlin.jvm'
3。将您的模块添加为 gradle 依赖项(参见我的 build.gradle)
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.31'
id "application"
}
apply plugin: "kotlinx-serialization"
group 'tz.or.self'
version '0.0.0'
mainClassName = "com.example.MainKt"
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
dependencies {
implementation project(':subA')
}
您可以像常规 java 项目一样继续构建 subB,甚至可以使用现有的插件,它会起作用
在 kotlin 1.3.61 中使用多平台插件:
以下适用于 src/jvmMain/kotlin/com/example/Hello.kt
Hello.kt 还必须将其包指定为 package com.example
我是这样配置我的 jvm 目标的:
kotlin {
targets {
jvm()
configure([jvm]) {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'com.example.HelloKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
}
}
让它与 luca992 所做的稍微修改的版本一起工作:
kotlin {
jvm() {
withJava()
jvmJar {
manifest {
attributes 'Main-Class': 'sample.MainKt'
}
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
...
}
使 gradle/multiplatform 正常工作的唯一方法似乎是无休止的反复试验;这是一场噩梦,它不是作为“构建”系统构建的,而是作为“构建系统”构建的;换句话说,这两个工具(一起或单独)是一种仅实现插件制造商预期的单一软件开发生命周期的方法,但是,如果您已经设计了所需的软件生命周期并且 CI/CD系统,现在您尝试实施该工程,使用这些工具比使用脚本、代码或 Maven 更难。造成这种情况的原因有很多:
- 由于插件制造商只公开了最低限度的可配置性,编码约定发生了巨大变化,可能只允许访问他们自己的个人项目所需的东西。
- 文档更新非常糟糕; Kotlin、gradle 和插件变化如此之快,我开始严重质疑这些工具的实用性。
因此,在撰写本文时,这似乎是使用 kotlin 1.3.72、多平台 1.3.72、ktor 1.3.2 和 gradle 6.2.2(使用 kts格式)。
注意 fatJar 似乎 assemble 正确但不会 运行,它找不到 class,所以我包含了第二个 运行Locally 任务我一直在使用。
这不是一个完整的解决方案,所以我不想在这里发布它,但据我所知...这是我在任何地方都能找到的最完整和最新的解决方案。
//Import variables from gradle.properties
val environment: String by project
val kotlinVersion: String by project
val ktorVersion: String by project
val kotlinExposedVersion: String by project
val mySqlConnectorVersion: String by project
val logbackVersion: String by project
val romeToolsVersion: String by project
val klaxonVersion: String by project
val kotlinLoggingVersion: String by project
val skrapeItVersion: String by project
val jsoupVersion: String by project
val devWebApiServer: String by project
val devWebApiServerVersion: 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 {
compilations {
val main = getByName("main")
tasks {
register<Jar>("buildFatJar") {
group = "application"
manifest {
attributes["Implementation-Title"] = "Gradle Jar File Example"
attributes["Implementation-Version"] = archiveVersion
attributes["Main-Class"] = "com.app.BackendAppKt"
}
archiveBaseName.set("${project.name}-fat")
from(main.output.classesDirs, main.compileDependencyFiles)
with(jar.get() as CopySpec)
}
register<JavaExec>("runLocally") {
group = "application"
setMain("com.app.BackendAppKt")
classpath = main.output.classesDirs
classpath += main.compileDependencyFiles
}
}
}
}
js {
browser { EXCLUDED FOR LENGTH }
}
sourceSets { EXCLUDED FOR LENGTH }
}