All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.jps.targets.KotlinJsModuleBuildTarget.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2021 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.
*/
package org.jetbrains.kotlin.jps.targets
import org.jetbrains.jps.builders.storage.BuildDataPaths
import org.jetbrains.jps.incremental.ModuleBuildTarget
import org.jetbrains.jps.incremental.ModuleLevelBuilder
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.JsBuildMetaInfo
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.JpsKotlinCompilerRunner
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.ChangesCollector
import org.jetbrains.kotlin.incremental.IncrementalJsCache
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderFromCache
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
import org.jetbrains.kotlin.jps.build.KotlinCompileContext
import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder
import org.jetbrains.kotlin.jps.build.ModuleBuildTarget
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalJsCache
import org.jetbrains.kotlin.jps.model.k2JsCompilerArguments
import org.jetbrains.kotlin.jps.model.kotlinCompilerSettings
import org.jetbrains.kotlin.jps.model.productionOutputFilePath
import org.jetbrains.kotlin.jps.model.testOutputFilePath
import org.jetbrains.kotlin.utils.JsLibraryUtils
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils.JS_EXT
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils.META_JS_SUFFIX
import java.io.File
import java.net.URI
import java.nio.file.Files
private const val JS_BUILD_META_INFO_FILE_NAME = "js-build-meta-info.txt"
class KotlinJsModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleBuildTarget: ModuleBuildTarget) :
KotlinModuleBuildTarget(kotlinContext, jpsModuleBuildTarget) {
override val globalLookupCacheId: String
get() = "js"
override val isIncrementalCompilationEnabled: Boolean
get() = IncrementalCompilation.isEnabledForJs()
override val buildMetaInfoFactory
get() = JsBuildMetaInfo
override val buildMetaInfoFileName: String
get() = JS_BUILD_META_INFO_FILE_NAME
val isFirstBuild: Boolean
get() {
val targetDataRoot = jpsGlobalContext.projectDescriptor.dataManager.dataPaths.getTargetDataRoot(jpsModuleBuildTarget)
return !IncrementalJsCache.hasHeaderFile(targetDataRoot)
}
override fun makeServices(
builder: Services.Builder,
incrementalCaches: Map, JpsIncrementalCache>,
lookupTracker: LookupTracker,
exceptActualTracer: ExpectActualTracker,
inlineConstTracker: InlineConstTracker
) {
super.makeServices(builder, incrementalCaches, lookupTracker, exceptActualTracer, inlineConstTracker)
with(builder) {
register(IncrementalResultsConsumer::class.java, IncrementalResultsConsumerImpl())
if (isIncrementalCompilationEnabled && !isFirstBuild) {
val cache = incrementalCaches[this@KotlinJsModuleBuildTarget] as IncrementalJsCache
register(
IncrementalDataProvider::class.java,
IncrementalDataProviderFromCache(cache)
)
}
}
}
override fun compileModuleChunk(
commonArguments: CommonCompilerArguments,
dirtyFilesHolder: KotlinDirtySourceFilesHolder,
environment: JpsCompilerEnvironment
): Boolean {
require(chunk.representativeTarget == this)
if (reportAndSkipCircular(environment)) return false
val sources = collectSourcesToCompile(dirtyFilesHolder)
if (!sources.logFiles()) {
return false
}
val libraries = libraryFiles + dependenciesMetaFiles
JpsKotlinCompilerRunner().runK2JsCompiler(
commonArguments,
module.k2JsCompilerArguments,
module.kotlinCompilerSettings,
environment,
sources.allFiles,
sources.crossCompiledFiles,
sourceMapRoots,
libraries,
friendBuildTargetsMetaFiles,
outputFile
)
return true
}
override fun doAfterBuild() {
copyJsLibraryFilesIfNeeded()
}
private fun copyJsLibraryFilesIfNeeded() {
if (module.kotlinCompilerSettings.copyJsLibraryFiles) {
val outputLibraryRuntimeDirectory = File(outputDir, module.kotlinCompilerSettings.outputDirectoryForJsLibraryFiles).absolutePath
JsLibraryUtils.copyJsFilesFromLibraries(
libraryFiles, outputLibraryRuntimeDirectory,
copySourceMap = module.k2JsCompilerArguments.sourceMap
)
}
}
private val sourceMapRoots: List
get() {
// Compiler starts to produce path relative to base dirs in source maps if at least one statement is true:
// 1) base dirs are specified;
// 2) prefix is specified (i.e. non-empty)
// Otherwise compiler produces paths relative to source maps location.
// We don't have UI to configure base dirs, but we have UI to configure prefix.
// If prefix is not specified (empty) in UI, we want to produce paths relative to source maps location
return if (module.k2JsCompilerArguments.sourceMapPrefix.isNullOrBlank()) emptyList()
else module.contentRootsList.urls
.map { URI.create(it) }
.filter { it.scheme == "file" }
.map { File(it.path) }
}
val friendBuildTargetsMetaFiles
get() = friendBuildTargets.mapNotNull {
(it as? KotlinJsModuleBuildTarget)?.outputMetaFile?.absoluteFile?.toString()
}
val outputFile
get() = explicitOutputPath?.let { File(it) } ?: implicitOutputFile
private val explicitOutputPath
get() = if (isTests) module.testOutputFilePath else module.productionOutputFilePath
private val implicitOutputFile: File
get() {
val suffix = if (isTests) "_test" else ""
return File(outputDir, module.name + suffix + JS_EXT)
}
private val outputFileBaseName: String
get() = outputFile.path.substringBeforeLast(".")
val outputMetaFile: File
get() = File(outputFileBaseName + META_JS_SUFFIX)
private val libraryFiles: List
get() = mutableListOf().also { result ->
for (library in allDependencies.libraries) {
for (root in library.getRoots(JpsOrderRootType.COMPILED)) {
result.add(JpsPathUtil.urlToPath(root.url))
}
}
}
private val dependenciesMetaFiles: List
get() = mutableListOf().also { result ->
allDependencies.processModules { module ->
if (isTests) addDependencyMetaFile(module, result, isTests = true)
// note: production targets should be also added as dependency to test targets
addDependencyMetaFile(module, result, isTests = false)
}
}
private fun addDependencyMetaFile(
module: JpsModule,
result: MutableList,
isTests: Boolean
) {
val dependencyBuildTarget = kotlinContext.targetsBinding[ModuleBuildTarget(module, isTests)]
if (dependencyBuildTarget != this@KotlinJsModuleBuildTarget &&
dependencyBuildTarget is KotlinJsModuleBuildTarget &&
dependencyBuildTarget.sources.isNotEmpty()
) {
val metaFile = dependencyBuildTarget.outputMetaFile.toPath()
if (Files.exists(metaFile)) {
result.add(metaFile.toAbsolutePath().toString())
}
}
}
override fun createCacheStorage(paths: BuildDataPaths) =
JpsIncrementalJsCache(jpsModuleBuildTarget, paths, kotlinContext.fileToPathConverter)
override fun updateCaches(
dirtyFilesHolder: KotlinDirtySourceFilesHolder,
jpsIncrementalCache: JpsIncrementalCache,
files: List,
changesCollector: ChangesCollector,
environment: JpsCompilerEnvironment
) {
super.updateCaches(dirtyFilesHolder, jpsIncrementalCache, files, changesCollector, environment)
val incrementalResults = environment.services[IncrementalResultsConsumer::class.java] as IncrementalResultsConsumerImpl
val jsCache = jpsIncrementalCache as IncrementalJsCache
jsCache.header = incrementalResults.headerMetadata
jsCache.updateSourceToOutputMap(files)
jsCache.compareAndUpdate(incrementalResults, changesCollector)
jsCache.clearCacheForRemovedClasses(changesCollector)
}
override fun registerOutputItems(outputConsumer: ModuleLevelBuilder.OutputConsumer, outputItems: List) {
if (isIncrementalCompilationEnabled) {
for (output in outputItems) {
for (source in output.sourceFiles) {
outputConsumer.registerOutputFile(jpsModuleBuildTarget, File("${source.path.hashCode()}"), listOf(source.path))
}
}
} else {
super.registerOutputItems(outputConsumer, outputItems)
}
}
}