From 6fa610156e60a1be8c6c2cfa983ce1934f2a9afe Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 26 Feb 2019 18:27:17 +0300 Subject: [PATCH] Create and configure Android compilations earlier (KT-29964) As Android variants are created after the project is evaluated, the build script and plugins might have added some item handlers to the domain object containers which are yet to be filled. To ensure that those handlers see properly configured compilations and their tasks, we need to add a compilations to the container only after it has been properly configured. Also, the `forEachVariant` handler is already executed in `afterEvaluate`, and there seems to be no need to wrap our code working with variants in `afterEvaluate`. Issue #KT-29964 Fixed --- .../AbstractKotlinAndroidGradleTests.kt | 2 + .../new-mpp-android/lib/build.gradle | 15 ++++++ .../kotlin/gradle/plugin/KotlinPlugin.kt | 47 ++++++++++--------- .../targets/android/KotlinAndroidTarget.kt | 2 +- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index e89944f64f4..a38ad7b2e0f 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -21,6 +21,8 @@ class KotlinAndroid32GradleIT : KotlinAndroid3GradleIT(androidGradlePluginVersio build("assemble", "compileDebugUnitTestJavaWithJavac", "printCompilerPluginOptions") { assertSuccessful() + assertContains("KT-29964 OK") // Output from lib/build.gradle + assertTasksExecuted( ":lib:compileDebugKotlinAndroidLib", ":lib:compileReleaseKotlinAndroidLib", diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-android/lib/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-android/lib/build.gradle index 70703d9f6f8..64d315c00a4 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-android/lib/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-android/lib/build.gradle @@ -36,6 +36,21 @@ dependencies { androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } +kotlin.targets.all { + compilations.all { + // KT-29964: check that Android compilations can be configured with an `all { ... }` handler: + kotlinOptions { + verbose = true + } + compileKotlinTask.doFirst { + if (!compileKotlinTask.kotlinOptions.verbose) { + throw new AssertionError("kotlinOptions were not configured properly") + } + println "KT-29964 OK" + } + } +} + kotlin { sourceSets { jvmLibMain { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 930d03d64b1..0f494fd5f09 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -727,44 +727,48 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT kotlinOptions.noJdk = true ext.addExtension(KOTLIN_OPTIONS_DSL_NAME, kotlinOptions) - project.afterEvaluate { project -> - forEachVariant(project) { variant -> - val variantName = getVariantName(variant) - val compilation = kotlinAndroidTarget.compilations.create(variantName) - setUpDependencyResolution(variant, compilation) - } + val androidPluginIds = listOf( + "android", "com.android.application", "android-library", "com.android.library", + "com.android.test", "com.android.feature", "com.android.dynamic-feature", "com.android.instantapp" + ) - val androidPluginIds = listOf( - "android", "com.android.application", "android-library", "com.android.library", - "com.android.test", "com.android.feature", "com.android.dynamic-feature", "com.android.instantapp" - ) - val plugin = androidPluginIds.asSequence() + val plugin by lazy { + androidPluginIds.asSequence() .mapNotNull { project.plugins.findPlugin(it) as? BasePlugin } .firstOrNull() ?: throw InvalidPluginException("'kotlin-android' expects one of the Android Gradle " + "plugins to be applied to the project:\n\t" + androidPluginIds.joinToString("\n\t") { "* $it" }) + } - checkAndroidAnnotationProcessorDependencyUsage(project) + forEachVariant(project) { variant -> + val variantName = getVariantName(variant) - forEachVariant(project) { - processVariant( - it, kotlinAndroidTarget, project, ext, plugin, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider - ) + // Create the compilation and configure it first, then add to the compilations container. As this code is executed + // in afterEvaluate, a user's build script might have already attached item handlers to the compilations container, and those + // handlers might break when fired on a compilation that is not yet properly configured (e.g. KT-29964): + kotlinAndroidTarget.compilationFactory.create(variantName).let { compilation -> + setUpDependencyResolution(variant, compilation) + + processVariant(variant, compilation, project, ext, plugin, kotlinOptions, kotlinConfigurationTools.kotlinTasksProvider) + + @Suppress("UNCHECKED_CAST") + (kotlinAndroidTarget.compilations as NamedDomainObjectCollection).add(compilation) } val subpluginEnvironment = SubpluginEnvironment.loadSubplugins(project, kotlinConfigurationTools.kotlinPluginVersion) + val compilation = kotlinAndroidTarget.compilations.getByName(getVariantName(variant)) + applySubplugins(project, compilation, variant, subpluginEnvironment) + } - forEachVariant(project) { variant -> - val compilation = kotlinAndroidTarget.compilations.getByName(getVariantName(variant)) - applySubplugins(project, compilation, variant, subpluginEnvironment) - } + project.whenEvaluated { + checkAndroidAnnotationProcessorDependencyUsage(project) } } private fun processVariant( variantData: V, - target: KotlinAndroidTarget, + compilation: KotlinJvmAndroidCompilation, project: Project, androidExt: BaseExtension, androidPlugin: BasePlugin, @@ -782,7 +786,6 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT return } - val compilation = target.compilations.getByName(variantDataName) val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName) val kotlinTaskName = compilation.compileKotlinTaskName diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt index a8f8d7b8706..830de45e83e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt @@ -26,7 +26,7 @@ open class KotlinAndroidTarget( override val platformType: KotlinPlatformType get() = KotlinPlatformType.androidJvm - private val compilationFactory = KotlinJvmAndroidCompilationFactory(project, this) + internal val compilationFactory = KotlinJvmAndroidCompilationFactory(project, this) override val compilations: NamedDomainObjectContainer = project.container(compilationFactory.itemClass, compilationFactory)