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
This commit is contained in:
Yahor Berdnikau
2022-09-14 21:16:52 +02:00
parent 4881e32e44
commit 9de0fe48f3
18 changed files with 328 additions and 258 deletions
@@ -530,7 +530,7 @@ abstract class AbstractKotlin2JsGradlePluginIT(protected val irBackend: Boolean)
":compileTestKotlin2Js" ":compileTestKotlin2Js"
) )
if (irBackend) { if (irBackend) {
assertFileInProjectExists("build/kotlin2js/main/default/manifest") assertFileInProjectExists("build/kotlin2js/main/module.js/default/manifest")
} else { } else {
assertFileInProjectExists("build/kotlin2js/main/module.js") assertFileInProjectExists("build/kotlin2js/main/module.js")
} }
@@ -37,7 +37,7 @@ if (isIrBackend) {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" 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" integrationTestImplementation "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version"
} }
@@ -156,7 +156,11 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) { protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) {
taskConfiguration.configureTask { taskConfiguration.configureTask {
it.description = taskDescription 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 }) it.libraries.from({ kotlinCompilation.compileDependencyFiles })
} }
} }
@@ -252,46 +256,11 @@ internal class Kotlin2JsSourceSetProcessor(
kotlinCompilation.javaSourceSet.clearJavaSrcDirs() kotlinCompilation.javaSourceSet.clearJavaSrcDirs()
} }
// outputFile can be set later during the configuration phase, get it only after the phase:
project.whenEvaluated { project.whenEvaluated {
kotlinTask.configure { kotlinTaskInstance -> val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project)
val kotlinOptions = kotlinTaskInstance.kotlinOptions if (kotlinCompilation is KotlinCompilation<*>) { // FIXME support compiler plugins with PM20
val outputFile = kotlinTaskInstance.outputFileProperty.get() subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation)
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)
}
} }
} }
} }
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.targets.js.binaryen
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.work.NormalizeLineEndings 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.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.newFileProperty import org.jetbrains.kotlin.gradle.utils.newFileProperty
@@ -75,7 +74,7 @@ constructor() : AbstractExecTask<BinaryenExec>(BinaryenExec::class.java) {
it.binaryen = binaryen it.binaryen = binaryen
it.executable = binaryen.requireConfigured().executablePath.absolutePath it.executable = binaryen.requireConfigured().executablePath.absolutePath
it.dependsOn(binaryen.setupTaskProvider) it.dependsOn(binaryen.setupTaskProvider)
it.dependsOn(compilation.compileKotlinTaskProvider) it.dependsOn(compilation.compileTaskProvider)
it.configuration() it.configuration()
} }
} }
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
/** /**
* @see [compiler/testData/cli/js/jsExtraHelp.out] * @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 PER_MODULE_OUTPUT_NAME = "-Xir-per-module-output-name"
internal const val WASM_BACKEND = "-Xwasm" internal const val WASM_BACKEND = "-Xwasm"
fun KotlinJsOptions.isProduceUnzippedKlib() = PRODUCE_UNZIPPED_KLIB in freeCompilerArgs
fun KotlinJsOptions.isProduceZippedKlib() = PRODUCE_ZIPPED_KLIB in freeCompilerArgs
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Copy
import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin
@@ -117,9 +118,12 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
), ),
listOf(compilation) listOf(compilation)
) { task -> ) { task ->
task.dependsOn(binary.linkSyncTask)
val entryFileProvider = binary.linkSyncTask.flatMap { syncTask -> val entryFileProvider = binary.linkSyncTask.flatMap { syncTask ->
binary.linkTask.map { binary.linkTask.flatMap { linkTask ->
syncTask.destinationDir.resolve(it.outputFileProperty.get().name) linkTask.outputFileProperty.map {
syncTask.destinationDir.resolve(it.name)
}
} }
} }
@@ -203,9 +207,13 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
), ),
listOf(compilation) listOf(compilation)
) { task -> ) { task ->
val entryFileProvider = binary.linkSyncTask.map { task.dependsOn(binary.linkSyncTask)
it.destinationDir val entryFileProvider = binary.linkSyncTask.flatMap { linkSyncTask ->
.resolve(binary.linkTask.get().outputFileProperty.get().name) binary.linkTask.flatMap { linkTask ->
linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
}
} }
task.description = "build webpack ${mode.name.toLowerCase()} bundle" task.description = "build webpack ${mode.name.toLowerCase()} bundle"
@@ -266,9 +274,7 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
configureOptimization(mode) configureOptimization(mode)
entryProperty.set( entryProperty.fileProvider(entryFileProvider)
project.layout.file(entryFileProvider)
)
configurationActions.forEach { configure -> configurationActions.forEach { configure ->
configure() configure()
@@ -33,13 +33,15 @@ abstract class KotlinD8Ir @Inject constructor(target: KotlinJsIrTarget) :
val runTaskHolder = D8Exec.create(binary.compilation, name) { val runTaskHolder = D8Exec.create(binary.compilation, name) {
group = taskGroupName group = taskGroupName
inputFileProperty.set( dependsOn(binary.linkSyncTask)
project.layout.file( inputFileProperty.fileProvider(
binary.linkSyncTask.map { binary.linkSyncTask.flatMap { linkSyncTask ->
it.destinationDir binary.linkTask.flatMap { linkTask ->
.resolve(binary.linkTask.get().outputFileProperty.get().name) linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
} }
) }
) )
} }
target.runTask.dependsOn(runTaskHolder) target.runTask.dependsOn(runTaskHolder)
@@ -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.DefaultDistribution
import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinJsSubTarget import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinJsSubTarget
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.io.File
import javax.inject.Inject import javax.inject.Inject
open class KotlinJsBinaryContainer open class KotlinJsBinaryContainer
@@ -43,10 +42,7 @@ constructor(
private fun configureBinaryen(binary: JsIrBinary, binaryenDsl: BinaryenExec.() -> Unit) { private fun configureBinaryen(binary: JsIrBinary, binaryenDsl: BinaryenExec.() -> Unit) {
val linkTask = binary.linkTask val linkTask = binary.linkTask
val compiledMjsFile = linkTask.map { link -> val compiledMjsFile = linkTask.flatMap { it.outputFileProperty }
link.kotlinOptions.outputFile?.let(::File)
?: link.destinationDirectory.locationOnly.get().asFile.resolve("${link.compilation.ownModuleName}.mjs")
}
val compiledWasmFile = compiledMjsFile.map { val compiledWasmFile = compiledMjsFile.map {
it.parentFile.resolve("${it.nameWithoutExtension}.wasm") 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) //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") { val binaryenTask = BinaryenExec.create(binary.compilation, "${linkTask.name}Optimize") {
dependsOn(linkTask)
inputFileProperty.fileProvider(compiledWasmFile) inputFileProperty.fileProvider(compiledWasmFile)
outputFileProperty.fileProvider(compiledWasmFile) outputFileProperty.fileProvider(compiledWasmFile)
binaryenDsl() binaryenDsl()
} }
binary.compilation.compileKotlinTask.finalizedBy(binaryenTask) binary.compilation.compileTaskProvider.configure {
it.finalizedBy(binaryenTask)
}
binary.linkSyncTask.configure { binary.linkSyncTask.configure {
it.dependsOn(binaryenTask) it.dependsOn(binaryenTask)
} }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.ProjectLayout
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.tasks.* 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.cli.common.arguments.parseCommandLineArguments
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.gradle.dsl.CompilerJsOptionsDefault 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.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService 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
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT 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.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.toHexString import org.jetbrains.kotlin.gradle.utils.toHexString
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -38,7 +34,6 @@ import javax.inject.Inject
abstract class KotlinJsIrLink @Inject constructor( abstract class KotlinJsIrLink @Inject constructor(
objectFactory: ObjectFactory, objectFactory: ObjectFactory,
workerExecutor: WorkerExecutor, workerExecutor: WorkerExecutor,
private val projectLayout: ProjectLayout
) : Kotlin2JsCompile( ) : Kotlin2JsCompile(
objectFactory.newInstance(CompilerJsOptionsDefault::class.java), objectFactory.newInstance(CompilerJsOptionsDefault::class.java),
objectFactory, objectFactory,
@@ -61,10 +56,6 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:Internal @get:Internal
internal lateinit var compilation: KotlinCompilationData<*> internal lateinit var compilation: KotlinCompilationData<*>
private val platformType by project.provider {
compilation.platformType
}
@Transient @Transient
@get:Internal @get:Internal
internal val propertiesProvider = PropertiesProvider(project) internal val propertiesProvider = PropertiesProvider(project)
@@ -95,23 +86,12 @@ abstract class KotlinJsIrLink @Inject constructor(
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
internal abstract val entryModule: DirectoryProperty internal abstract val entryModule: DirectoryProperty
@Deprecated(
message = "Replace with destinationDirectory",
replaceWith = ReplaceWith("destinationDirectory")
)
@get:Internal @get:Internal
override val destinationDirectory: DirectoryProperty = objectFactory.directoryProperty() val normalizedDestinationDirectory: DirectoryProperty get() = destinationDirectory
@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
}
}
)
}
@get:Internal @get:Internal
val rootCacheDirectory by lazy { val rootCacheDirectory by lazy {
@@ -132,6 +112,9 @@ abstract class KotlinJsIrLink @Inject constructor(
KotlinJsIrOutputGranularity.WHOLE_PROGRAM.name.toLowerCase() KotlinJsIrOutputGranularity.WHOLE_PROGRAM.name.toLowerCase()
) )
} }
args.includes = entryModule.get().asFile.canonicalPath
if (incrementalJsIr && mode == DEVELOPMENT) { if (incrementalJsIr && mode == DEVELOPMENT) {
val digest = MessageDigest.getInstance("SHA-256") val digest = MessageDigest.getInstance("SHA-256")
args.cacheDirectories = args.libraries?.splitByPathSeparator() args.cacheDirectories = args.libraries?.splitByPathSeparator()
@@ -161,45 +144,4 @@ abstract class KotlinJsIrLink @Inject constructor(
.toTypedArray() .toTypedArray()
.filterNot { it.isEmpty() } .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
}
}
} }
@@ -121,13 +121,15 @@ abstract class KotlinJsIrSubTarget(
KotlinJsBinaryMode.DEVELOPMENT KotlinJsBinaryMode.DEVELOPMENT
).single() ).single()
testJs.inputFileProperty.set( testJs.dependsOn(binary.linkSyncTask)
project.layout.file( testJs.inputFileProperty.fileProvider(
binary.linkSyncTask.map { binary.linkSyncTask.flatMap { linkSyncTask ->
it.destinationDir binary.linkTask.flatMap { linkTask ->
.resolve(binary.linkTask.get().outputFileProperty.get().name) linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
} }
) }
) )
configureTestDependencies(testJs) configureTestDependencies(testJs)
@@ -5,22 +5,18 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.InvalidUserDataException
import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip 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.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages 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.KotlinJsReportAggregatingTestRun
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName 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() : open class KotlinJsIrTargetConfigurator() :
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true), KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true),
@@ -73,70 +69,30 @@ open class KotlinJsIrTargetConfigurator() :
super.configureCompilations(target) super.configureCompilations(target)
target.compilations.all { compilation -> target.compilations.all { compilation ->
compilation.kotlinOptions { compilation.compilerOptions.configure {
configureOptions() configureOptions()
if (target.platformType == KotlinPlatformType.wasm) { if (target.platformType == KotlinPlatformType.wasm) {
freeCompilerArgs = freeCompilerArgs + WASM_BACKEND freeCompilerArgs.add(WASM_BACKEND)
} }
var produceUnzippedKlib = isProduceUnzippedKlib() freeCompilerArgs.add(DISABLE_PRE_IR)
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"
} }
compilation.binaries compilation.binaries
.withType(JsIrBinary::class.java) .withType(JsIrBinary::class.java)
.all { binary -> .all { binary ->
binary.linkTask.configure { linkTask -> binary.linkTask.configure { linkTask ->
linkTask.kotlinOptions.configureOptions() linkTask.compilerOptions.configureOptions()
} }
} }
} }
} }
private fun KotlinJsOptions.configureOptions() { private fun CompilerJsOptions.configureOptions() {
moduleKind = "umd" moduleKind.set(JsModuleKind.MODULE_UMD)
sourceMap = true sourceMap.set(true)
sourceMapEmbedSources = "never" sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_NEVER)
} }
override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) { override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) {
@@ -34,13 +34,15 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
val runTaskHolder = NodeJsExec.create(binary.compilation, name) { val runTaskHolder = NodeJsExec.create(binary.compilation, name) {
group = taskGroupName group = taskGroupName
inputFileProperty.set( dependsOn(binary.linkSyncTask)
project.layout.file( inputFileProperty.fileProvider(
binary.linkSyncTask.map { binary.linkSyncTask.flatMap { linkSyncTask ->
it.destinationDir binary.linkTask.flatMap { linkTask ->
.resolve(binary.linkTask.get().outputFileProperty.get().name) linkTask.outputFileProperty.map {
linkSyncTask.destinationDir.resolve(it.name)
}
} }
) }
) )
} }
target.runTask.dependsOn(runTaskHolder) target.runTask.dependsOn(runTaskHolder)
@@ -289,14 +289,16 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
KotlinJsBinaryMode.DEVELOPMENT -> devDceTaskProvider KotlinJsBinaryMode.DEVELOPMENT -> devDceTaskProvider
} }
dependsOn(actualDceTaskProvider)
entryProperty.set( entryProperty.set(
project.layout.file( actualDceTaskProvider.flatMap { dceTask ->
actualDceTaskProvider compilation.compileTaskProvider.flatMap { compileTask ->
.map { dceTask.destinationDirectory.file(
it.destinationDirectory.file(compilation.compileKotlinTask.outputFileProperty.get().name) compileTask.outputFileProperty.map { it.name }
} )
.flatMap { it.map { it.asFile } } }
) }
) )
resolveFromModulesFirst = true resolveFromModulesFirst = true
@@ -98,7 +98,7 @@ abstract class KotlinJsSubTarget(
testRun.subtargetTestTaskName(), testRun.subtargetTestTaskName(),
listOf(compilation) listOf(compilation)
) { testJs -> ) { testJs ->
val compileTask = compilation.compileKotlinTaskProvider val compileTask = compilation.compileTaskProvider
testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP
testJs.description = testTaskDescription testJs.description = testTaskDescription
@@ -102,7 +102,11 @@ constructor(
@get:PathSensitive(PathSensitivity.ABSOLUTE) @get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:InputFile @get:InputFile
@get:NormalizeLineEndings @get:NormalizeLineEndings
val entryProperty: RegularFileProperty = objects.fileProperty().fileProvider(compilation.compileKotlinTask.outputFileProperty) val entryProperty: RegularFileProperty = objects
.fileProperty()
.fileProvider(
compilation.compileTaskProvider.flatMap { it.outputFileProperty }
)
init { init {
onlyIf { onlyIf {
@@ -6,14 +6,12 @@
package org.jetbrains.kotlin.gradle.tasks package org.jetbrains.kotlin.gradle.tasks
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.DefaultTask import org.gradle.api.*
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.* import org.gradle.api.file.*
import org.gradle.api.invocation.Gradle import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.provider.SetProperty 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.BuildReportsService
import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.report.ReportingSettings
import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJvmOptionsCompat 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.gradle.utils.*
import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled
@@ -940,25 +943,32 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Input @get:Input
internal var incrementalJsKlib: Boolean = true internal var incrementalJsKlib: Boolean = true
override fun isIncrementalCompilationEnabled(): Boolean = override fun isIncrementalCompilationEnabled(): Boolean {
when { val freeArgs = enhancedFreeCompilerArgs.get()
"-Xir-produce-js" in kotlinOptions.freeCompilerArgs -> { return when {
false PRODUCE_JS in freeArgs -> false
}
"-Xir-produce-klib-dir" in kotlinOptions.freeCompilerArgs -> { PRODUCE_UNZIPPED_KLIB in freeArgs -> {
KotlinBuildStatsService.applyIfInitialised { KotlinBuildStatsService.applyIfInitialised {
it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib)
} }
incrementalJsKlib incrementalJsKlib
} }
"-Xir-produce-klib-file" in kotlinOptions.freeCompilerArgs -> {
PRODUCE_ZIPPED_KLIB in freeArgs -> {
KotlinBuildStatsService.applyIfInitialised { KotlinBuildStatsService.applyIfInitialised {
it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib)
} }
incrementalJsKlib incrementalJsKlib
} }
else -> incremental 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 // This can be file or directory
@get:Internal @get:Internal
@@ -973,6 +983,14 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Optional @get:Optional
abstract val optionalOutputFile: RegularFileProperty 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<String>
override fun createCompilerArgs(): K2JSCompilerArguments = override fun createCompilerArgs(): K2JSCompilerArguments =
K2JSCompilerArguments() K2JSCompilerArguments()
@@ -992,6 +1010,14 @@ abstract class Kotlin2JsCompile @Inject constructor(
if (defaultsOnly) return if (defaultsOnly) return
(compilerOptions as CompilerJsOptionsDefault).fillCompilerArguments(args) (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 @get:InputFiles
@@ -1018,26 +1044,32 @@ abstract class Kotlin2JsCompile @Inject constructor(
private fun isHybridKotlinJsLibrary(file: File): Boolean = private fun isHybridKotlinJsLibrary(file: File): Boolean =
JsLibraryUtils.isKotlinJavascriptLibrary(file) && isKotlinLibrary(file) JsLibraryUtils.isKotlinJavascriptLibrary(file) && isKotlinLibrary(file)
private fun KotlinJsOptions.isPreIrBackendDisabled(): Boolean = private val preIrBackendCompilerFlags = listOf(
listOf( DISABLE_PRE_IR,
"-Xir-only", PRODUCE_JS,
"-Xir-produce-js", PRODUCE_ZIPPED_KLIB
"-Xir-produce-klib-file" )
).any(freeCompilerArgs::contains)
private fun isPreIrBackendDisabled(): Boolean = enhancedFreeCompilerArgs
.get()
.any { preIrBackendCompilerFlags.contains(it) }
// see also isIncrementalCompilationEnabled // see also isIncrementalCompilationEnabled
private fun KotlinJsOptions.isIrBackendEnabled(): Boolean = private val irBackendCompilerFlags = listOf(
listOf( PRODUCE_UNZIPPED_KLIB,
"-Xir-produce-klib-dir", PRODUCE_JS,
"-Xir-produce-js", PRODUCE_ZIPPED_KLIB
"-Xir-produce-klib-file" )
).any(freeCompilerArgs::contains)
private fun isIrBackendEnabled(): Boolean = enhancedFreeCompilerArgs
.get()
.any { irBackendCompilerFlags.contains(it) }
private val File.asLibraryFilterCacheKey: LibraryFilterCachingService.LibraryFilterCacheKey private val File.asLibraryFilterCacheKey: LibraryFilterCachingService.LibraryFilterCacheKey
get() = LibraryFilterCachingService.LibraryFilterCacheKey( get() = LibraryFilterCachingService.LibraryFilterCacheKey(
this, this,
irEnabled = kotlinOptions.isIrBackendEnabled(), irEnabled = isIrBackendEnabled(),
preIrDisabled = kotlinOptions.isPreIrBackendDisabled() preIrDisabled = isPreIrBackendDisabled()
) )
// Kotlin/JS can operate in 3 modes: // Kotlin/JS can operate in 3 modes:
@@ -1045,8 +1077,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
// 2) purely IR backend // 2) purely IR backend
// 3) hybrid pre-IR and IR backend. Can only accept libraries with both JS and IR parts. // 3) hybrid pre-IR and IR backend. Can only accept libraries with both JS and IR parts.
private val libraryFilterBody: (File) -> Boolean private val libraryFilterBody: (File) -> Boolean
get() = if (kotlinOptions.isIrBackendEnabled()) { get() = if (isIrBackendEnabled()) {
if (kotlinOptions.isPreIrBackendDisabled()) { if (isPreIrBackendDisabled()) {
//::isKotlinLibrary //::isKotlinLibrary
// Workaround for KT-47797 // Workaround for KT-47797
{ isKotlinLibrary(it) } { isKotlinLibrary(it) }
@@ -1088,7 +1120,9 @@ abstract class Kotlin2JsCompile @Inject constructor(
) { ) {
logger.debug("Calling compiler") logger.debug("Calling compiler")
if (kotlinOptions.isIrBackendEnabled()) { validateOutputDirectory()
if (isIrBackendEnabled()) {
logger.info(USING_JS_IR_BACKEND_MESSAGE) 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 } args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath }
if (!args.sourceMapPrefix.isNullOrEmpty()) {
args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath
}
args.legacyDeprecatedNoWarn = jsLegacyNoWarn.get() args.legacyDeprecatedNoWarn = jsLegacyNoWarn.get()
logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}") logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}")
@@ -1141,6 +1170,22 @@ abstract class Kotlin2JsCompile @Inject constructor(
taskOutputsBackup 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( data class KotlinCompilerPluginData(
@@ -7,8 +7,13 @@ package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData 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.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.klibModuleName
import java.io.File import java.io.File
internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig<Kotlin2JsCompile> internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig<Kotlin2JsCompile>
@@ -27,18 +32,96 @@ internal open class BaseKotlin2JsCompileConfig<TASK : Kotlin2JsCompile>(
task.incremental = propertiesProvider.incrementalJs ?: true task.incremental = propertiesProvider.incrementalJs ?: true
task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true
task.outputFileProperty.value(task.project.provider { configureAdditionalFreeCompilerArguments(task, compilation)
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()
task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile -> @Suppress("DEPRECATION")
task.project.provider { task.compilerOptions.outputFile.convention(
outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() } 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() } 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<String>.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)}")
}
}
} }
@@ -5,8 +5,11 @@
package org.jetbrains.kotlin.gradle.tasks.configuration package org.jetbrains.kotlin.gradle.tasks.configuration
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation import org.gradle.api.InvalidUserDataException
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink 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( internal open class KotlinJsIrLinkConfig(
compilation: KotlinJsIrCompilation compilation: KotlinJsIrCompilation
@@ -17,9 +20,70 @@ internal open class KotlinJsIrLinkConfig(
// Link tasks are not affected by compiler plugin, so set to empty // Link tasks are not affected by compiler plugin, so set to empty
task.pluginClasspath.setFrom(objectFactory.fileCollection()) 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.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<String>.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)
} }
} }
} }