Draft
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
index 7ccff51..f9e8e9e 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinMultiplatformExtension.kt
@@ -25,10 +25,10 @@
     override val presets: NamedDomainObjectCollection<KotlinTargetPreset<*>> = project.container(KotlinTargetPreset::class.java)
 
     final override val targets: NamedDomainObjectCollection<KotlinTarget> = project.container(KotlinTarget::class.java)
+    internal val targetsState = project.suspendableProperty(targets)
 
     internal suspend fun awaitTargets(): NamedDomainObjectCollection<KotlinTarget> {
-        AfterFinaliseDsl.await()
-        return targets
+        return targetsState.awaitFinalValue()
     }
 
     override val compilerTypeFromProperties: KotlinJsCompilerType? = project.kotlinPropertiesProvider.jsCompiler
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt
new file mode 100644
index 0000000..b1a70ed
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ConsistentAfterEvaluate.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.plugin
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.completeWith
+import org.gradle.api.Project
+import org.gradle.api.provider.Provider
+import org.jetbrains.kotlin.gradle.utils.getOrPut
+import kotlin.coroutines.*
+
+internal class SuspendableExecutor {
+    private val supervisorJob = SupervisorJob()
+    private val lateEvaluations = mutableListOf<suspend () -> Unit>()
+    fun runNow(block: suspend () -> Unit) {
+        val job = Job(supervisorJob)
+        val continuation = Continuation<Unit>(job) { it.getOrThrow(); job.complete() }
+        block.startCoroutine(continuation)
+    }
+
+    fun runLater(block: suspend () -> Unit) {
+        lateEvaluations += block
+    }
+
+    fun runDeferredEvaluations() {
+        try {
+            while (lateEvaluations.isNotEmpty()) {
+                val code = lateEvaluations.removeFirst()
+                runNow { code() }
+            }
+            supervisorJob.complete()
+        } catch (e: Throwable) {
+            supervisorJob.completeExceptionally(e)
+        }
+
+        check(supervisorJob.children.all { it.isCompleted }) {
+            "Following children are not completed: ${supervisorJob.children.filter { it.isActive }.toList()}"
+        }
+    }
+}
+
+internal interface SuspendableState<T> {
+    fun getFinalValueOrThrow(): T
+    suspend fun awaitFinalValue(): T
+}
+
+private class SuspendableStateImpl<T> : SuspendableState<T> {
+    private val deferred = CompletableDeferred<T>()
+    fun completeWith(result: Result<T>) {
+        deferred.completeWith(result)
+    }
+
+    override fun getFinalValueOrThrow(): T {
+        val exception = deferred.getCompletionExceptionOrNull()
+        if (exception != null) throw exception
+        return deferred.getCompleted()
+    }
+
+    override suspend fun awaitFinalValue(): T = deferred.await()
+}
+
+private fun <T> SuspendableExecutor.evaluate(code: suspend () -> T): SuspendableState<T> {
+    val provider = SuspendableStateImpl<T>()
+    runNow { provider.completeWith(runCatching { code() }) }
+    return provider
+}
+
+internal interface SuspendableMutableState<T> : SuspendableState<T> {
+    fun updateWith(code: suspend (currentValue: T) -> T)
+}
+
+private fun <T> SuspendableExecutor.mutableState(initialValue: T): SuspendableMutableState<T> {
+    val property = SuspendableMutableStateImpl(initialValue)
+    runLater { property.finalizeValue() }
+    return property
+}
+
+private class SuspendableMutableStateImpl<T>(
+    private val initialValue: T,
+    private val state: SuspendableStateImpl<T> = SuspendableStateImpl()
+): SuspendableMutableState<T> {
+    private val mutations: MutableList<suspend (T) -> T> = mutableListOf()
+
+    suspend fun finalizeValue() {
+        val finalResult = runCatching {
+            mutations.fold(initialValue) { currentValue, mutation -> mutation(currentValue) }
+        }
+        state.completeWith(finalResult)
+    }
+
+    override fun updateWith(code: suspend (currentValue: T) -> T) {
+        mutations += code
+    }
+
+    override suspend fun awaitFinalValue(): T = state.awaitFinalValue()
+
+    override fun getFinalValueOrThrow(): T = state.getFinalValueOrThrow()
+}
+
+private val Project.suspendableExecutor get() =
+    extraProperties.getOrPut(SuspendableExecutor::class.java.name) {
+        SuspendableExecutor()
+    }
+
+internal fun <T> Project.provider(code: suspend () -> T): Provider<T> {
+    val suspendableState = suspendableExecutor.evaluate(code)
+    return provider { suspendableState.getFinalValueOrThrow() }
+}
+
+internal fun <T> Project.suspendableProperty(initialValue: T): SuspendableMutableState<T> {
+    val suspendableState = suspendableExecutor.mutableState(initialValue)
+    return suspendableState
+}
+
+internal class SuspendableWrappers(
+    private val executor: SuspendableExecutor
+) {
+    private val entities = mutableMapOf<Any, WrappedEntity<*>>()
+    class WrappedEntity<T: Any> (
+        val state: SuspendableMutableState<T>,
+        val entity: T
+    )
+
+    fun <T: Any> getOrWrap(entity: T): WrappedEntity<T> {
+        @Suppress("UNCHECKED_CAST")
+        return entities.getOrPut(entity) {
+            val state = executor.mutableState(entity)
+            WrappedEntity(state, entity)
+        } as WrappedEntity<T>
+    }
+}
+
+fun main() {
+    val evaluator = SuspendableExecutor()
+    val p1 = evaluator.mutableState(emptyList<Int>())
+    val p2 = evaluator.mutableState(emptyList<Int>())
+    val p3 = evaluator.mutableState(emptyList<Int>())
+    val p0 = evaluator.evaluate { p1.awaitFinalValue() }
+    p1.updateWith { it + p2.awaitFinalValue() + 1 }
+    p2.updateWith { it + p3.awaitFinalValue() + 2 }
+    p3.updateWith { it + 3 }
+
+    evaluator.runDeferredEvaluations()
+    println(p0.getFinalValueOrThrow())
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
index d152174..13848b0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt
@@ -65,9 +65,9 @@
  *
  * If the lifecycle already finished and Gradle moved to its execution phase, then the block will be invoked right away.
  */
-internal fun Project.launch(block: suspend KotlinPluginLifecycle.() -> Unit) {
-    kotlinPluginLifecycle.launch(block)
-}
+//internal fun Project.launch(block: suspend KotlinPluginLifecycle.() -> Unit) {
+//    kotlinPluginLifecycle.launch(block)
+//}
 
 /**
  * See [launch] and [launchInRequiredStage]
@@ -76,12 +76,12 @@
  * @param block Is guaranteed to be executed *not before* [stage]. However, when this function is called in a higher stage then specified
  * the [block] will still be launched.
  */
-internal fun Project.launchInStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
-    launch {
-        await(stage)
-        block()
-    }
-}
+//internal fun Project.launchInStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
+//    launch {
+//        await(stage)
+//        block()
+//    }
+//}
 
 /**
  * See also [launch]
@@ -98,13 +98,13 @@
  * }
  * ```
  */
