diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt index 859694c029f..8dc7febdb6b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt @@ -515,7 +515,7 @@ class CocoaPodsIT : KGPBaseTest() { @GradleTest fun testCinteropCommonizationOff(gradleVersion: GradleVersion) { nativeProjectWithCocoapodsAndIosAppPodFile(cocoapodsCommonizationProjectName, gradleVersion) { - buildWithCocoapodsWrapper(":commonize") { + buildWithCocoapodsWrapper(":commonize", "-Pkotlin.mpp.enableCInteropCommonization=false") { assertTasksExecuted(":commonizeNativeDistribution") assertTasksNotExecuted(":cinteropAFNetworkingIosArm64") assertTasksNotExecuted(":cinteropAFNetworkingIosX64") @@ -527,8 +527,21 @@ class CocoaPodsIT : KGPBaseTest() { @DisplayName("Cinterop commonization on") @GradleTest fun testCinteropCommonizationOn(gradleVersion: GradleVersion) { + testCinteropCommonizationExecutes(gradleVersion, buildArguments=arrayOf("-Pkotlin.mpp.enableCInteropCommonization=true")) + } + + @DisplayName("Cinterop commonization unspecified") + @GradleTest + fun testCinteropCommonizationUnspecified(gradleVersion: GradleVersion) { + testCinteropCommonizationExecutes(gradleVersion, buildArguments=emptyArray()) + } + + private fun testCinteropCommonizationExecutes( + gradleVersion: GradleVersion, + buildArguments: Array + ) { nativeProjectWithCocoapodsAndIosAppPodFile(cocoapodsCommonizationProjectName, gradleVersion) { - buildWithCocoapodsWrapper(":commonize", "-Pkotlin.mpp.enableCInteropCommonization=true") { + buildWithCocoapodsWrapper(":commonize", *buildArguments) { assertTasksExecuted(":commonizeNativeDistribution") assertTasksExecuted(":cinteropAFNetworkingIosArm64") assertTasksExecuted(":cinteropAFNetworkingIosX64") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt index 529247f5430..73b5d9d89f3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/PropertiesProvider.kt @@ -380,9 +380,16 @@ internal class PropertiesProvider private constructor(private val project: Proje /** * Enables experimental commonization of user defined c-interop libraries. */ - val enableCInteropCommonization: Boolean - get() = booleanProperty(KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION) ?: false + val enableCInteropCommonization: Boolean? + get() = booleanProperty(KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION) + private val enableCInteropCommonizationSetByExternalPluginKey = "kotlin.internal.mpp.enableCInteropCommonization.setByExternalPlugin" + + internal var enableCInteropCommonizationSetByExternalPlugin: Boolean? + get() = booleanProperty(enableCInteropCommonizationSetByExternalPluginKey) + set(value) { + project.extensions.extraProperties.set(enableCInteropCommonizationSetByExternalPluginKey, "$value") + } val commonizerLogLevel: String? get() = this.property("kotlin.mpp.commonizerLogLevel") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/DisabledCinteropCommonizationInHmppProjectChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/DisabledCinteropCommonizationInHmppProjectChecker.kt index 33d5ad8b115..11fe32e16bb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/DisabledCinteropCommonizationInHmppProjectChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/DisabledCinteropCommonizationInHmppProjectChecker.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation +import org.jetbrains.kotlin.gradle.targets.native.internal.* import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerDependent import org.jetbrains.kotlin.gradle.targets.native.internal.from import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer @@ -23,7 +24,7 @@ internal object DisabledCinteropCommonizationInHmppProjectChecker : KotlinGradle if (multiplatformExtension == null || !project.isAllowCommonizer() - || kotlinPropertiesProvider.enableCInteropCommonization + || project.cInteropCommonizationEnabled() || kotlinPropertiesProvider.ignoreDisabledCInteropCommonization ) return diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt index 8ecc927921d..3f1830f66a9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCInteropMetadataDependencyClasspathResolver.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.cinteropMetadataDepen import org.jetbrains.kotlin.gradle.targets.native.internal.commonizerTarget import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropMetadataDependencyClasspathForIde import org.jetbrains.kotlin.gradle.tasks.locateTask +import org.jetbrains.kotlin.gradle.utils.future internal object IdeCInteropMetadataDependencyClasspathResolver : IdeDependencyResolver, IdeDependencyResolver.WithBuildDependencies { override fun resolve(sourceSet: KotlinSourceSet): Set { @@ -26,7 +27,7 @@ internal object IdeCInteropMetadataDependencyClasspathResolver : IdeDependencyRe val project = sourceSet.project project.locateDependencyTask(sourceSet) ?: return emptySet() - val cinteropFiles = project.createCInteropMetadataDependencyClasspathForIde(sourceSet) + val cinteropFiles = project.future { createCInteropMetadataDependencyClasspathForIde(sourceSet) }.getOrThrow() return project.resolveCInteropDependencies(cinteropFiles) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt index a0b6dbfc953..c3eb16f8267 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeCommonizedCinteropDependencyResolver.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.targets.native.internal.cinteropCommonizerDependencies import org.jetbrains.kotlin.gradle.targets.native.internal.copyCommonizeCInteropForIdeTask +import org.jetbrains.kotlin.gradle.utils.future +import org.jetbrains.kotlin.gradle.utils.lenient internal object IdeCommonizedCinteropDependencyResolver : IdeDependencyResolver, IdeDependencyResolver.WithBuildDependencies { override fun resolve(sourceSet: KotlinSourceSet): Set { @@ -23,6 +25,6 @@ internal object IdeCommonizedCinteropDependencyResolver : IdeDependencyResolver, } override fun dependencies(project: Project): Iterable { - return listOfNotNull(project.copyCommonizeCInteropForIdeTask) + return listOfNotNull(project.future { copyCommonizeCInteropForIdeTask() }.getOrThrow()) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt index b3f6e955abb..c477a4195c9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ProjectMetadataProviderImpl.kt @@ -85,8 +85,8 @@ private suspend fun KotlinMultiplatformExtension.sourceSetsMetadataOutputs(): Ma private suspend fun KotlinMultiplatformExtension.cInteropMetadataOfSourceSets( sourceSets: Iterable ): Map { - val taskForCLI = project.commonizeCInteropTask ?: return emptyMap() - val taskForIde = project.copyCommonizeCInteropForIdeTask ?: return emptyMap() + val taskForCLI = project.commonizeCInteropTask() ?: return emptyMap() + val taskForIde = project.copyCommonizeCInteropForIdeTask() ?: return emptyMap() return sourceSets.associateWith { sourceSet -> val dependent = CInteropCommonizerDependent.from(sourceSet) ?: return@associateWith null diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index 33dd48c9521..4661fd008fa 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.native.* +import org.jetbrains.kotlin.gradle.targets.native.internal.* import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropApiElementsKlibArtifact import org.jetbrains.kotlin.gradle.targets.native.internal.locateOrCreateCInteropApiElementsConfiguration @@ -149,8 +150,12 @@ open class KotlinNativeTargetConfigurator : AbstractKotl it.enabled = compilation.konanTarget.enabledOnCurrentHost } - project.commonizeCInteropTask?.configure { commonizeCInteropTask -> - commonizeCInteropTask.from(interopTask) + + project.launch { + project.commonizeCInteropTask()?.configure { commonizeCInteropTask -> + commonizeCInteropTask.from(interopTask) + } + project.copyCommonizeCInteropForIdeTask() } val interopOutput = project.files(interopTask.map { it.outputFileProvider }) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt index 5fbe7826d92..6341b8ca135 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt @@ -21,6 +21,7 @@ import org.gradle.api.tasks.wrapper.Wrapper import org.jetbrains.kotlin.daemon.common.trimQuotes import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.addExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic @@ -825,10 +826,15 @@ open class KotlinCocoapodsPlugin : Plugin { } } + // Enable cinterop commonization if it is not explicitly specified + private fun Project.enableCInteropCommonizationSetByExternalPlugin() { + kotlinPropertiesProvider.enableCInteropCommonizationSetByExternalPlugin = true + } override fun apply(project: Project): Unit = with(project) { pluginManager.withPlugin("kotlin-multiplatform") { + enableCInteropCommonizationSetByExternalPlugin() val kotlinExtension = project.multiplatformExtension val kotlinArtifactsExtension = project.kotlinArtifactsExtension val cocoapodsExtension = project.objects.newInstance(CocoapodsExtension::class.java, this) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt index 1613e267282..95ca9d091d5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerCompositeMetadataJarBundling.kt @@ -22,7 +22,7 @@ internal fun Project.includeCommonizedCInteropMetadata( } internal suspend fun Project.includeCommonizedCInteropMetadata(metadataKlib: Zip, compilation: KotlinSharedNativeCompilation) { - val commonizerTask = commonizeCInteropTask?.get() ?: return + val commonizerTask = commonizeCInteropTask()?.get() ?: return val commonizerDependencyToken = CInteropCommonizerDependent.from(compilation) ?: return val outputDirectory = commonizerTask.commonizedOutputDirectory(commonizerDependencyToken) ?: return diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt index f6741b92b22..5f6fdff0826 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerDependencies.kt @@ -30,8 +30,8 @@ internal fun Project.setupCInteropCommonizerDependencies() { } } -private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilation: KotlinSharedNativeCompilation) { - val cinteropCommonizerTask = project.commonizeCInteropTask ?: return +private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilation: KotlinSharedNativeCompilation) = launch { + val cinteropCommonizerTask = project.commonizeCInteropTask() ?: return@launch compilation.compileDependencyFiles += filesProvider { val cinteropCommonizerDependent = future { CInteropCommonizerDependent.from(compilation) }.getOrThrow() @@ -45,15 +45,15 @@ private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilatio * This will use the [Project.copyCommonizeCInteropForIdeTask] over the regular cinterop commonization task. * The copying task prevent red code within the IDE after cleaning the build output. */ -private fun Project.setupCInteropCommonizerDependenciesForIde(sourceSet: DefaultKotlinSourceSet) { +private fun Project.setupCInteropCommonizerDependenciesForIde(sourceSet: DefaultKotlinSourceSet) = launch { addIntransitiveMetadataDependencyIfPossible(sourceSet, cinteropCommonizerDependencies(sourceSet)) } internal fun Project.cinteropCommonizerDependencies(sourceSet: DefaultKotlinSourceSet): FileCollection { - val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask ?: return project.files() - return filesProvider { future { + val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask() ?: return@future project.files() + val directlyDependent = CInteropCommonizerDependent.from(sourceSet) val associateDependent = CInteropCommonizerDependent.fromAssociateCompilations(sourceSet) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyClasspath.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyClasspath.kt index 77eccc9e744..f942303fd1b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyClasspath.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyClasspath.kt @@ -16,13 +16,14 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.metadataDependencyResolutionsOrEmp import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.metadataTransformation import org.jetbrains.kotlin.gradle.utils.filesProvider +import org.jetbrains.kotlin.gradle.utils.future import java.io.File -internal fun Project.createCInteropMetadataDependencyClasspath(sourceSet: DefaultKotlinSourceSet): FileCollection { +internal suspend fun Project.createCInteropMetadataDependencyClasspath(sourceSet: DefaultKotlinSourceSet): FileCollection { return createCInteropMetadataDependencyClasspath(sourceSet, forIde = false) } -internal fun Project.createCInteropMetadataDependencyClasspathForIde(sourceSet: DefaultKotlinSourceSet): FileCollection { +internal suspend fun Project.createCInteropMetadataDependencyClasspathForIde(sourceSet: DefaultKotlinSourceSet): FileCollection { return createCInteropMetadataDependencyClasspath(sourceSet, forIde = true) } @@ -30,7 +31,7 @@ internal fun Project.createCInteropMetadataDependencyClasspathForIde(sourceSet: * @param forIde: A different task for dependency transformation will be used. This task will not use the regular 'build' directory * as transformation output to ensure IDE still being able to resolve the dependencies even when the project is cleaned. */ -internal fun Project.createCInteropMetadataDependencyClasspath(sourceSet: DefaultKotlinSourceSet, forIde: Boolean): FileCollection { +internal suspend fun Project.createCInteropMetadataDependencyClasspath(sourceSet: DefaultKotlinSourceSet, forIde: Boolean): FileCollection { val dependencyTransformationTask = if (forIde) locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(sourceSet) else locateOrRegisterCInteropMetadataDependencyTransformationTask(sourceSet) if (dependencyTransformationTask == null) return project.files() @@ -99,7 +100,7 @@ private fun Project.createCInteropMetadataDependencyClasspathFromAssociatedCompi .filter { (_, otherCommonizerTarget) -> otherCommonizerTarget.targets.containsAll(commonizerTarget.targets) } .minByOrNull { (_, otherCommonizerTarget) -> otherCommonizerTarget.targets.size } ?: return@files emptySet() - createCInteropMetadataDependencyClasspath(associatedSourceSet, forIde) + project.future { createCInteropMetadataDependencyClasspath(associatedSourceSet, forIde) }.getOrThrow() } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt index a482f2de46b..31462482c51 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropMetadataDependencyTransformationTask.kt @@ -41,10 +41,10 @@ internal val KotlinSourceSet.cinteropMetadataDependencyTransformationTaskName: S internal val KotlinSourceSet.cinteropMetadataDependencyTransformationForIdeTaskName: String get() = lowerCamelCaseName("transform", name, "CInteropDependenciesMetadataForIde") -internal fun Project.locateOrRegisterCInteropMetadataDependencyTransformationTask( +internal suspend fun Project.locateOrRegisterCInteropMetadataDependencyTransformationTask( sourceSet: DefaultKotlinSourceSet, ): TaskProvider? { - if (!kotlinPropertiesProvider.enableCInteropCommonization) return null + if (!cInteropCommonizationEnabled()) return null return locateOrRegisterTask( sourceSet.cinteropMetadataDependencyTransformationTaskName, @@ -61,10 +61,10 @@ internal fun Project.locateOrRegisterCInteropMetadataDependencyTransformationTas ) } -internal fun Project.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde( +internal suspend fun Project.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde( sourceSet: DefaultKotlinSourceSet, ): TaskProvider? { - if (!kotlinPropertiesProvider.enableCInteropCommonization) return null + if (!cInteropCommonizationEnabled()) return null return locateOrRegisterTask( sourceSet.cinteropMetadataDependencyTransformationForIdeTaskName, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt index 4e3d2e06d19..84d085b44d2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CommonizerTasks.kt @@ -16,8 +16,11 @@ import org.gradle.api.tasks.TaskProvider import org.gradle.work.DisableCachingByDefault import org.jetbrains.kotlin.compilerRunner.maybeCreateCommonizerClasspathConfiguration import org.jetbrains.kotlin.gradle.internal.isInIdeaSync +import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider -import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider +import org.jetbrains.kotlin.gradle.plugin.await import org.jetbrains.kotlin.gradle.plugin.ide.Idea222Api import org.jetbrains.kotlin.gradle.plugin.ide.ideaImportDependsOn import org.jetbrains.kotlin.gradle.plugin.whenEvaluated @@ -26,7 +29,12 @@ import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask import java.io.File import javax.inject.Inject -internal val Project.isCInteropCommonizationEnabled: Boolean get() = PropertiesProvider(this).enableCInteropCommonization +internal suspend fun Project.cInteropCommonizationEnabled(): Boolean { + KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript.await() + return kotlinPropertiesProvider.enableCInteropCommonization + ?: kotlinPropertiesProvider.enableCInteropCommonizationSetByExternalPlugin + ?: false +} internal val Project.isIntransitiveMetadataConfigurationEnabled: Boolean get() = PropertiesProvider(this).enableIntransitiveMetadataConfiguration @@ -67,55 +75,55 @@ internal val Project.runCommonizerTask: TaskProvider } ) -internal val Project.commonizeCInteropTask: TaskProvider? - get() { - if (isCInteropCommonizationEnabled) { - return locateOrRegisterTask( - "commonizeCInterop", - invokeWhenRegistered = { - val task = this +private const val commonizeCInteropTaskName = "commonizeCInterop" + +internal suspend fun Project.commonizeCInteropTask(): TaskProvider? { + if (cInteropCommonizationEnabled()) { + return locateOrRegisterTask( + commonizeCInteropTaskName, + invokeWhenRegistered = { + val task = this + commonizeTask.dependsOn(this) + whenEvaluated { + commonizeNativeDistributionTask?.let(task::dependsOn) + } + }, + configureTask = { + group = "interop" + description = "Invokes the commonizer on c-interop bindings of the project" + + kotlinPluginVersion.set(getKotlinPluginVersion()) + commonizerClasspath.from(project.maybeCreateCommonizerClasspathConfiguration()) + customJvmArgs.set(PropertiesProvider(project).commonizerJvmArgs) + } + ) + } + return null +} + +internal suspend fun Project.copyCommonizeCInteropForIdeTask(): TaskProvider? { + val commonizeCInteropTask = commonizeCInteropTask() + if (commonizeCInteropTask != null) { + return locateOrRegisterTask( + "copyCommonizeCInteropForIde", + invokeWhenRegistered = { + @OptIn(Idea222Api::class) + ideaImportDependsOn(this) + + /* Older IDEs will still call 'runCommonizer' -> 'commonize' tasks */ + if (isInIdeaSync) { commonizeTask.dependsOn(this) - whenEvaluated { - commonizeNativeDistributionTask?.let(task::dependsOn) - } - }, - configureTask = { - group = "interop" - description = "Invokes the commonizer on c-interop bindings of the project" - - kotlinPluginVersion.set(getKotlinPluginVersion()) - commonizerClasspath.from(project.maybeCreateCommonizerClasspathConfiguration()) - customJvmArgs.set(PropertiesProvider(project).commonizerJvmArgs) } - ) - } - return null - } - -internal val Project.copyCommonizeCInteropForIdeTask: TaskProvider? - get() { - val commonizeCInteropTask = commonizeCInteropTask - if (commonizeCInteropTask != null) { - return locateOrRegisterTask( - "copyCommonizeCInteropForIde", - invokeWhenRegistered = { - @OptIn(Idea222Api::class) - ideaImportDependsOn(this) - - /* Older IDEs will still call 'runCommonizer' -> 'commonize' tasks */ - if (isInIdeaSync) { - commonizeTask.dependsOn(this) - } - }, - configureTask = { - group = "interop" - description = "Copies the output of ${commonizeCInteropTask.get().name} into " + - "the root projects .gradle folder for the IDE" - } - ) - } - return null + }, + configureTask = { + group = "interop" + description = "Copies the output of $commonizeCInteropTaskName into " + + "the root projects .gradle folder for the IDE" + } + ) } + return null +} internal val Project.commonizeNativeDistributionTask: TaskProvider? get() { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CopyCInteropCommonizerTaskOutputForIdeTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CopyCInteropCommonizerTaskOutputForIdeTask.kt index 228658ca1ec..5c726e72787 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CopyCInteropCommonizerTaskOutputForIdeTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CopyCInteropCommonizerTaskOutputForIdeTask.kt @@ -9,13 +9,14 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.work.DisableCachingByDefault import org.gradle.work.NormalizeLineEndings +import org.jetbrains.kotlin.gradle.utils.future import java.io.File @DisableCachingByDefault internal open class CopyCommonizeCInteropForIdeTask : AbstractCInteropCommonizerTask() { private val commonizeCInteropTask: TaskProvider - get() = project.commonizeCInteropTask ?: throw IllegalStateException("Missing commonizeCInteropTask") + get() = project.future { project.commonizeCInteropTask() }.getOrThrow() ?: throw IllegalStateException("Missing commonizeCInteropTask") @get:IgnoreEmptyDirectories @get:InputFiles diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropCommonizerTaskTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropCommonizerTaskTest.kt index ee928538135..495ef7c8083 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropCommonizerTaskTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropCommonizerTaskTest.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.unitTests -import org.gradle.api.GradleException import org.jetbrains.kotlin.commonizer.CommonizerTarget import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.gradle.util.MultiplatformExtensionTest @@ -19,12 +18,17 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask import org.jetbrains.kotlin.gradle.util.enableCInteropCommonization import org.jetbrains.kotlin.gradle.util.main import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest +import org.jetbrains.kotlin.gradle.utils.Future +import org.jetbrains.kotlin.gradle.utils.future import org.jetbrains.kotlin.konan.target.KonanTarget.* import kotlin.test.* class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { - private val task: CInteropCommonizerTask get() = project.commonizeCInteropTask?.get() ?: fail("Missing commonizeCInteropTask") + private val task: Future + get() = project.future { + project.commonizeCInteropTask()?.get() ?: fail("Missing commonizeCInteropTask") + } @BeforeTest override fun setup() { @@ -34,7 +38,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { } @Test - fun `commonizeCInteropTask configuration - avoids cinterop task configuration`() { + fun `commonizeCInteropTask configuration - avoids cinterop task configuration`() = project.runLifecycleAwareTest { project.enableCInteropCommonization(true) listOf( @@ -46,12 +50,12 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { } } - project.commonizeCInteropTask?.get() ?: fail("Expected commonizeCInteropTask to be present") - project.evaluate() + project.commonizeCInteropTask()?.get() ?: fail("Expected commonizeCInteropTask to be present") } @Test fun `nativeMain linux macos`() = project.runLifecycleAwareTest { + val task = this@CInteropCommonizerTaskTest.task.await() val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName") val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName") @@ -106,6 +110,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { @Test fun `nativeMain iosMain linux macos iosX64 iosArm64`() = project.runLifecycleAwareTest { + val task = this@CInteropCommonizerTaskTest.task.await() val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier val iosX64Interop = kotlin.iosX64("iosX64").compilations.getByName("main").cinterops.create("anyInteropName").identifier @@ -159,8 +164,9 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { } private fun `nativeTest nativeMain linux macos`( - nativeTestDependsOnNativeMain: Boolean + nativeTestDependsOnNativeMain: Boolean, ) = project.runLifecycleAwareTest { + val task = this@CInteropCommonizerTaskTest.task.await() val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier @@ -222,8 +228,9 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { } private fun `nativeTest nativeMain linux macos - test compilation defines custom cinterop`( - nativeTestDependsOnNativeMain: Boolean + nativeTestDependsOnNativeMain: Boolean, ) = project.runLifecycleAwareTest { + val task = this@CInteropCommonizerTaskTest.task.await() val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier kotlin.linuxX64("linux").compilations.getByName("test").cinterops.create("anyOtherName").identifier @@ -285,6 +292,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() { } private fun `hierarchical project`(testSourceSetsDependOnMainSourceSets: Boolean) = project.runLifecycleAwareTest { + val task = this@CInteropCommonizerTaskTest.task.await() /* Define targets */ val linux = kotlin.linuxX64("linux") val macos = kotlin.macosX64("macos") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropMetadataDependencyTransformationTaskTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropMetadataDependencyTransformationTaskTest.kt index 1f364d88be1..37bd5c79801 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropMetadataDependencyTransformationTaskTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/CInteropMetadataDependencyTransformationTaskTest.kt @@ -11,21 +11,20 @@ import org.gradle.api.Project import org.gradle.api.internal.TaskInternal import org.gradle.testfixtures.ProjectBuilder import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle +import org.jetbrains.kotlin.gradle.plugin.await import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.targets.native.internal.locateOrRegisterCInteropMetadataDependencyTransformationTask import org.jetbrains.kotlin.gradle.targets.native.internal.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde -import org.jetbrains.kotlin.gradle.util.MultiplatformExtensionTest -import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP -import org.jetbrains.kotlin.gradle.util.enableCInteropCommonization -import org.jetbrains.kotlin.gradle.util.kotlin +import org.jetbrains.kotlin.gradle.util.* import java.io.File import kotlin.test.* class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionTest() { @Test - fun `task not registered when cinterop commonization is disabled`() { - project.enableCInteropCommonization(false) + fun `task not registered when cinterop commonization is disabled`() = project.runLifecycleAwareTest { + enableCInteropCommonization(false) kotlin.linuxArm64() kotlin.linuxX64() @@ -40,13 +39,13 @@ class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionT linuxX64Main.dependsOn(linuxMain) /* Expect no tasks being registered without the cinterop commonization feature flag */ - assertNull(project.locateOrRegisterCInteropMetadataDependencyTransformationTask(linuxMain)) - assertNull(project.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(linuxMain)) + assertNull(locateOrRegisterCInteropMetadataDependencyTransformationTask(linuxMain)) + assertNull(locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(linuxMain)) } @Test - fun `test task ordering`() { - project.enableCInteropCommonization(true) + fun `test task ordering`() = project.runLifecycleAwareTest { + enableCInteropCommonization(true) kotlin.linuxX64() kotlin.linuxArm64() @@ -67,16 +66,17 @@ class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionT linuxX64Test.dependsOn(nativeTest) linuxArm64Test.dependsOn(nativeTest) - project.evaluate() - val nativeTestTransformationTask = project.locateOrRegisterCInteropMetadataDependencyTransformationTask(nativeTest) + KotlinPluginLifecycle.Stage.ReadyForExecution.await() + + val nativeTestTransformationTask = locateOrRegisterCInteropMetadataDependencyTransformationTask(nativeTest) assertNotNull(nativeTestTransformationTask, "Expected transformation task registered for 'nativeTest'") assertEquals( listOf(commonMain, commonTest, nativeMain).flatMap { sourceSet -> listOf( - project.locateOrRegisterCInteropMetadataDependencyTransformationTask(sourceSet as DefaultKotlinSourceSet)?.get() + locateOrRegisterCInteropMetadataDependencyTransformationTask(sourceSet as DefaultKotlinSourceSet)?.get() ?: fail("Expected transformation task registered for '${sourceSet.name}'"), - project.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(sourceSet)?.get() + locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(sourceSet)?.get() ?: fail("Expected transformation task registered for '${sourceSet.name}'(forIde)") ) }.toSet(), @@ -101,31 +101,33 @@ class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionT linuxArm64Main.dependsOn(linuxMain) linuxX64Main.dependsOn(linuxMain) - project.evaluate() + project.runLifecycleAwareTest { + KotlinPluginLifecycle.Stage.ReadyForExecution.await() - listOf( - "commonMain", "jvmMain", "linuxArm64Main", "linuxX64Main" - ).map { sourceSetName -> kotlin.sourceSets.getByName(sourceSetName) }.forEach { sourceSet -> - val task = project.locateOrRegisterCInteropMetadataDependencyTransformationTask(sourceSet as DefaultKotlinSourceSet) - ?: return@forEach + listOf( + "commonMain", "jvmMain", "linuxArm64Main", "linuxX64Main" + ).map { sourceSetName -> kotlin.sourceSets.getByName(sourceSetName) }.forEach { sourceSet -> + val task = locateOrRegisterCInteropMetadataDependencyTransformationTask(sourceSet as DefaultKotlinSourceSet) + ?: return@forEach - assertFalse( - task.get().onlyIf.isSatisfiedBy(task.get() as TaskInternal), - "Expected task ${task.name} to be disabled (not a shared native source set)" + assertFalse( + task.get().onlyIf.isSatisfiedBy(task.get() as TaskInternal), + "Expected task ${task.name} to be disabled (not a shared native source set)" + ) + } + + val linuxMainTask = locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(linuxMain) + ?: fail("Expected transformation task registered for 'linuxMain'") + + assertTrue( + linuxMainTask.get().onlyIf.isSatisfiedBy(linuxMainTask.get() as TaskInternal), + "Expected task ${linuxMainTask.name} to be enabled" ) } - - val linuxMainTask = project.locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde(linuxMain) - ?: fail("Expected transformation task registered for 'linuxMain'") - - assertTrue( - linuxMainTask.get().onlyIf.isSatisfiedBy(linuxMainTask.get() as TaskInternal), - "Expected task ${linuxMainTask.name} to be enabled" - ) } @Test - fun `test IDE task outputs doesnt conflict`() { + fun `test IDE task outputs doesnt conflict`() = project.runLifecycleAwareTest { fun projectWithCinterops(name: String, parent: Project? = null) = buildProjectWithMPP( projectBuilder = { withName(name); if (parent != null) withParent(parent) } ) { @@ -137,7 +139,7 @@ class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionT } }.also { it.evaluate() } - fun Project.transformationTaskOutputs(): Set { + suspend fun Project.transformationTaskOutputs(): Set { val kotlin = multiplatformExtension val nativeMain = kotlin.sourceSets.findByName("nativeMain") ?: fail("Expected source set 'nativeMain") val cinteropTransformationTaskProvider = locateOrRegisterCInteropMetadataDependencyTransformationTaskForIde( @@ -154,7 +156,7 @@ class CInteropMetadataDependencyTransformationTaskTest : MultiplatformExtensionT .minus(File(".gradle/kotlin/kotlinTransformedCInteropMetadataLibraries")) } - fun assertTasksOutputsDoesntIntersect(a: Project, b: Project) { + suspend fun assertTasksOutputsDoesntIntersect(a: Project, b: Project) { val outputsA = a.transformationTaskOutputs() val outputsB = b.transformationTaskOutputs()