Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

- Add Kotlin DSL examples in docs. ([#1306](https://github.com/GradleUp/shadow/pull/1306))
- Support using type-safe dependency accessors in `ShadowJar.dependencies`. ([#1322](https://github.com/GradleUp/shadow/pull/1322))
- Set `Main-Class` attr for KMP 2.1.0 or above. ([#1337](https://github.com/GradleUp/shadow/pull/1337))

**Changed**

Expand Down
10 changes: 8 additions & 2 deletions docs/kmp-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ configure additional tasks for bundling the shadowed JAR for its `jvm` target.
val ktorVersion = "3.1.0"

kotlin {
jvm()
jvm().mainRun {
// Optionally, set the main class for `runJvm`, it's available from Kotlin 2.1.0
mainClass = "myapp.MainKt"
}
sourceSets {
val commonMain by getting {
dependencies {
Expand Down Expand Up @@ -49,7 +52,10 @@ configure additional tasks for bundling the shadowed JAR for its `jvm` target.
def ktorVersion = "3.1.0"

kotlin {
jvm()
jvm().mainRun {
// Optionally, set the main class for `runJvm`, it's available from Kotlin 2.1.0
it.mainClass.set('myapp.MainKt')
}
sourceSets {
commonMain {
dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.github.jengelman.gradle.plugins.shadow

import assertk.assertThat
import assertk.assertions.isEqualTo
import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
import com.github.jengelman.gradle.plugins.shadow.util.containsEntries
import com.github.jengelman.gradle.plugins.shadow.util.getMainAttr
import kotlin.io.path.appendText
import kotlin.io.path.writeText
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class KmpPluginTest : BasePluginTest() {
@BeforeEach
Expand Down Expand Up @@ -51,4 +56,42 @@ class KmpPluginTest : BasePluginTest() {
)
}
}

@ParameterizedTest
@ValueSource(booleans = [false, true])
fun canSetMainClassAttribute(useShadowAttr: Boolean) {
val mainClassEntry = writeClass(sourceSet = "jvmMain", isJava = false)
val main2ClassEntry = writeClass(sourceSet = "jvmMain", isJava = false, className = "Main2")
val mainClassName = "my.Main"
val main2ClassName = "my.Main2"
val mainAttr = if (useShadowAttr) "attributes '$mainClassAttributeKey': '$main2ClassName'" else ""
projectScriptPath.appendText(
"""
kotlin {
jvm().mainRun {
it.mainClass.set('$mainClassName')
}
}
$shadowJar {
manifest {
$mainAttr
}
}
""".trimIndent(),
)

run(shadowJarTask)

assertThat(outputShadowJar).useAll {
containsEntries(
mainClassEntry,
main2ClassEntry,
)
if (useShadowAttr) {
getMainAttr(mainClassAttributeKey).isEqualTo(main2ClassName)
} else {
getMainAttr("Main-Class").isEqualTo(mainClassName)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package com.github.jengelman.gradle.plugins.shadow

import com.github.jengelman.gradle.plugins.shadow.ShadowJavaPlugin.Companion.registerShadowJarCommon
import com.github.jengelman.gradle.plugins.shadow.internal.mainClassAttributeKey
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import kotlin.collections.contains
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion as KgpVersion

public abstract class ShadowKmpPlugin : Plugin<Project> {
private lateinit var kmpExtension: KotlinMultiplatformExtension

override fun apply(project: Project) {
with(project) {
val kmpExtension = extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension = extensions.getByType(KotlinMultiplatformExtension::class.java)
val kotlinJvmMain = kmpExtension.jvm().compilations.named("main")
registerShadowJarCommon { task ->
task.from(kotlinJvmMain.map { it.output.allOutputs })
Expand All @@ -18,6 +24,24 @@ public abstract class ShadowKmpPlugin : Plugin<Project> {
listOf(configurations.getByName(kotlinJvmMain.get().runtimeDependencyConfigurationName))
},
)
configureMainClass(task)
}
}
}

private fun Project.configureMainClass(task: ShadowJar) {
if (KgpVersion.DEFAULT < KgpVersion.KOTLIN_2_1) return

@OptIn(ExperimentalKotlinGradlePluginApi::class)
kmpExtension.jvm().mainRun {
// Fix cannot serialize object of type 'org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRun'.
val mainClassName = provider { mainClass }
task.inputs.property("mainClassName", mainClassName)
task.doFirst {
val realClass = mainClassName.get().orNull
if (!task.manifest.attributes.contains(mainClassAttributeKey) && !realClass.isNullOrEmpty()) {
task.manifest.attributes[mainClassAttributeKey] = realClass
}
}
}
}
Expand Down