Skip to content

Commit 7f5351b

Browse files
committed
Generate module-info using jdeps and include it in the JAR
1 parent 45585a1 commit 7f5351b

File tree

4 files changed

+55
-111
lines changed

4 files changed

+55
-111
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ val JDK_11 by ext(jdkPath(11))
2727

2828
allprojects {
2929
repositories {
30+
mavenLocal()
3031
mavenCentral()
3132
}
3233
}

buildSrc/build.gradle.kts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import java.util.Properties
1+
import org.jetbrains.kotlin.gradle.plugin.*
2+
import java.util.*
23

34
plugins {
45
`kotlin-dsl`
@@ -7,11 +8,3 @@ plugins {
78
repositories {
89
mavenCentral()
910
}
10-
11-
val kotlinVersion = file("../gradle.properties").inputStream().use {
12-
Properties().apply { load(it) }
13-
}.getProperty("kotlinVersion") ?: throw IllegalStateException("Property 'kotlinVersion' must be defined in ../gradle.properties")
14-
15-
dependencies {
16-
implementation(kotlin("gradle-plugin", kotlinVersion))
17-
}
Lines changed: 52 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,63 @@
1-
import org.gradle.api.*
2-
import org.gradle.api.tasks.bundling.*
3-
import org.gradle.api.tasks.compile.*
4-
import org.gradle.kotlin.dsl.*
5-
import org.jetbrains.kotlin.gradle.dsl.*
6-
import org.jetbrains.kotlin.gradle.plugin.mpp.*
7-
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
8-
import org.jetbrains.kotlin.gradle.targets.jvm.*
9-
import java.io.*
1+
import org.gradle.api.Project
2+
import org.gradle.api.tasks.bundling.Jar
3+
import org.gradle.api.tasks.compile.AbstractCompile
4+
import org.gradle.api.tasks.compile.JavaCompile
5+
import org.gradle.kotlin.dsl.register
6+
import java.util.spi.ToolProvider
107

118
object Java9Modularity {
12-
139
@JvmStatic
14-
@JvmOverloads
15-
fun configureJava9ModuleInfo(project: Project, multiRelease: Boolean = true) {
16-
val kotlin = project.extensions.findByType<KotlinProjectExtension>() ?: return
17-
project.configureModuleInfoForKotlinProject(kotlin, multiRelease)
18-
}
19-
20-
private fun Project.configureModuleInfoForKotlinProject(kotlin: KotlinProjectExtension, multiRelease: Boolean = true) {
21-
val jvmTargets = kotlin.targets.filter { it is KotlinJvmTarget || it is KotlinWithJavaTarget<*> }
22-
if (jvmTargets.isEmpty()) {
23-
logger.warn("No Kotlin JVM targets found, can't configure compilation of module-info!")
24-
}
25-
jvmTargets.forEach { target ->
26-
val artifactTask = tasks.getByName<Jar>(target.artifactsTaskName) {
27-
if (multiRelease) {
28-
manifest {
29-
attributes("Multi-Release" to true)
10+
fun configureJava9ModuleInfo(project: Project) {
11+
project.afterEvaluate {
12+
val jdeps = ToolProvider.findFirst("jdeps").orElseThrow { IllegalStateException("Tool 'jdeps' is not available") }
13+
val compileKotlinJvm = tasks.findByName("compileKotlinJvm") as AbstractCompile?
14+
val jvmJar = tasks.findByName("jvmJar") as Jar?
15+
16+
if (compileKotlinJvm != null && jvmJar != null) {
17+
val modularityDir = buildDir.resolve("modularity")
18+
val generatedDir = modularityDir.resolve("generated")
19+
val classesDir = modularityDir.resolve("classes")
20+
val jvmGenerateModuleInfo = tasks.register("jvmGenerateModuleInfo", Jar::class) {
21+
dependsOn(compileKotlinJvm)
22+
destinationDirectory.set(modularityDir)
23+
from(jvmJar.source)
24+
exclude { it.file.startsWith(classesDir) }
25+
doLast {
26+
generatedDir.deleteRecursively()
27+
jdeps.run(
28+
System.out, System.err,
29+
"--multi-release", "9",
30+
"--generate-module-info", generatedDir.toString(),
31+
"--module-path", compileKotlinJvm.classpath.asPath,
32+
archiveFile.get().toString()
33+
)
3034
}
3135
}
32-
}
33-
34-
target.compilations.forEach { compilation ->
35-
val compileKotlinTask = compilation.compileKotlinTask as AbstractCompile
36-
val defaultSourceSet = compilation.defaultSourceSet
37-
38-
// derive the names of the source set and compile module task
39-
val sourceSetName = defaultSourceSet.name + "Module"
40-
val compileModuleTaskName = compileKotlinTask.name + "Module"
41-
42-
kotlin.sourceSets.create(sourceSetName) {
43-
val sourceFile = this.kotlin.find { it.name == "module-info.java" }
44-
val targetFile = compileKotlinTask.destinationDirectory.file("../module-info.class").get().asFile
45-
46-
// only configure the compilation if necessary
47-
if (sourceFile != null) {
48-
// the default source set depends on this new source set
49-
defaultSourceSet.dependsOn(this)
50-
51-
// register a new compile module task
52-
val compileModuleTask = registerCompileModuleTask(compileModuleTaskName, compileKotlinTask, sourceFile, targetFile)
53-
54-
// add the resulting module descriptor to this target's artifact
55-
artifactTask.dependsOn(compileModuleTask)
56-
artifactTask.from(targetFile) {
57-
if (multiRelease) {
58-
into("META-INF/versions/9/")
59-
}
60-
}
61-
} else {
62-
logger.info("No module-info.java file found in ${this.kotlin.srcDirs}, can't configure compilation of module-info!")
63-
// remove the source set to prevent Gradle warnings
64-
kotlin.sourceSets.remove(this)
36+
val jvmCompileModuleInfo = tasks.register("jvmCompileModuleInfo", JavaCompile::class) {
37+
dependsOn(jvmGenerateModuleInfo)
38+
destinationDirectory.set(classesDir)
39+
source(generatedDir)
40+
classpath = files()
41+
doFirst {
42+
val moduleName = generatedDir.listFiles().first().name
43+
options.compilerArgs = listOf(
44+
"--release", "9",
45+
"--module-path", compileKotlinJvm.classpath.asPath,
46+
"--patch-module", "$moduleName=${compileKotlinJvm.destinationDir}",
47+
"-Xlint:-requires-transitive-automatic"
48+
)
49+
}
50+
}
51+
jvmJar.apply {
52+
dependsOn(jvmCompileModuleInfo)
53+
from(classesDir) {
54+
into("META-INF/versions/9")
55+
}
56+
manifest {
57+
attributes(jvmJar.manifest.attributes + mapOf("Multi-Release" to true))
6558
}
6659
}
6760
}
6861
}
6962
}
70-
71-
private fun Project.registerCompileModuleTask(taskName: String, compileTask: AbstractCompile, sourceFile: File, targetFile: File) =
72-
tasks.register(taskName, JavaCompile::class) {
73-
// Also add the module-info.java source file to the Kotlin compile task;
74-
// the Kotlin compiler will parse and check module dependencies,
75-
// but it currently won't compile to a module-info.class file.
76-
compileTask.source(sourceFile)
77-
78-
79-
// Configure the module compile task.
80-
dependsOn(compileTask)
81-
source(sourceFile)
82-
outputs.file(targetFile)
83-
classpath = files()
84-
destinationDirectory.set(compileTask.destinationDirectory)
85-
sourceCompatibility = JavaVersion.VERSION_1_9.toString()
86-
targetCompatibility = JavaVersion.VERSION_1_9.toString()
87-
88-
doFirst {
89-
// Provide the module path to the compiler instead of using a classpath.
90-
// The module path should be the same as the classpath of the compiler.
91-
options.compilerArgs = listOf(
92-
"--release", "9",
93-
"--module-path", compileTask.classpath.asPath,
94-
"-Xlint:-requires-transitive-automatic"
95-
)
96-
}
97-
98-
doLast {
99-
// Move the compiled file out of the Kotlin compile task's destination dir,
100-
// so it won't disturb Gradle's caching mechanisms.
101-
val compiledFile = destinationDirectory.file(targetFile.name).get().asFile
102-
targetFile.parentFile.mkdirs()
103-
compiledFile.renameTo(targetFile)
104-
}
105-
}
10663
}

core/jvmMain/module/module-info.java

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)