diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt index 989af60477e..d4ff3d5b264 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt @@ -891,6 +891,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { it.useExperimental = languageSettings.experimentalAnnotationsInUse.toTypedArray() it.pluginOptions = languageSettings.compilerPluginArguments it.pluginClasspaths = languageSettings.compilerPluginClasspath.map(File::getPath).toTypedArray() + it.freeArgs = languageSettings.freeCompilerArgs.toMutableList() } } } diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt index ab17d84aa42..19d2c4ee470 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt @@ -79,6 +79,7 @@ interface KotlinLanguageSettings : Serializable { val experimentalAnnotationsInUse: Set val compilerPluginArguments: Array val compilerPluginClasspath: Set + val freeCompilerArgs: Array } interface KotlinCompilationOutput : Serializable { diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt index e1edbaec389..d0e45a23445 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt @@ -214,6 +214,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { val getExperimentalAnnotationsInUse = languageSettingsClass.getMethodOrNull("getExperimentalAnnotationsInUse") val getCompilerPluginArguments = languageSettingsClass.getMethodOrNull("getCompilerPluginArguments") val getCompilerPluginClasspath = languageSettingsClass.getMethodOrNull("getCompilerPluginClasspath") + val getFreeCompilerArgs = languageSettingsClass.getMethodOrNull("getFreeCompilerArgs") @Suppress("UNCHECKED_CAST") return KotlinLanguageSettingsImpl( getLanguageVersion(gradleLanguageSettings) as? String, @@ -222,7 +223,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { getEnabledLanguageFeatures(gradleLanguageSettings) as? Set ?: emptySet(), getExperimentalAnnotationsInUse?.invoke(gradleLanguageSettings) as? Set ?: emptySet(), (getCompilerPluginArguments?.invoke(gradleLanguageSettings) as? List ?: emptyList()).toTypedArray(), - (getCompilerPluginClasspath?.invoke(gradleLanguageSettings) as? FileCollection)?.files ?: emptySet() + (getCompilerPluginClasspath?.invoke(gradleLanguageSettings) as? FileCollection)?.files ?: emptySet(), + (getFreeCompilerArgs?.invoke(gradleLanguageSettings) as? List).orEmpty().toTypedArray() ) } diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt index fdfc5d0f953..0af4fc51449 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt @@ -66,7 +66,8 @@ data class KotlinLanguageSettingsImpl( override val enabledLanguageFeatures: Set, override val experimentalAnnotationsInUse: Set, override val compilerPluginArguments: Array, - override val compilerPluginClasspath: Set + override val compilerPluginClasspath: Set, + override val freeCompilerArgs: Array ) : KotlinLanguageSettings { constructor(settings: KotlinLanguageSettings) : this( settings.languageVersion, @@ -75,7 +76,8 @@ data class KotlinLanguageSettingsImpl( settings.enabledLanguageFeatures, settings.experimentalAnnotationsInUse, settings.compilerPluginArguments, - settings.compilerPluginClasspath + settings.compilerPluginClasspath, + settings.freeCompilerArgs ) } 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 57ff78f48bd..7f3fc940bb3 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 @@ -534,18 +534,22 @@ class NewMultiplatformIT : BaseGradleIT() { useExperimentalAnnotation('kotlin.contracts.ExperimentalContracts') progressiveMode = true } + project.ext.set("kotlin.mpp.freeCompilerArgsForSourceSet.${'$'}name", ["-Xno-inline"]) } """.trimIndent() ) - listOf("compileKotlinJvm6", "compileKotlinNodeJs", "compileKotlin${nativeHostTargetName.capitalize()}").forEach { + listOf( + "compileKotlinMetadata", "compileKotlinJvm6", "compileKotlinNodeJs", "compileKotlin${nativeHostTargetName.capitalize()}" + ).forEach { build(it) { assertSuccessful() assertTasksExecuted(":$it") assertContains( "-language-version 1.3", "-api-version 1.3", "-XXLanguage:+InlineClasses", " -progressive", "-Xopt-in=kotlin.ExperimentalUnsignedTypes", - "-Xopt-in=kotlin.contracts.ExperimentalContracts" + "-Xopt-in=kotlin.contracts.ExperimentalContracts", + "-Xno-inline" ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 4354b26ee51..19a98635fbe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -93,12 +93,12 @@ class KotlinMultiplatformPlugin( targetsContainer.withType(AbstractKotlinTarget::class.java).all { applyUserDefinedAttributes(it) } // propagate compiler plugin options to the source set language settings - setupCompilerPluginOptions(project) + setupAdditionalCompilerArguments(project) project.pluginManager.apply(ScriptingGradleSubplugin::class.java) } - private fun setupCompilerPluginOptions(project: Project) { + private fun setupAdditionalCompilerArguments(project: Project) { // common source sets use the compiler options from the metadata compilation: val metadataCompilation = project.multiplatformExtension.metadata().compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) @@ -131,6 +131,22 @@ class KotlinMultiplatformPlugin( val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as AbstractCompile } + + // Also set ad-hoc free compiler args from the internal project property + freeCompilerArgsProvider = project.provider { + val propertyValue = with (project.extensions.extraProperties) { + val sourceSetFreeCompilerArgsPropertyName = sourceSetFreeCompilerArgsPropertyName(sourceSet.name) + if (has(sourceSetFreeCompilerArgsPropertyName)) { + get(sourceSetFreeCompilerArgsPropertyName) + } else null + } + mutableListOf().apply { + when (propertyValue) { + is String -> add(propertyValue) + is Iterable<*> -> addAll(propertyValue.map { it.toString() }) + } + } + } } } } @@ -283,6 +299,9 @@ class KotlinMultiplatformPlugin( companion object { const val METADATA_TARGET_NAME = "metadata" + private fun sourceSetFreeCompilerArgsPropertyName(sourceSetName: String) = + "kotlin.mpp.freeCompilerArgsForSourceSet.$sourceSetName" + internal const val GRADLE_NO_METADATA_WARNING = "This build consumes Gradle module metadata but does not produce " + "it when publishing Kotlin multiplatform libraries. \n" + "To enable Gradle module metadata in publications, add 'enableFeaturePreview(\"GRADLE_METADATA\")' " + diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index 21aff84cabe..5e4455f2d8e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -7,11 +7,13 @@ package org.jetbrains.kotlin.gradle.plugin.sources import org.gradle.api.InvalidUserDataException import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile @@ -88,26 +90,40 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { else -> error("Unexpected task: $pluginClasspathTask") } } + + var freeCompilerArgsProvider: Provider>? = null + + val freeCompilerArgs: List + get() = freeCompilerArgsProvider?.get().orEmpty() } -internal fun applyLanguageSettingsToKotlinTask( +internal fun applyLanguageSettingsToKotlinOptions( languageSettingsBuilder: LanguageSettingsBuilder, - kotlinTask: org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*> -) = with(kotlinTask.kotlinOptions) { + kotlinOptions: KotlinCommonOptions +) = with(kotlinOptions) { languageVersion = languageVersion ?: languageSettingsBuilder.languageVersion apiVersion = apiVersion ?: languageSettingsBuilder.apiVersion - - if (languageSettingsBuilder.progressiveMode) { - freeCompilerArgs += "-progressive" + + val freeArgs = mutableListOf().apply { + if (languageSettingsBuilder.progressiveMode) { + add("-progressive") + } + + languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName -> + add("-XXLanguage:+$featureName") + } + + languageSettingsBuilder.experimentalAnnotationsInUse.forEach { annotationName -> + add("-Xopt-in=$annotationName") + } + + if (languageSettingsBuilder is DefaultLanguageSettingsBuilder) { + addAll(languageSettingsBuilder.freeCompilerArgs) + } } - languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName -> - freeCompilerArgs += "-XXLanguage:+$featureName" - } + freeCompilerArgs = freeCompilerArgs + freeArgs - languageSettingsBuilder.experimentalAnnotationsInUse.forEach { annotationName -> - freeCompilerArgs += "-Xopt-in=$annotationName" - } KotlinBuildStatsService.getInstance()?.apply { report(BooleanMetrics.KOTLIN_PROGRESSIVE_MODE, languageSettingsBuilder.progressiveMode) apiVersion?.also { v -> report(StringMetrics.KOTLIN_API_VERSION, v) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt index ab8bb398c34..f15d3cfdb0a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt @@ -9,7 +9,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask +import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator class KotlinMetadataTargetPreset( @@ -58,7 +58,7 @@ class KotlinMetadataTargetPreset( project.whenEvaluated { // Since there's no default source set, apply language settings from commonMain: val compileKotlinMetadata = mainCompilation.compileKotlinTask - applyLanguageSettingsToKotlinTask(commonMainSourceSet.languageSettings, compileKotlinMetadata) + applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index fc262e96433..d3d17d2aba9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind.* import org.jetbrains.kotlin.konan.target.KonanTarget @@ -231,6 +232,10 @@ abstract class AbstractKotlinNativeCompile : Abstra if (!defaultsOnly) { addAll(additionalCompilerOptions) } + + (compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run { + addAll(freeCompilerArgs) + } } // Args passed to the compiler only (except sources). diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt index de1ed2b3ef0..05631b80fca 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt @@ -22,7 +22,7 @@ import org.gradle.api.UnknownTaskException import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask +import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions /** * Registers the task with [name] and [type] and initialization script [body] @@ -122,9 +122,9 @@ internal open class KotlinTasksProvider(val targetName: String) { project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) { propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get()) - applyLanguageSettingsToKotlinTask( + applyLanguageSettingsToKotlinOptions( compilation.defaultSourceSet.languageSettings, - kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*> + (kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions ) } }