Add a non-public-API mechanism to import free args for MPP source sets

Arguments can be set using a project extra property following the
pattern: `kotlin.mpp.freeCompilerArgsForSourceSet.$sourceSetName`.

Only a compilation's default source set free args are appended to the
compiler args during Gradle builds.
This commit is contained in:
Sergey Igushkin
2020-01-31 18:24:41 +03:00
parent a8aa334203
commit 764bf1cb32
10 changed files with 74 additions and 24 deletions
@@ -891,6 +891,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
it.useExperimental = languageSettings.experimentalAnnotationsInUse.toTypedArray() it.useExperimental = languageSettings.experimentalAnnotationsInUse.toTypedArray()
it.pluginOptions = languageSettings.compilerPluginArguments it.pluginOptions = languageSettings.compilerPluginArguments
it.pluginClasspaths = languageSettings.compilerPluginClasspath.map(File::getPath).toTypedArray() it.pluginClasspaths = languageSettings.compilerPluginClasspath.map(File::getPath).toTypedArray()
it.freeArgs = languageSettings.freeCompilerArgs.toMutableList()
} }
} }
} }
@@ -79,6 +79,7 @@ interface KotlinLanguageSettings : Serializable {
val experimentalAnnotationsInUse: Set<String> val experimentalAnnotationsInUse: Set<String>
val compilerPluginArguments: Array<String> val compilerPluginArguments: Array<String>
val compilerPluginClasspath: Set<File> val compilerPluginClasspath: Set<File>
val freeCompilerArgs: Array<String>
} }
interface KotlinCompilationOutput : Serializable { interface KotlinCompilationOutput : Serializable {
@@ -214,6 +214,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
val getExperimentalAnnotationsInUse = languageSettingsClass.getMethodOrNull("getExperimentalAnnotationsInUse") val getExperimentalAnnotationsInUse = languageSettingsClass.getMethodOrNull("getExperimentalAnnotationsInUse")
val getCompilerPluginArguments = languageSettingsClass.getMethodOrNull("getCompilerPluginArguments") val getCompilerPluginArguments = languageSettingsClass.getMethodOrNull("getCompilerPluginArguments")
val getCompilerPluginClasspath = languageSettingsClass.getMethodOrNull("getCompilerPluginClasspath") val getCompilerPluginClasspath = languageSettingsClass.getMethodOrNull("getCompilerPluginClasspath")
val getFreeCompilerArgs = languageSettingsClass.getMethodOrNull("getFreeCompilerArgs")
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return KotlinLanguageSettingsImpl( return KotlinLanguageSettingsImpl(
getLanguageVersion(gradleLanguageSettings) as? String, getLanguageVersion(gradleLanguageSettings) as? String,
@@ -222,7 +223,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
getEnabledLanguageFeatures(gradleLanguageSettings) as? Set<String> ?: emptySet(), getEnabledLanguageFeatures(gradleLanguageSettings) as? Set<String> ?: emptySet(),
getExperimentalAnnotationsInUse?.invoke(gradleLanguageSettings) as? Set<String> ?: emptySet(), getExperimentalAnnotationsInUse?.invoke(gradleLanguageSettings) as? Set<String> ?: emptySet(),
(getCompilerPluginArguments?.invoke(gradleLanguageSettings) as? List<String> ?: emptyList()).toTypedArray(), (getCompilerPluginArguments?.invoke(gradleLanguageSettings) as? List<String> ?: emptyList()).toTypedArray(),
(getCompilerPluginClasspath?.invoke(gradleLanguageSettings) as? FileCollection)?.files ?: emptySet() (getCompilerPluginClasspath?.invoke(gradleLanguageSettings) as? FileCollection)?.files ?: emptySet(),
(getFreeCompilerArgs?.invoke(gradleLanguageSettings) as? List<String>).orEmpty().toTypedArray()
) )
} }
@@ -66,7 +66,8 @@ data class KotlinLanguageSettingsImpl(
override val enabledLanguageFeatures: Set<String>, override val enabledLanguageFeatures: Set<String>,
override val experimentalAnnotationsInUse: Set<String>, override val experimentalAnnotationsInUse: Set<String>,
override val compilerPluginArguments: Array<String>, override val compilerPluginArguments: Array<String>,
override val compilerPluginClasspath: Set<File> override val compilerPluginClasspath: Set<File>,
override val freeCompilerArgs: Array<String>
) : KotlinLanguageSettings { ) : KotlinLanguageSettings {
constructor(settings: KotlinLanguageSettings) : this( constructor(settings: KotlinLanguageSettings) : this(
settings.languageVersion, settings.languageVersion,
@@ -75,7 +76,8 @@ data class KotlinLanguageSettingsImpl(
settings.enabledLanguageFeatures, settings.enabledLanguageFeatures,
settings.experimentalAnnotationsInUse, settings.experimentalAnnotationsInUse,
settings.compilerPluginArguments, settings.compilerPluginArguments,
settings.compilerPluginClasspath settings.compilerPluginClasspath,
settings.freeCompilerArgs
) )
} }
@@ -534,18 +534,22 @@ class NewMultiplatformIT : BaseGradleIT() {
useExperimentalAnnotation('kotlin.contracts.ExperimentalContracts') useExperimentalAnnotation('kotlin.contracts.ExperimentalContracts')
progressiveMode = true progressiveMode = true
} }
project.ext.set("kotlin.mpp.freeCompilerArgsForSourceSet.${'$'}name", ["-Xno-inline"])
} }
""".trimIndent() """.trimIndent()
) )
listOf("compileKotlinJvm6", "compileKotlinNodeJs", "compileKotlin${nativeHostTargetName.capitalize()}").forEach { listOf(
"compileKotlinMetadata", "compileKotlinJvm6", "compileKotlinNodeJs", "compileKotlin${nativeHostTargetName.capitalize()}"
).forEach {
build(it) { build(it) {
assertSuccessful() assertSuccessful()
assertTasksExecuted(":$it") assertTasksExecuted(":$it")
assertContains( assertContains(
"-language-version 1.3", "-api-version 1.3", "-XXLanguage:+InlineClasses", "-language-version 1.3", "-api-version 1.3", "-XXLanguage:+InlineClasses",
" -progressive", "-Xopt-in=kotlin.ExperimentalUnsignedTypes", " -progressive", "-Xopt-in=kotlin.ExperimentalUnsignedTypes",
"-Xopt-in=kotlin.contracts.ExperimentalContracts" "-Xopt-in=kotlin.contracts.ExperimentalContracts",
"-Xno-inline"
) )
} }
} }
@@ -93,12 +93,12 @@ class KotlinMultiplatformPlugin(
targetsContainer.withType(AbstractKotlinTarget::class.java).all { applyUserDefinedAttributes(it) } targetsContainer.withType(AbstractKotlinTarget::class.java).all { applyUserDefinedAttributes(it) }
// propagate compiler plugin options to the source set language settings // propagate compiler plugin options to the source set language settings
setupCompilerPluginOptions(project) setupAdditionalCompilerArguments(project)
project.pluginManager.apply(ScriptingGradleSubplugin::class.java) 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: // common source sets use the compiler options from the metadata compilation:
val metadataCompilation = val metadataCompilation =
project.multiplatformExtension.metadata().compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) project.multiplatformExtension.metadata().compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
@@ -131,6 +131,22 @@ class KotlinMultiplatformPlugin(
val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation
project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as AbstractCompile 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<String>().apply {
when (propertyValue) {
is String -> add(propertyValue)
is Iterable<*> -> addAll(propertyValue.map { it.toString() })
}
}
}
} }
} }
} }
@@ -283,6 +299,9 @@ class KotlinMultiplatformPlugin(
companion object { companion object {
const val METADATA_TARGET_NAME = "metadata" 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 " + internal const val GRADLE_NO_METADATA_WARNING = "This build consumes Gradle module metadata but does not produce " +
"it when publishing Kotlin multiplatform libraries. \n" + "it when publishing Kotlin multiplatform libraries. \n" +
"To enable Gradle module metadata in publications, add 'enableFeaturePreview(\"GRADLE_METADATA\")' " + "To enable Gradle module metadata in publications, add 'enableFeaturePreview(\"GRADLE_METADATA\")' " +
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.gradle.plugin.sources
import org.gradle.api.InvalidUserDataException import org.gradle.api.InvalidUserDataException
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersion 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.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
@@ -88,26 +90,40 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
else -> error("Unexpected task: $pluginClasspathTask") else -> error("Unexpected task: $pluginClasspathTask")
} }
} }
var freeCompilerArgsProvider: Provider<List<String>>? = null
val freeCompilerArgs: List<String>
get() = freeCompilerArgsProvider?.get().orEmpty()
} }
internal fun applyLanguageSettingsToKotlinTask( internal fun applyLanguageSettingsToKotlinOptions(
languageSettingsBuilder: LanguageSettingsBuilder, languageSettingsBuilder: LanguageSettingsBuilder,
kotlinTask: org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*> kotlinOptions: KotlinCommonOptions
) = with(kotlinTask.kotlinOptions) { ) = with(kotlinOptions) {
languageVersion = languageVersion ?: languageSettingsBuilder.languageVersion languageVersion = languageVersion ?: languageSettingsBuilder.languageVersion
apiVersion = apiVersion ?: languageSettingsBuilder.apiVersion apiVersion = apiVersion ?: languageSettingsBuilder.apiVersion
if (languageSettingsBuilder.progressiveMode) { val freeArgs = mutableListOf<String>().apply {
freeCompilerArgs += "-progressive" 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 = freeCompilerArgs + freeArgs
freeCompilerArgs += "-XXLanguage:+$featureName"
}
languageSettingsBuilder.experimentalAnnotationsInUse.forEach { annotationName ->
freeCompilerArgs += "-Xopt-in=$annotationName"
}
KotlinBuildStatsService.getInstance()?.apply { KotlinBuildStatsService.getInstance()?.apply {
report(BooleanMetrics.KOTLIN_PROGRESSIVE_MODE, languageSettingsBuilder.progressiveMode) report(BooleanMetrics.KOTLIN_PROGRESSIVE_MODE, languageSettingsBuilder.progressiveMode)
apiVersion?.also { v -> report(StringMetrics.KOTLIN_API_VERSION, v) } apiVersion?.also { v -> report(StringMetrics.KOTLIN_API_VERSION, v) }
@@ -9,7 +9,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.* 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 import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
class KotlinMetadataTargetPreset( class KotlinMetadataTargetPreset(
@@ -58,7 +58,7 @@ class KotlinMetadataTargetPreset(
project.whenEvaluated { project.whenEvaluated {
// Since there's no default source set, apply language settings from commonMain: // Since there's no default source set, apply language settings from commonMain:
val compileKotlinMetadata = mainCompilation.compileKotlinTask val compileKotlinMetadata = mainCompilation.compileKotlinTask
applyLanguageSettingsToKotlinTask(commonMainSourceSet.languageSettings, compileKotlinMetadata) applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions)
} }
} }
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
import org.jetbrains.kotlin.gradle.plugin.mpp.* 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.CompilerOutputKind.* import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -231,6 +232,10 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
if (!defaultsOnly) { if (!defaultsOnly) {
addAll(additionalCompilerOptions) addAll(additionalCompilerOptions)
} }
(compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
addAll(freeCompilerArgs)
}
} }
// Args passed to the compiler only (except sources). // Args passed to the compiler only (except sources).
@@ -22,7 +22,7 @@ import org.gradle.api.UnknownTaskException
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation 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] * 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) { project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) {
propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get()) propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get())
applyLanguageSettingsToKotlinTask( applyLanguageSettingsToKotlinOptions(
compilation.defaultSourceSet.languageSettings, compilation.defaultSourceSet.languageSettings,
kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*> (kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions
) )
} }
} }