From 9de0fe48f3cea6d39881907f7745741d3e29e16e Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Wed, 14 Sep 2022 21:16:52 +0200 Subject: [PATCH] Unify approach in Kotlin/JS tasks configuration. Move tasks configuration into JS tasks configurators. Introduce enhancedFreeCompilerArgs workaround when freeCompilerArgs are modified based on existing values. Introduce workaround for 'destinationDirectory' input when it content are depenends on multiple other task inputs. ^KT-27301 In Progress --- .../kotlin/gradle/Kotlin2JsGradlePluginIT.kt | 2 +- .../build.gradle | 2 +- .../kotlin/gradle/plugin/KotlinPlugin.kt | 49 ++------ .../targets/js/binaryen/BinaryenExec.kt | 3 +- .../gradle/targets/js/ir/CompilerFlags.kt | 5 - .../gradle/targets/js/ir/KotlinBrowserJsIr.kt | 22 ++-- .../kotlin/gradle/targets/js/ir/KotlinD8Ir.kt | 14 ++- .../targets/js/ir/KotlinJsBinaryContainer.kt | 11 +- .../gradle/targets/js/ir/KotlinJsIrLink.kt | 74 ++---------- .../targets/js/ir/KotlinJsIrSubTarget.kt | 14 ++- .../js/ir/KotlinJsIrTargetConfigurator.kt | 66 ++--------- .../gradle/targets/js/ir/KotlinNodeJsIr.kt | 14 ++- .../targets/js/subtargets/KotlinBrowserJs.kt | 16 +-- .../js/subtargets/KotlinJsSubTarget.kt | 2 +- .../targets/js/webpack/KotlinWebpack.kt | 6 +- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 111 ++++++++++++------ .../configuration/Kotlin2JsCompileConfig.kt | 103 ++++++++++++++-- .../configuration/KotlinJsIrLinkConfig.kt | 72 +++++++++++- 18 files changed, 328 insertions(+), 258 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt index 1d8990f10cb..2049ce9e2d1 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt @@ -530,7 +530,7 @@ abstract class AbstractKotlin2JsGradlePluginIT(protected val irBackend: Boolean) ":compileTestKotlin2Js" ) if (irBackend) { - assertFileInProjectExists("build/kotlin2js/main/default/manifest") + assertFileInProjectExists("build/kotlin2js/main/module.js/default/manifest") } else { assertFileInProjectExists("build/kotlin2js/main/module.js") } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle index f8c09c062b9..da2613bc19c 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle @@ -37,7 +37,7 @@ if (isIrBackend) { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" - integrationTestImplementation files(file(compileKotlin2Js.kotlinOptions.outputFile).parent) + integrationTestImplementation files(compileKotlin2Js.destinationDirectory) integrationTestImplementation "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index d617be5fc85..fc7a28474a2 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -156,7 +156,11 @@ internal abstract class KotlinSourceSetProcessor>( protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) { taskConfiguration.configureTask { it.description = taskDescription - it.destinationDirectory.convention(defaultKotlinDestinationDir) + if (it is Kotlin2JsCompile) { + it.defaultDestinationDirectory.convention(defaultKotlinDestinationDir) + } else { + it.destinationDirectory.convention(defaultKotlinDestinationDir) + } it.libraries.from({ kotlinCompilation.compileDependencyFiles }) } } @@ -252,46 +256,11 @@ internal class Kotlin2JsSourceSetProcessor( kotlinCompilation.javaSourceSet.clearJavaSrcDirs() } - // outputFile can be set later during the configuration phase, get it only after the phase: + project.whenEvaluated { - kotlinTask.configure { kotlinTaskInstance -> - val kotlinOptions = kotlinTaskInstance.kotlinOptions - val outputFile = kotlinTaskInstance.outputFileProperty.get() - val outputDir: File = outputFile.parentFile - kotlinOptions.outputFile = if (!kotlinOptions.isProduceUnzippedKlib()) { - outputFile.absolutePath - } else { - outputFile.parentFile.absolutePath - } - if (outputDir.isParentOf(project.rootDir)) - throw InvalidUserDataException( - "The output directory '$outputDir' (defined by outputFile of $kotlinTaskInstance) contains or " + - "matches the project root directory '${project.rootDir}'.\n" + - "Gradle will not be able to build the project because of the root directory lock.\n" + - "To fix this, consider using the default outputFile location instead of providing it explicitly." - ) - kotlinTaskInstance.destinationDirectory.set(outputDir) - - if ( - kotlinOptions.freeCompilerArgs.contains(PRODUCE_JS) || - kotlinOptions.freeCompilerArgs.contains(PRODUCE_UNZIPPED_KLIB) || - kotlinOptions.freeCompilerArgs.contains(PRODUCE_ZIPPED_KLIB) - ) { - // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). - val baseName = if (kotlinCompilation.isMainCompilationData()) { - project.name - } else { - "${project.name}_${kotlinCompilation.compilationPurpose}" - } - kotlinTaskInstance.kotlinOptions.freeCompilerArgs += "$MODULE_NAME=${project.klibModuleName(baseName)}" - } - } - - project.whenEvaluated { - val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) - if (kotlinCompilation is KotlinCompilation<*>) { // FIXME support compiler plugins with PM20 - subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation) - } + val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) + if (kotlinCompilation is KotlinCompilation<*>) { // FIXME support compiler plugins with PM20 + subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt index 753a4d68b70..98c49b70a04 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.targets.js.binaryen import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.* import org.gradle.work.NormalizeLineEndings -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.newFileProperty @@ -75,7 +74,7 @@ constructor() : AbstractExecTask(BinaryenExec::class.java) { it.binaryen = binaryen it.executable = binaryen.requireConfigured().executablePath.absolutePath it.dependsOn(binaryen.setupTaskProvider) - it.dependsOn(compilation.compileKotlinTaskProvider) + it.dependsOn(compilation.compileTaskProvider) it.configuration() } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt index 8ab9f5ba377..580a421d894 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions - /** * @see [compiler/testData/cli/js/jsExtraHelp.out] */ @@ -30,6 +28,3 @@ internal const val PER_MODULE = "-Xir-per-module" internal const val PER_MODULE_OUTPUT_NAME = "-Xir-per-module-output-name" internal const val WASM_BACKEND = "-Xwasm" - -fun KotlinJsOptions.isProduceUnzippedKlib() = PRODUCE_UNZIPPED_KLIB in freeCompilerArgs -fun KotlinJsOptions.isProduceZippedKlib() = PRODUCE_ZIPPED_KLIB in freeCompilerArgs \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt index d1ee7cebb59..3ee3775cb69 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.Task +import org.gradle.api.file.RegularFile import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy import org.gradle.language.base.plugins.LifecycleBasePlugin @@ -117,9 +118,12 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : ), listOf(compilation) ) { task -> + task.dependsOn(binary.linkSyncTask) val entryFileProvider = binary.linkSyncTask.flatMap { syncTask -> - binary.linkTask.map { - syncTask.destinationDir.resolve(it.outputFileProperty.get().name) + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + syncTask.destinationDir.resolve(it.name) + } } } @@ -203,9 +207,13 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : ), listOf(compilation) ) { task -> - val entryFileProvider = binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + task.dependsOn(binary.linkSyncTask) + val entryFileProvider = binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } + } } task.description = "build webpack ${mode.name.toLowerCase()} bundle" @@ -266,9 +274,7 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : configureOptimization(mode) - entryProperty.set( - project.layout.file(entryFileProvider) - ) + entryProperty.fileProvider(entryFileProvider) configurationActions.forEach { configure -> configure() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt index 7eecec75509..7e0b2df8698 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt @@ -33,13 +33,15 @@ abstract class KotlinD8Ir @Inject constructor(target: KotlinJsIrTarget) : val runTaskHolder = D8Exec.create(binary.compilation, name) { group = taskGroupName - inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + dependsOn(binary.linkSyncTask) + inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) } target.runTask.dependsOn(runTaskHolder) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt index 0a36791c46f..bb331e924be 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.targets.js.subtargets.DefaultDistribution import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinJsSubTarget import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName -import java.io.File import javax.inject.Inject open class KotlinJsBinaryContainer @@ -43,10 +42,7 @@ constructor( private fun configureBinaryen(binary: JsIrBinary, binaryenDsl: BinaryenExec.() -> Unit) { val linkTask = binary.linkTask - val compiledMjsFile = linkTask.map { link -> - link.kotlinOptions.outputFile?.let(::File) - ?: link.destinationDirectory.locationOnly.get().asFile.resolve("${link.compilation.ownModuleName}.mjs") - } + val compiledMjsFile = linkTask.flatMap { it.outputFileProperty } val compiledWasmFile = compiledMjsFile.map { it.parentFile.resolve("${it.nameWithoutExtension}.wasm") @@ -54,12 +50,15 @@ constructor( //TODO This is temporary solution that overrides compiled files that triggers recompile and reoptimize wasm every time (when binaryen is enabled) val binaryenTask = BinaryenExec.create(binary.compilation, "${linkTask.name}Optimize") { + dependsOn(linkTask) inputFileProperty.fileProvider(compiledWasmFile) outputFileProperty.fileProvider(compiledWasmFile) binaryenDsl() } - binary.compilation.compileKotlinTask.finalizedBy(binaryenTask) + binary.compilation.compileTaskProvider.configure { + it.finalizedBy(binaryenTask) + } binary.linkSyncTask.configure { it.dependsOn(binaryenTask) } 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 5bfe17798fa..ef77d4d13c2 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 @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection -import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* @@ -17,15 +16,12 @@ 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.CompilerJsOptionsDefault -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData 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.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.toHexString import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics @@ -38,7 +34,6 @@ import javax.inject.Inject abstract class KotlinJsIrLink @Inject constructor( objectFactory: ObjectFactory, workerExecutor: WorkerExecutor, - private val projectLayout: ProjectLayout ) : Kotlin2JsCompile( objectFactory.newInstance(CompilerJsOptionsDefault::class.java), objectFactory, @@ -61,10 +56,6 @@ abstract class KotlinJsIrLink @Inject constructor( @get:Internal internal lateinit var compilation: KotlinCompilationData<*> - private val platformType by project.provider { - compilation.platformType - } - @Transient @get:Internal internal val propertiesProvider = PropertiesProvider(project) @@ -95,23 +86,12 @@ abstract class KotlinJsIrLink @Inject constructor( @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val entryModule: DirectoryProperty + @Deprecated( + message = "Replace with destinationDirectory", + replaceWith = ReplaceWith("destinationDirectory") + ) @get:Internal - override val destinationDirectory: DirectoryProperty = objectFactory.directoryProperty() - - @get:OutputDirectory - val normalizedDestinationDirectory: DirectoryProperty = objectFactory - .directoryProperty() - .apply { - set( - destinationDirectory.map { dir -> - if (compilerOptions.outputFile.orNull != null) { - projectLayout.dir(outputFileProperty.map { it.parentFile }).get() - } else { - dir - } - } - ) - } + val normalizedDestinationDirectory: DirectoryProperty get() = destinationDirectory @get:Internal val rootCacheDirectory by lazy { @@ -132,6 +112,9 @@ abstract class KotlinJsIrLink @Inject constructor( KotlinJsIrOutputGranularity.WHOLE_PROGRAM.name.toLowerCase() ) } + + args.includes = entryModule.get().asFile.canonicalPath + if (incrementalJsIr && mode == DEVELOPMENT) { val digest = MessageDigest.getInstance("SHA-256") args.cacheDirectories = args.libraries?.splitByPathSeparator() @@ -161,45 +144,4 @@ abstract class KotlinJsIrLink @Inject constructor( .toTypedArray() .filterNot { it.isEmpty() } } - - override fun setupCompilerArgs( - args: K2JSCompilerArguments, - defaultsOnly: Boolean, - ignoreClasspathResolutionErrors: Boolean - ) { - when (mode) { - PRODUCTION -> { - args.configureOptions(ENABLE_DCE, GENERATE_D_TS, MINIMIZED_MEMBER_NAMES) - } - - DEVELOPMENT -> { - args.configureOptions(GENERATE_D_TS) - } - } - val alreadyDefinedOutputMode = compilerOptions.freeCompilerArgs.get() - .any { it.startsWith(PER_MODULE) } - if (!alreadyDefinedOutputMode) { - args.freeArgs += outputGranularity.toCompilerArgument() - } - super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) - } - - private fun K2JSCompilerArguments.configureOptions(vararg additionalCompilerArgs: String) { - freeArgs = freeArgs + ( - additionalCompilerArgs - .mapNotNull { arg -> - if (compilerOptions.freeCompilerArgs.get().any { it.startsWith(arg) }) { - null - } else { - arg - } - } + - PRODUCE_JS + - "$ENTRY_IR_MODULE=${entryModule.get().asFile.canonicalPath}" - ) - - if (platformType == KotlinPlatformType.wasm) { - freeArgs = freeArgs + WASM_BACKEND - } - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt index 0bdf2595116..a8f61a23f64 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt @@ -121,13 +121,15 @@ abstract class KotlinJsIrSubTarget( KotlinJsBinaryMode.DEVELOPMENT ).single() - testJs.inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + testJs.dependsOn(binary.linkSyncTask) + testJs.inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) configureTestDependencies(testJs) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt index f388b0e345b..b0d7ef5a10d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt @@ -5,22 +5,18 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.gradle.api.InvalidUserDataException import org.gradle.api.attributes.Usage import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Zip -import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions +import org.jetbrains.kotlin.gradle.dsl.CompilerJsOptions +import org.jetbrains.kotlin.gradle.dsl.JsModuleKind +import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages -import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun -import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName -import org.jetbrains.kotlin.gradle.utils.isParentOf -import org.jetbrains.kotlin.gradle.utils.klibModuleName -import java.io.File open class KotlinJsIrTargetConfigurator() : KotlinOnlyTargetConfigurator(true), @@ -73,70 +69,30 @@ open class KotlinJsIrTargetConfigurator() : super.configureCompilations(target) target.compilations.all { compilation -> - compilation.kotlinOptions { + compilation.compilerOptions.configure { configureOptions() if (target.platformType == KotlinPlatformType.wasm) { - freeCompilerArgs = freeCompilerArgs + WASM_BACKEND + freeCompilerArgs.add(WASM_BACKEND) } - var produceUnzippedKlib = isProduceUnzippedKlib() - val produceZippedKlib = isProduceZippedKlib() - - freeCompilerArgs = freeCompilerArgs + DISABLE_PRE_IR - - val isMainCompilation = compilation.isMain() - - if (!produceUnzippedKlib && !produceZippedKlib) { - freeCompilerArgs = freeCompilerArgs + PRODUCE_UNZIPPED_KLIB - produceUnzippedKlib = true - } - - // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). - val baseName = if (isMainCompilation) { - target.project.name - } else { - "${target.project.name}_${compilation.name}" - } - - compilation.compileKotlinTaskProvider.configure { task -> - val outputFilePath = outputFile ?: if (produceUnzippedKlib) { - task.destinationDirectory.get().asFile.absoluteFile.normalize().absolutePath - } else { - File(task.destinationDirectory.get().asFile, "$baseName.$KLIB_TYPE").absoluteFile.normalize().absolutePath - } - outputFile = outputFilePath - - val taskOutputDir = if (produceUnzippedKlib) File(outputFilePath) else File(outputFilePath).parentFile - if (taskOutputDir.isParentOf(task.project.rootDir)) - throw InvalidUserDataException( - "The output directory '$taskOutputDir' (defined by outputFile of $task) contains or " + - "matches the project root directory '${task.project.rootDir}'.\n" + - "Gradle will not be able to build the project because of the root directory lock.\n" + - "To fix this, consider using the default outputFile location instead of providing it explicitly." - ) - - task.destinationDirectory.set(taskOutputDir) - } - - val klibModuleName = target.project.klibModuleName(baseName) - freeCompilerArgs = freeCompilerArgs + "$MODULE_NAME=$klibModuleName" + freeCompilerArgs.add(DISABLE_PRE_IR) } compilation.binaries .withType(JsIrBinary::class.java) .all { binary -> binary.linkTask.configure { linkTask -> - linkTask.kotlinOptions.configureOptions() + linkTask.compilerOptions.configureOptions() } } } } - private fun KotlinJsOptions.configureOptions() { - moduleKind = "umd" - sourceMap = true - sourceMapEmbedSources = "never" + private fun CompilerJsOptions.configureOptions() { + moduleKind.set(JsModuleKind.MODULE_UMD) + sourceMap.set(true) + sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_NEVER) } override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt index d3c05a4607a..3f4a5f955fb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt @@ -34,13 +34,15 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) : val runTaskHolder = NodeJsExec.create(binary.compilation, name) { group = taskGroupName - inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + dependsOn(binary.linkSyncTask) + inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) } target.runTask.dependsOn(runTaskHolder) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt index 33c64c85697..7af81ce8482 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt @@ -289,14 +289,16 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) : KotlinJsBinaryMode.DEVELOPMENT -> devDceTaskProvider } + dependsOn(actualDceTaskProvider) + entryProperty.set( - project.layout.file( - actualDceTaskProvider - .map { - it.destinationDirectory.file(compilation.compileKotlinTask.outputFileProperty.get().name) - } - .flatMap { it.map { it.asFile } } - ) + actualDceTaskProvider.flatMap { dceTask -> + compilation.compileTaskProvider.flatMap { compileTask -> + dceTask.destinationDirectory.file( + compileTask.outputFileProperty.map { it.name } + ) + } + } ) resolveFromModulesFirst = true diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt index 9bbf7f9a20c..c54563498ac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt @@ -98,7 +98,7 @@ abstract class KotlinJsSubTarget( testRun.subtargetTestTaskName(), listOf(compilation) ) { testJs -> - val compileTask = compilation.compileKotlinTaskProvider + val compileTask = compilation.compileTaskProvider testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP testJs.description = testTaskDescription diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt index 5e40df833cb..54dceb104f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt @@ -102,7 +102,11 @@ constructor( @get:PathSensitive(PathSensitivity.ABSOLUTE) @get:InputFile @get:NormalizeLineEndings - val entryProperty: RegularFileProperty = objects.fileProperty().fileProvider(compilation.compileKotlinTask.outputFileProperty) + val entryProperty: RegularFileProperty = objects + .fileProperty() + .fileProvider( + compilation.compileTaskProvider.flatMap { it.outputFileProperty } + ) init { onlyIf { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index e6f4cea8df9..ec3120f57c2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -6,14 +6,12 @@ package org.jetbrains.kotlin.gradle.tasks import groovy.lang.Closure -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.Project -import org.gradle.api.Task +import org.gradle.api.* import org.gradle.api.file.* import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logger 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.provider.SetProperty @@ -57,6 +55,11 @@ import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.BuildReportsService import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJvmOptionsCompat +import org.jetbrains.kotlin.gradle.targets.js.ir.* +import org.jetbrains.kotlin.gradle.targets.js.ir.DISABLE_PRE_IR +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_JS +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_UNZIPPED_KLIB +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_ZIPPED_KLIB import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled @@ -940,25 +943,32 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Input internal var incrementalJsKlib: Boolean = true - override fun isIncrementalCompilationEnabled(): Boolean = - when { - "-Xir-produce-js" in kotlinOptions.freeCompilerArgs -> { - false - } - "-Xir-produce-klib-dir" in kotlinOptions.freeCompilerArgs -> { + override fun isIncrementalCompilationEnabled(): Boolean { + val freeArgs = enhancedFreeCompilerArgs.get() + return when { + PRODUCE_JS in freeArgs -> false + + PRODUCE_UNZIPPED_KLIB in freeArgs -> { KotlinBuildStatsService.applyIfInitialised { it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) } incrementalJsKlib } - "-Xir-produce-klib-file" in kotlinOptions.freeCompilerArgs -> { + + PRODUCE_ZIPPED_KLIB in freeArgs -> { KotlinBuildStatsService.applyIfInitialised { it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) } incrementalJsKlib } + else -> incremental } + } + + // Workaround to be able to use default value and change it later based on external input + @get:Internal + internal abstract val defaultDestinationDirectory: DirectoryProperty // This can be file or directory @get:Internal @@ -973,6 +983,14 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Optional abstract val optionalOutputFile: RegularFileProperty + // Workaround to add additional compiler args based on the exising one + // Currently there is a logic to add additional compiler arguments based on already existing one. + // And it is not possible to update compilerOptions.freeCompilerArgs using some kind of .map + // or .flatMap call - this will cause StackOverlowException as upstream source will be updated + // and .map will be called again. + @get:Input + internal abstract val enhancedFreeCompilerArgs: ListProperty + override fun createCompilerArgs(): K2JSCompilerArguments = K2JSCompilerArguments() @@ -992,6 +1010,14 @@ abstract class Kotlin2JsCompile @Inject constructor( if (defaultsOnly) return (compilerOptions as CompilerJsOptionsDefault).fillCompilerArguments(args) + if (!args.sourceMapPrefix.isNullOrEmpty()) { + args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath + } + // Rewriting default outputFile property back to outputFilePropertyValue + args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath + // Overriding freeArgs from compilerOptions with enhanced one + // containing additional arguments based on the js compilation configuration + args.freeArgs = enhancedFreeCompilerArgs.get() } @get:InputFiles @@ -1018,26 +1044,32 @@ abstract class Kotlin2JsCompile @Inject constructor( private fun isHybridKotlinJsLibrary(file: File): Boolean = JsLibraryUtils.isKotlinJavascriptLibrary(file) && isKotlinLibrary(file) - private fun KotlinJsOptions.isPreIrBackendDisabled(): Boolean = - listOf( - "-Xir-only", - "-Xir-produce-js", - "-Xir-produce-klib-file" - ).any(freeCompilerArgs::contains) + private val preIrBackendCompilerFlags = listOf( + DISABLE_PRE_IR, + PRODUCE_JS, + PRODUCE_ZIPPED_KLIB + ) + + private fun isPreIrBackendDisabled(): Boolean = enhancedFreeCompilerArgs + .get() + .any { preIrBackendCompilerFlags.contains(it) } // see also isIncrementalCompilationEnabled - private fun KotlinJsOptions.isIrBackendEnabled(): Boolean = - listOf( - "-Xir-produce-klib-dir", - "-Xir-produce-js", - "-Xir-produce-klib-file" - ).any(freeCompilerArgs::contains) + private val irBackendCompilerFlags = listOf( + PRODUCE_UNZIPPED_KLIB, + PRODUCE_JS, + PRODUCE_ZIPPED_KLIB + ) + + private fun isIrBackendEnabled(): Boolean = enhancedFreeCompilerArgs + .get() + .any { irBackendCompilerFlags.contains(it) } private val File.asLibraryFilterCacheKey: LibraryFilterCachingService.LibraryFilterCacheKey get() = LibraryFilterCachingService.LibraryFilterCacheKey( this, - irEnabled = kotlinOptions.isIrBackendEnabled(), - preIrDisabled = kotlinOptions.isPreIrBackendDisabled() + irEnabled = isIrBackendEnabled(), + preIrDisabled = isPreIrBackendDisabled() ) // Kotlin/JS can operate in 3 modes: @@ -1045,8 +1077,8 @@ abstract class Kotlin2JsCompile @Inject constructor( // 2) purely IR backend // 3) hybrid pre-IR and IR backend. Can only accept libraries with both JS and IR parts. private val libraryFilterBody: (File) -> Boolean - get() = if (kotlinOptions.isIrBackendEnabled()) { - if (kotlinOptions.isPreIrBackendDisabled()) { + get() = if (isIrBackendEnabled()) { + if (isPreIrBackendDisabled()) { //::isKotlinLibrary // Workaround for KT-47797 { isKotlinLibrary(it) } @@ -1088,7 +1120,9 @@ abstract class Kotlin2JsCompile @Inject constructor( ) { logger.debug("Calling compiler") - if (kotlinOptions.isIrBackendEnabled()) { + validateOutputDirectory() + + if (isIrBackendEnabled()) { logger.info(USING_JS_IR_BACKEND_MESSAGE) } @@ -1103,11 +1137,6 @@ abstract class Kotlin2JsCompile @Inject constructor( } args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath } - - if (!args.sourceMapPrefix.isNullOrEmpty()) { - args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath - } - args.legacyDeprecatedNoWarn = jsLegacyNoWarn.get() logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}") @@ -1141,6 +1170,22 @@ abstract class Kotlin2JsCompile @Inject constructor( taskOutputsBackup ) } + + private val projectRootDir = project.rootDir + + private fun validateOutputDirectory() { + val outputFile = outputFileProperty.get() + val outputDir = outputFile.parentFile + + if (outputDir.isParentOf(projectRootDir)) { + throw InvalidUserDataException( + "The output directory '$outputDir' (defined by outputFile of ':$name') contains or " + + "matches the project root directory '${projectRootDir}'.\n" + + "Gradle will not be able to build the project because of the root directory lock.\n" + + "To fix this, consider using the default outputFile location instead of providing it explicitly." + ) + } + } } data class KotlinCompilerPluginData( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt index b5f35682a7b..80bf55adfc8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt @@ -7,8 +7,13 @@ package org.jetbrains.kotlin.gradle.tasks.configuration import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData -import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData +import org.jetbrains.kotlin.gradle.targets.js.ir.* +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_JS +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_UNZIPPED_KLIB +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_ZIPPED_KLIB import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile +import org.jetbrains.kotlin.gradle.utils.klibModuleName import java.io.File internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig @@ -27,18 +32,96 @@ internal open class BaseKotlin2JsCompileConfig( task.incremental = propertiesProvider.incrementalJs ?: true task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true - task.outputFileProperty.value(task.project.provider { - val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" - task.compilerOptions.outputFile.orNull?.let(::File) - ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}$extensionName") - }).disallowChanges() + configureAdditionalFreeCompilerArguments(task, compilation) - task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile -> - task.project.provider { - outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() } + @Suppress("DEPRECATION") + task.compilerOptions.outputFile.convention( + task.defaultDestinationDirectory.zip(task.enhancedFreeCompilerArgs) { destDir, freeArgs -> + val baseName = if (compilation.isMainCompilationData()) { + project.name + } else { + "${project.name}_${compilation.compilationPurpose}" + } + + if (freeArgs.contains(PRODUCE_UNZIPPED_KLIB)) { + destDir.asFile.absoluteFile.normalize().absolutePath + } else { + if (compilation is KotlinJsIrCompilation) { + destDir.asFile.resolve("$baseName.$KLIB_TYPE").absoluteFile.normalize().absolutePath + } else { + val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" + destDir.asFile.resolve("${compilation.ownModuleName}$extensionName").absolutePath + } + } } - }).disallowChanges() + ) + + @Suppress("DEPRECATION") + task.outputFileProperty.value( + task.compilerOptions.outputFile.map { File(it) } + ) + + task.destinationDirectory + .fileProvider( + task.outputFileProperty.zip(task.enhancedFreeCompilerArgs) { outputFile, freeArgs -> + if (freeArgs.contains(PRODUCE_UNZIPPED_KLIB)) { + outputFile + } else { + outputFile.parentFile + } + } + ) + .disallowChanges() + + task.optionalOutputFile.fileProvider( + task.outputFileProperty.flatMap { outputFile -> + task.enhancedFreeCompilerArgs.flatMap { freeArgs -> + task.project.providers.provider { + outputFile.takeUnless { + freeArgs.contains(PRODUCE_UNZIPPED_KLIB) + } + } + } + } + ).disallowChanges() task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() } } } + + protected open fun configureAdditionalFreeCompilerArguments( + task: TASK, + compilation: KotlinCompilationData<*> + ) { + task.enhancedFreeCompilerArgs.value( + task.compilerOptions.freeCompilerArgs.map { freeArgs -> + freeArgs.toMutableList().apply { + commonJsAdditionalCompilerFlags(compilation) + } + } + ).disallowChanges() + } + + protected fun MutableList.commonJsAdditionalCompilerFlags( + compilation: KotlinCompilationData<*> + ) { + if (contains(DISABLE_PRE_IR) && + !contains(PRODUCE_UNZIPPED_KLIB) && + !contains(PRODUCE_ZIPPED_KLIB) + ) { + add(PRODUCE_UNZIPPED_KLIB) + } + + if (contains(PRODUCE_JS) || + contains(PRODUCE_UNZIPPED_KLIB) || + contains(PRODUCE_ZIPPED_KLIB) + ) { + // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). + val baseName = if (compilation.isMainCompilationData()) { + project.name + } else { + "${project.name}_${compilation.compilationPurpose}" + } + add("$MODULE_NAME=${project.klibModuleName(baseName)}") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt index d134c024dc0..883b3d2747d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt @@ -5,8 +5,11 @@ package org.jetbrains.kotlin.gradle.tasks.configuration -import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation -import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink +import org.gradle.api.InvalidUserDataException +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode +import org.jetbrains.kotlin.gradle.targets.js.ir.* internal open class KotlinJsIrLinkConfig( compilation: KotlinJsIrCompilation @@ -17,9 +20,70 @@ internal open class KotlinJsIrLinkConfig( // Link tasks are not affected by compiler plugin, so set to empty task.pluginClasspath.setFrom(objectFactory.fileCollection()) - task.entryModule.fileProvider(compilation.output.classesDirs.elements.map { it.single().asFile }).disallowChanges() + task.dependsOn(compilation.compileTaskProvider) + task.dependsOn(compilation.output.classesDirs) + task.entryModule.fileProvider( + compilation.output.classesDirs.elements.flatMap { + task.project.providers.provider { + it.single().asFile + } + } + ).disallowChanges() task.compilation = compilation - task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile }) + } + } + + override fun configureAdditionalFreeCompilerArguments( + task: KotlinJsIrLink, + compilation: KotlinCompilationData<*> + ) { + task.enhancedFreeCompilerArgs.value( + task.compilerOptions.freeCompilerArgs.zip(task.modeProperty) { freeArgs, mode -> + freeArgs.toMutableList().apply { + commonJsAdditionalCompilerFlags(compilation) + + when (mode) { + KotlinJsBinaryMode.PRODUCTION -> { + configureOptions( + compilation, + ENABLE_DCE, + GENERATE_D_TS, + MINIMIZED_MEMBER_NAMES + ) + } + + KotlinJsBinaryMode.DEVELOPMENT -> { + configureOptions( + compilation, + GENERATE_D_TS + ) + } + else -> throw InvalidUserDataException( + "Unknown KotlinJsBinaryMode to configure the build: $mode" + ) + } + + val alreadyDefinedOutputMode = any { it.startsWith(PER_MODULE) } + if (!alreadyDefinedOutputMode) { + add(task.outputGranularity.toCompilerArgument()) + } + } + } + ).disallowChanges() + } + + private fun MutableList.configureOptions( + compilation: KotlinCompilationData<*>, + vararg additionalCompilerArgs: String + ) { + additionalCompilerArgs.forEach { arg -> + if (none { it.startsWith(arg) }) add(arg) + } + + add(PRODUCE_JS) + + if (compilation.platformType == KotlinPlatformType.wasm) { + add(WASM_BACKEND) } } } \ No newline at end of file