diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt index 577b6356ccd..d18a40cd0e4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt @@ -163,7 +163,7 @@ constructor( val exportLibraries: FileCollection get() = exportLibrariesResolvedGraph?.files ?: objectFactory.fileCollection() private val exportLibrariesResolvedGraph = if (binary is AbstractNativeLibrary) { - ResolvedDependencyGraph(project.configurations.getByName(binary.exportConfigurationName)) + LazyResolvedConfiguration(project.configurations.getByName(binary.exportConfigurationName)) } else { null } @@ -247,7 +247,7 @@ constructor( protected val friendModule: FileCollection = objectFactory.fileCollection().from({ compilation.friendPaths }) @Suppress("DEPRECATION") - private val resolvedDependencyGraph = ResolvedDependencyGraph( + private val resolvedConfiguration = LazyResolvedConfiguration( project.configurations.getByName(compilation.compileDependencyConfigurationName) ) @@ -315,7 +315,7 @@ constructor( settings = cacheBuilderSettings, konanPropertiesService = konanPropertiesService.get() ) - addAll(cacheBuilder.buildCompilerArgs(resolvedDependencyGraph)) + addAll(cacheBuilder.buildCompilerArgs(resolvedConfiguration)) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index eb91bf8f9e6..6715b43ae1f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -757,20 +757,20 @@ internal class CacheBuilder( get() = PARTIAL_LINKAGE in settings.toolOptions.freeCompilerArgs.get() private fun getCacheDirectory( - resolvedDependencyGraph: ResolvedDependencyGraph, + resolvedConfiguration: LazyResolvedConfiguration, dependency: ResolvedDependencyResult ): File = getCacheDirectory( rootCacheDirectory = rootCacheDirectory, dependency = dependency, artifact = null, - resolvedDependencyGraph = resolvedDependencyGraph, + resolvedConfiguration = resolvedConfiguration, partialLinkage = partialLinkage ) private fun needCache(libraryPath: String) = libraryPath.startsWith(settings.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib") - private fun ResolvedDependencyGraph.ensureDependencyPrecached( + private fun LazyResolvedConfiguration.ensureDependencyPrecached( dependency: ResolvedDependencyResult, visitedDependencies: MutableSet ) { @@ -792,7 +792,7 @@ internal class CacheBuilder( rootCacheDirectory = rootCacheDirectory, dependency = dependency, considerArtifact = false, - resolvedDependencyGraph = this, + resolvedConfiguration = this, partialLinkage = partialLinkage ) ?: return @@ -916,17 +916,17 @@ internal class CacheBuilder( ensureCompilerProvidedLibPrecached(platformLibName, platformLibs, visitedLibs) } - fun buildCompilerArgs(resolvedDependencyGraph: ResolvedDependencyGraph): List = mutableListOf().apply { + fun buildCompilerArgs(resolvedConfiguration: LazyResolvedConfiguration): List = mutableListOf().apply { if (konanCacheKind != NativeCacheKind.NONE && !optimized && konanPropertiesService.cacheWorksFor(konanTarget)) { rootCacheDirectory.mkdirs() ensureCompilerProvidedLibsPrecached() add("-Xcache-directory=${rootCacheDirectory.absolutePath}") val visitedDependencies = mutableSetOf() val allCacheDirectories = mutableSetOf() - for (root in resolvedDependencyGraph.root.dependencies.filterIsInstance()) { - resolvedDependencyGraph.ensureDependencyPrecached(root, visitedDependencies) + for (root in resolvedConfiguration.root.dependencies.filterIsInstance()) { + resolvedConfiguration.ensureDependencyPrecached(root, visitedDependencies) for (dependency in listOf(root) + getAllDependencies(root)) { - val cacheDirectory = getCacheDirectory(resolvedDependencyGraph, dependency) + val cacheDirectory = getCacheDirectory(resolvedConfiguration, dependency) if (cacheDirectory.exists()) allCacheDirectories += cacheDirectory.absolutePath } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/LazyResolvedConfiguration.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/LazyResolvedConfiguration.kt new file mode 100644 index 00000000000..2c7b7f0f84c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/LazyResolvedConfiguration.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2023 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.gradle.utils + +import org.gradle.api.artifacts.ArtifactCollection +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.result.DependencyResult +import org.gradle.api.artifacts.result.ResolvedArtifactResult +import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.artifacts.result.ResolvedDependencyResult +import org.gradle.api.file.FileCollection + +/** + * Represents a Gradle Configuration that was resolved after configuration time. + * But still can be accessed during Configuration time, triggering configuration resolution + * + * Serializable to configuration cache. So it can be stored in task state and be accessed during execution time. + * + * Has similar API as non-configuration cache friendly Gradle's [ResolvedConfiguration] + */ +internal class LazyResolvedConfiguration +private constructor( + private val resolvedComponentsRootProvider: Lazy, + private val artifactCollection: ArtifactCollection +) { + constructor(configuration: Configuration) : this( + // Calling resolutionResult doesn't actually trigger resolution. But accessing its root ResolvedComponentResult + // via ResolutionResult::root does. ResolutionResult can't be serialised for Configuration Cache + // but ResolvedComponentResult can. Wrapping it in `lazy` makes it resolve upon serialisation. + resolvedComponentsRootProvider = configuration.incoming.resolutionResult.let { rr -> lazy { rr.root } }, + artifactCollection = configuration.incoming.artifacts // lazy ArtifactCollection + ) + + val root get() = resolvedComponentsRootProvider.value + val files: FileCollection get() = artifactCollection.artifactFiles + val artifacts get() = artifactCollection.artifacts + + private val artifactsByComponentId by TransientLazy { artifacts.groupBy { it.id.componentIdentifier } } + + val allDependencies: List get() { + fun DependencyResult.allDependenciesRecursive(): List = + if (this is ResolvedDependencyResult) { + listOf(this) + selected.dependencies.flatMap { it.allDependenciesRecursive() } + } else { + listOf(this) + } + + return root.dependencies.flatMap { it.allDependenciesRecursive() } + } + + fun dependencyArtifacts(dependency: ResolvedDependencyResult): List { + val componentId = dependency.selected.id + return artifactsByComponentId[componentId] ?: emptyList() + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt index 64125593cfa..2cd08d57aea 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/cacheKlibUtils.kt @@ -18,7 +18,7 @@ internal fun getCacheDirectory( rootCacheDirectory: File, dependency: ResolvedDependencyResult, artifact: ResolvedArtifactResult?, - resolvedDependencyGraph: ResolvedDependencyGraph, + resolvedConfiguration: LazyResolvedConfiguration, partialLinkage: Boolean ): File { val moduleCacheDirectory = File(rootCacheDirectory, dependency.selected.moduleVersion?.name ?: "undefined") @@ -41,17 +41,17 @@ internal fun getCacheDirectory( versionCacheDirectory.resolve(hash) } else versionCacheDirectory - return File(cacheDirectory, computeDependenciesHash(dependency, resolvedDependencyGraph, partialLinkage)) + return File(cacheDirectory, computeDependenciesHash(dependency, resolvedConfiguration, partialLinkage)) } internal fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } -private fun computeDependenciesHash(dependency: ResolvedDependencyResult, resolvedDependencyGraph: ResolvedDependencyGraph, partialLinkage: Boolean): String { +private fun computeDependenciesHash(dependency: ResolvedDependencyResult, resolvedConfiguration: LazyResolvedConfiguration, partialLinkage: Boolean): String { val hashedValue = buildString { if (partialLinkage) append("#__PL__#") (listOf(dependency) + getAllDependencies(dependency)) - .flatMap { resolvedDependencyGraph.dependencyArtifacts(it) } + .flatMap { resolvedConfiguration.dependencyArtifacts(it) } .map { it.file.absolutePath } .distinct() .sortedBy { it } @@ -66,19 +66,19 @@ private fun computeDependenciesHash(dependency: ResolvedDependencyResult, resolv internal fun getDependenciesCacheDirectories( rootCacheDirectory: File, dependency: ResolvedDependencyResult, - resolvedDependencyGraph: ResolvedDependencyGraph, + resolvedConfiguration: LazyResolvedConfiguration, considerArtifact: Boolean, partialLinkage: Boolean ): List? { return getAllDependencies(dependency) .flatMap { childDependency -> - resolvedDependencyGraph.dependencyArtifacts(childDependency).map { + resolvedConfiguration.dependencyArtifacts(childDependency).map { if (libraryFilter(it)) { val cacheDirectory = getCacheDirectory( rootCacheDirectory = rootCacheDirectory, dependency = childDependency, artifact = if (considerArtifact) it else null, - resolvedDependencyGraph = resolvedDependencyGraph, + resolvedConfiguration = resolvedConfiguration, partialLinkage = partialLinkage ) if (!cacheDirectory.exists()) return null diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt index 39b61a24082..005ba5fb1db 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt @@ -5,15 +5,7 @@ package org.jetbrains.kotlin.gradle.utils -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.result.DependencyResult -import org.gradle.api.artifacts.result.ResolvedArtifactResult -import org.gradle.api.artifacts.result.ResolvedComponentResult -import org.gradle.api.artifacts.result.ResolvedDependencyResult -import org.gradle.api.file.FileCollection -import org.gradle.api.provider.Provider const val COMPILE_ONLY = "compileOnly" const val COMPILE = "compile" @@ -23,45 +15,6 @@ const val RUNTIME_ONLY = "runtimeOnly" const val RUNTIME = "runtime" internal const val INTRANSITIVE = "intransitive" -/** - * Gradle Configuration Cache-friendly representation of resolved Configuration - */ -internal class ResolvedDependencyGraph -private constructor( - private val resolvedComponentsRootProvider: Lazy, - private val artifactCollection: ArtifactCollection -) { - constructor(configuration: Configuration) : this( - // Calling resolutionResult doesn't actually trigger resolution. But accessing its root ResolvedComponentResult - // via ResolutionResult::root does. ResolutionResult can't be serialised for Configuration Cache - // but ResolvedComponentResult can. Wrapping it in `lazy` makes it resolve upon serialisation. - resolvedComponentsRootProvider = configuration.incoming.resolutionResult.let { rr -> lazy { rr.root } }, - artifactCollection = configuration.incoming.artifacts // lazy ArtifactCollection - ) - - val root get() = resolvedComponentsRootProvider.value - val files: FileCollection get() = artifactCollection.artifactFiles - val artifacts get() = artifactCollection.artifacts - - private val artifactsByComponentId by TransientLazy { artifacts.groupBy { it.id.componentIdentifier } } - - val allDependencies: List get() { - fun DependencyResult.allDependenciesRecursive(): List = - if (this is ResolvedDependencyResult) { - listOf(this) + selected.dependencies.flatMap { it.allDependenciesRecursive() } - } else { - listOf(this) - } - - return root.dependencies.flatMap { it.allDependenciesRecursive() } - } - - fun dependencyArtifacts(dependency: ResolvedDependencyResult): List { - val componentId = dependency.selected.id - return artifactsByComponentId[componentId] ?: emptyList() - } -} - internal fun Configuration.markConsumable(): Configuration = apply { this.isCanBeConsumed = true this.isCanBeResolved = false