From 8df905a326ab70101214b66a51727df574b7148d Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Mon, 24 Jul 2023 22:39:09 +0200 Subject: [PATCH] [Gradle] LanguageSettings now is wrapper for related compiler options 'KotlinSourceSet.LanguageSettings' is now acts as a wrapper for the related Kotlin compilation task 'compilerOptions' object, similar to how 'kotlinOptions' is working now. Source sets consistency check now will ignore shared source sets with no linked compilation to avoid users need to configure them as well. ^KT-57292 In Progress --- .../kotlin/gradle/CompilerOptionsIT.kt | 99 +++++++- .../kotlin/gradle/CompilerOptionsProjectIT.kt | 2 +- .../kotlin/gradle/NewMultiplatformIT.kt | 51 ++-- .../mpp-default-hierarchy/build.gradle | 20 ++ .../plugin/mpp/GradleProjectModuleBuilder.kt | 2 +- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 7 +- .../DefautlKotlinCompilationPreConfigure.kt | 3 +- ...CompilationLanguageSettingsConfigurator.kt | 42 ++++ .../KotlinCompilationSourceSetInclusion.kt | 6 +- .../mpp/pm20/GradleKpmFragmentInternal.kt | 2 +- .../pm20/GradleKpmModuleDependencyResolver.kt | 2 +- .../plugin/sources/ConsistencyChecker.kt | 49 +++- .../plugin/sources/DefaultKotlinSourceSet.kt | 11 +- .../sources/DefaultLanguageSettingsBuilder.kt | 230 ++++++++++-------- .../KotlinMetadataTargetConfigurator.kt | 9 - .../metadata/KotlinMetadataTargetPreset.kt | 8 - .../native/KotlinNativeTargetConfigurator.kt | 18 +- .../targets/native/NativeCompilerOptions.kt | 7 - .../targets/native/tasks/KotlinNativeTasks.kt | 25 +- .../AbstractKotlinCompileConfig.kt | 25 +- .../configuration/KotlinCompileConfig.kt | 9 +- .../unitTests/ExternalKotlinTargetApiTests.kt | 8 +- ...ExternalKotlinTargetSourcesJarUtilsTest.kt | 4 +- ...inMultiplatformSourceSetConventionsTest.kt | 36 ++- .../gradle/unitTests/LanguageSettingsTests.kt | 107 ++++++++ .../gradle/util/externalTargetApiUtils.kt | 9 +- 26 files changed, 540 insertions(+), 251 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt index 0f009095b8f..eb9b76ac587 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt @@ -209,11 +209,11 @@ internal class CompilerOptionsIT : KGPBaseTest() { """.trimMargin() ) - build("compileKotlinJvm6", forceOutput = true) { + build("compileKotlinJvm6") { assertTasksExecuted(":compileKotlinJvm6") - assert(output.contains("-opt-in another.custom.UnderOptIn,my.custom.OptInAnnotation")) { + assert(output.contains("-opt-in my.custom.OptInAnnotation,another.custom.UnderOptIn")) { printBuildOutput() - "Output does not contain '-opt-in another.custom.UnderOptIn,my.custom.OptInAnnotation'!" + "Output does not contain '-opt-in my.custom.OptInAnnotation,another.custom.UnderOptIn'!" } } } @@ -528,4 +528,97 @@ internal class CompilerOptionsIT : KGPBaseTest() { } } } + + @GradleTest + @DisplayName("Syncs languageSettings changes to the related compiler options") + @MppGradlePluginTests + fun syncLanguageSettingsToCompilerOptions(gradleVersion: GradleVersion) { + project("mpp-default-hierarchy", gradleVersion) { + buildGradle.appendText( + //language=groovy + """ + | + |kotlin.sourceSets.configureEach { + | languageSettings.apiVersion = "1.7" + | languageSettings.languageVersion = "1.8" + |} + | + |tasks.register("printCompilerOptions") { + | dependsOn(kotlinTaskToCheck) + | def tasksContainer = project.tasks + | doLast { + | def kotlinTask = tasks.getByName(kotlinTaskToCheck) as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask + | logger.warn("###AV:${'$'}{kotlinTask.compilerOptions.apiVersion.getOrNull()}") + | logger.warn("###LV:${'$'}{kotlinTask.compilerOptions.languageVersion.getOrNull()}") + | } + |} + """.trimMargin() + ) + + listOf( + "compileCommonMainKotlinMetadata", + "compileKotlinJvm", + "compileNativeMainKotlinMetadata", + "compileLinuxMainKotlinMetadata", + "compileAppleMainKotlinMetadata", + "compileIosMainKotlinMetadata", + "compileKotlinLinuxX64", + "compileKotlinLinuxArm64", + "compileKotlinIosX64", + "compileKotlinIosArm64" + ).forEach { task -> + build("printCompilerOptions", "-PkotlinTaskToCheck=$task") { + assertOutputContains("###AV:KOTLIN_1_7") + assertOutputContains("###LV:KOTLIN_1_8") + } + } + } + } + + @GradleTest + @DisplayName("Syncs compiler option changes to the related language settings") + @MppGradlePluginTests + fun syncCompilerOptionsToLanguageSettings(gradleVersion: GradleVersion) { + project("mpp-default-hierarchy", gradleVersion) { + buildGradle.appendText( + //language=groovy + """ + | + |tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class).all { + | compilerOptions { + | apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_7 + | languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8 + | } + |} + | + |tasks.register("printLanguageSettingsOptions") { + | doLast { + | def languageSettings = kotlin.sourceSets.getByName(kotlinSourceSet).languageSettings + | logger.warn("") + | logger.warn("###AV:${'$'}{languageSettings.apiVersion}") + | logger.warn("###LV:${'$'}{languageSettings.languageVersion}") + | } + |} + """.trimMargin() + ) + + listOf( + "commonMain", + "jvmMain", + "nativeMain", + "linuxMain", + "appleMain", + "iosMain", + "linuxX64Main", + "linuxArm64Main", + "iosX64Main", + "iosArm64Main", + ).forEach { sourceSet -> + build("printLanguageSettingsOptions", "-PkotlinSourceSet=${sourceSet}") { + assertOutputContains("###AV:1.7") + assertOutputContains("###LV:1.8") + } + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt index f5f34c7f3a8..f13a42dae71 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt @@ -140,7 +140,7 @@ class CompilerOptionsProjectIT : KGPBaseTest() { | languageVersion = '1.9' | apiVersion = '1.9' | progressiveMode = false - | optInAnnotationsInUse.add("another.CustomOptInAnnotation") + | optIn("another.CustomOptInAnnotation") | enableLanguageFeature("UnitConversionsOnArbitraryExpressions") | } | } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 472ec3d1ec8..348dfc08563 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -778,47 +778,58 @@ open class NewMultiplatformIT : BaseGradleIT() { } @Test - fun testLanguageSettingsConsistency() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) { + fun testLanguageSettingsConsistency() = with( + Project("sample-lib", gradleVersion, "new-mpp-lib-and-app", minLogLevel = LogLevel.INFO) + ) { setupWorkingDir() - gradleBuildScript().appendText( - "\n" + """ - kotlin.sourceSets { - foo { } - bar { dependsOn foo } - } - """.trimIndent() - ) - fun testMonotonousCheck( - initialSetupForSourceSets: String?, sourceSetConfigurationChange: String, expectedErrorHint: String, + initialSetupForSourceSets: String? = null, ) { if (initialSetupForSourceSets != null) { gradleBuildScript().appendText( - "\nkotlin.sourceSets.foo.${initialSetupForSourceSets}\n" + "" + - "kotlin.sourceSets.bar.${initialSetupForSourceSets}", + """ + | + |kotlin.sourceSets.commonMain.${initialSetupForSourceSets} + |kotlin.sourceSets.nativeMain.${initialSetupForSourceSets} + |kotlin.sourceSets.linux64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.macos64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.jvm6Main.${initialSetupForSourceSets} + |kotlin.sourceSets.mingw64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.nodeJsMain.${initialSetupForSourceSets} + |kotlin.sourceSets.wasmMain.${initialSetupForSourceSets} + """.trimMargin() ) } - gradleBuildScript().appendText("\nkotlin.sourceSets.foo.${sourceSetConfigurationChange}") + gradleBuildScript().appendText("\nkotlin.sourceSets.commonMain.${sourceSetConfigurationChange}") build("tasks") { assertFailed() assertContains(expectedErrorHint) } - gradleBuildScript().appendText("\nkotlin.sourceSets.bar.${sourceSetConfigurationChange}") + gradleBuildScript().appendText( + """ + | + |kotlin.sourceSets.nativeMain.${sourceSetConfigurationChange} + |kotlin.sourceSets.linux64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.macos64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.jvm6Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.mingw64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.nodeJsMain.${sourceSetConfigurationChange} + |kotlin.sourceSets.wasmMain.${sourceSetConfigurationChange} + """.trimMargin() + ) build("tasks") { assertSuccessful() } } - fun testMonotonousCheck(sourceSetConfigurationChange: String, expectedErrorHint: String): Unit = - testMonotonousCheck(null, sourceSetConfigurationChange, expectedErrorHint) testMonotonousCheck( - "languageSettings.languageVersion = '1.3'", "languageSettings.languageVersion = '1.4'", - "The language version of the dependent source set must be greater than or equal to that of its dependency." + "The language version of the dependent source set must be greater than or equal to that of its dependency.", + "languageSettings.languageVersion = '1.3'", ) testMonotonousCheck( @@ -835,7 +846,7 @@ open class NewMultiplatformIT : BaseGradleIT() { // don't require doing the same for dependent source sets: gradleBuildScript().appendText( "\n" + """ - kotlin.sourceSets.foo.languageSettings { + kotlin.sourceSets.commonMain.languageSettings { apiVersion = '1.4' enableLanguageFeature('SoundSmartcastForEnumEntries') progressiveMode = true diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle new file mode 100644 index 00000000000..8855596e94e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" +} + +repositories { + mavenLocal() + mavenCentral() +} + +kotlin { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt index a67722bbb10..a45c4e1b7ae 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt @@ -165,7 +165,7 @@ class GradleProjectModuleBuilder(private val addInferredSourceSetVisibilityAsExp ?: listOf(compilation.defaultSourceSetName) variantNames.forEach { variantName -> - val variant = KpmBasicVariant(this@apply, variantName, DefaultLanguageSettingsBuilder()) + val variant = KpmBasicVariant(this@apply, variantName, DefaultLanguageSettingsBuilder(project)) moduleByFragment[variant] = this@apply variantToCompilation[variant] = compilation fragments.add(variant) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 495b8a2391a..a80cc197ee4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -204,9 +204,10 @@ internal fun Project.setupGeneralKotlinExtensionParameters() { .awaitPlatformCompilations() .any { KotlinSourceSetTree.orNull(it) == KotlinSourceSetTree.main } - languageSettings.explicitApi = project.providers.provider { - val explicitApiFlag = project.kotlinExtension.explicitApiModeAsCompilerArg() - explicitApiFlag.takeIf { isMainSourceSet } + if (isMainSourceSet) { + languageSettings.explicitApi = project.providers.provider { + project.kotlinExtension.explicitApiModeAsCompilerArg() + } } languageSettings.freeCompilerArgsProvider = project.provider { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt index 881cdcd32fb..e8b202dedee 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt @@ -8,5 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory internal val DefaultKotlinCompilationPreConfigure = KotlinCompilationImplFactory.PreConfigure.composite( - KotlinCompilationK2MultiplatformConfigurator + KotlinCompilationK2MultiplatformConfigurator, + KotlinCompilationLanguageSettingsConfigurator, ) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt new file mode 100644 index 00000000000..dc8b711fffa --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt @@ -0,0 +1,42 @@ +/* + * 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.mpp.compilationImpl + +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget + +/** + * Wires compilations compiler options into source sets [org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.languageSettings]. + */ +internal object KotlinCompilationLanguageSettingsConfigurator : KotlinCompilationImplFactory.PreConfigure { + override fun configure(compilation: KotlinCompilationImpl) { + // Ignoring non-klib common compilation as it reuses defaultSourceSet with klib common compilation + if (compilation.platformType == KotlinPlatformType.common && + compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME + ) return + + // Ignoring jsLegacy as it shares a source set with jsIR + if (compilation.platformType == KotlinPlatformType.js && + compilation.target is KotlinJsTarget + ) return + + val languageSettingsBuilder = (compilation.defaultSourceSet.languageSettings as DefaultLanguageSettingsBuilder) + if (languageSettingsBuilder.compilationCompilerOptions.isCompleted) { + compilation.target.project.logger.warn( + "Compiler options for compilation ${compilation.name} default source set ${compilation.defaultSourceSet.name} " + + "'languageSettings' was already set!" + ) + return + } + + languageSettingsBuilder + .compilationCompilerOptions + .complete(compilation.compilerOptions.options) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt index 88d5a8a516c..72ce544f2c3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt @@ -9,7 +9,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.launchInStage import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.addSourcesToKotlinCompileTask import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker @@ -63,7 +65,9 @@ internal class KotlinCompilationSourceSetInclusion( // Temporary solution for checking consistency across source sets participating in a compilation that may // not be interconnected with the dependsOn relation: check the settings as if the default source set of // the compilation depends on the one added to the compilation: - defaultSourceSetLanguageSettingsChecker.runAllChecks(compilation.defaultSourceSet, sourceSet) + compilation.project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { + defaultSourceSetLanguageSettingsChecker.runAllChecks(compilation.defaultSourceSet, sourceSet) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt index a5ff495d897..57833e9e04d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt @@ -41,7 +41,7 @@ abstract class GradleKpmFragmentInternal @Inject constructor( // TODO pull up to KotlinModuleFragment // FIXME apply to compilation // FIXME check for consistency - override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() + override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project) override fun refines(other: GradleKpmFragment) { checkCanRefine(other) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt index 66627fe7281..f4211610dd8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt @@ -81,7 +81,7 @@ internal fun buildSyntheticPlainModule( ): GradleKpmExternalPlainModule { val moduleDependency = resolvedComponentResult.toKpmModuleDependency() return GradleKpmExternalPlainModule(KpmBasicModule(moduleDependency.moduleIdentifier).apply { - KpmBasicVariant(this@apply, singleVariantName, DefaultLanguageSettingsBuilder()).apply { + KpmBasicVariant(this@apply, singleVariantName, DefaultLanguageSettingsBuilder(TODO())).apply { fragments.add(this) this.declaredModuleDependencies.addAll( resolvedComponentResult.dependencies diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt index fb61c3d3baa..3393e72931a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.sources import org.gradle.api.InvalidUserDataException import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.project.model.LanguageSettings internal class ConsistencyCheck( @@ -21,45 +21,68 @@ internal class FragmentConsistencyChecks( unitName: String, // "fragment" or "source set" private val languageSettings: T.() -> LanguageSettings ) { - private val defaultLanguageVersion = LanguageVersion.LATEST_STABLE + private val defaultLanguageVersion = KotlinVersion.DEFAULT private val languageVersionCheckHint = "The language version of the dependent $unitName must be greater than or equal to that of its dependency." - val languageVersionCheck = ConsistencyCheck( + private val languageVersionCheck = ConsistencyCheck( name = "language version", getValue = { unit -> - unit.languageSettings().languageVersion?.let { parseLanguageVersionSetting(it) } ?: defaultLanguageVersion + unit.languageSettings().getValueIfExists { + languageVersion?.let { KotlinVersion.fromVersion(it) } ?: defaultLanguageVersion + } + }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left >= right }, - leftExtendsRightConsistently = { left, right -> left >= right }, consistencyConditionHint = languageVersionCheckHint ) private val unstableFeaturesHint = "The dependent $unitName must enable all unstable language features that its dependency has." - val unstableFeaturesCheck = ConsistencyCheck>( + private val unstableFeaturesCheck = ConsistencyCheck?>( name = "unstable language feature set", getValue = { unit -> - unit.languageSettings().enabledLanguageFeatures - .map { parseLanguageFeature(it)!! } - .filterTo(mutableSetOf()) { it.kind == LanguageFeature.Kind.UNSTABLE_FEATURE } + unit.languageSettings().getValueIfExists { + enabledLanguageFeatures + .mapNotNull { parseLanguageFeature(it) } + .filterTo(mutableSetOf()) { it.kind == LanguageFeature.Kind.UNSTABLE_FEATURE } + } + }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left.containsAll(right) }, - leftExtendsRightConsistently = { left, right -> left.containsAll(right) }, consistencyConditionHint = unstableFeaturesHint ) private val optInAnnotationsInUseHint = "The dependent $unitName must use all opt-in annotations that its dependency uses." - val optInAnnotationsCheck = ConsistencyCheck>( + private val optInAnnotationsCheck = ConsistencyCheck?>( name = "set of opt-in annotations in use", - getValue = { unit -> unit.languageSettings().optInAnnotationsInUse }, - leftExtendsRightConsistently = { left, right -> left.containsAll(right) }, + getValue = { unit -> unit.languageSettings().getValueIfExists { optInAnnotationsInUse } }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left.containsAll(right) + }, consistencyConditionHint = optInAnnotationsInUseHint ) val allChecks = listOf(languageVersionCheck, unstableFeaturesCheck, optInAnnotationsCheck) + + private fun LanguageSettings.getValueIfExists( + getValue: LanguageSettings.() -> T? + ): T? { + val defaultLanguageSettingsBuilder = this as DefaultLanguageSettingsBuilder + return if (defaultLanguageSettingsBuilder.compilationCompilerOptions.isCompleted) { + getValue(defaultLanguageSettingsBuilder) + } else { + null + } + } } +internal fun parseLanguageFeature(featureName: String) = LanguageFeature.fromString(featureName) + internal class FragmentConsistencyChecker( private val unitsName: String, private val name: T.() -> String, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt index a4e75a9ee35..9f731e8060b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt @@ -12,9 +12,8 @@ import org.gradle.api.Project import org.gradle.api.file.SourceDirectorySet import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.launchInStage import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.tooling.core.MutableExtras @@ -68,7 +67,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( override val kotlin: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name Kotlin source") - override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() + override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project) override val resources: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name resources") @@ -95,7 +94,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( dependencies { configure.execute(this) } override fun afterDependsOnAdded(other: KotlinSourceSet) { - project.runProjectConfigurationHealthCheckWhenEvaluated { + project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { defaultSourceSetLanguageSettingsChecker.runAllChecks(this@DefaultKotlinSourceSet, other) } } @@ -175,7 +174,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( } internal val defaultSourceSetLanguageSettingsChecker = - FragmentConsistencyChecker( + FragmentConsistencyChecker( unitsName = "source sets", name = { name }, checks = FragmentConsistencyChecks( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index a4e84496bdd..f0a1618efcf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -5,74 +5,118 @@ package org.jetbrains.kotlin.gradle.plugin.sources -import org.gradle.api.InvalidUserDataException +import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersion -import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptionsDefault import org.jetbrains.kotlin.gradle.dsl.KotlinVersion -import org.jetbrains.kotlin.gradle.dsl.toCompilerValue -import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions -import org.jetbrains.kotlin.project.model.LanguageSettings -import kotlin.properties.Delegates +import org.jetbrains.kotlin.gradle.utils.* +import javax.inject.Inject -internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { - private var languageVersionImpl: LanguageVersion? = null +internal open class DefaultLanguageSettingsBuilder @Inject constructor( + @Transient private val project: Project +) : LanguageSettingsBuilder { + internal var compilationCompilerOptions: CompletableFuture = CompletableFuture() - override var languageVersion: String? - get() = languageVersionImpl?.versionString - set(value) { - languageVersionImpl = value?.let { versionString -> - LanguageVersion.fromVersionString(versionString) ?: throw InvalidUserDataException( - "Incorrect language version. Expected one of: ${LanguageVersion.values().joinToString { "'${it.versionString}'" }}" - ) + init { + project.launch { + KotlinPluginLifecycle.Stage.AfterFinaliseCompilations.await() + if (!compilationCompilerOptions.isCompleted) { + // For shared source sets without any associated compilation, it would be a separate instance of common compiler options + compilationCompilerOptions.complete(project.objects.newInstance()) } } - - private var apiVersionImpl: ApiVersion? = null - - override var apiVersion: String? - get() = apiVersionImpl?.versionString - set(value) { - apiVersionImpl = value?.let { versionString -> - parseApiVersionSettings(versionString) ?: throw InvalidUserDataException( - "Incorrect API version. Expected one of: ${apiVersionValues.joinToString { "'${it.versionString}'" }}" - ) - } - } - - // By using 'observable' delegate we are tracking value set by user and not default value, - // so we could propagate it to the compiler options only if it was configured explicitly - internal var setByUserProgressiveMode: Boolean? = null - override var progressiveMode: Boolean by Delegates.observable(false) { _, _, newValue -> - setByUserProgressiveMode = newValue } - private val enabledLanguageFeaturesImpl = mutableSetOf() + override var languageVersion: String? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().languageVersion.orNull?.version + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .languageVersion + .set(value?.let { KotlinVersion.fromVersion(it) }) + } + } + + override var apiVersion: String? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().apiVersion.orNull?.version + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .apiVersion + .set(value?.let { KotlinVersion.fromVersion(it) }) + } + } + + override var progressiveMode: Boolean = false + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().progressiveMode.get() + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .progressiveMode + .set(value) + } + } + + private val enabledLanguageFeaturesField = mutableSetOf() override val enabledLanguageFeatures: Set - get() = enabledLanguageFeaturesImpl.map { it.name }.toSet() + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow() + .freeCompilerArgs + .get() + .filter { it.startsWith("-XXLanguage:+") } + .map { it.substringAfter("-XXLanguage:+") } + .toSet() + } else { + enabledLanguageFeaturesField.toSet() + } override fun enableLanguageFeature(name: String) { - val languageFeature = parseLanguageFeature(name) ?: throw InvalidUserDataException( - "Unknown language feature '${name}'" - ) - enabledLanguageFeaturesImpl += languageFeature + enabledLanguageFeaturesField.add(name) + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs + .add("-XXLanguage:+$name") + } } - private val optInAnnotationsInUseImpl = mutableSetOf() + private val optInAnnotationsInUseField = mutableSetOf() - override val optInAnnotationsInUse: Set = optInAnnotationsInUseImpl + override val optInAnnotationsInUse: Set + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().optIn.get().toSet() + } else { + optInAnnotationsInUseField.toSet() + } override fun optIn(annotationName: String) { - optInAnnotationsInUseImpl += annotationName + optInAnnotationsInUseField.add(annotationName) + project.launch { + compilationCompilerOptions.await() + .optIn.add(annotationName) + } } /* A Kotlin task that is responsible for code analysis of the owner of this language settings builder. */ @@ -100,65 +144,51 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { } var freeCompilerArgsProvider: Provider>? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().freeCompilerArgs + } else { + field + } + set(value) { + field = value + // Checking if the provider has value as it overwrites the convention + // https://github.com/gradle/gradle/issues/20266 + if (value != null && value.isPresent) { + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs.addAll(value) + } + } + } // Kept here for compatibility with IDEA Kotlin import. It relies on explicit api argument in `freeCompilerArgs` to enable related // inspections internal var explicitApi: Provider? = null - - internal val freeCompilerArgsForNonImport: List - get() = freeCompilerArgsProvider?.get().orEmpty() + get() = if (compilationCompilerOptions.isCompleted) { + val freeArgs = compilationCompilerOptions.getOrThrow() + .freeCompilerArgs + .get() + freeArgs.find { it.startsWith("-Xexplicit-api") }?.let { project.providers.provider { it } } + } else { + field + } + set(value) { + field = value + // Checking if the provider has value as it overwrites the convention + // https://github.com/gradle/gradle/issues/20266 + if (value != null && value.isPresent) { + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs + .add(value) + } + } + } val freeCompilerArgs: List - get() = freeCompilerArgsProvider?.get() - .orEmpty() - .plus(explicitApi?.orNull) - .filterNotNull() + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().freeCompilerArgs.get() + } else { + emptyList() + } } - -internal fun applyLanguageSettingsToCompilerOptions( - languageSettingsBuilder: LanguageSettings, - compilerOptions: KotlinCommonCompilerOptions, -) = with(compilerOptions) { - val languageSettingsBuilderDefault = languageSettingsBuilder as DefaultLanguageSettingsBuilder - languageSettingsBuilderDefault.languageVersion?.let { - languageVersion.convention(KotlinVersion.fromVersion(it)) - } - languageSettingsBuilderDefault.apiVersion?.let { - apiVersion.convention(KotlinVersion.fromVersion(it)) - } - languageSettingsBuilderDefault.setByUserProgressiveMode?.let { - progressiveMode.convention(it) - } - if (languageSettingsBuilder.optInAnnotationsInUse.isNotEmpty()) optIn.addAll(languageSettingsBuilder.optInAnnotationsInUse) - - val freeArgs = mutableListOf() - languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName -> - freeArgs.add("-XXLanguage:+$featureName") - } - freeArgs.addAll(languageSettingsBuilderDefault.freeCompilerArgsForNonImport) - - if (freeArgs.isNotEmpty()) { - freeCompilerArgs.addAll(freeArgs) - } -} - -private val apiVersionValues = ApiVersion.run { - listOf( - KOTLIN_1_0, - KOTLIN_1_1, - KOTLIN_1_2, - KOTLIN_1_3, - KOTLIN_1_4, - KOTLIN_1_5, - KOTLIN_1_6, - KOTLIN_1_7, - KOTLIN_1_8, - KOTLIN_1_9, - KOTLIN_2_0, - KOTLIN_2_1, - ) -} - -internal fun parseLanguageVersionSetting(versionString: String) = LanguageVersion.fromVersionString(versionString) -internal fun parseApiVersionSettings(versionString: String) = apiVersionValues.find { it.versionString == versionString } -internal fun parseLanguageFeature(featureName: String) = LanguageFeature.fromString(featureName) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 17e06b91ed4..969043abd9c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -330,15 +330,6 @@ class KotlinMetadataTargetConfigurator : compileDependencyFiles = project.files() } } - - target.project.runOnceAfterEvaluated("Sync common compilation language settings to compiler options") { - target.compilations.all { compilation -> - applyLanguageSettingsToCompilerOptions( - compilation.defaultSourceSet.languageSettings, - compilation.compilerOptions.options - ) - } - } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt index 874e151b6c1..f2eb084bc07 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt @@ -10,7 +10,6 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.DeprecatedTargetPresetApi import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator @DeprecatedTargetPresetApi @@ -58,12 +57,5 @@ class KotlinMetadataTargetPreset( @Suppress("DEPRECATION") mainCompilation.addSourceSet(commonMainSourceSet) - - project.whenEvaluated { - // Since there's no default source set, apply language settings from commonMain: - mainCompilation.compileTaskProvider.configure { compileKotlinMetadata -> - applyLanguageSettingsToCompilerOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.compilerOptions) - } - } } } 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 6c96a6851fc..415bb3972a5 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 @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerEmbedAndSignAppleFra import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant 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.* @@ -51,6 +50,7 @@ import org.jetbrains.kotlin.gradle.testing.internal.configureConventions import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName import org.jetbrains.kotlin.gradle.utils.XcodeUtils +import org.jetbrains.kotlin.gradle.utils.named import org.jetbrains.kotlin.gradle.utils.newInstance import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget @@ -95,14 +95,11 @@ open class KotlinNativeTargetConfigurator : AbstractKotl } private fun Project.syncLanguageSettingsToLinkTask(binary: NativeBinary) { - tasks.named(binary.linkTaskName, KotlinNativeLink::class.java).configure { + tasks.named(binary.linkTaskName).configure { linkTask -> // We propagate compilation free args to the link task for now (see KT-33717). - val defaultLanguageSettings = binary.compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder - if (defaultLanguageSettings != null && defaultLanguageSettings.freeCompilerArgsForNonImport.isNotEmpty()) { - it.toolOptions.freeCompilerArgs.addAll( - defaultLanguageSettings.freeCompilerArgsForNonImport - ) - } + linkTask.toolOptions.freeCompilerArgs.addAll( + binary.compilation.compilerOptions.options.freeCompilerArgs + ) } } @@ -254,11 +251,6 @@ open class KotlinNativeTargetConfigurator : AbstractKotl project.syncLanguageSettingsToLinkTask(binary) } } - project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { - target.compilations.all { compilation -> - compilation.compilerOptions.syncLanguageSettings(compilation.defaultSourceSet.languageSettings) - } - } target.binaries.withType(Executable::class.java).all { project.createRunTask(it) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt index 0b90bb34823..b71d6b51b05 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt @@ -6,21 +6,14 @@ package org.jetbrains.kotlin.gradle.targets.native import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptionsDefault import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.utils.configureExperimentalTryK2 -import org.jetbrains.kotlin.project.model.LanguageSettings class NativeCompilerOptions(project: Project) : HasCompilerOptions { override val options: KotlinNativeCompilerOptions = project.objects .newInstance(KotlinNativeCompilerOptionsDefault::class.java) .configureExperimentalTryK2(project) - - internal fun syncLanguageSettings(languageSettings: LanguageSettings) { - applyLanguageSettingsToCompilerOptions(languageSettings, options) - } } 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 106d2c9ce74..28d82638581 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 @@ -38,10 +38,8 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeCompilationData -import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService -import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.targets.native.tasks.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty @@ -205,16 +203,16 @@ abstract class AbstractKotlinNativeCompile< @get:Input abstract val additionalCompilerOptions: Provider> + @Deprecated("Use implementations compilerOptions") @get:Internal - val languageSettings: LanguageSettings by project.provider { - compilation.languageSettings - } + val languageSettings: LanguageSettings + get() = compilation.languageSettings @Suppress("DeprecatedCallableAddReplaceWith") @get:Deprecated("Replaced with 'compilerOptions.progressiveMode'") @get:Internal val progressiveMode: Boolean - get() = languageSettings.progressiveMode + get() = compilation.compilerOptions.options.progressiveMode.get() // endregion. @Suppress("DeprecatedCallableAddReplaceWith") @@ -373,17 +371,21 @@ internal constructor( replaceWith = ReplaceWith("kotlinOptions.languageVersion") ) val languageVersion: String? - @Optional @Input get() = languageSettings.languageVersion + @Optional @Input get() = compilerOptions.languageVersion.orNull?.version @Deprecated( message = "Replaced with kotlinOptions.apiVersion", replaceWith = ReplaceWith("kotlinOptions.apiVersion") ) val apiVersion: String? - @Optional @Input get() = languageSettings.apiVersion + @Optional @Input get() = compilerOptions.apiVersion.orNull?.version + @Deprecated("Language features is internal Kotlin compiler flags and should not be used directly") val enabledLanguageFeatures: Set - @Input get() = languageSettings.enabledLanguageFeatures + @Internal get() = compilerOptions + .freeCompilerArgs.get() + .filter { it.startsWith("-XXLanguage:+") } + .toSet() @Deprecated( message = "Replaced with compilerOptions.optIn", @@ -414,15 +416,14 @@ internal constructor( fn.call() } + @Suppress("UNCHECKED_CAST") @Deprecated( message = "Replaced with compilerOptions.freeCompilerArgs", replaceWith = ReplaceWith("compilerOptions.freeCompilerArgs.get()") ) @get:Input override val additionalCompilerOptions: Provider> - get() = compilerOptions - .freeCompilerArgs - .map { it + (languageSettings as DefaultLanguageSettingsBuilder).freeCompilerArgsForNonImport } + get() = compilerOptions.freeCompilerArgs as Provider> private val runnerSettings = KotlinNativeCompilerRunner.Settings.fromProject(project) // endregion. diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt index 5e468dc57cf..596849af912 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension import org.jetbrains.kotlin.gradle.dsl.topLevelExtension import org.jetbrains.kotlin.gradle.incremental.IncrementalModuleInfoBuildService import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService -import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService @@ -27,13 +26,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure import org.jetbrains.kotlin.gradle.plugin.mpp.internal -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.report.BuildMetricsService import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME -import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention -import org.jetbrains.kotlin.project.model.LanguageSettings /** * Configuration for the base compile task, [org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile]. @@ -43,25 +39,10 @@ import org.jetbrains.kotlin.project.model.LanguageSettings */ internal abstract class AbstractKotlinCompileConfig>( project: Project, - val ext: KotlinTopLevelExtension, - private val languageSettings: Provider + val ext: KotlinTopLevelExtension ) : TaskConfigAction(project) { init { - configureTaskProvider { taskProvider -> - project.launchInStage(KotlinPluginLifecycle.Stage.AfterFinaliseCompilations) { - taskProvider.configure { - // KaptGenerateStubs will receive value from linked KotlinCompile task - if (it is KaptGenerateStubsTask) return@configure - - applyLanguageSettingsToCompilerOptions( - languageSettings.get(), - (it as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>).compilerOptions, - ) - } - } - } - val compilerSystemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project) val buildMetricsService = BuildMetricsService.registerIfAbsent(project) val incrementalModuleInfoProvider = @@ -120,6 +101,7 @@ internal abstract class AbstractKotlinCompileConfig task.friendPaths.from({ compilationInfo.friendPaths }) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt index 5f6b4a7c09b..2d7fbd571cd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.tasks.configuration import org.gradle.api.Project import org.gradle.api.attributes.Attribute -import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension @@ -17,12 +16,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation import org.jetbrains.kotlin.gradle.utils.markResolvable -import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.tcsOrNull import org.jetbrains.kotlin.gradle.report.BuildMetricsService import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention -import org.jetbrains.kotlin.project.model.LanguageSettings internal typealias KotlinCompileConfig = BaseKotlinCompileConfig @@ -99,7 +96,7 @@ internal open class BaseKotlinCompileConfig : AbstractKotl constructor(project: Project, ext: KotlinTopLevelExtension) : super( - project, ext, languageSettings = getDefaultLangSetting(project) + project, ext ) companion object { @@ -109,10 +106,6 @@ internal open class BaseKotlinCompileConfig : AbstractKotl private const val DIRECTORY_ARTIFACT_TYPE = "directory" private const val JAR_ARTIFACT_TYPE = "jar" const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot" - - private fun getDefaultLangSetting(project: Project): Provider { - return project.provider { DefaultLanguageSettingsBuilder() } - } } private fun registerTransformsOnce(project: Project) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt index 28feeeb2f2b..bb852aeb8ba 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt @@ -90,12 +90,12 @@ class ExternalKotlinTargetApiTests { "Expected CompilationAssociator.default being set in ${ExternalKotlinCompilationDescriptorBuilder::class.simpleName}" ) - defaults(kotlin) + defaults(kotlin, "fakeMain") compileTaskName = "main" } val auxCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeAux") compilationName = "aux" } @@ -114,13 +114,13 @@ class ExternalKotlinTargetApiTests { } val mainCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeMain") this.compilationAssociator = compilationAssociator this.compileTaskName = "main" } val auxCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeAux") this.compilationName = "aux" this.compilationAssociator = compilationAssociator } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt index b57da4a691c..822b8b2a49c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt @@ -61,12 +61,12 @@ class ExternalKotlinTargetSourcesJarUtilsTest { val target = multiplatformExtension.createExternalKotlinTarget { defaults() } val mainCompilation = target.createCompilation { - defaults(multiplatformExtension) + defaults(multiplatformExtension, "mainFake") compilationName = "main" } val auxCompilation = target.createCompilation { - defaults(multiplatformExtension) + defaults(multiplatformExtension, "auxFake") compilationName = "aux" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt index b9e1d3337e7..714390936ab 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.gradle.unitTests import org.gradle.kotlin.dsl.provideDelegate +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.jvmMain +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.jvmTest import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.configurationResult @@ -50,21 +52,31 @@ class KotlinMultiplatformSourceSetConventionsTest { } @Test - fun `test - languageSettings`() = buildProjectWithMPP().runLifecycleAwareTest { - multiplatformExtension.apply { - jvm() + fun `test - languageSettings`() { + val project = buildProjectWithMPP() + project.runLifecycleAwareTest { + multiplatformExtension.apply { + jvm() + + sourceSets.jvmMain.languageSettings { + optIn("jvmMain.optIn") + } + + sourceSets.jvmTest.languageSettings { + this.optIn("jvmTest.optIn") + } - sourceSets.jvmMain.languageSettings { - this.optIn("jvmMain.optIn") } - - sourceSets.jvmTest.languageSettings { - this.optIn("jvmTest.optIn") - } - - assertEquals(setOf("jvmMain.optIn"), sourceSets.jvmMain.get().languageSettings.optInAnnotationsInUse) - assertEquals(setOf("jvmTest.optIn"), sourceSets.jvmTest.get().languageSettings.optInAnnotationsInUse) } + + assertEquals( + setOf("jvmMain.optIn"), + project.multiplatformExtension.sourceSets.jvmMain.get().languageSettings.optInAnnotationsInUse + ) + assertEquals( + setOf("jvmTest.optIn"), + project.multiplatformExtension.sourceSets.jvmTest.get().languageSettings.optInAnnotationsInUse + ) } @Test diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt new file mode 100644 index 00000000000..c08cfb6cb03 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt @@ -0,0 +1,107 @@ +/* + * 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.unitTests + +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask +import org.jetbrains.kotlin.gradle.tasks.withType +import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP +import org.junit.Test +import kotlin.test.assertEquals + +class LanguageSettingsTests { + + @Test + fun languageSettingsSyncToCompilerOptions() { + val project = buildProjectWithMPP { + with(multiplatformExtension) { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() + + sourceSets.configureEach { + it.languageSettings { + apiVersion = "1.7" + languageVersion = "1.8" + } + } + } + } + + project.evaluate() + + listOf( + "compileCommonMainKotlinMetadata", + "compileKotlinJvm", + "compileNativeMainKotlinMetadata", + "compileLinuxMainKotlinMetadata", + "compileAppleMainKotlinMetadata", + "compileIosMainKotlinMetadata", + "compileKotlinLinuxX64", + "compileKotlinLinuxArm64", + "compileKotlinIosX64", + "compileKotlinIosArm64" + ).forEach { taskName -> + val compileTask = project.tasks.getByName(taskName) as KotlinCompilationTask<*> + with(compileTask.compilerOptions) { + assertEquals(apiVersion.orNull, KotlinVersion.KOTLIN_1_7) + assertEquals(languageVersion.orNull, KotlinVersion.KOTLIN_1_8) + } + } + } + + @Test + fun compilerOptionsSyncToLanguageSettings() { + val project = buildProjectWithMPP { + with(multiplatformExtension) { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() + } + + + tasks.withType>().all { + it.compilerOptions { + apiVersion.set(KotlinVersion.KOTLIN_1_7) + languageVersion.set(KotlinVersion.KOTLIN_1_8) + } + } + } + + project.evaluate() + + listOf( + "commonMain", + "jvmMain", + "nativeMain", + "linuxMain", + "appleMain", + "iosMain", + "linuxX64Main", + "linuxArm64Main", + "iosX64Main", + "iosArm64Main", + ).forEach { sourceSetName -> + with(project.multiplatformExtension.sourceSets.getByName(sourceSetName).languageSettings) { + assertEquals("1.7", apiVersion) + assertEquals("1.8", languageVersion) + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt index dfbf1b63cde..fb0a463addd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt @@ -20,8 +20,11 @@ fun ExternalKotlinTargetDescriptorBuilder.defaults() { targetFactory = TargetFactory(::FakeTarget) } -fun ExternalKotlinCompilationDescriptorBuilder.defaults(kotlin: KotlinMultiplatformExtension) { - compilationName = "fake" +fun ExternalKotlinCompilationDescriptorBuilder.defaults( + kotlin: KotlinMultiplatformExtension, + name: String = "fake" +) { + compilationName = name compilationFactory = CompilationFactory(::FakeCompilation) - defaultSourceSet = kotlin.sourceSets.maybeCreate("fake") + defaultSourceSet = kotlin.sourceSets.maybeCreate(name) }