Fix compilation against JRE 9 on JPS

Write the modular JDK (9+) path to the module.xml file passed to the
compiler from the JPS plugin. This path is then recorded in the compiler
configuration in KotlinToJVMBytecodeCompiler.configureSourceRoots. This
is needed because in JPS plugin, we pass "-no-jdk" and thus no JDK home
path was recorded in the compiler configuration in
K2JVMCompiler.setupJdkClasspathRoots. Presence of JDK home path in the
configuration is crucial for JDK 9 support (see
KotlinCoreEnvironment.Companion.createApplicationEnvironment), because
classes there can only be loaded with the special "jrt" file system, not
as .class files in .jar files

 #KT-17801 Fixed

Original commit: 965b4199f4
This commit is contained in:
Alexander Udalov
2017-05-16 13:04:10 +03:00
parent f679043929
commit 7231c777c1
7 changed files with 101 additions and 8 deletions
@@ -21,10 +21,12 @@ import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.testFramework.LightVirtualFile
import com.intellij.testFramework.UsefulTestCase
import com.intellij.util.ArrayUtil
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.io.URLUtil
import com.intellij.util.io.ZipUtil
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.api.CanceledStatus
@@ -45,6 +47,8 @@ import org.jetbrains.jps.model.JpsModuleRootModificationUtil
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.java.JpsJavaSdkType
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.codegen.AsmUtil
@@ -899,6 +903,18 @@ class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() {
KotlinTestUtils.assertEqualsToFile(expectedFile, actual.toString())
}
fun testJre9() {
val path = KotlinTestUtils.getJre9HomeIfPossible()?.absolutePath ?: return
val jdk = myModel.global.addSdk(JDK_NAME, path, "9", JpsJavaSdkType.INSTANCE)
jdk.addRoot(StandardFileSystems.JRT_PROTOCOL_PREFIX + path + URLUtil.JAR_SEPARATOR + "java.base", JpsOrderRootType.COMPILED)
loadProject(workDir.absolutePath + File.separator + PROJECT_NAME + ".ipr")
addKotlinRuntimeDependency()
buildAllModules().assertSuccessful()
}
private fun BuildResult.checkErrors() {
val actualErrors = getMessages(BuildMessage.Kind.ERROR)
.map { it as CompilerMessage }
@@ -46,6 +46,7 @@ class ClasspathOrderTest : TestCaseWithTmpdir() {
listOf(sourceDir),
listOf(JvmSourceRoot(sourceDir)),
listOf(PathUtil.getKotlinPathsForDistDirectory().runtimePath),
null,
JavaModuleBuildTargetType.PRODUCTION.typeId,
JavaModuleBuildTargetType.PRODUCTION.isTests,
setOf(),
@@ -33,10 +33,11 @@ public class KotlinModuleXmlGeneratorTest extends TestCase {
Arrays.asList(new File("s1"), new File("s2")),
Collections.singletonList(new JvmSourceRoot(new File("java"), null)),
Arrays.asList(new File("cp1"), new File("cp2")),
null,
JavaModuleBuildTargetType.PRODUCTION.getTypeId(),
JavaModuleBuildTargetType.PRODUCTION.isTests(),
Collections.<File>emptySet(),
Collections.<File>emptyList()
Collections.emptySet(),
Collections.emptyList()
).asText().toString();
KotlinTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/basic.xml"), actual);
}
@@ -46,12 +47,13 @@ public class KotlinModuleXmlGeneratorTest extends TestCase {
"name",
"output",
Arrays.asList(new File("s1"), new File("s2")),
Collections.<JvmSourceRoot>emptyList(),
Collections.emptyList(),
Arrays.asList(new File("cp1"), new File("cp2")),
null,
JavaModuleBuildTargetType.PRODUCTION.getTypeId(),
JavaModuleBuildTargetType.PRODUCTION.isTests(),
Collections.singleton(new File("cp1")),
Collections.<File>emptyList()
Collections.emptyList()
).asText().toString();
KotlinTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/filtered.xml"), actual);
}
@@ -62,25 +64,43 @@ public class KotlinModuleXmlGeneratorTest extends TestCase {
"name",
"output",
Arrays.asList(new File("s1"), new File("s2")),
Collections.<JvmSourceRoot>emptyList(),
Collections.emptyList(),
Arrays.asList(new File("cp1"), new File("cp2")),
null,
JavaModuleBuildTargetType.PRODUCTION.getTypeId(),
JavaModuleBuildTargetType.PRODUCTION.isTests(),
Collections.singleton(new File("cp1")),
Collections.<File>emptyList()
Collections.emptyList()
);
builder.addModule(
"name2",
"output2",
Arrays.asList(new File("s12"), new File("s22")),
Collections.<JvmSourceRoot>emptyList(),
Collections.emptyList(),
Arrays.asList(new File("cp12"), new File("cp22")),
null,
JavaModuleBuildTargetType.TEST.getTypeId(),
JavaModuleBuildTargetType.TEST.isTests(),
Collections.singleton(new File("cp12")),
Collections.<File>emptyList()
Collections.emptyList()
);
String actual = builder.asText().toString();
KotlinTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/multiple.xml"), actual);
}
public void testModularJdkRoot() throws Exception {
String actual = new KotlinModuleXmlBuilder().addModule(
"name",
"output",
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
new File("/path/to/modular/jdk"),
JavaModuleBuildTargetType.PRODUCTION.getTypeId(),
JavaModuleBuildTargetType.PRODUCTION.isTests(),
Collections.emptySet(),
Collections.emptyList()
).asText().toString();
KotlinTestUtils.assertEqualsToFile(new File("idea/testData/modules.xml/modularJdkRoot.xml"), actual);
}
}
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.jps.build
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.MultiMap
import com.intellij.util.io.URLUtil
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType
import org.jetbrains.jps.incremental.CompileContext
@@ -28,6 +30,7 @@ import org.jetbrains.jps.incremental.ModuleBuildTarget
import org.jetbrains.jps.incremental.ProjectBuildException
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsSdkDependency
import org.jetbrains.kotlin.build.JvmSourceRoot
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.jps.build.JpsUtils.getAllDependencies
@@ -113,6 +116,7 @@ object KotlinBuilderModuleScriptGenerator {
moduleSources,
findSourceRoots(context, target),
findClassPathRoots(target),
findModularJdkRoot(target),
targetId.type,
(targetType as JavaModuleBuildTargetType).isTests,
// this excludes the output directories from the class path, to be removed for true incremental compilation
@@ -162,6 +166,18 @@ object KotlinBuilderModuleScriptGenerator {
}
}
private fun findModularJdkRoot(target: ModuleBuildTarget): File? {
// List of paths to JRE modules in the following format:
// jrt:///Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home!/java.base
val urls = JpsJavaExtensionService.dependencies(target.module)
.satisfying { dependency -> dependency is JpsSdkDependency }
.classes().urls
val url = urls.firstOrNull { it.startsWith(StandardFileSystems.JRT_PROTOCOL_PREFIX) } ?: return null
return File(url.substringAfter(StandardFileSystems.JRT_PROTOCOL_PREFIX).substringBeforeLast(URLUtil.JAR_SEPARATOR))
}
private fun findSourceRoots(context: CompileContext, target: ModuleBuildTarget): List<JvmSourceRoot> {
val roots = context.projectDescriptor.buildRootIndex.getTargetRoots(target, context)
val result = ContainerUtil.newArrayList<JvmSourceRoot>()
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="IDEA_JDK" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="kotlinProject" />
</component>
</module>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
</component>
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/kotlinProject.iml" filepath="$PROJECT_DIR$/kotlinProject.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA_JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
@@ -0,0 +1,14 @@
import java.nio.file.Path
import java.util.stream.IntStream
import java.util.function.Consumer
class Foo : Consumer<Path> {
override fun accept(path: Path) {}
}
fun foo(s: IntStream): List<String> {
println(s.boxed())
Any()
if (s.count() == 0L) throw Exception()
return object : ArrayList<String>() {}
}