[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
This commit is contained in:
Yahor Berdnikau
2023-07-24 22:39:09 +02:00
committed by Space Team
parent bed16f92b1
commit 8df905a326
26 changed files with 540 additions and 251 deletions
@@ -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")
}
}
}
}
}
@@ -140,7 +140,7 @@ class CompilerOptionsProjectIT : KGPBaseTest() {
| languageVersion = '1.9'
| apiVersion = '1.9'
| progressiveMode = false
| optInAnnotationsInUse.add("another.CustomOptInAnnotation")
| optIn("another.CustomOptInAnnotation")
| enableLanguageFeature("UnitConversionsOnArbitraryExpressions")
| }
| }
@@ -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
@@ -0,0 +1,20 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
}
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
jvm()
linuxX64()
linuxArm64()
iosX64()
iosArm64()
applyDefaultHierarchyTemplate()
}
@@ -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)
@@ -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 {
@@ -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,
)
@@ -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)
}
}
@@ -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)
}
}
}
@@ -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)
@@ -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
@@ -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<T, S>(
@@ -21,45 +21,68 @@ internal class FragmentConsistencyChecks<T>(
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<T, LanguageVersion>(
private val languageVersionCheck = ConsistencyCheck<T, KotlinVersion?>(
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<T, Set<LanguageFeature>>(
private val unstableFeaturesCheck = ConsistencyCheck<T, Set<LanguageFeature>?>(
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<T, Set<String>>(
private val optInAnnotationsCheck = ConsistencyCheck<T, Set<String>?>(
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 <T> 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<T>(
private val unitsName: String,
private val name: T.() -> String,
@@ -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<KotlinSourceSet>(
FragmentConsistencyChecker(
unitsName = "source sets",
name = { name },
checks = FragmentConsistencyChecks<KotlinSourceSet>(
@@ -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<KotlinCommonCompilerOptions> = 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<KotlinCommonCompilerOptionsDefault>())
}
}
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<LanguageFeature>()
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<String>()
override val enabledLanguageFeatures: Set<String>
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<String>()
private val optInAnnotationsInUseField = mutableSetOf<String>()
override val optInAnnotationsInUse: Set<String> = optInAnnotationsInUseImpl
override val optInAnnotationsInUse: Set<String>
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<List<String>>? = 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<String>? = null
internal val freeCompilerArgsForNonImport: List<String>
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<String>
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<String>()
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)
@@ -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
)
}
}
}
}
@@ -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)
}
}
}
}
@@ -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<T : KotlinNativeTarget> : AbstractKotl
}
private fun Project.syncLanguageSettingsToLinkTask(binary: NativeBinary) {
tasks.named(binary.linkTaskName, KotlinNativeLink::class.java).configure {
tasks.named<KotlinNativeLink>(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<T : KotlinNativeTarget> : 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)
@@ -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<KotlinNativeCompilerOptions> {
override val options: KotlinNativeCompilerOptions = project.objects
.newInstance(KotlinNativeCompilerOptionsDefault::class.java)
.configureExperimentalTryK2(project)
internal fun syncLanguageSettings(languageSettings: LanguageSettings) {
applyLanguageSettingsToCompilerOptions(languageSettings, options)
}
}
@@ -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<Collection<String>>
@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<String>
@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<Collection<String>>
get() = compilerOptions
.freeCompilerArgs
.map { it + (languageSettings as DefaultLanguageSettingsBuilder).freeCompilerArgsForNonImport }
get() = compilerOptions.freeCompilerArgs as Provider<Collection<String>>
private val runnerSettings = KotlinNativeCompilerRunner.Settings.fromProject(project)
// endregion.
@@ -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<TASK : AbstractKotlinCompile<*>>(
project: Project,
val ext: KotlinTopLevelExtension,
private val languageSettings: Provider<LanguageSettings>
val ext: KotlinTopLevelExtension
) : TaskConfigAction<TASK>(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 : AbstractKotlinCompile
task.incremental = false
task.useModuleDetection.convention(false)
if (propertiesProvider.useK2 == true) {
@Suppress("DEPRECATION")
task.compilerOptions.useK2.value(true)
}
task.runViaBuildToolsApi.convention(propertiesProvider.runKotlinCompilerViaBuildToolsApi).finalizeValueOnRead()
@@ -139,8 +121,7 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
constructor(compilationInfo: KotlinCompilationInfo) : this(
compilationInfo.project,
compilationInfo.project.topLevelExtension,
compilationInfo.project.provider { compilationInfo.languageSettings }
compilationInfo.project.topLevelExtension
) {
configureTask { task ->
task.friendPaths.from({ compilationInfo.friendPaths })
@@ -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<KotlinCompile>
@@ -99,7 +96,7 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
constructor(project: Project, ext: KotlinTopLevelExtension) : super(
project, ext, languageSettings = getDefaultLangSetting(project)
project, ext
)
companion object {
@@ -109,10 +106,6 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : 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<LanguageSettings> {
return project.provider { DefaultLanguageSettingsBuilder() }
}
}
private fun registerTransformsOnce(project: Project) {
@@ -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<FakeCompilation> {
defaults(kotlin)
defaults(kotlin, "fakeAux")
compilationName = "aux"
}
@@ -114,13 +114,13 @@ class ExternalKotlinTargetApiTests {
}
val mainCompilation = target.createCompilation<FakeCompilation> {
defaults(kotlin)
defaults(kotlin, "fakeMain")
this.compilationAssociator = compilationAssociator
this.compileTaskName = "main"
}
val auxCompilation = target.createCompilation<FakeCompilation> {
defaults(kotlin)
defaults(kotlin, "fakeAux")
this.compilationName = "aux"
this.compilationAssociator = compilationAssociator
}
@@ -61,12 +61,12 @@ class ExternalKotlinTargetSourcesJarUtilsTest {
val target = multiplatformExtension.createExternalKotlinTarget<FakeTarget> { defaults() }
val mainCompilation = target.createCompilation<FakeCompilation> {
defaults(multiplatformExtension)
defaults(multiplatformExtension, "mainFake")
compilationName = "main"
}
val auxCompilation = target.createCompilation<FakeCompilation> {
defaults(multiplatformExtension)
defaults(multiplatformExtension, "auxFake")
compilationName = "aux"
}
@@ -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
@@ -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<KotlinCompilationTask<*>>().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)
}
}
}
}
@@ -20,8 +20,11 @@ fun ExternalKotlinTargetDescriptorBuilder<FakeTarget>.defaults() {
targetFactory = TargetFactory(::FakeTarget)
}
fun ExternalKotlinCompilationDescriptorBuilder<FakeCompilation>.defaults(kotlin: KotlinMultiplatformExtension) {
compilationName = "fake"
fun ExternalKotlinCompilationDescriptorBuilder<FakeCompilation>.defaults(
kotlin: KotlinMultiplatformExtension,
name: String = "fake"
) {
compilationName = name
compilationFactory = CompilationFactory(::FakeCompilation)
defaultSourceSet = kotlin.sourceSets.maybeCreate("fake")
defaultSourceSet = kotlin.sourceSets.maybeCreate(name)
}