[Gradle, Wasm] Binaryen by default for production main binary

^KT-64553 fixed
This commit is contained in:
Ilya Goncharov
2024-02-19 09:06:44 +00:00
committed by Space Team
parent 3dda88ddc2
commit 87fdf8e764
6 changed files with 90 additions and 120 deletions
@@ -1679,7 +1679,6 @@ open class NewMultiplatformIT : BaseGradleIT() {
}
build(":wasmJs${name}Test") {
assertTasksExecuted(":compileKotlinWasmJs")
assertTasksNotExecuted(":compileTestDevelopmentExecutableKotlinWasmJsOptimize")
assertTasksFailed(":wasmJs${name}Test")
assertTestResults(
@@ -5,8 +5,12 @@
package org.jetbrains.kotlin.gradle.targets.js.binaryen
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.work.DisableCachingByDefault
import org.gradle.work.NormalizeLineEndings
@@ -37,8 +41,16 @@ constructor() : AbstractExecTask<BinaryenExec>(BinaryenExec::class.java) {
@NormalizeLineEndings
val inputFileProperty: RegularFileProperty = project.newFileProperty()
@OutputFile
val outputFileProperty: RegularFileProperty = project.newFileProperty()
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
@get:Input
abstract val outputFileName: Property<String>
@Internal
val outputFileProperty: Provider<RegularFile> = project.provider {
outputDirectory.file(outputFileName).get()
}
override fun exec() {
val inputFile = inputFileProperty.asFile.get()
@@ -46,7 +58,7 @@ constructor() : AbstractExecTask<BinaryenExec>(BinaryenExec::class.java) {
newArgs.addAll(binaryenArgs)
newArgs.add(inputFile.canonicalPath)
newArgs.add("-o")
newArgs.add(outputFileProperty.asFile.get().canonicalPath)
newArgs.add(outputDirectory.file(outputFileName).get().asFile.normalize().absolutePath)
workingDir = inputFile.parentFile
this.args = newArgs
super.exec()
@@ -56,7 +68,7 @@ constructor() : AbstractExecTask<BinaryenExec>(BinaryenExec::class.java) {
fun create(
compilation: KotlinJsIrCompilation,
name: String,
configuration: BinaryenExec.() -> Unit = {}
configuration: BinaryenExec.() -> Unit = {},
): TaskProvider<BinaryenExec> {
val target = compilation.target
val project = target.project
@@ -17,8 +17,15 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
interface KotlinWasmTargetDsl : KotlinTarget, HasBinaries<KotlinJsBinaryContainer> {
val wasmTargetType: KotlinWasmTargetType?
@Suppress("DEPRECATION")
@Deprecated("Binaryen is enabled by default. This call is redundant.")
fun applyBinaryen() = applyBinaryen { }
@Deprecated("Binaryen is enabled by default. This call is redundant.")
fun applyBinaryen(body: BinaryenExec.() -> Unit)
@Suppress("DEPRECATION")
@Deprecated("Binaryen is enabled by default. This call is redundant.")
fun applyBinaryen(fn: Action<BinaryenExec>) {
applyBinaryen {
fn.execute(this)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
@@ -23,7 +24,6 @@ import org.jetbrains.kotlin.gradle.targets.js.subtargets.createDefaultDistributi
import org.jetbrains.kotlin.gradle.targets.js.typescript.TypeScriptValidationTask
import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinJsIrLinkConfig
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.mapToFile
@@ -189,10 +189,45 @@ open class ExecutableWasm(
) {
val optimizeTaskName: String = optimizeTaskName()
val optimizeTask: TaskProvider<BinaryenExec>
get() = target.project.tasks
.withType<BinaryenExec>()
.named(optimizeTaskName)
val optimizeTask: TaskProvider<BinaryenExec> = BinaryenExec.create(compilation, optimizeTaskName) {
val compileWasmDestDir = linkTask.map {
it.destinationDirectory
}
val compiledWasmFile = linkTask.flatMap { link ->
link.destinationDirectory.locationOnly.zip(link.compilerOptions.moduleName) { destDir, moduleName ->
destDir.file("$moduleName.wasm")
}
}
dependsOn(linkTask)
inputFileProperty.set(compiledWasmFile)
val outputDirectory: Provider<Directory> = target.project.layout.buildDirectory
.dir(COMPILE_SYNC)
.map { it.dir(compilation.target.targetName) }
.map { it.dir(compilation.name) }
.map { it.dir(name) }
.map { it.dir("optimized") }
this.outputDirectory.set(outputDirectory)
outputFileName.set(
compiledWasmFile.map { it.asFile.name }
)
doLast {
fs.copy {
it.from(compileWasmDestDir)
it.into(outputDirectory)
it.eachFile {
if (it.relativePath.getFile(outputDirectory.get().asFile).exists()) {
it.exclude()
}
}
}
}
}
private fun optimizeTaskName(): String =
"${linkTaskName}Optimize"
@@ -16,10 +16,8 @@ import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlatformTestRun
import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetType
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenExec
import org.jetbrains.kotlin.gradle.targets.js.dsl.Distribution
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalDistributionDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
@@ -27,11 +25,12 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
import org.jetbrains.kotlin.gradle.utils.withType
abstract class KotlinJsIrSubTarget(
val target: KotlinJsIrTarget,
@@ -55,13 +54,17 @@ abstract class KotlinJsIrSubTarget(
}
internal fun configure() {
configureTests()
target.compilations.all {
val npmProject = it.npmProject
@Suppress("DEPRECATION")
it.compilerOptions.options.freeCompilerArgs.add("$PER_MODULE_OUTPUT_NAME=${npmProject.name}")
it.binaries
.withType<ExecutableWasm>()
.configureEach { binary ->
configureBinaryen(binary)
}
}
configureTests()
}
private val produceExecutable: Unit by lazy {
@@ -126,15 +129,8 @@ abstract class KotlinJsIrSubTarget(
testJs.dependsOn(binary.linkSyncTask)
binary.mainFileSyncPath
} else {
if (project.locateTask<BinaryenExec>((binary as ExecutableWasm).optimizeTaskName) != null) {
testJs.dependsOn(binary.optimizeTask)
binary.optimizeTask.flatMap { optimizeTask ->
optimizeTask.outputFileProperty
}
} else {
testJs.dependsOn(binary.linkTask)
binary.mainFile
}
testJs.dependsOn(binary.linkTask)
binary.mainFile
}
testJs.inputFileProperty.set(
@@ -233,6 +229,21 @@ abstract class KotlinJsIrSubTarget(
}
}
private fun configureBinaryen(binary: ExecutableWasm) {
val binaryenExec = binary.optimizeTask
if (binary.compilation.isMain() && binary.mode == KotlinJsBinaryMode.PRODUCTION) {
if (target.wasmTargetType == KotlinWasmTargetType.WASI) {
project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(binaryenExec)
} else {
binary.linkSyncTask.configure {
it.from.setFrom(binaryenExec.flatMap { it.outputFileProperty.map { it.asFile.parentFile } })
it.dependsOn(binaryenExec)
}
}
}
}
internal inline fun <reified T : Task> registerSubTargetTask(
name: String,
args: List<Any> = emptyList(),
@@ -151,7 +151,6 @@ constructor(
.withType(JsIrBinary::class.java)
.all { binary ->
val syncTask = binary.linkSyncTask
binaryenReplaceInput[binary]?.invoke()
val tsValidationTask = registerTypeScriptCheckTask(binary)
binary.linkTask.configure {
@@ -182,97 +181,8 @@ constructor(
}
}
//Binaryen
private var binaryenReplaceInput: MutableMap<JsIrBinary, () -> Unit> = mutableMapOf()
@Deprecated("Binaryen is enabled by default. This call is redundant.")
override fun applyBinaryen(body: BinaryenExec.() -> Unit) {
compilations.all {
it.binaries.all { binary ->
if (binary is ExecutableWasm) {
val binaryenExec = createBinaryen(binary, body)
if (
wasmTargetType == KotlinWasmTargetType.WASI && nodejsLazyDelegate.isInitialized() ||
project.locateTask<IncrementalSyncTask>(binary.linkSyncTaskName) != null
) {
configureBinaryen(binary, binaryenExec)
} else {
binaryenReplaceInput[binary] = {
configureBinaryen(binary, binaryenExec)
}
}
}
}
}
}
private fun createBinaryen(binary: ExecutableWasm, binaryenDsl: BinaryenExec.() -> Unit): TaskProvider<BinaryenExec> {
val linkTask = binary.linkTask
val compileWasmDestDir = linkTask.map {
it.destinationDirectory
}
val compiledWasmFile = linkTask.map { link ->
link.destinationDirectory.asFile.get().resolve(link.compilerOptions.moduleName.get() + ".wasm")
}
return BinaryenExec.create(binary.compilation, binary.optimizeTaskName) {
val compilation = binary.compilation
dependsOn(linkTask)
inputFileProperty.fileProvider(compiledWasmFile)
val outputDirectory: Provider<File> = binary.target.project.layout.buildDirectory
.dir(COMPILE_SYNC)
.map { it.dir(compilation.target.targetName) }
.map { it.dir(compilation.name) }
.map { it.dir(binary.name) }
.map { it.dir("optimized") }
.map { it.asFile }
val outputFile = outputDirectory.map { it.resolve(compiledWasmFile.get().name) }
outputFileProperty.fileProvider(
outputFile
)
doLast {
fs.copy {
it.from(compileWasmDestDir)
it.into(outputDirectory)
it.eachFile {
if (it.relativePath.getFile(outputDirectory.get()).exists()) {
it.exclude()
}
}
}
}
binaryenDsl()
}
}
private fun configureBinaryen(binary: JsIrBinary, binaryenExec: TaskProvider<BinaryenExec>) {
if (wasmTargetType == KotlinWasmTargetType.WASI) {
if (binary.compilation.isMain() && binary.mode == KotlinJsBinaryMode.PRODUCTION) {
project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(binaryenExec)
}
whenNodejsConfigured {
testTask {
val name = binary.mainFileName
it.inputFileProperty.fileProvider(
binaryenExec.flatMap { it.outputFileProperty.map { it.asFile.parentFile.resolve(name.get()) } }
)
it.dependsOn(binaryenExec)
}
}
} else {
binary.linkSyncTask.configure {
it.from.setFrom(binaryenExec.flatMap { it.outputFileProperty.map { it.asFile.parentFile } })
it.dependsOn(binaryenExec)
}
}
}
//Browser
@@ -304,12 +214,8 @@ constructor(
commonLazy
} else {
NodeJsRootPlugin.apply(project.rootProject)
compilations.all { compilation ->
compilation.binaries.all { binary ->
binaryenReplaceInput[binary]?.invoke()
}
}
}
project.objects.newInstance(KotlinNodeJsIr::class.java, this).also {
it.configureSubTarget()
nodejsConfiguredHandlers.forEach { handler ->