Introduce "-Xreport-output-files" to report source-output mapping for JPS

This makes "-verbose" not required for JPS to run correctly and
therefore allows to print more useful debugging stuff in the compiler
and read them in CLI, for example. The output will also be more readable
because there'll be no "output" messages
This commit is contained in:
Alexander Udalov
2017-04-06 20:19:22 +03:00
parent ce145c015d
commit d8d3bafbe9
19 changed files with 73 additions and 52 deletions
@@ -84,6 +84,9 @@ public abstract class CommonCompilerArguments implements Serializable {
@Argument(value = "-Xallow-kotlin-package", description = "Allow compiling code in package 'kotlin'")
public boolean allowKotlinPackage;
@Argument(value = "-Xreport-output-files", description = "Report source to output files mapping")
public boolean reportOutputFiles;
@Argument(value = "-Xplugin", valueDescription = "<path>", description = "Load plugins from the given classpath")
public String[] pluginClasspaths;
@@ -32,7 +32,7 @@ public enum CompilerMessageSeverity {
OUTPUT;
public static final EnumSet<CompilerMessageSeverity> ERRORS = EnumSet.of(ERROR, EXCEPTION);
public static final EnumSet<CompilerMessageSeverity> VERBOSE = EnumSet.of(OUTPUT, LOGGING);
public static final EnumSet<CompilerMessageSeverity> VERBOSE = EnumSet.of(LOGGING);
public boolean isError() {
return ERRORS.contains(this);
@@ -220,6 +220,9 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
if (arguments.intellijPluginRoot != null) {
configuration.put(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT, arguments.intellijPluginRoot);
}
if (arguments.reportOutputFiles) {
configuration.put(CommonConfigurationKeys.REPORT_OUTPUT_FILES, true);
}
@SuppressWarnings("deprecation")
CompilerJarLocator locator = services.get(CompilerJarLocator.class);
if (locator != null) {
@@ -24,23 +24,22 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import java.io.File
fun OutputFileCollection.writeAll(outputDir: File, report: (file: OutputFile, sources: List<File>, output: File) -> Unit) {
fun OutputFileCollection.writeAll(outputDir: File, report: ((file: OutputFile, sources: List<File>, output: File) -> Unit)?) {
for (file in asList()) {
val sources = file.sourceFiles
val output = File(outputDir, file.relativePath)
report(file, sources, output)
report?.invoke(file, sources, output)
FileUtil.writeToFile(output, file.asByteArray())
}
}
private val REPORT_NOTHING: (OutputFile, List<File>, File) -> Unit = { _, _, _ -> }
fun OutputFileCollection.writeAllTo(outputDir: File) {
writeAll(outputDir, REPORT_NOTHING)
writeAll(outputDir, null)
}
fun OutputFileCollection.writeAll(outputDir: File, messageCollector: MessageCollector) {
writeAll(outputDir) { _, sources, output ->
fun OutputFileCollection.writeAll(outputDir: File, messageCollector: MessageCollector, reportOutputFiles: Boolean) {
if (!reportOutputFiles) writeAllTo(outputDir)
else writeAll(outputDir) { _, sources, output ->
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
}
}
@@ -211,7 +211,8 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
OutputUtilsKt.writeAll(outputFiles, outputDir, messageCollector);
OutputUtilsKt.writeAll(outputFiles, outputDir, messageCollector,
configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES));
return OK;
}
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.codegen.GeneratedClassLoader
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.addKotlinSourceRoots
@@ -87,19 +88,21 @@ object KotlinToJVMBytecodeCompiler {
outputFiles: OutputFileCollection,
mainClass: FqName?
) {
val reportOutputFiles = configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
val jarPath = configuration.get(JVMConfigurationKeys.OUTPUT_JAR)
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
if (jarPath != null) {
val includeRuntime = configuration.get(JVMConfigurationKeys.INCLUDE_RUNTIME, false)
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, mainClass, outputFiles)
messageCollector.report(
OUTPUT, OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
)
if (reportOutputFiles) {
val message = OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
messageCollector.report(OUTPUT, message)
}
return
}
val outputDir = configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY) ?: File(".")
outputFiles.writeAll(outputDir, messageCollector)
outputFiles.writeAll(outputDir, messageCollector, reportOutputFiles)
}
private fun createOutputFilesFlushingCallbackIfPossible(configuration: CompilerConfiguration): GenerationStateEventCallback {
@@ -25,6 +25,9 @@ object CommonConfigurationKeys {
@JvmField
val MODULE_NAME = CompilerConfigurationKey<String>("module name")
@JvmField
val REPORT_OUTPUT_FILES = CompilerConfigurationKey<Boolean>("report output files")
}
var CompilerConfiguration.languageVersionSettings: LanguageVersionSettings
@@ -424,6 +424,7 @@ class IncrementalJvmCompilerRunner(
val destination = args.destination
args.destination = null
args.module = moduleFile.absolutePath
args.reportOutputFiles = true
val outputItemCollector = OutputItemsCollectorImpl()
@Suppress("NAME_SHADOWING")
val messageCollector = MessageCollectorWrapper(messageCollector, outputItemCollector)
+1
View File
@@ -5,6 +5,7 @@ where advanced options include:
-Xrepeat=<count> Repeat compilation (for performance analysis)
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
-Xallow-kotlin-package Allow compiling code in package 'kotlin'
-Xreport-output-files Report source to output files mapping
-Xplugin=<path> Load plugins from the given classpath
-Xmulti-platform Enable experimental language support for multi-platform projects
-Xno-check-impl Do not check presence of 'impl' modifier in multi-platform projects
+1
View File
@@ -18,6 +18,7 @@ where advanced options include:
-Xrepeat=<count> Repeat compilation (for performance analysis)
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
-Xallow-kotlin-package Allow compiling code in package 'kotlin'
-Xreport-output-files Report source to output files mapping
-Xplugin=<path> Load plugins from the given classpath
-Xmulti-platform Enable experimental language support for multi-platform projects
-Xno-check-impl Do not check presence of 'impl' modifier in multi-platform projects
@@ -4,10 +4,6 @@ Buildfile: [TestData]/build.xml
build:
[kotlin2js] Compiling [[TestData]/root1] => [[Temp]/out.js]
[kotlin2js] logging: compiling source files: [TestData]/root1/foo.kt
[kotlin2js] output: output:
[kotlin2js] [Temp]/out.js
[kotlin2js] Sources:
[kotlin2js] [TestData]/root1/foo.kt
BUILD SUCCESSFUL
Total time: [time]
@@ -5,10 +5,6 @@ build:
[kotlinc] Compiling [[TestData]/hello.kt] => [[Temp]/hello.jar]
[kotlinc] logging: using Kotlin home directory [KotlinProjectHome]/dist/kotlinc
[kotlinc] logging: configuring the compilation environment
[kotlinc] output: output:
[kotlinc] [Temp]/hello.jar
[kotlinc] Sources:
[kotlinc] [TestData]/hello.kt
BUILD SUCCESSFUL
Total time: [time]
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.scripts.captureOut
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.utils.keysToMap
import org.junit.Assert
import java.io.File
import java.net.URLClassLoader
@@ -110,7 +109,8 @@ class CompilerApiTest : KotlinIntegrationTestBase() {
fun testHelloAppLocal() {
val messageCollector = TestMessageCollector()
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
val (code, outputs) = compileLocally(messageCollector, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar)
val (code, outputs) = compileLocally(messageCollector, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath,
"-d", jar, "-Xreport-output-files")
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(jar, outputs.first().outputFile?.absolutePath)
@@ -129,12 +129,13 @@ class CompilerApiTest : KotlinIntegrationTestBase() {
val daemonJVMOptions = configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
inheritMemoryLimits = false, inheritAdditionalProperties = false)
val messageCollector = TestMessageCollector()
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
try {
val (code, outputs) = compileOnDaemon(flagFile, compilerId, daemonJVMOptions, daemonOptions, messageCollector,
"-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar)
val (code, outputs) = compileOnDaemon(
flagFile, compilerId, daemonJVMOptions, daemonOptions, TestMessageCollector(), "-include-runtime",
File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar, "-Xreport-output-files"
)
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(jar, outputs.first().outputFile?.absolutePath)
@@ -149,7 +150,8 @@ class CompilerApiTest : KotlinIntegrationTestBase() {
fun testSimpleScriptLocal() {
val messageCollector = TestMessageCollector()
val (code, outputs) = compileLocally(messageCollector, File(getSimpleScriptBaseDir(), "script.kts").absolutePath, "-d", tmpdir.absolutePath)
val (code, outputs) = compileLocally(messageCollector, File(getSimpleScriptBaseDir(), "script.kts").absolutePath,
"-d", tmpdir.absolutePath, "-Xreport-output-files")
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(File(tmpdir, "Script.class").absolutePath, outputs.first().outputFile?.absolutePath)
@@ -168,12 +170,11 @@ class CompilerApiTest : KotlinIntegrationTestBase() {
val daemonJVMOptions = configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
inheritMemoryLimits = false, inheritAdditionalProperties = false)
val messageCollector = TestMessageCollector()
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
try {
val (code, outputs) = compileOnDaemon(flagFile, compilerId, daemonJVMOptions, daemonOptions, messageCollector,
File(getSimpleScriptBaseDir(), "script.kts").absolutePath, "-d", tmpdir.absolutePath)
val (code, outputs) = compileOnDaemon(
flagFile, compilerId, daemonJVMOptions, daemonOptions, TestMessageCollector(),
File(getSimpleScriptBaseDir(), "script.kts").absolutePath, "-Xreport-output-files", "-d", tmpdir.absolutePath
)
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(File(tmpdir, "Script.class").absolutePath, outputs.first().outputFile?.absolutePath)
@@ -247,8 +247,9 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
return ABORT
}
val commonArguments = compilerArgumentsForChunk(chunk)
commonArguments.verbose = true // Make compiler report source to output files mapping
val commonArguments = compilerArgumentsForChunk(chunk).apply {
reportOutputFiles = true
}
val allCompiledFiles = getAllCompiledFilesContainer(context)
val filesToCompile = KotlinSourceFileCollector.getDirtySourceFiles(dirtyFilesHolder)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
@@ -89,10 +90,10 @@ class AnnotationCollectorComponentRegistrar : ComponentRegistrar {
}
val stubs = configuration.get(AnnotationCollectorConfigurationKeys.STUBS_PATH)
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
if (stubs != null) {
AnalysisHandlerExtension.registerExtension(project, StubProducerExtension(File(stubs), messageCollector))
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
val reportOutputFiles = configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
AnalysisHandlerExtension.registerExtension(project, StubProducerExtension(File(stubs), messageCollector, reportOutputFiles))
}
}
}
@@ -32,7 +32,11 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.org.objectweb.asm.ClassWriter
import java.io.File
class StubProducerExtension(val stubsOutputDir: File, val messageCollector: MessageCollector) : AnalysisHandlerExtension {
class StubProducerExtension(
private val stubsOutputDir: File,
private val messageCollector: MessageCollector,
private val reportOutputFiles: Boolean
) : AnalysisHandlerExtension {
override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
@@ -50,7 +54,7 @@ class StubProducerExtension(val stubsOutputDir: File, val messageCollector: Mess
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
if (!stubsOutputDir.exists()) stubsOutputDir.mkdirs()
generationState.factory.writeAll(stubsOutputDir, messageCollector)
generationState.factory.writeAll(stubsOutputDir, messageCollector, reportOutputFiles)
generationState.destroy()
return AnalysisResult.success(BindingContext.EMPTY, module, shouldGenerateCode = false)
@@ -19,13 +19,15 @@ package org.jetbrains.kotlin.kapt3
import com.intellij.openapi.project.Project
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.kapt3.diagnostic.ErrorsKapt3
@@ -250,17 +252,21 @@ abstract class AbstractKapt3Extension(
converter: ClassFileToSourceStubConverter) {
val incrementalDataOutputDir = this.incrementalDataOutputDir ?: return
generationState.factory.writeAll(incrementalDataOutputDir) { file, sources, output ->
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
if (stubFileObject != null) {
val stubFile = File(stubsOutputDir, stubFileObject.name)
if (stubFile.exists()) {
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, stubFile))
}
}
val reportOutputFiles = generationState.configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
generationState.factory.writeAll(
incrementalDataOutputDir,
if (!reportOutputFiles) null else fun(file: OutputFile, sources: List<File>, output: File) {
val stubFileObject = converter.bindings[file.relativePath.substringBeforeLast(".class", missingDelimiterValue = "")]
if (stubFileObject != null) {
val stubFile = File(stubsOutputDir, stubFileObject.name)
if (stubFile.exists()) {
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, stubFile))
}
}
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
}
messageCollector.report(OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
}
)
}
protected abstract fun loadProcessors(): List<Processor>
@@ -62,7 +62,7 @@ abstract class AbstractAnnotationProcessorBoxTest : KotlinTestWithEnvironment()
if (supportStubs) {
val stubsDir = KotlinTestUtils.tmpDir("class-stubs")
val stubProducerExtension = StubProducerExtension(stubsDir, MessageCollector.NONE)
val stubProducerExtension = StubProducerExtension(stubsDir, MessageCollector.NONE, false)
AnalysisHandlerExtension.registerExtension(project, stubProducerExtension)
}
@@ -208,7 +208,8 @@ class SourceSectionsTest : TestCaseWithTmpdir() {
sourceToOutput.forEach { (source, expectedOutput) ->
val args = arrayOf(source.canonicalPath, "-d", tmpdir.canonicalPath,
"-Xplugin=${sourceSectionsPluginJar.canonicalPath}",
"-P", TEST_ALLOWED_SECTIONS.joinToString(",") { "plugin:${SourceSectionsCommandLineProcessor.PLUGIN_ID}:${SourceSectionsCommandLineProcessor.SECTIONS_OPTION.name}=$it" })
"-P", TEST_ALLOWED_SECTIONS.joinToString(",") { "plugin:${SourceSectionsCommandLineProcessor.PLUGIN_ID}:${SourceSectionsCommandLineProcessor.SECTIONS_OPTION.name}=$it" },
"-Xreport-output-files")
messageCollector.clear()
val outputs = arrayListOf<OutputMessageUtil.Output>()