diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CInteropIdeaSyncIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CInteropIdeaSyncIT.kt index 6343e4f1a15..8054b597285 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CInteropIdeaSyncIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CInteropIdeaSyncIT.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.native import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.testbase.* -import org.jetbrains.kotlin.konan.file.File import org.junit.jupiter.api.DisplayName import kotlin.io.path.writeText @@ -35,24 +34,10 @@ class CInteropIdeaSyncIT : KGPBaseTest() { assertOutputContains(ideaSyncWarningMessage) } - /* - The implementation before fixing KT-52243 considered the cinterop task as *not* up-to-date - when it was previously running in the IDE and therefore failing leniently. It would have always tried to re-run - this task to anticipate untracked environmental changes. - - This cannot be easily implemented whilst also fixing KT-52243, which is more desirable. - A new mechanism for 'run tasks at import' leniency is proposed (using --continue), which is supposed to replace - the special cinterop mechanism. - - https://youtrack.jetbrains.com/issue/KT-52243/ - https://github.com/JetBrains/kotlin/pull/4812#issuecomment-1117287222 - */ - runCatching { - /* Task is not considered up-to-date after lenient failure */ - build("commonize", buildOptions = ideaSyncBuildOptions) { - assertTasksExecuted(interopTaskName) - assertOutputContains(ideaSyncWarningMessage) - } + /* Task is not considered up-to-date after lenient failure */ + build("commonize", buildOptions = ideaSyncBuildOptions) { + assertTasksExecuted(interopTaskName) + assertOutputContains(ideaSyncWarningMessage) } /* Remove noise that causes failure */ diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt index 873facda146..95041df0492 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt @@ -5,48 +5,55 @@ package org.jetbrains.kotlin.gradle.targets.native.tasks -import org.gradle.api.Task -import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime import org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner import org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner -import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter +import org.jetbrains.kotlin.gradle.tasks.CInteropProcess +import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty internal fun KotlinNativeCInteropRunner.Companion.createExecutionContext( - task: Task, + task: CInteropProcess, isInIdeaSync: Boolean, runnerSettings: KotlinNativeToolRunner.Settings, gradleExecutionContext: KotlinToolRunner.GradleExecutionContext, metricsReporter: BuildMetricsReporter ): KotlinNativeCInteropRunner.ExecutionContext { return if (isInIdeaSync) IdeaSyncKotlinNativeCInteropRunnerExecutionContext(runnerSettings, gradleExecutionContext, task, metricsReporter) - else DefaultKotlinNativeCInteropRunnerExecutionContext(runnerSettings, gradleExecutionContext, metricsReporter) + else DefaultKotlinNativeCInteropRunnerExecutionContext(runnerSettings, gradleExecutionContext, task, metricsReporter) } private class DefaultKotlinNativeCInteropRunnerExecutionContext( override val runnerSettings: KotlinNativeToolRunner.Settings, override val gradleExecutionContext: KotlinToolRunner.GradleExecutionContext, + private val task: CInteropProcess, override val metricsReporter: BuildMetricsReporter ) : KotlinNativeCInteropRunner.ExecutionContext { - override fun runWithContext(action: () -> Unit) = action() + override fun runWithContext(action: () -> Unit) { + task.errorFileProvider.get().delete() + action() + } } private class IdeaSyncKotlinNativeCInteropRunnerExecutionContext( override val runnerSettings: KotlinNativeToolRunner.Settings, override val gradleExecutionContext: KotlinToolRunner.GradleExecutionContext, - private val task: Task, + private val task: CInteropProcess, override val metricsReporter: BuildMetricsReporter ) : KotlinNativeCInteropRunner.ExecutionContext { override fun runWithContext(action: () -> Unit) { + val errorFile = task.errorFileProvider.get() + errorFile.delete() try { action() } catch (t: Throwable) { - task.logger.warn("Warning: Failed to generate cinterop for ${task.path}: ${t.message ?: ""}", t) + val errorText = "Warning: Failed to generate cinterop for ${task.path}: ${t.message ?: ""}" + task.logger.warn(errorText, t) task.outputs.files.forEach { file -> file.deleteRecursively() } + errorFile.writeText(errorText) } } } 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 f5e67b8d867..df6a42e093c 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 @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.gradle.targets.native.tasks.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.GradleLoggerAdapter import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty +import org.jetbrains.kotlin.incremental.deleteDirectoryContents import org.jetbrains.kotlin.ir.linkage.partial.PartialLinkageMode import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER import org.jetbrains.kotlin.konan.properties.saveToFile @@ -1086,6 +1087,19 @@ abstract class CInteropProcess @Inject internal constructor(params: Params) : @OutputFile val outputFileProvider: Provider = project.provider { destinationDir.get().resolve(outputFileName) } + //Error file will be written only for errors during a project sync because for the sync task mustn't fail + //see: org.jetbrains.kotlin.gradle.targets.native.tasks.IdeaSyncKotlinNativeCInteropRunnerExecutionContext + @get:OutputFile + internal val errorFileProvider: Provider = project.provider { destinationDir.get().resolve("cinterop_error.out") } + + init { + //KTIJ-25563: + //Failed CInterop task is successful if it was run during import to have properly imported project. + //But successful task is up-to-date for next invocations. + //We have to check up-to-date-ness only if CInterop didn't generate an error file + outputs.upToDateWhen { !errorFileProvider.get().exists() } + } + @get:InputFile @get:PathSensitive(PathSensitivity.RELATIVE) @get:NormalizeLineEndings