-internal fun Project.launchInRequiredStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
-    launchInStage(stage) {
-        requiredStage(stage) {
-            block()
-        }
-    }
-}
+//internal fun Project.launchInRequiredStage(stage: Stage, block: suspend KotlinPluginLifecycle.() -> Unit) {
+//    launchInStage(stage) {
+//        requiredStage(stage) {
+//            block()
+//        }
+//    }
+//}
 
 /**
  * Universal way of retrieving the current lifecycle
@@ -118,9 +118,9 @@
 /**
  * Will start the lifecycle, this shall be called before the [kotlinPluginLifecycle] is effectively used
  */
-internal fun Project.startKotlinPluginLifecycle() {
-    (kotlinPluginLifecycle as KotlinPluginLifecycleImpl).start()
-}
+//internal fun Project.startKotlinPluginLifecycle() {
+//    (kotlinPluginLifecycle as KotlinPluginLifecycleImpl).start()
+//}
 
 /**
  * Similar to [currentCoroutineContext]: Returns the current [KotlinPluginLifecycle] instance used to launch
@@ -135,9 +135,9 @@
  * Suspends execution until we *at least* reached the specified [this@await]
  * This will return right away if the specified [this@await] was already executed or we are currently executing the [this@await]
  */
-internal suspend fun Stage.await() {
-    currentKotlinPluginLifecycle().await(this)
-}
+//internal suspend fun Stage.await() {
+//    currentKotlinPluginLifecycle().await(this)
+//}
 
 /**
  * See [LifecycleAwareProperty]
@@ -154,18 +154,18 @@
  * }
  * ```
  */
-internal inline fun <reified T : Any> Project.newKotlinPluginLifecycleAwareProperty(
-    finaliseIn: Stage = Stage.FinaliseDsl, initialValue: T? = null
-): LifecycleAwareProperty<T> {
-    return kotlinPluginLifecycle.newLifecycleAwareProperty(T::class.java, finaliseIn, initialValue)
-}
+//internal inline fun <reified T : Any> Project.newKotlinPluginLifecycleAwareProperty(
+//    finaliseIn: Stage = Stage.FinaliseDsl, initialValue: T? = null
+//): LifecycleAwareProperty<T> {
+//    return kotlinPluginLifecycle.newLifecycleAwareProperty(T::class.java, finaliseIn, initialValue)
+//}
 
 /**
  * Will return the [LifecycleAwareProperty] instance if the given receiver was created by [newKotlinPluginLifecycleAwareProperty]
  */
