diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 8eb80df9f09..ce5011a6d66 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -629,7 +629,7 @@ constructor( } val externalDependenciesArgs = ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() - val cacheArgs = CacheBuilder(project, binary, konanTarget, externalDependenciesArgs).buildCompilerArgs() + val cacheArgs = CacheBuilder(project, binary, konanTarget, localKotlinOptions, externalDependenciesArgs).buildCompilerArgs() val buildArgs = buildKotlinNativeBinaryLinkerArgs( output, @@ -837,6 +837,7 @@ internal class CacheBuilder( val project: Project, val binary: NativeBinary, val konanTarget: KonanTarget, + val kotlinOptions: KotlinCommonToolOptions, val externalDependenciesArgs: List ) { @@ -870,11 +871,15 @@ internal class CacheBuilder( getRootCacheDirectory(File(project.konanHome), konanTarget, debuggable, konanCacheKind) } - private fun getCacheDirectory( - dependency: ResolvedDependency - ): File { - return getCacheDirectory(rootCacheDirectory, dependency) - } + private val partialLinkage: Boolean + get() = PARTIAL_LINKAGE in kotlinOptions.freeCompilerArgs + + private fun getCacheDirectory(dependency: ResolvedDependency): File = getCacheDirectory( + rootCacheDirectory = rootCacheDirectory, + dependency = dependency, + artifact = null, + partialLinkage = partialLinkage + ) private fun needCache(libraryPath: String) = libraryPath.startsWith(project.gradle.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib") @@ -889,8 +894,10 @@ internal class CacheBuilder( if (artifactsToAddToCache.isEmpty()) return val dependenciesCacheDirectories = getDependenciesCacheDirectories( - rootCacheDirectory, - dependency + rootCacheDirectory = rootCacheDirectory, + dependency = dependency, + considerArtifact = false, + partialLinkage = partialLinkage ) ?: return val cacheDirectory = getCacheDirectory(dependency) @@ -933,10 +940,10 @@ internal class CacheBuilder( "-p", konanCacheKind.produce!!, "-target", target ) - if (debuggable) - args += "-g" + if (debuggable) args += "-g" args += konanPropertiesService.additionalCacheFlags(konanTarget) args += externalDependenciesArgs + if (partialLinkage) args += PARTIAL_LINKAGE args += "-Xadd-cache=${library.libraryFile.absolutePath}" args += "-Xcache-directory=${cacheDirectory.absolutePath}" args += "-Xcache-directory=${rootCacheDirectory.absolutePath}" @@ -1045,6 +1052,8 @@ internal class CacheBuilder( cacheKind.outputKind?.let { "${baseName}-cache" } ?: error("No output for kind $cacheKind") + + private const val PARTIAL_LINKAGE = "-Xpartial-linkage" } } 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 8a8fe7850a5..66181163ef4 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 @@ -17,8 +17,8 @@ import java.security.MessageDigest fun getCacheDirectory( rootCacheDirectory: File, dependency: ResolvedDependency, - artifact: ResolvedArtifact? = null, - libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") } + artifact: ResolvedArtifact?, + partialLinkage: Boolean ): File { val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName) val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion) @@ -40,38 +40,42 @@ fun getCacheDirectory( versionCacheDirectory.resolve(hash) } else versionCacheDirectory - return File(cacheDirectory, computeDependenciesHash(dependency)) + return File(cacheDirectory, computeDependenciesHash(dependency, partialLinkage)) } internal fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } -private fun computeDependenciesHash(dependency: ResolvedDependency): String { - val allArtifactsPaths = +private fun computeDependenciesHash(dependency: ResolvedDependency, partialLinkage: Boolean): String { + val hashedValue = buildString { + if (partialLinkage) append("#__PL__#") + (dependency.moduleArtifacts + getAllDependencies(dependency).flatMap { it.moduleArtifacts }) .map { it.file.absolutePath } .distinct() .sortedBy { it } - .joinToString("|") { it } + .joinTo(this, separator = "|") + } + val digest = MessageDigest.getInstance("SHA-256") - val hash = digest.digest(allArtifactsPaths.toByteArray(StandardCharsets.UTF_8)) + val hash = digest.digest(hashedValue.toByteArray(StandardCharsets.UTF_8)) return hash.toHexString() } fun getDependenciesCacheDirectories( rootCacheDirectory: File, dependency: ResolvedDependency, - libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") }, - considerArtifact: Boolean = false + considerArtifact: Boolean, + partialLinkage: Boolean ): List? { return getAllDependencies(dependency) .flatMap { childDependency -> childDependency.moduleArtifacts.map { if (libraryFilter(it)) { val cacheDirectory = getCacheDirectory( - rootCacheDirectory, - childDependency, - if (considerArtifact) it else null, - libraryFilter + rootCacheDirectory = rootCacheDirectory, + dependency = childDependency, + artifact = if (considerArtifact) it else null, + partialLinkage = partialLinkage ) if (!cacheDirectory.exists()) return null cacheDirectory @@ -104,3 +108,5 @@ internal class GradleLoggerAdapter(private val gradleLogger: Logger) : org.jetbr override fun error(message: String) = kotlin.error(message) override fun fatal(message: String): Nothing = kotlin.error(message) } + +private fun libraryFilter(artifact: ResolvedArtifact): Boolean = artifact.file.absolutePath.endsWith(".klib")