Skip to content

Commit

Permalink
Generate JPMS modules (#406)
Browse files Browse the repository at this point in the history
  • Loading branch information
fzhinkin authored Oct 21, 2024
1 parent 7e0b9b4 commit fa3afc3
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 0 deletions.
90 changes: 90 additions & 0 deletions build-logic/src/main/kotlin/MultiReleaseJarUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file.
*/

package kotlinx.io.build

import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.withType
import org.gradle.process.CommandLineArgumentProvider
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import java.util.*

private val Project.sourceSets: SourceSetContainer
get() = this.extensions.getByName("sourceSets") as SourceSetContainer

private val Project.javaToolchains: JavaToolchainService
get() = this.extensions.getByName("javaToolchains") as JavaToolchainService


/**
* Setup tasks to compile `module-info.java` file for a module named [moduleName]
* from a source set with name [sourceSetName] using Java toolchain with version [toolchainVersion].
* It is assumed that source set with [sourceSetName] only extends main JVM source set.
* [parentCompilation] represent a compilation corresponding to such a main source set.
*/
public fun Project.configureJava9ModuleInfoCompilation(
sourceSetName: String,
toolchainVersion: JavaLanguageVersion,
parentCompilation: KotlinJvmCompilation,
moduleName: String
) {
val moduleOutputs = listOf(parentCompilation.output.allOutputs)
val compileClasspathConfiguration = parentCompilation.configurations.compileDependencyConfiguration
val sourceSetNameCapitalized = sourceSetName.replaceFirstChar { it.titlecase(Locale.getDefault()) }
val javaCompileClasspath = configurations["${sourceSetName}CompileClasspath"]
javaCompileClasspath.extendsFrom(compileClasspathConfiguration)

tasks.named("compile${sourceSetNameCapitalized}Java", JavaCompile::class.java) {
dependsOn(moduleOutputs)

targetCompatibility = "9"
sourceCompatibility = "9"

javaCompiler.set(
javaToolchains.compilerFor {
languageVersion.set(toolchainVersion)
}
)

val javaSourceSet = sourceSets[sourceSetName].java
destinationDirectory.set(
javaSourceSet.destinationDirectory.asFile.get()
.resolve("META-INF/versions/9")
)
options.sourcepath = files(javaSourceSet.srcDirs)
val moduleFiles = objects.fileCollection().from(moduleOutputs)
val modulePath = javaCompileClasspath.filter { it !in moduleFiles.files }
dependsOn(modulePath)
classpath = objects.fileCollection().from()
options.compilerArgumentProviders.add(
JigsawArgumentsProvider(
moduleName,
moduleFiles,
modulePath
)
)
}
}

private class JigsawArgumentsProvider(
private val moduleName: String,
private val moduleFiles: FileCollection,
private val modulePath: FileCollection
) : CommandLineArgumentProvider {
override fun asArguments(): Iterable<String> = listOf(
"--module-path", modulePath.asPath,
"--patch-module", "$moduleName=${moduleFiles.asPath}",
"--release", "9"
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file.
*/

import kotlinx.io.build.configureJava9ModuleInfoCompilation
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
Expand Down Expand Up @@ -41,6 +42,20 @@ kotlin {
}
}
}

val mrjToolchain = versionCatalog.findVersion("multi.release.toolchain").getOrNull()?.requiredVersion
?: throw GradleException("Version 'multi.release.toolchain' is not specified in the version catalog")

// N.B.: it seems like modules don't work well with "regular" multi-release compilation,
// so if we need to compile some Kotlin classes for a specific JDK release, a separate compilation is needed.
configureJava9ModuleInfoCompilation(
sourceSetName = project.sourceSets.create("java9ModuleInfo") {
java.srcDir("jvm/module")
}.name,
parentCompilation = compilations.getByName("main"),
moduleName = project.name.replace("-", "."),
toolchainVersion = JavaLanguageVersion.of(mrjToolchain)
)
}

js {
Expand Down Expand Up @@ -104,6 +119,15 @@ kotlin {
}
}
}

tasks {
val jvmJar by existing(Jar::class) {
manifest {
attributes("Multi-Release" to true)
}
from(project.sourceSets["java9ModuleInfo"].output)
}
}
}

fun KotlinSourceSet.configureSourceSet() {
Expand Down
6 changes: 6 additions & 0 deletions bytestring/jvm/module/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module kotlinx.io.bytestring {
requires transitive kotlin.stdlib;

exports kotlinx.io.bytestring;
exports kotlinx.io.bytestring.unsafe;
}
8 changes: 8 additions & 0 deletions core/jvm/module/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module kotlinx.io.core {
requires transitive kotlin.stdlib;
requires transitive kotlinx.io.bytestring;

exports kotlinx.io;
exports kotlinx.io.files;
exports kotlinx.io.unsafe;
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[versions]
kotlin = "2.0.0"
java = "8"
multi-release-toolchain = "17"
dokka = "1.9.20"
kover = "0.8.2"
bcv = "0.16.3"
Expand Down

0 comments on commit fa3afc3

Please sign in to comment.