[JS IR] Build stdlib using compiler from repo
Previously JS IR versions of stdlib and kotlin-test were build
by default using compiler previously built on a buildserver.
It had some issues:
- This required us to advance bootstrap every time we made any
incompatible IR changes. This happens often since IR ABI is
not quite stable yet.
- We never tested the exact combination of compiler and stdlib we publish
We tested:
- new compiler with new stdlib build by new compiler (in box tests)
- old compiler with new stdlib build by old compiler (in stdlib tests)
We published:
- new compiler with new stdlib build by old compiler
After this change JS IR compiler tests, builds and publishes
single configuration:
new compiler with new stdlib build by new compiler
JS IR stdlib and kotlin-test are now built using JavaExec of CLI instead
of Gradle plugin to avoid troubles of loading a freshly built plugin.
This also allows to have a granular dependencies: we don't rebuild klib
if we changed a lowering in a compiler backend, but we do rebuild it if
we changed IR serialization algorithm.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
// Internal CLI for building JS IR libraries
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import java.io.File
|
||||
|
||||
fun buildConfiguration(environment: KotlinCoreEnvironment, moduleName: String): CompilerConfiguration {
|
||||
val runtimeConfiguration = environment.configuration.copy()
|
||||
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||
runtimeConfiguration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
|
||||
runtimeConfiguration.put(
|
||||
CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY,
|
||||
PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, false)
|
||||
)
|
||||
|
||||
runtimeConfiguration.languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE,
|
||||
specificFeatures = mapOf(
|
||||
LanguageFeature.AllowContractsForCustomFunctions to LanguageFeature.State.ENABLED,
|
||||
LanguageFeature.MultiPlatformProjects to LanguageFeature.State.ENABLED
|
||||
),
|
||||
analysisFlags = mapOf(
|
||||
AnalysisFlags.useExperimental to listOf(
|
||||
"kotlin.contracts.ExperimentalContracts",
|
||||
"kotlin.Experimental",
|
||||
"kotlin.ExperimentalMultiplatform"
|
||||
),
|
||||
AnalysisFlags.allowResultReturnType to true
|
||||
)
|
||||
)
|
||||
|
||||
return runtimeConfiguration
|
||||
}
|
||||
|
||||
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
|
||||
fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
|
||||
fun buildKLib(
|
||||
moduleName: String,
|
||||
sources: List<String>,
|
||||
outputPath: String,
|
||||
allDependencies: KotlinLibraryResolveResult,
|
||||
commonSources: List<String>
|
||||
) {
|
||||
generateKLib(
|
||||
project = environment.project,
|
||||
files = sources.map { source ->
|
||||
val file = createPsiFile(source)
|
||||
if (source in commonSources) {
|
||||
file.isCommonSource = true
|
||||
}
|
||||
file
|
||||
},
|
||||
configuration = buildConfiguration(environment, moduleName),
|
||||
allDependencies = allDependencies,
|
||||
friendDependencies = emptyList(),
|
||||
outputKlibPath = outputPath,
|
||||
nopack = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun listOfKtFilesFrom(paths: List<String>): List<String> {
|
||||
val currentDir = File("")
|
||||
return paths.flatMap { path ->
|
||||
File(path)
|
||||
.walkTopDown()
|
||||
.filter { it.extension == "kt" }
|
||||
.map { it.relativeToOrSelf(currentDir).path }
|
||||
.asIterable()
|
||||
}.distinct()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val inputFiles = mutableListOf<String>()
|
||||
var outputPath: String? = null
|
||||
val dependencies = mutableListOf<String>()
|
||||
val commonSources = mutableListOf<String>()
|
||||
|
||||
var index = 0
|
||||
while (index < args.size) {
|
||||
val arg = args[index++]
|
||||
|
||||
when (arg) {
|
||||
"-o" -> outputPath = args[index++]
|
||||
"-d" -> dependencies += args[index++]
|
||||
"-c" -> commonSources += args[index++]
|
||||
else -> inputFiles += arg
|
||||
}
|
||||
}
|
||||
|
||||
if (outputPath == null) {
|
||||
error("Please set path to .klm file: `-o some/dir/module-name.klm`")
|
||||
}
|
||||
|
||||
val resolvedLibraries = jsResolveLibraries(
|
||||
dependencies, messageCollectorLogger(MessageCollector.NONE)
|
||||
)
|
||||
|
||||
buildKLib(File(outputPath).absolutePath, listOfKtFilesFrom(inputFiles), outputPath, resolvedLibraries, listOfKtFilesFrom(commonSources))
|
||||
}
|
||||
|
||||
// Copied here from `K2JsIrCompiler` instead of reusing in order to avoid circular dependencies between Gradle tasks
|
||||
private fun messageCollectorLogger(collector: MessageCollector) = object : Logger {
|
||||
override fun warning(message: String)= collector.report(CompilerMessageSeverity.STRONG_WARNING, message)
|
||||
override fun error(message: String) = collector.report(CompilerMessageSeverity.ERROR, message)
|
||||
override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message)
|
||||
override fun fatal(message: String): Nothing {
|
||||
collector.report(CompilerMessageSeverity.ERROR, message)
|
||||
(collector as? GroupingMessageCollector)?.flush()
|
||||
kotlin.error(message)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user