|
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 |
10 | 7 |
|
11 | 8 | object Java9Modularity {
|
12 |
| - |
13 | 9 | @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 | + ) |
30 | 34 | }
|
31 | 35 | }
|
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)) |
65 | 58 | }
|
66 | 59 | }
|
67 | 60 | }
|
68 | 61 | }
|
69 | 62 | }
|
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 |
| - } |
106 | 63 | }
|
0 commit comments