-internal suspend fun <T : Any> Property<T>.findKotlinPluginLifecycleAwareProperty(): LifecycleAwareProperty<T>? {
-    return (currentKotlinPluginLifecycle() as KotlinPluginLifecycleImpl).findLifecycleAwareProperty(this)
-}
+//internal suspend fun <T : Any> Property<T>.findKotlinPluginLifecycleAwareProperty(): LifecycleAwareProperty<T>? {
+//    return (currentKotlinPluginLifecycle() as KotlinPluginLifecycleImpl).findLifecycleAwareProperty(this)
+//}
 
 /**
  * Will suspend until the property finalises its value and therefore a final value can returned.
@@ -175,32 +175,32 @@
  * If a property was not created using 'newKotlinPluginLifecycleAwareProperty' then the execution
  * will suspend until 'FinaliseDsl' and calls [Property.finalizeValue] before returnign the actual value
  */
-internal suspend fun <T : Any> Property<T>.awaitFinalValue(): T? {
-    val lifecycleAwareProperty = findKotlinPluginLifecycleAwareProperty()
-    if (lifecycleAwareProperty != null) {
-        return lifecycleAwareProperty.awaitFinalValue()
-    }
-
-    Stage.FinaliseDsl.await()
-    finalizeValue()
-    return orNull
-}
+//internal suspend fun <T : Any> Property<T>.awaitFinalValue(): T? {
+//    val lifecycleAwareProperty = findKotlinPluginLifecycleAwareProperty()
+//    if (lifecycleAwareProperty != null) {
+//        return lifecycleAwareProperty.awaitFinalValue()
+//    }
+//
+//    Stage.FinaliseDsl.await()
+//    finalizeValue()
+//    return orNull
+//}
 
 /**
  * @return true if this property has an associated [LifecycleAwareProperty]
  */
-internal suspend fun Property<*>.isKotlinPluginLifecycleAware(): Boolean {
-    return findKotlinPluginLifecycleAwareProperty() != null
-}
+//internal suspend fun Property<*>.isKotlinPluginLifecycleAware(): Boolean {
+//    return findKotlinPluginLifecycleAwareProperty() != null
+//}
 
 /**
  * See also [withRestrictedStages]
  *
  * Will ensure that the given [block] can only execute in the given [stage]
  */
-internal suspend fun <T> requiredStage(stage: Stage, block: suspend () -> T): T {
-    return withRestrictedStages(hashSetOf(stage), block)
-}
+//internal suspend fun <T> requiredStage(stage: Stage, block: suspend () -> T): T {
+//    return withRestrictedStages(hashSetOf(stage), block)
+//}
 
 /**
  * See also [withRestrictedStages]
@@ -216,9 +216,9 @@
  * }
  * ```
  */
-internal suspend fun <T> requireCurrentStage(block: suspend () -> T): T {
-    return requiredStage(currentKotlinPluginLifecycle().stage, block)
-}
+//internal suspend fun <T> requireCurrentStage(block: suspend () -> T): T {
+//    return requiredStage(currentKotlinPluginLifecycle().stage, block)
+//}
 
 /**
  * Will ensure that the given [block] cannot leave the specified allowed stages [allowed]
@@ -233,11 +233,11 @@
  * }
  * ```
  */
-internal suspend fun <T> withRestrictedStages(allowed: Set<Stage>, block: suspend () -> T): T {
-    return withContext(RestrictedLifecycleStages(currentKotlinPluginLifecycle(), allowed)) {
-        block()
-    }
-}
+//internal suspend fun <T> withRestrictedStages(allowed: Set<Stage>, block: suspend () -> T): T {
+//    return withContext(RestrictedLifecycleStages(currentKotlinPluginLifecycle(), allowed)) {
+//        block()
+//    }
+//}
 
 /*
 Definition of the Lifecycle and its stages
@@ -476,7 +476,7 @@
     ) : LifecycleAwareProperty<T> {
 
         override suspend fun awaitFinalValue(): T? {
-            finaliseIn.await()
+            //finaliseIn.await()
             return property.orNull
         }
     }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
index 9329a46..614b43d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt
@@ -6,9 +6,12 @@
 @file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
 package org.jetbrains.kotlin.gradle.utils
 
+import org.gradle.api.InvalidUserCodeException
 import org.gradle.api.Project
 import org.gradle.api.artifacts.repositories.ArtifactRepository
 import org.gradle.api.file.FileTree
+import org.gradle.api.initialization.resolve.RepositoriesMode
+import org.gradle.api.internal.GradleInternal
 import org.gradle.api.logging.Logger
 import org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner
 import org.jetbrains.kotlin.compilerRunner.konanHome
@@ -87,14 +90,19 @@
         }
 
     private fun setupRepo(repoUrl: String): ArtifactRepository {
-        return project.repositories.ivy { repo ->
-            repo.setUrl(repoUrl)
-            repo.patternLayout {
-                it.artifact("[artifact]-[revision].[ext]")
+        try {
+            return project.repositories.ivy { repo ->
+                repo.setUrl(repoUrl)
+                repo.patternLayout {
+                    it.artifact("[artifact]-[revision].[ext]")
+                }
+                repo.metadataSources {
+                    it.artifact()
+                }
             }
-            repo.metadataSources {
-                it.artifact()
-            }
+        } catch (e: InvalidUserCodeException) {
+            logger.error("e: Can't add Kotlin Native Distribution repository. Please add it yourself, default repository url: '$repoUrl'")
+            throw e
         }
     }