[Gradle] Kotlin2JsCompile: Implement KotlinCompilerArgumentsProducer

KTIJ-24976
This commit is contained in:
Sebastian Sellmair
2023-03-21 10:49:04 +01:00
committed by Space Team
parent d4cc842200
commit ff0b070398
6 changed files with 187 additions and 14 deletions
@@ -92,12 +92,10 @@ internal open class GradleCompilerRunner(
* @see [GradleKotlinCompilerWork]
*/
fun runJsCompilerAsync(
kotlinSources: List<File>,
args: K2JSCompilerArguments,
environment: GradleCompilerEnvironment,
taskOutputsBackup: TaskOutputsBackup?
): WorkQueue? {
args.freeArgs += kotlinSources.map { it.absolutePath }
return runCompilerAsync(KotlinCompilerClass.JS, args, environment, taskOutputsBackup)
}
@@ -16,13 +16,13 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptionsDefault
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.ContributeCompilerArgumentsContext
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -124,6 +124,40 @@ abstract class KotlinJsIrLink @Inject constructor(
}
}
override fun contributeAdditionalCompilerArguments(context: ContributeCompilerArgumentsContext<K2JSCompilerArguments>) {
super.contributeAdditionalCompilerArguments(context)
context.contribute(KotlinCompilerArgumentsProducer.ArgumentType.Primitive) { args ->
// TODO Ilya Goncharov: This should not be part of creating compiler arguments;
KotlinBuildStatsService.applyIfInitialised {
it.report(BooleanMetrics.JS_IR_INCREMENTAL, this.incrementalJsIr)
val newArgs = K2JSCompilerArguments()
parseCommandLineArguments(ArgumentUtils.convertArgumentsToStringList(args), newArgs)
it.report(
StringMetrics.JS_OUTPUT_GRANULARITY,
if (newArgs.irPerModule)
KotlinJsIrOutputGranularity.PER_MODULE.name.toLowerCaseAsciiOnly()
else
KotlinJsIrOutputGranularity.WHOLE_PROGRAM.name.toLowerCaseAsciiOnly()
)
}
// moduleName can start with @ for group of NPM packages
// but args parsing @ as start of argfile
// so WA we provide moduleName as one parameter
if (args.moduleName != null) {
args.freeArgs += "-ir-output-name=${args.moduleName}"
args.moduleName = null
}
args.includes = entryModule.get().asFile.canonicalPath
if (usingCacheDirectory()) {
args.cacheDirectory = rootCacheDirectory.get().asFile.also { it.mkdirs() }.absolutePath
}
}
}
private fun usingCacheDirectory() =
incrementalJsIr && modeProperty.get() == DEVELOPMENT
}
@@ -12,7 +12,6 @@ import org.gradle.api.file.FileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.work.Incremental
import org.gradle.work.InputChanges
@@ -24,14 +23,17 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.IncrementalCompilationEnvironment
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptionsDefault
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradleErrorMessageCollector
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.ContributeCompilerArgumentsContext
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.report.BuildReportMode
import org.jetbrains.kotlin.gradle.targets.js.internal.LibraryFilterCachingService
import org.jetbrains.kotlin.gradle.targets.js.internal.UsesLibraryFilterCachingService
import org.jetbrains.kotlin.gradle.targets.js.ir.DISABLE_PRE_IR
@@ -41,7 +43,7 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_ZIPPED_KLIB
import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJsOptionsCompat
import org.jetbrains.kotlin.gradle.utils.isParentOf
import org.jetbrains.kotlin.gradle.utils.newInstance
import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.gradle.utils.toPathsArray
import org.jetbrains.kotlin.incremental.ClasspathChanges
import org.jetbrains.kotlin.library.impl.isKotlinLibrary
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
@@ -56,6 +58,7 @@ abstract class Kotlin2JsCompile @Inject constructor(
workerExecutor: WorkerExecutor
) : AbstractKotlinCompile<K2JSCompilerArguments>(objectFactory, workerExecutor),
KotlinCompilationTask<KotlinJsCompilerOptions>,
KotlinCompilerArgumentsProducer,
UsesLibraryFilterCachingService,
KotlinJsCompile,
K2MultiplatformCompilationTask {
@@ -125,9 +128,11 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Nested
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
@Suppress("OVERRIDE_DEPRECATION")
override fun createCompilerArgs(): K2JSCompilerArguments =
K2JSCompilerArguments()
@Suppress("OVERRIDE_DEPRECATION")
override fun setupCompilerArgs(args: K2JSCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
KotlinJsCompilerOptionsHelper.fillDefaultValues(args)
super.setupCompilerArgs(args, defaultsOnly = defaultsOnly, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors)
@@ -161,7 +166,88 @@ abstract class Kotlin2JsCompile @Inject constructor(
// Overriding freeArgs from compilerOptions with enhanced one + additional one set on execution phase
// containing additional arguments based on the js compilation configuration
val localExecutionTimeFreeCompilerArgs = executionTimeFreeCompilerArgs
args.freeArgs = if (localExecutionTimeFreeCompilerArgs != null) localExecutionTimeFreeCompilerArgs else enhancedFreeCompilerArgs.get()
args.freeArgs =
if (localExecutionTimeFreeCompilerArgs != null) localExecutionTimeFreeCompilerArgs else enhancedFreeCompilerArgs.get()
}
override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create<K2JSCompilerArguments> {
contribute(KotlinCompilerArgumentsProducer.ArgumentType.Primitive) { args ->
args.multiPlatform = multiPlatformEnabled.get()
args.pluginOptions = (pluginOptions.toSingleCompilerPluginOptions() + kotlinPluginData?.orNull?.options)
.arguments.toTypedArray()
if (reportingSettings().buildReportMode == BuildReportMode.VERBOSE) {
args.reportPerf = true
}
KotlinJsCompilerOptionsHelper.fillCompilerArguments(compilerOptions, args)
if (isIrBackendEnabled()) {
val outputFilePath: String? = compilerOptions.outputFile.orNull
if (outputFilePath != null) {
val outputFile = File(outputFilePath)
args.outputDir = (if (outputFile.extension == "") outputFile else outputFile.parentFile).normalize().absolutePath
args.moduleName = outputFile.nameWithoutExtension
} else {
args.outputDir = destinationDirectory.get().asFile.normalize().absolutePath
args.moduleName = compilerOptions.moduleName.get()
}
} else {
args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath
}
if (compilerOptions.usesK2.get()) {
args.fragments = multiplatformStructure.fragmentsCompilerArgs
args.fragmentRefines = multiplatformStructure.fragmentRefinesCompilerArgs
}
if (!isIrBackendEnabled()) {
args.forceDeprecatedLegacyCompilerUsage = true
}
// Overriding freeArgs from compilerOptions with enhanced one + additional one set on execution phase
// containing additional arguments based on the js compilation configuration
args.freeArgs = executionTimeFreeCompilerArgs ?: enhancedFreeCompilerArgs.get()
}
contribute(KotlinCompilerArgumentsProducer.ArgumentType.PluginClasspath) { args ->
args.pluginClasspaths = tryLenient {
listOfNotNull(
pluginClasspath, kotlinPluginData?.orNull?.classpath
).reduce(FileCollection::plus).toPathsArray()
}
}
contribute(KotlinCompilerArgumentsProducer.ArgumentType.DependencyClasspath) { args ->
args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath }
val dependencies = libraries
.filter { it.exists() && libraryFilter(it) }
.map { it.normalize().absolutePath }
args.libraries = dependencies.distinct().let {
if (it.isNotEmpty())
it.joinToString(File.pathSeparator) else
null
}
}
contribute(KotlinCompilerArgumentsProducer.ArgumentType.Sources) { args ->
if (!args.sourceMapPrefix.isNullOrEmpty()) {
args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath
}
if (compilerOptions.usesK2.get()) {
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs
} else {
args.commonSources = commonSourceSet.asFileTree.toPathsArray()
}
args.freeArgs += sources.asFileTree.files.map { it.absolutePath }
}
contributeAdditionalCompilerArguments(this)
}
@get:InputFiles
@@ -248,6 +334,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
}
open fun contributeAdditionalCompilerArguments(context: ContributeCompilerArgumentsContext<K2JSCompilerArguments>) = Unit
override fun callCompilerAsync(
args: K2JSCompilerArguments,
kotlinSources: Set<File>,
@@ -277,7 +365,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}")
val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = getKotlinPluginVersion(logger))
val gradleMessageCollector =
GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = getKotlinPluginVersion(logger))
val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner.get()
@@ -301,7 +390,6 @@ abstract class Kotlin2JsCompile @Inject constructor(
)
processArgs(args)
compilerRunner.runJsCompilerAsync(
kotlinSources.toList(),
args,
environment,
taskOutputsBackup
@@ -0,0 +1,53 @@
/*
* 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests.compilerArgumetns
import org.gradle.kotlin.dsl.repositories
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.gradle.dependencyResolutionTests.mavenCentralCacheRedirector
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments
import org.jetbrains.kotlin.gradle.plugin.CreateCompilerArgumentsContext
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.ArgumentType
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
import org.jetbrains.kotlin.gradle.util.main
import kotlin.test.Test
import kotlin.test.assertEquals
class JsCompilerArgumentTests {
@Suppress("DEPRECATION")
@Test
fun `test - simple project`() {
val project = buildProjectWithMPP {
repositories {
mavenLocal()
mavenCentralCacheRedirector()
}
}
val kotlin = project.multiplatformExtension
val jsTarget = kotlin.js(KotlinJsCompilerType.IR)
val jsMainCompilation = jsTarget.compilations.main
project.evaluate()
val jsMainCompileTask = jsMainCompilation.compileTaskProvider.get()
val argumentsFromCompilerArgumentsProducer = jsMainCompileTask.createCompilerArguments(
CreateCompilerArgumentsContext(
isLenient = true,
includeArgumentTypes = ArgumentType.all - ArgumentType.DependencyClasspath
)
)
val argumentsFromCompilerArgumentsAware = jsMainCompileTask.prepareCompilerArguments(true)
assertEquals(
ArgumentUtils.convertArgumentsToStringList(argumentsFromCompilerArgumentsAware),
ArgumentUtils.convertArgumentsToStringList(argumentsFromCompilerArgumentsProducer),
)
}
}
@@ -5,7 +5,7 @@
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.unitTests
package org.jetbrains.kotlin.gradle.unitTests.compilerArgumetns
import org.gradle.kotlin.dsl.repositories
import org.jetbrains.kotlin.cli.common.arguments.Argument
@@ -8,5 +8,5 @@ package org.jetbrains.kotlin.gradle.util
import org.gradle.api.NamedDomainObjectCollection
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
val NamedDomainObjectCollection<out KotlinCompilation<*>>.main: KotlinCompilation<*> get() = getByName("main")
val NamedDomainObjectCollection<out KotlinCompilation<*>>.test: KotlinCompilation<*> get() = getByName("test")
val <T: KotlinCompilation<*>> NamedDomainObjectCollection<out T>.main: T get() = getByName("main")
val <T: KotlinCompilation<*>> NamedDomainObjectCollection<out T>.test: T get() = getByName("test")