[JS IR BE] Support mode of linking multiple klibs without .kt files
This commit is contained in:
+7
@@ -128,6 +128,13 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xir-only", description = "Disables pre-IR backend")
|
||||
var irOnly: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(
|
||||
value = "-Xinclude",
|
||||
valueDescription = "<path>",
|
||||
description = "A path to an intermediate library that should be processed in the same manner as source files."
|
||||
)
|
||||
var includes: String? by NullableStringFreezableVar(null)
|
||||
|
||||
@Argument(
|
||||
value = "-Xgenerate-dts",
|
||||
description = "Generate TypeScript declarations .d.ts file alongside JS file. Available in IR backend only."
|
||||
|
||||
@@ -36,11 +36,11 @@ import org.jetbrains.kotlin.js.config.EcmaVersion
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import org.jetbrains.kotlin.utils.JsMetadataVersion
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||
@@ -102,11 +102,13 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
if (arguments.version) {
|
||||
return OK
|
||||
}
|
||||
messageCollector.report(ERROR, "Specify at least one source file or directory", null)
|
||||
return COMPILATION_ERROR
|
||||
if (arguments.includes.isNullOrEmpty()) {
|
||||
messageCollector.report(ERROR, "Specify at least one source file or directory", null)
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
val libraries: List<String> = configureLibraries(arguments.libraries)
|
||||
val libraries: List<String> = configureLibraries(arguments.libraries) + listOfNotNull(arguments.includes)
|
||||
val friendLibraries: List<String> = configureLibraries(arguments.friendModules)
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, libraries)
|
||||
@@ -138,7 +140,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
return ExitCode.COMPILATION_ERROR
|
||||
}
|
||||
|
||||
if (sourcesFiles.isEmpty() && !IncrementalCompilation.isEnabledForJs()) {
|
||||
if (sourcesFiles.isEmpty() && !IncrementalCompilation.isEnabledForJs() && arguments.includes.isNullOrEmpty()) {
|
||||
messageCollector.report(ERROR, "No source files", null)
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
@@ -200,10 +202,23 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
if (arguments.irProduceJs) {
|
||||
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
|
||||
|
||||
val includes = arguments.includes
|
||||
|
||||
val mainModule = if (includes != null) {
|
||||
if (sourcesFiles.isNotEmpty()) {
|
||||
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
|
||||
}
|
||||
val allLibraries = resolvedLibraries.getFullList()
|
||||
val mainLib = allLibraries.find { it.libraryFile.absolutePath == File(includes).absolutePath }!!
|
||||
MainModule.Klib(mainLib)
|
||||
} else {
|
||||
MainModule.SourceFiles(sourcesFiles)
|
||||
}
|
||||
|
||||
val compiledModule = try {
|
||||
compile(
|
||||
projectJs,
|
||||
sourcesFiles,
|
||||
mainModule,
|
||||
config.configuration,
|
||||
phaseConfig,
|
||||
allDependencies = resolvedLibraries,
|
||||
|
||||
@@ -47,7 +47,7 @@ class CompilerResult(
|
||||
|
||||
fun compile(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
mainModule: MainModule,
|
||||
configuration: CompilerConfiguration,
|
||||
phaseConfig: PhaseConfig,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
@@ -57,8 +57,8 @@ fun compile(
|
||||
generateFullJs: Boolean = true,
|
||||
generateDceJs: Boolean = false
|
||||
): CompilerResult {
|
||||
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(project, files, configuration, allDependencies, friendDependencies)
|
||||
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(project, mainModule, configuration, allDependencies, friendDependencies)
|
||||
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
|
||||
@@ -72,7 +72,12 @@ fun compile(
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
}
|
||||
|
||||
val irFiles = dependencyModules.flatMap { it.files } + moduleFragment.files
|
||||
val allModules = when (mainModule) {
|
||||
is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
|
||||
is MainModule.Klib -> dependencyModules
|
||||
}
|
||||
|
||||
val irFiles = allModules.flatMap { it.files }
|
||||
|
||||
moduleFragment.files.clear()
|
||||
moduleFragment.files += irFiles
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.wasm.codegen.IrModuleToWasm
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
||||
import org.jetbrains.kotlin.ir.backend.js.loadIr
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
|
||||
@@ -31,7 +32,7 @@ fun compileWasm(
|
||||
exportedDeclarations: Set<FqName> = emptySet()
|
||||
): WasmCompilerResult {
|
||||
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(project, files, configuration, allDependencies, friendDependencies)
|
||||
loadIr(project, MainModule.SourceFiles(files), configuration, allDependencies, friendDependencies)
|
||||
|
||||
val moduleDescriptor = moduleFragment.descriptor
|
||||
val context = WasmBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
|
||||
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
|
||||
import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
@@ -19,8 +20,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
@@ -32,10 +31,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetad
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
|
||||
import org.jetbrains.kotlin.ir.util.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
@@ -126,7 +122,7 @@ fun generateKLib(
|
||||
icData = emptyList()
|
||||
}
|
||||
|
||||
val depsDescriptors = ModulesStructure(project, files, configuration, allDependencies, friendDependencies)
|
||||
val depsDescriptors = ModulesStructure(project, MainModule.SourceFiles(files), configuration, allDependencies, friendDependencies)
|
||||
|
||||
val psi2IrContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
|
||||
|
||||
@@ -174,30 +170,63 @@ private fun sortDependencies(dependencies: List<KotlinLibrary>, mapping: Map<Kot
|
||||
|
||||
fun loadIr(
|
||||
project: Project,
|
||||
files: List<KtFile>,
|
||||
mainModule: MainModule,
|
||||
configuration: CompilerConfiguration,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
friendDependencies: List<KotlinLibrary>
|
||||
): IrModuleInfo {
|
||||
val depsDescriptors = ModulesStructure(project, files, configuration, allDependencies, friendDependencies)
|
||||
val depsDescriptors = ModulesStructure(project, mainModule, configuration, allDependencies, friendDependencies)
|
||||
|
||||
val psi2IrContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
|
||||
when (mainModule) {
|
||||
is MainModule.SourceFiles -> {
|
||||
val psi2IrContext: GeneratorContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
|
||||
val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
val symbolTable = psi2IrContext.symbolTable
|
||||
val moduleDescriptor = psi2IrContext.moduleDescriptor
|
||||
|
||||
val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
val symbolTable = psi2IrContext.symbolTable
|
||||
val moduleDescriptor = psi2IrContext.moduleDescriptor
|
||||
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
|
||||
|
||||
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
|
||||
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
|
||||
}
|
||||
|
||||
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
|
||||
deserializer.initializeExpectActualLinker()
|
||||
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, mainModule.files, deserializer)
|
||||
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
|
||||
}
|
||||
is MainModule.Klib -> {
|
||||
val moduleDescriptor = depsDescriptors.getModuleDescriptor(mainModule.lib)
|
||||
val symbolTable = SymbolTable()
|
||||
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
|
||||
val typeTranslator = TypeTranslator(
|
||||
symbolTable,
|
||||
depsDescriptors.compilerConfiguration.languageVersionSettings,
|
||||
builtIns = moduleDescriptor.builtIns
|
||||
)
|
||||
typeTranslator.constantValueGenerator = constantValueGenerator
|
||||
constantValueGenerator.typeTranslator = typeTranslator
|
||||
val irBuiltIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
|
||||
|
||||
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
|
||||
val strategy =
|
||||
if (it == mainModule.lib)
|
||||
DeserializationStrategy.ALL
|
||||
else
|
||||
DeserializationStrategy.EXPLICITLY_EXPORTED
|
||||
|
||||
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), strategy)
|
||||
}
|
||||
deserializer.initializeExpectActualLinker()
|
||||
val moduleFragment = deserializedModuleFragments.last()
|
||||
|
||||
val irProviders = generateTypicalIrProviderList(moduleDescriptor, irBuiltIns, symbolTable, deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
|
||||
|
||||
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.initializeExpectActualLinker()
|
||||
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, files, deserializer)
|
||||
|
||||
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
|
||||
}
|
||||
|
||||
private fun runAnalysisAndPreparePsi2Ir(depsDescriptors: ModulesStructure): GeneratorContext {
|
||||
@@ -277,9 +306,14 @@ fun getModuleDescriptorByLibrary(current: KotlinLibrary, mapping: Map<String, Mo
|
||||
|
||||
object JsIrCompilationError : Throwable()
|
||||
|
||||
sealed class MainModule {
|
||||
class SourceFiles(val files: List<KtFile>) : MainModule()
|
||||
class Klib(val lib: KotlinLibrary) : MainModule()
|
||||
}
|
||||
|
||||
private class ModulesStructure(
|
||||
private val project: Project,
|
||||
private val files: List<KtFile>,
|
||||
private val mainModule: MainModule,
|
||||
val compilerConfiguration: CompilerConfiguration,
|
||||
val allDependencies: KotlinLibraryResolveResult,
|
||||
private val friendDependencies: List<KotlinLibrary>
|
||||
@@ -299,6 +333,9 @@ private class ModulesStructure(
|
||||
val builtInsDep = allDependencies.getFullList().find { it.isBuiltIns }
|
||||
|
||||
fun runAnalysis(): JsAnalysisResult {
|
||||
require(mainModule is MainModule.SourceFiles)
|
||||
val files = mainModule.files
|
||||
|
||||
// TODO: Should we not provide default message collector?
|
||||
val messageCollector: MessageCollector =
|
||||
compilerConfiguration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) ?: MessageCollector.NONE
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ where advanced options include:
|
||||
-Xfriend-modules=<path> Paths to friend modules
|
||||
-Xfriend-modules-disabled Disable internal declaration export
|
||||
-Xgenerate-dts Generate TypeScript declarations .d.ts file alongside JS file. Available in IR backend only.
|
||||
-Xinclude=<path> A path to an intermediate library that should be processed in the same manner as source files.
|
||||
-Xir-dce Perform experimental dead code elimination
|
||||
-Xir-only Disables pre-IR backend
|
||||
-Xir-produce-js Generates JS file using IR backend. Also disables pre-IR backend
|
||||
|
||||
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.js.messageCollectorLogger
|
||||
import org.jetbrains.kotlin.ir.backend.js.compile
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateKLib
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsPhases
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||
@@ -115,7 +112,7 @@ abstract class BasicIrBoxTest(
|
||||
|
||||
val compiledModule = compile(
|
||||
project = config.project,
|
||||
files = filesToCompile,
|
||||
mainModule = MainModule.SourceFiles(filesToCompile),
|
||||
configuration = config.configuration,
|
||||
phaseConfig = phaseConfig,
|
||||
allDependencies = resolvedLibraries,
|
||||
|
||||
Reference in New Issue
Block a user