diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 7efcc1bd1fc..745b117595b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -92,12 +92,10 @@ internal open class GradleCompilerRunner( * @see [GradleKotlinCompilerWork] */ fun runJsCompilerAsync( - kotlinSources: List, args: K2JSCompilerArguments, environment: GradleCompilerEnvironment, taskOutputsBackup: TaskOutputsBackup? ): WorkQueue? { - args.freeArgs += kotlinSources.map { it.absolutePath } return runCompilerAsync(KotlinCompilerClass.JS, args, environment, taskOutputsBackup) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index f57c7744c15..00e15f2318f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -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) { + 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 } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt index 4ba562e23c1..3f11cca6324 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt @@ -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(objectFactory, workerExecutor), KotlinCompilationTask, + 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 { + 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) = Unit + override fun callCompilerAsync( args: K2JSCompilerArguments, kotlinSources: Set, @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JsCompilerArgumentTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JsCompilerArgumentTests.kt new file mode 100644 index 00000000000..8a43982d110 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JsCompilerArgumentTests.kt @@ -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), + ) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/JvmCompilerArgumentsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JvmCompilerArgumentsTest.kt similarity index 98% rename from libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/JvmCompilerArgumentsTest.kt rename to libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JvmCompilerArgumentsTest.kt index e047f3a1c2f..2a1424a167a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/JvmCompilerArgumentsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/compilerArgumetns/JvmCompilerArgumentsTest.kt @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/compilationUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/compilationUtils.kt index 341862eaf90..aedd72c1c9c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/compilationUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/compilationUtils.kt @@ -8,5 +8,5 @@ package org.jetbrains.kotlin.gradle.util import org.gradle.api.NamedDomainObjectCollection import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -val NamedDomainObjectCollection>.main: KotlinCompilation<*> get() = getByName("main") -val NamedDomainObjectCollection>.test: KotlinCompilation<*> get() = getByName("test") +val > NamedDomainObjectCollection.main: T get() = getByName("main") +val > NamedDomainObjectCollection.test: T get() = getByName("test")