From 1604ab1e0bd56b23fca526515c28971015e9b39a Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Thu, 30 Nov 2023 22:28:53 +0100 Subject: [PATCH] [Gradle] Add SetupKotlinNativePlatformDependenciesAndStdlib This extension point adds NativePlatformDependencies And Stdlib to compileFiles of Native Compilations. ^KT-61559 Verification Pending --- .../checkers/MissingNativeStdlibChecker.kt | 2 +- .../KotlinCompilationSideEffect.kt | 7 ++ .../plugin/registerKotlinPluginExtensions.kt | 2 + .../KotlinNativePlatformDependencies.kt | 74 +------------------ ...tlinNativePlatformDependenciesAndStdlib.kt | 72 ++++++++++++++++++ .../gradle/utils/kotlinExtensionUtils.kt | 7 ++ 6 files changed, 93 insertions(+), 71 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/MissingNativeStdlibChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/MissingNativeStdlibChecker.kt index 64d7b5b4049..48d8d8c5c96 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/MissingNativeStdlibChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/MissingNativeStdlibChecker.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext -import org.jetbrains.kotlin.gradle.targets.native.internal.konanDistribution import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.gradle.utils.konanDistribution internal object MissingNativeStdlibChecker : KotlinGradleProjectChecker { override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSideEffect.kt index 606e9afd5fe..f47ec35bf1a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSideEffect.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSideEffect.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinGradlePluginExtensionPoint import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.plugin.launch internal fun interface KotlinCompilationSideEffect { operator fun invoke(compilation: KotlinCompilation<*>) @@ -23,6 +24,12 @@ internal inline fun > KotlinCompilationSideEffe if (compilation is T) effect(compilation) } +internal inline fun > KotlinCompilationSideEffectCoroutine( + crossinline effect: suspend (T) -> Unit, +) = KotlinCompilationSideEffect { compilation -> + if (compilation is T) compilation.project.launch { effect(compilation) } +} + internal fun KotlinTarget.runKotlinCompilationSideEffects() = compilations.all { compilation -> KotlinCompilationSideEffect.extensionPoint[project].forEach { effect -> effect(compilation) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt index f51b1651168..7584ed7bf91 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeConfigureBinariesS import org.jetbrains.kotlin.gradle.targets.native.SetupEmbedAndSignAppleFrameworkTaskSideEffect import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizedCInteropApiElementsConfigurationsSetupAction import org.jetbrains.kotlin.gradle.targets.native.internal.SetupCInteropApiElementsConfigurationSideEffect +import org.jetbrains.kotlin.gradle.targets.native.internal.SetupKotlinNativePlatformDependenciesAndStdlib import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.KotlinArtifactsExtensionSetupAction import org.jetbrains.kotlin.gradle.tooling.RegisterBuildKotlinToolingMetadataTask @@ -95,6 +96,7 @@ internal fun Project.registerKotlinPluginExtensions() { register(project, KotlinCompilationProcessorSideEffect) register(project, KotlinCreateNativeCInteropTasksSideEffect) register(project, KotlinCreateCompilationArchivesTask) + register(project, SetupKotlinNativePlatformDependenciesAndStdlib) } KotlinTargetArtifact.extensionPoint.apply { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/KotlinNativePlatformDependencies.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/KotlinNativePlatformDependencies.kt index 09afbeb22e4..4dc6f8b5c2b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/KotlinNativePlatformDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/KotlinNativePlatformDependencies.kt @@ -16,35 +16,20 @@ import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP import org.jetbrains.kotlin.gradle.internal.PLATFORM_INTEGERS_SUPPORT_LIBRARY import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.ide.ideaImportDependsOn +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSideEffectCoroutine import org.jetbrains.kotlin.gradle.plugin.sources.* import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.targets.metadata.findMetadataCompilation import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.utils.filesProvider +import org.jetbrains.kotlin.gradle.utils.konanDistribution import java.io.File internal fun Project.setupKotlinNativePlatformDependencies() { val kotlin = multiplatformExtensionOrNull ?: return - if (isAllowCommonizer()) { - checkNotNull(commonizeNativeDistributionTask) { "Missing commonizeNativeDistributionTask" } - } - - kotlin.sourceSets.all { sourceSet -> - launch { - val target = sourceSet.internal.commonizerTarget.await() ?: return@launch - addDependencies(sourceSet, getNativeDistributionDependencies(target)) - addDependencies( - sourceSet, project.filesProvider { setOf(konanDistribution.stdlib) }, - /* - Shared Native compilations already implicitly add this dependency. - Adding it again will result in a warning - */ - isCompilationDependency = false - ) - } - } - launch { if (isPlatformIntegerCommonizationEnabled) { kotlin.nativeRootSourceSets().forEach { sourceSet -> @@ -57,19 +42,6 @@ internal fun Project.setupKotlinNativePlatformDependencies() { } } -internal fun Project.getNativeDistributionDependencies(target: CommonizerTarget): FileCollection { - return when (target) { - is LeafCommonizerTarget -> getOriginalPlatformLibrariesFor(target) - is SharedCommonizerTarget -> { - val commonizerTaskProvider = commonizeNativeDistributionTask ?: return project.files() - val commonizedLibrariesProvider = commonizerTaskProvider.flatMap { task -> - task.rootOutputDirectoryProperty.map { getCommonizedPlatformLibrariesFor(it.asFile, target) } - } - project.files(commonizedLibrariesProvider) - } - } -} - internal suspend fun KotlinMultiplatformExtension.nativeRootSourceSets(): Collection { val nativeSourceSets = sourceSets.filter { sourceSet -> sourceSet.internal.commonizerTarget.await() != null } return nativeSourceSets.filter { sourceSet -> @@ -80,44 +52,6 @@ internal suspend fun KotlinMultiplatformExtension.nativeRootSourceSets(): Collec } } -private fun Project.getOriginalPlatformLibrariesFor(target: LeafCommonizerTarget): FileCollection = project.filesProvider { - konanDistribution.platformLibsDir.resolve(target.konanTarget.name).listLibraryFiles().toSet() -} - -private fun getCommonizedPlatformLibrariesFor(rootOutputDirectory: File, target: SharedCommonizerTarget): List { - val targetOutputDirectory = CommonizerOutputFileLayout.resolveCommonizedDirectory(rootOutputDirectory, target) - return targetOutputDirectory.listLibraryFiles() -} - -private suspend fun InternalKotlinSourceSet.singlePlatformCompilationOrNull(): KotlinCompilation<*>? { - return awaitPlatformCompilations().distinctBy { it.target }.singleOrNull() -} - -private suspend fun Project.addDependencies( - sourceSet: KotlinSourceSet, libraries: FileCollection, isCompilationDependency: Boolean = true, isIdeDependency: Boolean = true -) { - if (isCompilationDependency) { - val compilation = findMetadataCompilation(sourceSet) ?: sourceSet.internal.singlePlatformCompilationOrNull() - if (compilation != null) { - compilation.compileDependencyFiles += libraries - } - } - - if (isIdeDependency && sourceSet is DefaultKotlinSourceSet) { - val metadataConfigurationName = - if (project.isIntransitiveMetadataConfigurationEnabled) sourceSet.intransitiveMetadataConfigurationName - else sourceSet.implementationMetadataConfigurationName - dependencies.add(metadataConfigurationName, libraries) - } -} - -internal val Project.konanDistribution: KonanDistribution - get() = KonanDistribution(project.file(konanHome)) - -private fun File.listLibraryFiles(): List = listFiles().orEmpty() - .filter { it.isDirectory || it.extension == "klib" } - - /** * Function signature needs to be kept stable since this is used during import * in IDEs (KotlinCommonizerModelBuilder) < 222 diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt new file mode 100644 index 00000000000..c6926edc25e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/SetupKotlinNativePlatformDependenciesAndStdlib.kt @@ -0,0 +1,72 @@ +/* + * 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.targets.native.internal + +import org.gradle.api.Project +import org.gradle.api.file.FileCollection +import org.jetbrains.kotlin.commonizer.* +import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSideEffectCoroutine +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.utils.filesProvider +import org.jetbrains.kotlin.gradle.utils.konanDistribution +import java.io.File + +internal val SetupKotlinNativePlatformDependenciesAndStdlib = + KotlinCompilationSideEffectCoroutine { compilation -> + val project = compilation.project + + // Commonizer target must not be null for AbstractKotlinNativeCompilation, but we are graceful here and just return + val commonizerTarget = compilation.commonizerTarget.await() ?: return@KotlinCompilationSideEffectCoroutine + val nativeDistributionDependencies = project.getNativeDistributionDependencies(commonizerTarget) + compilation.compileDependencyFiles += nativeDistributionDependencies + + val stdlib = project.files(project.konanDistribution.stdlib) + compilation.compileDependencyFiles += stdlib + + val defaultSourceSet = compilation.defaultSourceSet + if (defaultSourceSet is DefaultKotlinSourceSet) { + defaultSourceSet.addDependencyForLegacyImport(nativeDistributionDependencies) + defaultSourceSet.addDependencyForLegacyImport(stdlib) + } + } + +internal fun Project.getNativeDistributionDependencies(target: CommonizerTarget): FileCollection { + return when (target) { + is LeafCommonizerTarget -> getOriginalPlatformLibrariesFor(target) + is SharedCommonizerTarget -> { + val commonizerTaskProvider = commonizeNativeDistributionTask ?: return project.files() + val commonizedLibrariesProvider = commonizerTaskProvider.flatMap { task -> + task.rootOutputDirectoryProperty.map { getCommonizedPlatformLibrariesFor(it.asFile, target) } + } + project.files(commonizedLibrariesProvider) + } + } +} + +private fun Project.getOriginalPlatformLibrariesFor(target: LeafCommonizerTarget): FileCollection = project.filesProvider { + konanDistribution.platformLibsDir.resolve(target.konanTarget.name).listLibraryFiles().toSet() +} + +private fun getCommonizedPlatformLibrariesFor(rootOutputDirectory: File, target: SharedCommonizerTarget): List { + val targetOutputDirectory = CommonizerOutputFileLayout.resolveCommonizedDirectory(rootOutputDirectory, target) + return targetOutputDirectory.listLibraryFiles() +} + +private fun File.listLibraryFiles(): List = listFiles().orEmpty() + .filter { it.isDirectory || it.extension == "klib" } + +/** + * Legacy resolves [implementationMetadataConfigurationName] and [intransitiveMetadataConfigurationName] + * to get dependencies for given source set. Therefore, compileDependencyFiles and dependencies in those configurations + * must be synced. + */ +private fun DefaultKotlinSourceSet.addDependencyForLegacyImport(libraries: FileCollection) { + val metadataConfigurationName = + if (project.isIntransitiveMetadataConfigurationEnabled) intransitiveMetadataConfigurationName + else implementationMetadataConfigurationName + project.dependencies.add(metadataConfigurationName, libraries) +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/kotlinExtensionUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/kotlinExtensionUtils.kt index 93f83431a2c..dce9e777506 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/kotlinExtensionUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/kotlinExtensionUtils.kt @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.gradle.utils +import org.gradle.api.Project +import org.jetbrains.kotlin.commonizer.KonanDistribution +import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension @@ -27,3 +30,7 @@ internal fun KotlinProjectExtension.forAllTargets(action: (target: KotlinTarget) else -> error("Unexpected 'kotlin' extension $this") } } + +internal val Project.konanDistribution: KonanDistribution + get() = KonanDistribution(project.file(konanHome)) +