Add JVM project level compiler options DSL

These options are used as initial convention values for compilerOptions
in target compilations.

^KT-57159 In Progress
This commit is contained in:
Yahor Berdnikau
2023-03-10 17:25:59 +01:00
committed by Space Team
parent 6509b0201c
commit dfec9efbb0
11 changed files with 304 additions and 26 deletions
@@ -472,7 +472,8 @@ open class IncrementalJvmCompilerRunner(
isIncremental: Boolean
): Services.Builder =
super.makeServices(args, lookupTracker, expectActualTracker, caches, dirtySources, isIncremental).apply {
val targetId = TargetId(args.moduleName!!, "java-production")
val moduleName = requireNotNull(args.moduleName) { "'moduleName' is null!" }
val targetId = TargetId(moduleName, "java-production")
val targetToCache = mapOf(targetId to caches.platformCache)
val incrementalComponents = IncrementalCompilationComponentsImpl(targetToCache)
register(IncrementalCompilationComponents::class.java, incrementalComponents)
@@ -0,0 +1,216 @@
/*
* 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
import org.gradle.api.logging.LogLevel
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
import kotlin.io.path.appendText
class CompilerOptionsProjectIT : KGPBaseTest() {
@DisplayName("Jvm project compiler options are passed to compilation")
@JvmGradlePluginTests
@GradleTest
fun jvmProjectLevelOptions(gradleVersion: GradleVersion) {
project(
projectName = "simpleProject",
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
buildGradle.appendText(
//language=Groovy
"""
|
|kotlin {
| compilerOptions {
| javaParameters = true
| verbose = false
| }
|}
""".trimMargin()
)
build("compileKotlin") {
assertTasksExecuted(":compileKotlin")
val compilationArgs = output.lineSequence().first { it.contains("Kotlin compiler args:") }
assert(compilationArgs.contains("-java-parameters")) {
printBuildOutput()
"Compiler arguments does not contain '-progressive': $compilationArgs"
}
// '-verbose' by default will be set to 'true' by debug log level
assert(!compilationArgs.contains("-verbose")) {
printBuildOutput()
"Compiler arguments contains '-verbose': $compilationArgs"
}
}
}
}
@DisplayName("languageSettings should not override project options when not configured")
@JvmGradlePluginTests
@GradleTest
fun nonConfiguredLanguageSettings(gradleVersion: GradleVersion) {
project(
projectName = "simpleProject",
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
buildGradle.appendText(
//language=Groovy
"""
|
|kotlin {
| compilerOptions {
| languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0
| apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0
| progressiveMode = true
| optIn.add("my.custom.OptInAnnotation")
| freeCompilerArgs.add("-Xuse-ir")
| }
|}
""".trimMargin()
)
build("compileKotlin") {
assertTasksExecuted(":compileKotlin")
val compilationArgs = output.lineSequence().first { it.contains("Kotlin compiler args:") }
assert(compilationArgs.contains("-language-version 2.0")) {
printBuildOutput()
"Compiler arguments does not contain '-language-version 2.0': $compilationArgs"
}
assert(compilationArgs.contains("-api-version 2.0")) {
printBuildOutput()
"Compiler arguments does not contain '-api-version 2.0': $compilationArgs"
}
assert(compilationArgs.contains("-progressive")) {
printBuildOutput()
"Compiler arguments does not contain '-progressive': $compilationArgs"
}
assert(compilationArgs.contains("-opt-in my.custom.OptInAnnotation")) {
printBuildOutput()
"Compiler arguments does not contain '-opt-in my.custom.OptInAnnotation': $compilationArgs"
}
assert(compilationArgs.contains("-Xuse-ir")) {
printBuildOutput()
"Compiler arguments does not contain '-Xuse-ir': $compilationArgs"
}
}
}
}
@DisplayName("languageSettings override project options when configured")
@JvmGradlePluginTests
@GradleTest
fun configuredLanguageSettings(gradleVersion: GradleVersion) {
project(
projectName = "simpleProject",
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
buildGradle.appendText(
//language=Groovy
"""
|
|kotlin {
| compilerOptions {
| languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0
| apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0
| progressiveMode = true
| optIn.add("my.custom.OptInAnnotation")
| freeCompilerArgs.add("-Xuse-ir")
| }
|
| sourceSets.all {
| languageSettings {
| languageVersion = '1.9'
| apiVersion = '1.9'
| progressiveMode = false
| optInAnnotationsInUse.add("another.CustomOptInAnnotation")
| enableLanguageFeature("UnitConversionsOnArbitraryExpressions")
| }
| }
|}
""".trimMargin()
)
build("compileKotlin") {
assertTasksExecuted(":compileKotlin")
val compilationArgs = output.lineSequence().first { it.contains("Kotlin compiler args:") }
assert(compilationArgs.contains("-language-version 1.9")) {
printBuildOutput()
"Compiler arguments does not contain '-language-version 1.9': $compilationArgs"
}
assert(compilationArgs.contains("-api-version 1.9")) {
printBuildOutput()
"Compiler arguments does not contain '-api-version 2.0': $compilationArgs"
}
assert(!compilationArgs.contains("-progressive")) {
printBuildOutput()
"Compiler arguments contains '-progressive': $compilationArgs"
}
assert(compilationArgs.contains("-opt-in another.CustomOptInAnnotation")) {
printBuildOutput()
"Compiler arguments does not contain '-opt-in another.CustomOptInAnnotation': $compilationArgs"
}
assert(compilationArgs.contains("-XXLanguage:+UnitConversionsOnArbitraryExpressions")) {
printBuildOutput()
"Compiler arguments does not contain '-XXLanguage:+UnitConversionsOnArbitraryExpressions': $compilationArgs"
}
}
}
}
@DisplayName("moduleName overrides compilation moduleName")
@JvmGradlePluginTests
@GradleTest
fun moduleNameProject(gradleVersion: GradleVersion) {
project(
projectName = "simpleProject",
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
buildGradle.appendText(
//language=Groovy
"""
|
|kotlin {
| compilerOptions {
| moduleName = "customModule"
| }
|}
""".trimMargin()
)
build("compileKotlin") {
assertTasksExecuted(":compileKotlin")
val compilationArgs = output.lineSequence().first { it.contains("Kotlin compiler args:") }
assert(compilationArgs.contains("-module-name customModule")) {
printBuildOutput()
"Compiler arguments does not contain '-module-name customModule': $compilationArgs"
}
}
}
}
}
@@ -15,11 +15,9 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainSpec
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsSingleTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmDefaultProjectModelContainer
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.calculateJsCompilerType
@@ -171,6 +169,17 @@ abstract class KotlinJvmProjectExtension(project: Project) : KotlinSingleJavaTar
internal set
open fun target(body: KotlinWithJavaTarget<KotlinJvmOptions, KotlinJvmCompilerOptions>.() -> Unit) = target.run(body)
val compilerOptions: KotlinJvmCompilerOptions =
project.objects.newInstance(KotlinJvmCompilerOptionsDefault::class.java)
fun compilerOptions(configure: Action<KotlinJvmCompilerOptions>) {
configure.execute(compilerOptions)
}
fun compilerOptions(configure: KotlinJvmCompilerOptions.() -> Unit) {
configure(compilerOptions)
}
}
abstract class Kotlin2JsProjectExtension(project: Project) : KotlinSingleJavaTargetExtension(project) {
@@ -68,7 +68,6 @@ internal open class KotlinJvmCompilerArgumentsContributor(
) : AbstractKotlinCompileArgumentsContributor<K2JVMCompilerArguments>(taskProvider) {
private val taskName = taskProvider.taskName
private val moduleName = taskProvider.moduleName
private val friendPaths = taskProvider.friendPaths
private val compileClasspath = taskProvider.compileClasspath
private val destinationDir = taskProvider.destinationDir
@@ -82,7 +81,7 @@ internal open class KotlinJvmCompilerArgumentsContributor(
super.contributeArguments(args, flags)
args.moduleName = moduleName
args.moduleName = compilerOptions.moduleName.orNull
logger.kotlinDebug { "$taskName | args.moduleName = ${args.moduleName}" }
args.friendPaths = friendPaths.files.map { it.absolutePath }.toTypedArray()
@@ -63,7 +63,21 @@ internal open class KotlinJvmPlugin(
disambiguationClassifier = null // don't add anything to the task names
}
(project.kotlinExtension as KotlinJvmProjectExtension).target = target
val kotlinExtension = project.kotlinExtension as KotlinJvmProjectExtension
kotlinExtension.target = target
kotlinExtension.compilerOptions.verbose.convention(project.logger.isDebugEnabled)
target.compilations.configureEach {
KotlinJvmCompilerOptionsHelper.syncOptionsAsConvention(
from = kotlinExtension.compilerOptions,
into = it.compilerOptions.options
)
it.compilerOptions.options.moduleName.convention(
kotlinExtension.compilerOptions.moduleName.orElse(
@Suppress("DEPRECATION")
project.providers.provider { it.moduleName }
)
)
}
super.apply(project)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions
import org.jetbrains.kotlin.project.model.LanguageSettings
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import kotlin.properties.Delegates
internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
private var languageVersionImpl: LanguageVersion? = null
@@ -48,7 +49,12 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
}
}
override var progressiveMode: Boolean = false
// 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>()
@@ -102,25 +108,36 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
internal fun applyLanguageSettingsToCompilerOptions(
languageSettingsBuilder: LanguageSettings,
compilerOptions: KotlinCommonCompilerOptions
compilerOptions: KotlinCommonCompilerOptions,
addFreeCompilerArgsAsConvention: Boolean = true,
) = with(compilerOptions) {
languageVersion.convention(languageSettingsBuilder.languageVersion?.let { KotlinVersion.fromVersion(it) })
apiVersion.convention(languageSettingsBuilder.apiVersion?.let { KotlinVersion.fromVersion(it) })
progressiveMode.convention(languageSettingsBuilder.progressiveMode)
optIn.addAll(languageSettingsBuilder.optInAnnotationsInUse)
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>().apply {
languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName ->
add("-XXLanguage:+$featureName")
}
val freeArgs = mutableListOf<String>()
languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName ->
freeArgs.add("-XXLanguage:+$featureName")
}
freeArgs.addAll(languageSettingsBuilderDefault.freeCompilerArgs)
if (languageSettingsBuilder is DefaultLanguageSettingsBuilder) {
addAll(languageSettingsBuilder.freeCompilerArgs)
if (freeArgs.isNotEmpty()) {
if (addFreeCompilerArgsAsConvention) {
freeCompilerArgs.convention(freeArgs)
} else {
freeCompilerArgs.addAll(freeArgs)
}
}
freeCompilerArgs.addAll(freeArgs)
// TODO: Fix it - get actual values on execution
KotlinBuildStatsService.getInstance()?.apply {
report(BooleanMetrics.KOTLIN_PROGRESSIVE_MODE, languageSettingsBuilder.progressiveMode)
apiVersion.orNull?.also { v -> report(StringMetrics.KOTLIN_API_VERSION, v.version) }
@@ -41,6 +41,19 @@ open class KotlinJvmTargetConfigurator :
}
}
override fun configureCompilations(target: KotlinJvmTarget) {
super.configureCompilations(target)
target.compilations.configureEach {
it.compilerOptions.options.moduleName.convention(
target.project.providers.provider {
@Suppress("DEPRECATION")
it.moduleName
}
)
}
}
override val testRunClass: Class<KotlinJvmTestRun>
get() = KotlinJvmTestRun::class.java
@@ -56,6 +56,13 @@ class KotlinJvmWithJavaTargetPreset(
Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo(compilation))
}
target.compilations.configureEach {
it.compilerOptions.options.moduleName.convention(
@Suppress("DEPRECATION")
project.providers.provider { it.moduleName }
)
}
target.compilations.getByName("test").run {
val main = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
@@ -69,10 +69,8 @@ abstract class KotlinCompile @Inject constructor(
KotlinCompilationTask<KotlinJvmCompilerOptions>,
UsesKotlinJavaToolchain {
init {
compilerOptions.moduleName.convention(moduleName)
compilerOptions.verbose.convention(logger.isDebugEnabled)
}
@get:Internal // covered by compiler options
abstract override val moduleName: Property<String>
final override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsCompat(
{ this },
@@ -23,7 +23,6 @@ open class KotlinCompileArgumentsProvider<T : AbstractKotlinCompile<out CommonCo
class KotlinJvmCompilerArgumentsProvider
(taskProvider: KotlinCompile) : KotlinCompileArgumentsProvider<KotlinCompile>(taskProvider) {
val taskName: String = taskProvider.name
val moduleName: String = taskProvider.moduleName.get()
val friendPaths: FileCollection = taskProvider.friendPaths
val compileClasspath: Iterable<File> = taskProvider.libraries
val destinationDir: File = taskProvider.destinationDirectory.get().asFile
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.report.BuildMetricsService
import org.jetbrains.kotlin.gradle.report.BuildReportsService
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
@@ -50,7 +51,11 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
if (it is KaptGenerateStubsTask) return@configure
applyLanguageSettingsToCompilerOptions(
languageSettings.get(), (it as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>).compilerOptions
languageSettings.get(),
(it as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>).compilerOptions,
// KotlinJsIrTarget and KotlinJsIrTargetConfigurator add additional freeCompilerArgs essentially
// always overwriting convention value
addFreeCompilerArgsAsConvention = it !is Kotlin2JsCompile
)
}
}