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.pluginOptions = languageSettings.compilerPluginArguments
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 compilerPluginArguments: Array<String>
val compilerPluginClasspath: Set<File>
val freeCompilerArgs: Array<String>
}
interface KotlinCompilationOutput : Serializable {
@@ -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<String> ?: emptySet(),
getExperimentalAnnotationsInUse?.invoke(gradleLanguageSettings) as? Set<String> ?: emptySet(),
(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 experimentalAnnotationsInUse: Set<String>,
override val compilerPluginArguments: Array<String>,
override val compilerPluginClasspath: Set<File>
override val compilerPluginClasspath: Set<File>,
override val freeCompilerArgs: Array<String>
) : 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
)
}
@@ -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"
)
}
}
@@ -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<String>().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\")' " +
@@ -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<List<String>>? = null
val freeCompilerArgs: List<String>
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<String>().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) }
@@ -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)
}
}
}
@@ -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<T : KotlinCommonToolOptions> : Abstra
if (!defaultsOnly) {
addAll(additionalCompilerOptions)
}
(compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
addAll(freeCompilerArgs)
}
}
// 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.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
)
}
}