diff --git a/libraries/kotlin.test/js-ir/it/gradle.properties b/libraries/kotlin.test/js-ir/it/gradle.properties new file mode 100644 index 00000000000..4f723edc1fe --- /dev/null +++ b/libraries/kotlin.test/js-ir/it/gradle.properties @@ -0,0 +1 @@ +kotlin.incremental.js.ir=false \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index 5d0ac926d0f..2ff1eb010e2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ResolvedArtifact import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty @@ -42,6 +43,9 @@ import org.jetbrains.kotlin.gradle.utils.getAllDependencies import org.jetbrains.kotlin.gradle.utils.getCacheDirectory import org.jetbrains.kotlin.gradle.utils.getDependenciesCacheDirectories import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.library.resolveSingleFileKlib +import org.jetbrains.kotlin.library.uniqueName +import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics import java.io.File @@ -260,10 +264,12 @@ internal class CacheBuilder( .filter { it !in visitedDependenciesForCache } .forEach { dependencyForCache -> visitedDependenciesForCache.add(dependencyForCache) - val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependencyForCache) - if (cacheDirectory.exists()) { - allCacheDirectories.add(cacheDirectory) - } + dependencyForCache.moduleArtifacts + .map { + getCacheDirectory(rootCacheDirectory, dependencyForCache, it, { libraryFilter(it.file) }) + } + .filter { it.exists() } + .forEach { allCacheDirectories.add(it) } } } } @@ -301,20 +307,65 @@ internal class CacheBuilder( val dependenciesCacheDirectories = getDependenciesCacheDirectories( rootCacheDirectory, - dependency + dependency, + libraryFilter = { libraryFilter(it.file) } ) ?: return - val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependency) - cacheDirectory.mkdirs() + val nameMap: MutableMap = mutableMapOf() + val depsMap: MutableMap> = mutableMapOf() + val cacheMap: MutableMap = mutableMapOf() + var newOrderArtifactsToAddToCache = mutableListOf() - for (library in artifactsToAddToCache) { + if (artifactsToAddToCache.size > 1) { + artifactsToAddToCache.forEach { + val klib = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(it.file.absolutePath)) + nameMap[klib.uniqueName] = it + } + artifactsToAddToCache.forEach { artifact -> + val klib = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(artifact.file.absolutePath)) + klib.unresolvedDependencies + .forEach { depLib -> + val depName = depLib.path.substringAfterLast("/") + nameMap[depName]?.let { + val depsSet = depsMap.getOrPut(artifact) { + mutableListOf() + } + depsSet.add(it) + } + } + } + fun traverseDependency(library: ResolvedArtifact) { + depsMap[library]?.let { + it.forEach { + traverseDependency(it) + } + } + if (library !in newOrderArtifactsToAddToCache) { + newOrderArtifactsToAddToCache.add(library) + } + } + depsMap.forEach { key, deps -> + traverseDependency(key) + } + } else { + newOrderArtifactsToAddToCache = artifactsToAddToCache.toMutableList() + } + + for (library in newOrderArtifactsToAddToCache) { + val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependency, library, { libraryFilter(it.file) }) + cacheDirectory.mkdirs() + cacheMap[library] = cacheDirectory + val additionalDependencies = depsMap[library] ?: emptyList() + val additionalCacheDirectories = if (additionalDependencies.isNotEmpty()) { + additionalDependencies.map { cacheMap.getValue(it) } + } else emptyList() runCompiler( library.file, - getAllDependencies(dependency) - .flatMap { it.moduleArtifacts } + (getAllDependencies(dependency) + .flatMap { it.moduleArtifacts } + additionalDependencies) .map { it.file }, cacheDirectory, - dependenciesCacheDirectories + dependenciesCacheDirectories + additionalCacheDirectories ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt index ac2ae0a5d8b..43a548a9519 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt @@ -5,19 +5,42 @@ package org.jetbrains.kotlin.gradle.utils +import org.gradle.api.artifacts.ResolvedArtifact import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.logging.Logger +import org.jetbrains.kotlin.library.resolveSingleFileKlib +import org.jetbrains.kotlin.library.uniqueName import java.io.File import java.nio.charset.StandardCharsets import java.security.MessageDigest fun getCacheDirectory( rootCacheDirectory: File, - dependency: ResolvedDependency + dependency: ResolvedDependency, + artifact: ResolvedArtifact? = null, + libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") } ): File { val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName) val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion) - return File(versionCacheDirectory, computeDependenciesHash(dependency)) + val uniqueName = artifact + ?.let { + if (libraryFilter(it)) + it.file + else + null + } + ?.let { + resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(it.absolutePath)) + } + ?.uniqueName + + val cacheDirectory = if (uniqueName != null) { + val digest = MessageDigest.getInstance("SHA-256") + val hash = digest.digest(uniqueName.toByteArray(StandardCharsets.UTF_8)).toHexString() + versionCacheDirectory.resolve(hash) + } else versionCacheDirectory + + return File(cacheDirectory, computeDependenciesHash(dependency)) } private fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } @@ -36,17 +59,22 @@ private fun computeDependenciesHash(dependency: ResolvedDependency): String { fun getDependenciesCacheDirectories( rootCacheDirectory: File, - dependency: ResolvedDependency + dependency: ResolvedDependency, + libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") } ): List? { return getAllDependencies(dependency) - .map { childDependency -> - val hasKlibs = childDependency.moduleArtifacts.any { it.file.absolutePath.endsWith(".klib") } - val cacheDirectory = getCacheDirectory(rootCacheDirectory, childDependency) - // We can only compile klib to cache if all of its dependencies are also cached. - if (hasKlibs && !cacheDirectory.exists()) - return null - cacheDirectory + .flatMap { childDependency -> + childDependency.moduleArtifacts.map { + if (libraryFilter(it)) { + val cacheDirectory = getCacheDirectory(rootCacheDirectory, childDependency, it, libraryFilter) + if (!cacheDirectory.exists()) return null + cacheDirectory + } else { + null + } + } } + .filterNotNull() .filter { it.exists() } }