CLI: improve behavior of -include-runtime
1.fix KT-17344: Include kotlin-reflect to resulting jar if "-include-runtime" is specified, unless the -no-reflect option is specified. 2.fix KT-43220: -include-runtime should add .kotlin_builtins to the output
This commit is contained in:
committed by
Alexander Udalov
parent
496d857db1
commit
bd205317aa
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
|||||||
import org.jetbrains.kotlin.cli.common.modules.ModuleChunk;
|
import org.jetbrains.kotlin.cli.common.modules.ModuleChunk;
|
||||||
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser;
|
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol;
|
||||||
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
|
||||||
import org.jetbrains.kotlin.utils.PathUtil;
|
import org.jetbrains.kotlin.utils.PathUtil;
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ public class CompileEnvironmentUtil {
|
|||||||
OutputStream fos,
|
OutputStream fos,
|
||||||
@Nullable FqName mainClass,
|
@Nullable FqName mainClass,
|
||||||
boolean includeRuntime,
|
boolean includeRuntime,
|
||||||
|
boolean noReflect,
|
||||||
boolean resetJarTimestamps
|
boolean resetJarTimestamps
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
@@ -89,6 +91,9 @@ public class CompileEnvironmentUtil {
|
|||||||
}
|
}
|
||||||
if (includeRuntime) {
|
if (includeRuntime) {
|
||||||
writeRuntimeToJar(stream, resetJarTimestamps);
|
writeRuntimeToJar(stream, resetJarTimestamps);
|
||||||
|
if (!noReflect) {
|
||||||
|
writeReflectToJar(stream, resetJarTimestamps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stream.finish();
|
stream.finish();
|
||||||
}
|
}
|
||||||
@@ -98,12 +103,12 @@ public class CompileEnvironmentUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void writeToJar(
|
public static void writeToJar(
|
||||||
File jarPath, boolean jarRuntime, boolean resetJarTimestamps, FqName mainClass, OutputFileCollection outputFiles
|
File jarPath, boolean jarRuntime, boolean noReflect, boolean resetJarTimestamps, FqName mainClass, OutputFileCollection outputFiles
|
||||||
) {
|
) {
|
||||||
FileOutputStream outputStream = null;
|
FileOutputStream outputStream = null;
|
||||||
try {
|
try {
|
||||||
outputStream = new FileOutputStream(jarPath);
|
outputStream = new FileOutputStream(jarPath);
|
||||||
doWriteToJar(outputFiles, outputStream, mainClass, jarRuntime, resetJarTimestamps);
|
doWriteToJar(outputFiles, outputStream, mainClass, jarRuntime, noReflect, resetJarTimestamps);
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e) {
|
catch (FileNotFoundException e) {
|
||||||
@@ -125,13 +130,22 @@ public class CompileEnvironmentUtil {
|
|||||||
copyJarImpl(stream, stdlibPath, resetJarTimestamps);
|
copyJarImpl(stream, stdlibPath, resetJarTimestamps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void writeReflectToJar(JarOutputStream stream, boolean resetJarTimestamps) throws IOException {
|
||||||
|
File reflectPath = PathUtil.getKotlinPathsForCompiler().getReflectPath();
|
||||||
|
if (!reflectPath.exists()) {
|
||||||
|
throw new CompileEnvironmentException("Couldn't find kotlin-reflect at " + reflectPath);
|
||||||
|
}
|
||||||
|
copyJarImpl(stream, reflectPath, resetJarTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
private static void copyJarImpl(JarOutputStream stream, File jarPath, boolean resetJarTimestamps) throws IOException {
|
private static void copyJarImpl(JarOutputStream stream, File jarPath, boolean resetJarTimestamps) throws IOException {
|
||||||
try (JarInputStream jis = new JarInputStream(new FileInputStream(jarPath))) {
|
try (JarInputStream jis = new JarInputStream(new FileInputStream(jarPath))) {
|
||||||
while (true) {
|
while (true) {
|
||||||
JarEntry e = jis.getNextJarEntry();
|
JarEntry e = jis.getNextJarEntry();
|
||||||
if (e == null) break;
|
if (e == null) break;
|
||||||
|
|
||||||
if (!FileUtilRt.extensionEquals(e.getName(), "class") ||
|
if ((!FileUtilRt.extensionEquals(e.getName(), "class") &&
|
||||||
|
!FileUtilRt.extensionEquals(e.getName(), BuiltInSerializerProtocol.BUILTINS_FILE_EXTENSION)) ||
|
||||||
StringsKt.substringAfterLast(e.getName(), "/", e.getName()).equals("module-info.class")) {
|
StringsKt.substringAfterLast(e.getName(), "/", e.getName()).equals("module-info.class")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -86,8 +86,9 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||||
if (jarPath != null) {
|
if (jarPath != null) {
|
||||||
val includeRuntime = configuration.get(JVMConfigurationKeys.INCLUDE_RUNTIME, false)
|
val includeRuntime = configuration.get(JVMConfigurationKeys.INCLUDE_RUNTIME, false)
|
||||||
|
val noReflect = configuration.get(JVMConfigurationKeys.NO_REFLECT, false)
|
||||||
val resetJarTimestamps = !configuration.get(JVMConfigurationKeys.NO_RESET_JAR_TIMESTAMPS, false)
|
val resetJarTimestamps = !configuration.get(JVMConfigurationKeys.NO_RESET_JAR_TIMESTAMPS, false)
|
||||||
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, resetJarTimestamps, mainClassFqName, outputFiles)
|
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, noReflect, resetJarTimestamps, mainClassFqName, outputFiles)
|
||||||
if (reportOutputFiles) {
|
if (reportOutputFiles) {
|
||||||
val message = OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
|
val message = OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
|
||||||
messageCollector.report(OUTPUT, message)
|
messageCollector.report(OUTPUT, message)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.io.File
|
|||||||
|
|
||||||
fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArguments) {
|
fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArguments) {
|
||||||
put(JVMConfigurationKeys.INCLUDE_RUNTIME, arguments.includeRuntime)
|
put(JVMConfigurationKeys.INCLUDE_RUNTIME, arguments.includeRuntime)
|
||||||
|
put(JVMConfigurationKeys.NO_REFLECT, arguments.noReflect)
|
||||||
|
|
||||||
putIfNotNull(JVMConfigurationKeys.FRIEND_PATHS, arguments.friendPaths?.asList())
|
putIfNotNull(JVMConfigurationKeys.FRIEND_PATHS, arguments.friendPaths?.asList())
|
||||||
|
|
||||||
|
|||||||
@@ -146,4 +146,7 @@ public class JVMConfigurationKeys {
|
|||||||
|
|
||||||
public static final CompilerConfigurationKey<Boolean> ENABLE_JVM_PREVIEW =
|
public static final CompilerConfigurationKey<Boolean> ENABLE_JVM_PREVIEW =
|
||||||
CompilerConfigurationKey.create("Enable Java language preview features");
|
CompilerConfigurationKey.create("Enable Java language preview features");
|
||||||
|
|
||||||
|
public static final CompilerConfigurationKey<Boolean> NO_REFLECT =
|
||||||
|
CompilerConfigurationKey.create("Don't automatically include kotlin-reflect.jar into the output if the output is a jar");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ERR:
|
||||||
|
noReflect.kt:5:23: warning: call uses reflection API which is not found in compilation classpath. Make sure you have kotlin-reflect.jar in the classpath
|
||||||
|
String::class.annotations
|
||||||
|
^
|
||||||
|
|
||||||
|
Return code: 0
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package noReflect
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
try {
|
||||||
|
String::class.annotations
|
||||||
|
} catch (e: KotlinReflectionNotSupportedError) {
|
||||||
|
println("KotlinReflectionNotSupportedError has been caught")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
OUT:
|
||||||
|
KotlinReflectionNotSupportedError has been caught
|
||||||
|
|
||||||
|
Return code: 0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Return code: 0
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package reflect
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
String::class.annotations
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Return code: 0
|
||||||
@@ -187,4 +187,18 @@ public class CompilerSmokeTest extends CompilerSmokeTestBase {
|
|||||||
);
|
);
|
||||||
run("buildFile.run", "-cp", tmpdir.getAbsolutePath(), "MainKt");
|
run("buildFile.run", "-cp", tmpdir.getAbsolutePath(), "MainKt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testReflect() throws Exception {
|
||||||
|
String jar = tmpdir.getAbsolutePath() + File.separator + "reflect.jar";
|
||||||
|
assertEquals("compilation failed", 0,
|
||||||
|
runCompiler("reflect.compile", "-include-runtime", "reflect.kt", "-d", jar));
|
||||||
|
run("reflect.run", "-cp", jar, "reflect.ReflectKt");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNoReflect() throws Exception {
|
||||||
|
String jar = tmpdir.getAbsolutePath() + File.separator + "noReflect.jar";
|
||||||
|
assertEquals("compilation failed", 0,
|
||||||
|
runCompiler("noReflect.compile", "-include-runtime", "-no-reflect", "noReflect.kt", "-d", jar));
|
||||||
|
run("noReflect.run", "-cp", jar, "noReflect.NoReflectKt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user