FIR: extend cli pipeline with incremental compilation logic
use it in the IncrementalCompilationRunner
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.backend.jvm.jvmPhases
|
||||
import org.jetbrains.kotlin.cli.common.*
|
||||
@@ -46,7 +45,6 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompil
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.modules.JavaRootPath
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import java.io.File
|
||||
|
||||
@@ -119,40 +117,9 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
|
||||
messageCollector.report(LOGGING, "Configuring the compilation environment")
|
||||
try {
|
||||
val destination = arguments.destination?.let { File(it) }
|
||||
val buildFile = arguments.buildFile?.let { File(it) }
|
||||
|
||||
val moduleChunk = if (buildFile != null) {
|
||||
fun strongWarning(message: String) {
|
||||
messageCollector.report(STRONG_WARNING, message)
|
||||
}
|
||||
if (destination != null) {
|
||||
strongWarning("The '-d' option with a directory destination is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
if (arguments.javaSourceRoots != null) {
|
||||
strongWarning("The '-Xjava-source-roots' option is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
if (arguments.javaPackagePrefix != null) {
|
||||
strongWarning("The '-Xjava-package-prefix' option is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
configuration.configureContentRootsFromClassPath(arguments)
|
||||
val sanitizedCollector = FilteringMessageCollector(messageCollector, VERBOSE::contains)
|
||||
configuration.put(JVMConfigurationKeys.MODULE_XML_FILE, buildFile)
|
||||
CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector)
|
||||
} else {
|
||||
if (destination != null) {
|
||||
if (destination.path.endsWith(".jar")) {
|
||||
configuration.put(JVMConfigurationKeys.OUTPUT_JAR, destination)
|
||||
} else {
|
||||
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination)
|
||||
}
|
||||
}
|
||||
|
||||
val module = ModuleBuilder(moduleName, destination?.path ?: ".", "java-production")
|
||||
module.configureFromArgs(arguments)
|
||||
|
||||
ModuleChunk(listOf(module))
|
||||
}
|
||||
val moduleChunk = configuration.configureModuleChunk(arguments, buildFile)
|
||||
|
||||
val chunk = moduleChunk.modules
|
||||
configuration.configureSourceRoots(chunk, buildFile)
|
||||
@@ -195,30 +162,6 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ModuleBuilder.configureFromArgs(args: K2JVMCompilerArguments) {
|
||||
args.friendPaths?.forEach { addFriendDir(it) }
|
||||
args.classpath?.split(File.pathSeparator)?.forEach { addClasspathEntry(it) }
|
||||
args.javaSourceRoots?.forEach {
|
||||
addJavaSourceRoot(JavaRootPath(it, args.javaPackagePrefix))
|
||||
}
|
||||
|
||||
val commonSources = args.commonSources?.toSet().orEmpty()
|
||||
for (arg in args.freeArgs) {
|
||||
if (arg.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) {
|
||||
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
|
||||
} else {
|
||||
addSourceFiles(arg)
|
||||
if (arg in commonSources) {
|
||||
addCommonSourceFiles(arg)
|
||||
}
|
||||
|
||||
if (File(arg).isDirectory) {
|
||||
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun MutableList<String>.addPlatformOptions(arguments: K2JVMCompilerArguments) {
|
||||
if (arguments.scriptTemplates?.isNotEmpty() == true) {
|
||||
add("plugin:kotlin.scripting:script-templates=${arguments.scriptTemplates!!.joinToString(",")}")
|
||||
@@ -302,5 +245,50 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
}
|
||||
|
||||
fun CompilerConfiguration.configureModuleChunk(
|
||||
arguments: K2JVMCompilerArguments,
|
||||
buildFile: File?
|
||||
): ModuleChunk {
|
||||
val destination = arguments.destination?.let { File(it) }
|
||||
|
||||
return if (buildFile != null) {
|
||||
val messageCollector = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
|
||||
fun strongWarning(message: String) {
|
||||
messageCollector.report(STRONG_WARNING, message)
|
||||
}
|
||||
|
||||
if (destination != null) {
|
||||
strongWarning("The '-d' option with a directory destination is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
if (arguments.javaSourceRoots != null) {
|
||||
strongWarning("The '-Xjava-source-roots' option is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
if (arguments.javaPackagePrefix != null) {
|
||||
strongWarning("The '-Xjava-package-prefix' option is ignored because '-Xbuild-file' is specified")
|
||||
}
|
||||
configureContentRootsFromClassPath(arguments)
|
||||
val sanitizedCollector = FilteringMessageCollector(messageCollector, VERBOSE::contains)
|
||||
put(JVMConfigurationKeys.MODULE_XML_FILE, buildFile)
|
||||
CompileEnvironmentUtil.loadModuleChunk(buildFile, sanitizedCollector)
|
||||
} else {
|
||||
if (destination != null) {
|
||||
if (destination.path.endsWith(".jar")) {
|
||||
put(JVMConfigurationKeys.OUTPUT_JAR, destination)
|
||||
} else {
|
||||
put(JVMConfigurationKeys.OUTPUT_DIRECTORY, destination)
|
||||
}
|
||||
}
|
||||
|
||||
val module = ModuleBuilder(
|
||||
this[CommonConfigurationKeys.MODULE_NAME] ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME,
|
||||
destination?.path ?: ".", "java-production"
|
||||
)
|
||||
module.configureFromArgs(arguments)
|
||||
|
||||
ModuleChunk(listOf(module))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun main(args: Array<String>) = K2JVMCompiler.main(args)
|
||||
|
||||
+4
-4
@@ -186,7 +186,7 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
|
||||
val providerAndScopeForIncrementalCompilation = createComponentsForIncrementalCompilation(sourceScope)
|
||||
|
||||
providerAndScopeForIncrementalCompilation?.scope?.let {
|
||||
providerAndScopeForIncrementalCompilation?.precompiledBinariesFileScope?.let {
|
||||
librariesScope -= it
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
|
||||
private fun CompilationContext.createComponentsForIncrementalCompilation(
|
||||
sourceScope: AbstractProjectFileSearchScope
|
||||
): FirSessionFactory.ProviderAndScopeForIncrementalCompilation? {
|
||||
): FirSessionFactory.IncrementalCompilationContext? {
|
||||
if (targetIds == null || incrementalComponents == null) return null
|
||||
val directoryWithIncrementalPartsFromPreviousCompilation =
|
||||
moduleConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
|
||||
@@ -288,7 +288,7 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
projectEnvironment.getPackagePartProvider(sourceScope),
|
||||
targetIds.map(incrementalComponents::getIncrementalCache)
|
||||
)
|
||||
return FirSessionFactory.ProviderAndScopeForIncrementalCompilation(packagePartProvider, incrementalCompilationScope)
|
||||
return FirSessionFactory.IncrementalCompilationContext(emptyList(), packagePartProvider, incrementalCompilationScope)
|
||||
}
|
||||
|
||||
private fun CompilationContext.runBackend(
|
||||
@@ -368,7 +368,7 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
)
|
||||
}
|
||||
|
||||
internal fun findMainClass(fir: List<FirFile>): FqName? {
|
||||
fun findMainClass(fir: List<FirFile>): FqName? {
|
||||
// TODO: replace with proper main function detector, KT-44557
|
||||
val compatibleClasses = mutableListOf<FqName>()
|
||||
val visitor = object : FirVisitorVoid() {
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun CompilerConfiguration.configureSourceRoots(chunk: List<Module>, buildFile: File? = null) {
|
||||
fun CompilerConfiguration.configureSourceRoots(chunk: List<Module>, buildFile: File? = null) {
|
||||
for (module in chunk) {
|
||||
val commonSources = getBuildFilePaths(buildFile, module.getCommonSourceFiles()).toSet()
|
||||
|
||||
|
||||
@@ -77,6 +77,17 @@ open class VfsBasedProjectEnvironment(
|
||||
} ?: GlobalSearchScope.EMPTY_SCOPE
|
||||
)
|
||||
|
||||
override fun getSearchScopeByDirectories(directories: Iterable<File>): AbstractProjectFileSearchScope =
|
||||
PsiBasedProjectFileSearchScope(
|
||||
directories
|
||||
.mapNotNull { localFileSystem.findFileByPath(it.absolutePath) }
|
||||
.toSet()
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let {
|
||||
KotlinToJVMBytecodeCompiler.DirectoriesScope(project, it)
|
||||
} ?: GlobalSearchScope.EMPTY_SCOPE
|
||||
)
|
||||
|
||||
fun getSearchScopeByPsiFiles(files: Iterable<PsiFile>, allowOutOfProjectRoots: Boolean= false): AbstractProjectFileSearchScope =
|
||||
PsiBasedProjectFileSearchScope(
|
||||
files.map { it.virtualFile }.let {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -12,9 +13,11 @@ import com.intellij.openapi.vfs.VirtualFileSystem
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
|
||||
import org.jetbrains.kotlin.cli.common.output.writeAll
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
|
||||
@@ -22,6 +25,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.modules.JavaRootPath
|
||||
import org.jetbrains.kotlin.modules.Module
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -148,3 +152,28 @@ fun writeOutputs(
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun ModuleBuilder.configureFromArgs(args: K2JVMCompilerArguments) {
|
||||
args.friendPaths?.forEach { addFriendDir(it) }
|
||||
args.classpath?.split(File.pathSeparator)?.forEach { addClasspathEntry(it) }
|
||||
args.javaSourceRoots?.forEach {
|
||||
addJavaSourceRoot(JavaRootPath(it, args.javaPackagePrefix))
|
||||
}
|
||||
|
||||
val commonSources = args.commonSources?.toSet().orEmpty()
|
||||
for (arg in args.freeArgs) {
|
||||
if (arg.endsWith(JavaFileType.DOT_DEFAULT_EXTENSION)) {
|
||||
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
|
||||
} else {
|
||||
addSourceFiles(arg)
|
||||
if (arg in commonSources) {
|
||||
addCommonSourceFiles(arg)
|
||||
}
|
||||
|
||||
if (File(arg).isDirectory) {
|
||||
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+178
-85
@@ -45,15 +45,18 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
|
||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
|
||||
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.pipeline.buildFirViaLightTree
|
||||
import org.jetbrains.kotlin.fir.pipeline.convertToIr
|
||||
import org.jetbrains.kotlin.fir.pipeline.runCheckers
|
||||
import org.jetbrains.kotlin.fir.pipeline.runResolution
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionFactory
|
||||
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
|
||||
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
|
||||
@@ -88,7 +91,7 @@ fun compileModulesUsingFrontendIrAndLightTree(
|
||||
"ATTENTION!\n This build uses in-dev FIR: \n -Xuse-fir"
|
||||
)
|
||||
|
||||
val outputs = mutableMapOf<Module, GenerationState>()
|
||||
val outputs = mutableListOf<GenerationState>()
|
||||
var mainClassFqName: FqName? = null
|
||||
|
||||
for (module in chunk) {
|
||||
@@ -108,41 +111,120 @@ fun compileModulesUsingFrontendIrAndLightTree(
|
||||
|
||||
val diagnosticsReporter = DiagnosticReporterFactory.createReporter()
|
||||
|
||||
val (moduleMainClassName, generationState) = compileModule(
|
||||
ModuleCompilerInput(
|
||||
TargetId(module),
|
||||
CommonPlatforms.defaultCommonPlatform, commonSources,
|
||||
JvmPlatforms.unspecifiedJvmPlatform, platformSources,
|
||||
moduleConfiguration
|
||||
),
|
||||
ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
|
||||
val compilerInput = ModuleCompilerInput(
|
||||
TargetId(module),
|
||||
CommonPlatforms.defaultCommonPlatform, commonSources,
|
||||
JvmPlatforms.unspecifiedJvmPlatform, platformSources,
|
||||
moduleConfiguration
|
||||
)
|
||||
val compilerEnvironment = ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
|
||||
val analysisResults = compileModuleToAnalyzedFir(
|
||||
compilerInput,
|
||||
compilerEnvironment,
|
||||
emptyList(),
|
||||
null,
|
||||
)
|
||||
// TODO: consider what to do if many modules has main classes
|
||||
if (mainClassFqName == null && moduleConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
|
||||
mainClassFqName = findMainClass(analysisResults.fir)
|
||||
}
|
||||
|
||||
val irInput = convertAnalyzedFirToIr(compilerInput, analysisResults, compilerEnvironment)
|
||||
val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment)
|
||||
|
||||
FirDiagnosticsCompilerResultsReporter.reportToMessageCollector(
|
||||
diagnosticsReporter,
|
||||
messageCollector,
|
||||
moduleConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
)
|
||||
outputs[module] = generationState
|
||||
|
||||
// TODO: consider what to do if many modules contain main class
|
||||
if (mainClassFqName == null) {
|
||||
mainClassFqName = moduleMainClassName
|
||||
}
|
||||
outputs.add(codegenOutput.generationState)
|
||||
}
|
||||
|
||||
return writeOutputs(
|
||||
(projectEnvironment as? VfsBasedProjectEnvironment)?.project,
|
||||
projectEnvironment,
|
||||
compilerConfiguration,
|
||||
chunk,
|
||||
outputs,
|
||||
mainClassFqName
|
||||
)
|
||||
}
|
||||
|
||||
fun compileModule(
|
||||
fun convertAnalyzedFirToIr(
|
||||
input: ModuleCompilerInput,
|
||||
analysisResults: ModuleCompilerAnalyzedOutput,
|
||||
environment: ModuleCompilerEnvironment
|
||||
): ModuleCompilerIrBackendInput {
|
||||
val extensions = JvmGeneratorExtensionsImpl(input.configuration)
|
||||
|
||||
// fir2ir
|
||||
val irGenerationExtensions =
|
||||
(environment.projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }
|
||||
val (irModuleFragment, symbolTable, components) =
|
||||
analysisResults.session.convertToIr(
|
||||
analysisResults.scopeSession, analysisResults.fir, extensions, irGenerationExtensions ?: emptyList()
|
||||
)
|
||||
|
||||
return ModuleCompilerIrBackendInput(
|
||||
input.targetId,
|
||||
input.configuration,
|
||||
extensions,
|
||||
irModuleFragment,
|
||||
symbolTable,
|
||||
components,
|
||||
analysisResults.session
|
||||
)
|
||||
}
|
||||
|
||||
fun generateCodeFromIr(
|
||||
input: ModuleCompilerIrBackendInput,
|
||||
environment: ModuleCompilerEnvironment
|
||||
): ModuleCompilerOutput {
|
||||
// IR
|
||||
val codegenFactory = JvmIrCodegenFactory(
|
||||
input.configuration,
|
||||
input.configuration.get(CLIConfigurationKeys.PHASE_CONFIG),
|
||||
jvmGeneratorExtensions = input.extensions
|
||||
)
|
||||
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
|
||||
|
||||
val generationState = GenerationState.Builder(
|
||||
(environment.projectEnvironment as VfsBasedProjectEnvironment).project, ClassBuilderFactories.BINARIES,
|
||||
input.irModuleFragment.descriptor, dummyBindingContext, emptyList()/* !! */,
|
||||
input.configuration
|
||||
).codegenFactory(
|
||||
codegenFactory
|
||||
).targetId(
|
||||
input.targetId
|
||||
).moduleName(
|
||||
input.targetId.name
|
||||
).outDirectory(
|
||||
input.configuration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
|
||||
).onIndependentPartCompilationEnd(
|
||||
createOutputFilesFlushingCallbackIfPossible(input.configuration)
|
||||
).isIrBackend(
|
||||
true
|
||||
).jvmBackendClassResolver(
|
||||
FirJvmBackendClassResolver(input.components)
|
||||
).diagnosticReporter(
|
||||
environment.diagnosticsReporter
|
||||
).build()
|
||||
|
||||
generationState.beforeCompile()
|
||||
codegenFactory.generateModuleInFrontendIRMode(
|
||||
generationState, input.irModuleFragment, input.symbolTable, input.extensions,
|
||||
FirJvmBackendExtension(input.firSession, input.components)
|
||||
)
|
||||
CodegenFactory.doCheckCancelled(generationState)
|
||||
generationState.factory.done()
|
||||
|
||||
return ModuleCompilerOutput(generationState)
|
||||
}
|
||||
|
||||
fun compileModuleToAnalyzedFir(
|
||||
input: ModuleCompilerInput,
|
||||
environment: ModuleCompilerEnvironment,
|
||||
previousStepsSymbolProviders: List<FirSymbolProvider>,
|
||||
incrementalExcludesScope: AbstractProjectFileSearchScope?,
|
||||
): ModuleCompilerAnalyzedOutput {
|
||||
var sourcesScope = environment.projectEnvironment.getSearchScopeByIoFiles(input.platformSources) //!!
|
||||
val sessionProvider = FirProjectSessionProvider()
|
||||
val extendedAnalysisMode = input.configuration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS)
|
||||
@@ -160,6 +242,8 @@ fun compileModule(
|
||||
commonSourcesScope,
|
||||
CommonPlatformAnalyzerServices,
|
||||
sessionProvider,
|
||||
previousStepsSymbolProviders,
|
||||
incrementalExcludesScope,
|
||||
extendedAnalysisMode,
|
||||
needRegisterJavaElementFinder = false
|
||||
)
|
||||
@@ -173,6 +257,8 @@ fun compileModule(
|
||||
sourcesScope,
|
||||
JvmPlatformAnalyzerServices,
|
||||
sessionProvider,
|
||||
previousStepsSymbolProviders,
|
||||
incrementalExcludesScope,
|
||||
extendedAnalysisMode,
|
||||
needRegisterJavaElementFinder = true
|
||||
) {
|
||||
@@ -180,6 +266,7 @@ fun compileModule(
|
||||
sourceDependsOnDependencies(listOf(commonSession.moduleData))
|
||||
}
|
||||
friendDependencies(input.configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
|
||||
sourceFriendsDependencies(input.friendFirModules)
|
||||
}
|
||||
|
||||
// raw fir
|
||||
@@ -197,56 +284,43 @@ fun compileModule(
|
||||
// checkers
|
||||
session.runCheckers(scopeSession, fir, environment.diagnosticsReporter)
|
||||
|
||||
val mainClassFqName: FqName? = runIf(input.configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
|
||||
findMainClass(fir)
|
||||
return ModuleCompilerAnalyzedOutput(session, scopeSession, fir)
|
||||
}
|
||||
|
||||
fun writeOutputs(
|
||||
projectEnvironment: AbstractProjectEnvironment,
|
||||
configuration: CompilerConfiguration,
|
||||
outputs: Collection<GenerationState>,
|
||||
mainClassFqName: FqName?
|
||||
): Boolean {
|
||||
try {
|
||||
for (state in outputs) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
writeOutput(state.configuration, state.factory, mainClassFqName)
|
||||
}
|
||||
} finally {
|
||||
outputs.forEach(GenerationState::destroy)
|
||||
}
|
||||
|
||||
val extensions = JvmGeneratorExtensionsImpl(input.configuration)
|
||||
if (configuration.getBoolean(JVMConfigurationKeys.COMPILE_JAVA)) {
|
||||
val singleState = outputs.singleOrNull()
|
||||
if (singleState != null) {
|
||||
return JavacWrapper.getInstance((projectEnvironment as VfsBasedProjectEnvironment).project).use {
|
||||
it.compile(singleState.outDirectory)
|
||||
}
|
||||
} else {
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
|
||||
CompilerMessageSeverity.WARNING,
|
||||
"A chunk contains multiple modules (${outputs.joinToString { it.moduleName }}). " +
|
||||
"-Xuse-javac option couldn't be used to compile java files"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// fir2ir
|
||||
val irGenerationExtensions = (environment.projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }
|
||||
val (irModuleFragment, symbolTable, components) = session.convertToIr(scopeSession, fir, extensions, irGenerationExtensions ?: emptyList())
|
||||
|
||||
// IR
|
||||
val codegenFactory = JvmIrCodegenFactory(
|
||||
input.configuration,
|
||||
input.configuration.get(CLIConfigurationKeys.PHASE_CONFIG),
|
||||
jvmGeneratorExtensions = extensions
|
||||
)
|
||||
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
|
||||
|
||||
val generationState = GenerationState.Builder(
|
||||
(environment.projectEnvironment as VfsBasedProjectEnvironment).project, ClassBuilderFactories.BINARIES,
|
||||
irModuleFragment.descriptor, dummyBindingContext, emptyList()/* !! */,
|
||||
input.configuration
|
||||
).codegenFactory(
|
||||
codegenFactory
|
||||
).targetId(
|
||||
input.targetId
|
||||
).moduleName(
|
||||
input.targetId.name
|
||||
).outDirectory(
|
||||
input.configuration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
|
||||
).onIndependentPartCompilationEnd(
|
||||
createOutputFilesFlushingCallbackIfPossible(input.configuration)
|
||||
).isIrBackend(
|
||||
true
|
||||
).jvmBackendClassResolver(
|
||||
FirJvmBackendClassResolver(components)
|
||||
).diagnosticReporter(
|
||||
environment.diagnosticsReporter
|
||||
).build()
|
||||
|
||||
generationState.beforeCompile()
|
||||
codegenFactory.generateModuleInFrontendIRMode(
|
||||
generationState, irModuleFragment, symbolTable, extensions, FirJvmBackendExtension(session, components)
|
||||
)
|
||||
CodegenFactory.doCheckCancelled(generationState)
|
||||
generationState.factory.done()
|
||||
|
||||
return ModuleCompilerOutput(mainClassFqName, generationState)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
fun createSession(
|
||||
name: String,
|
||||
platform: TargetPlatform,
|
||||
@@ -255,6 +329,8 @@ fun createSession(
|
||||
sourceScope: AbstractProjectFileSearchScope,
|
||||
analyzerServices: PlatformDependentAnalyzerServices,
|
||||
sessionProvider: FirProjectSessionProvider?,
|
||||
previousStepsSymbolProviders: List<FirSymbolProvider>,
|
||||
incrementalExcludesScope: AbstractProjectFileSearchScope?,
|
||||
extendedAnalysisMode: Boolean,
|
||||
needRegisterJavaElementFinder: Boolean,
|
||||
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
|
||||
@@ -262,9 +338,16 @@ fun createSession(
|
||||
var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
|
||||
|
||||
val providerAndScopeForIncrementalCompilation =
|
||||
createComponentsForIncrementalCompilation(moduleConfiguration, projectEnvironment, sourceScope)?.also {
|
||||
librariesScope -= it.scope
|
||||
}
|
||||
createContextForIncrementalCompilation(
|
||||
moduleConfiguration,
|
||||
projectEnvironment,
|
||||
sourceScope,
|
||||
previousStepsSymbolProviders,
|
||||
incrementalExcludesScope
|
||||
)
|
||||
?.also { (_, _, precompiledBinariesFileScope) ->
|
||||
precompiledBinariesFileScope?.let { librariesScope -= it }
|
||||
}
|
||||
|
||||
return FirSessionFactory.createSessionWithDependencies(
|
||||
Name.identifier(name),
|
||||
@@ -293,27 +376,31 @@ fun createSession(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createComponentsForIncrementalCompilation(
|
||||
private fun createContextForIncrementalCompilation(
|
||||
compilerConfiguration: CompilerConfiguration,
|
||||
projectEnvironment: AbstractProjectEnvironment,
|
||||
sourceScope: AbstractProjectFileSearchScope
|
||||
): FirSessionFactory.ProviderAndScopeForIncrementalCompilation? {
|
||||
sourceScope: AbstractProjectFileSearchScope,
|
||||
previousStepsSymbolProviders: List<FirSymbolProvider>,
|
||||
incrementalExcludesScope: AbstractProjectFileSearchScope?,
|
||||
): FirSessionFactory.IncrementalCompilationContext? {
|
||||
val targetIds = compilerConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId)
|
||||
val incrementalComponents = compilerConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||
if (targetIds == null || incrementalComponents == null) return null
|
||||
val directoryWithIncrementalPartsFromPreviousCompilation =
|
||||
compilerConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]
|
||||
?: return null
|
||||
val incrementalCompilationScope = directoryWithIncrementalPartsFromPreviousCompilation.walk()
|
||||
.filter { it.extension == "class" }
|
||||
.let { projectEnvironment.getSearchScopeByIoFiles(it.asIterable()) }
|
||||
.takeIf { !it.isEmpty }
|
||||
?: return null
|
||||
val packagePartProvider = IncrementalPackagePartProvider(
|
||||
projectEnvironment.getPackagePartProvider(sourceScope),
|
||||
targetIds.map(incrementalComponents::getIncrementalCache)
|
||||
val incrementalCompilationScope =
|
||||
compilerConfiguration[JVMConfigurationKeys.OUTPUT_DIRECTORY]?.let { dir ->
|
||||
projectEnvironment.getSearchScopeByDirectories(setOf(dir)).let {
|
||||
if (incrementalExcludesScope?.isEmpty != false) it
|
||||
else it - incrementalExcludesScope
|
||||
}
|
||||
}
|
||||
|
||||
return if (incrementalCompilationScope == null && previousStepsSymbolProviders.isEmpty()) null
|
||||
else FirSessionFactory.IncrementalCompilationContext(
|
||||
previousStepsSymbolProviders, IncrementalPackagePartProvider(
|
||||
projectEnvironment.getPackagePartProvider(sourceScope),
|
||||
targetIds.map(incrementalComponents::getIncrementalCache)
|
||||
), incrementalCompilationScope
|
||||
)
|
||||
return FirSessionFactory.ProviderAndScopeForIncrementalCompilation(packagePartProvider, incrementalCompilationScope)
|
||||
}
|
||||
|
||||
private class ProjectEnvironmentWithCoreEnvironmentEmulation(
|
||||
@@ -417,13 +504,17 @@ fun createProjectEnvironment(
|
||||
}
|
||||
}
|
||||
|
||||
private fun contentRootToVirtualFile(root: JvmContentRoot, locaFileSystem: VirtualFileSystem, jarFileSystem: VirtualFileSystem, messageCollector: MessageCollector): VirtualFile? =
|
||||
private fun contentRootToVirtualFile(
|
||||
root: JvmContentRootBase, locaFileSystem: VirtualFileSystem, jarFileSystem: VirtualFileSystem, messageCollector: MessageCollector
|
||||
): VirtualFile? =
|
||||
when (root) {
|
||||
// TODO: find out why non-existent location is not reported for JARs, add comment or fix
|
||||
is JvmClasspathRoot ->
|
||||
if (root.file.isFile) jarFileSystem.findJarRoot(root.file) else locaFileSystem.findExistingRoot(root, "Classpath entry", messageCollector)
|
||||
if (root.file.isFile) jarFileSystem.findJarRoot(root.file)
|
||||
else locaFileSystem.findExistingRoot(root, "Classpath entry", messageCollector)
|
||||
is JvmModulePathRoot ->
|
||||
if (root.file.isFile) jarFileSystem.findJarRoot(root.file) else locaFileSystem.findExistingRoot(root, "Java module root", messageCollector)
|
||||
if (root.file.isFile) jarFileSystem.findJarRoot(root.file)
|
||||
else locaFileSystem.findExistingRoot(root, "Java module root", messageCollector)
|
||||
is JavaSourceRoot ->
|
||||
locaFileSystem.findExistingRoot(root, "Java source root", messageCollector)
|
||||
else ->
|
||||
@@ -433,7 +524,9 @@ private fun contentRootToVirtualFile(root: JvmContentRoot, locaFileSystem: Virtu
|
||||
private fun VirtualFileSystem.findJarRoot(file: File): VirtualFile? =
|
||||
findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
|
||||
|
||||
private fun VirtualFileSystem.findExistingRoot(root: JvmContentRoot, rootDescription: String, messageCollector: MessageCollector): VirtualFile? {
|
||||
private fun VirtualFileSystem.findExistingRoot(
|
||||
root: JvmContentRoot, rootDescription: String, messageCollector: MessageCollector
|
||||
): VirtualFile? {
|
||||
return findFileByPath(root.file.absolutePath).also {
|
||||
if (it == null) {
|
||||
messageCollector.report(
|
||||
|
||||
+25
-2
@@ -5,10 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler.pipeline
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensionsImpl
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -22,7 +30,8 @@ data class ModuleCompilerInput(
|
||||
val commonSources: Collection<File>,
|
||||
val platform: TargetPlatform,
|
||||
val platformSources: Collection<File>,
|
||||
val configuration: CompilerConfiguration
|
||||
val configuration: CompilerConfiguration,
|
||||
val friendFirModules: Collection<FirModuleData> = emptyList()
|
||||
)
|
||||
|
||||
data class ModuleCompilerEnvironment(
|
||||
@@ -31,9 +40,23 @@ data class ModuleCompilerEnvironment(
|
||||
)
|
||||
|
||||
data class ModuleCompilerOutput(
|
||||
val mainClassName: FqName?,
|
||||
val generationState: GenerationState
|
||||
)
|
||||
|
||||
// ---
|
||||
|
||||
data class ModuleCompilerAnalyzedOutput(
|
||||
val session: FirSession,
|
||||
val scopeSession: ScopeSession,
|
||||
val fir: List<FirFile>
|
||||
)
|
||||
|
||||
data class ModuleCompilerIrBackendInput(
|
||||
val targetId: TargetId,
|
||||
val configuration: CompilerConfiguration,
|
||||
val extensions: JvmGeneratorExtensionsImpl,
|
||||
val irModuleFragment: IrModuleFragment,
|
||||
val symbolTable: SymbolTable,
|
||||
val components: Fir2IrComponents,
|
||||
val firSession: FirSession
|
||||
)
|
||||
Reference in New Issue
Block a user