Skip to content

Commit fa3afc3

Browse files
authored
Generate JPMS modules (#406)
1 parent 7e0b9b4 commit fa3afc3

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2017-2024 JetBrains s.r.o. and respective authors and developers.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file.
4+
*/
5+
6+
package kotlinx.io.build
7+
8+
import org.gradle.api.Project
9+
import org.gradle.api.file.FileCollection
10+
import org.gradle.api.tasks.SourceSetContainer
11+
import org.gradle.api.tasks.compile.JavaCompile
12+
import org.gradle.jvm.toolchain.JavaLanguageVersion
13+
import org.gradle.jvm.toolchain.JavaToolchainService
14+
import org.gradle.kotlin.dsl.get
15+
import org.gradle.kotlin.dsl.withType
16+
import org.gradle.process.CommandLineArgumentProvider
17+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
18+
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
19+
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
20+
import java.util.*
21+
22+
private val Project.sourceSets: SourceSetContainer
23+
get() = this.extensions.getByName("sourceSets") as SourceSetContainer
24+
25+
private val Project.javaToolchains: JavaToolchainService
26+
get() = this.extensions.getByName("javaToolchains") as JavaToolchainService
27+
28+
29+
/**
30+
* Setup tasks to compile `module-info.java` file for a module named [moduleName]
31+
* from a source set with name [sourceSetName] using Java toolchain with version [toolchainVersion].
32+
33+
* It is assumed that source set with [sourceSetName] only extends main JVM source set.
34+
* [parentCompilation] represent a compilation corresponding to such a main source set.
35+
*/
36+
public fun Project.configureJava9ModuleInfoCompilation(
37+
sourceSetName: String,
38+
toolchainVersion: JavaLanguageVersion,
39+
parentCompilation: KotlinJvmCompilation,
40+
moduleName: String
41+
) {
42+
val moduleOutputs = listOf(parentCompilation.output.allOutputs)
43+
val compileClasspathConfiguration = parentCompilation.configurations.compileDependencyConfiguration
44+
val sourceSetNameCapitalized = sourceSetName.replaceFirstChar { it.titlecase(Locale.getDefault()) }
45+
val javaCompileClasspath = configurations["${sourceSetName}CompileClasspath"]
46+
javaCompileClasspath.extendsFrom(compileClasspathConfiguration)
47+
48+
tasks.named("compile${sourceSetNameCapitalized}Java", JavaCompile::class.java) {
49+
dependsOn(moduleOutputs)
50+
51+
targetCompatibility = "9"
52+
sourceCompatibility = "9"
53+
54+
javaCompiler.set(
55+
javaToolchains.compilerFor {
56+
languageVersion.set(toolchainVersion)
57+
}
58+
)
59+
60+
val javaSourceSet = sourceSets[sourceSetName].java
61+
destinationDirectory.set(
62+
javaSourceSet.destinationDirectory.asFile.get()
63+
.resolve("META-INF/versions/9")
64+
)
65+
options.sourcepath = files(javaSourceSet.srcDirs)
66+
val moduleFiles = objects.fileCollection().from(moduleOutputs)
67+
val modulePath = javaCompileClasspath.filter { it !in moduleFiles.files }
68+
dependsOn(modulePath)
69+
classpath = objects.fileCollection().from()
70+
options.compilerArgumentProviders.add(
71+
JigsawArgumentsProvider(
72+
moduleName,
73+
moduleFiles,
74+
modulePath
75+
)
76+
)
77+
}
78+
}
79+
80+
private class JigsawArgumentsProvider(
81+
private val moduleName: String,
82+
private val moduleFiles: FileCollection,
83+
private val modulePath: FileCollection
84+
) : CommandLineArgumentProvider {
85+
override fun asArguments(): Iterable<String> = listOf(
86+
"--module-path", modulePath.asPath,
87+
"--patch-module", "$moduleName=${moduleFiles.asPath}",
88+
"--release", "9"
89+
)
90+
}

build-logic/src/main/kotlin/kotlinx/io/conventions/kotlinx-io-multiplatform.gradle.kts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file.
44
*/
55

6+
import kotlinx.io.build.configureJava9ModuleInfoCompilation
67
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
78
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
89
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
@@ -41,6 +42,20 @@ kotlin {
4142
}
4243
}
4344
}
45+
46+
val mrjToolchain = versionCatalog.findVersion("multi.release.toolchain").getOrNull()?.requiredVersion
47+
?: throw GradleException("Version 'multi.release.toolchain' is not specified in the version catalog")
48+
49+
// N.B.: it seems like modules don't work well with "regular" multi-release compilation,
50+
// so if we need to compile some Kotlin classes for a specific JDK release, a separate compilation is needed.
51+
configureJava9ModuleInfoCompilation(
52+
sourceSetName = project.sourceSets.create("java9ModuleInfo") {
53+
java.srcDir("jvm/module")
54+
}.name,
55+
parentCompilation = compilations.getByName("main"),
56+
moduleName = project.name.replace("-", "."),
57+
toolchainVersion = JavaLanguageVersion.of(mrjToolchain)
58+
)
4459
}
4560

4661
js {
@@ -104,6 +119,15 @@ kotlin {
104119
}
105120
}
106121
}
122+
123+
tasks {
124+
val jvmJar by existing(Jar::class) {
125+
manifest {
126+
attributes("Multi-Release" to true)
127+
}
128+
from(project.sourceSets["java9ModuleInfo"].output)
129+
}
130+
}
107131
}
108132

109133
fun KotlinSourceSet.configureSourceSet() {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module kotlinx.io.bytestring {
2+
requires transitive kotlin.stdlib;
3+
4+
exports kotlinx.io.bytestring;
5+
exports kotlinx.io.bytestring.unsafe;
6+
}

core/jvm/module/module-info.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module kotlinx.io.core {
2+
requires transitive kotlin.stdlib;
3+
requires transitive kotlinx.io.bytestring;
4+
5+
exports kotlinx.io;
6+
exports kotlinx.io.files;
7+
exports kotlinx.io.unsafe;
8+
}

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[versions]
22
kotlin = "2.0.0"
33
java = "8"
4+
multi-release-toolchain = "17"
45
dokka = "1.9.20"
56
kover = "0.8.2"
67
bcv = "0.16.3"

0 commit comments

Comments
 (0)