Unverified Commit d65ac361 authored by Shagen Ogandzhanian's avatar Shagen Ogandzhanian Committed by GitHub

Simplify gradle web wasm build (#1089)

Following changes introduced in this PR:
* jsWasmMain and jsWasmTest sourcesets renamed to webMain and webTest
(it causes less confusion, regarding the fact that we already have
wasmJsMain, apart from that, this would be a standard name for this
sourceset in webMain)
* remove redunant resource processing (there's yet room for improvement
though)
   * Simplify wasm task introduction
* Remove flag for building js separately from wasm (this flag was a lie
- we can not have separate js target)
parent fa65bb4c
...@@ -81,14 +81,14 @@ kotlin { ...@@ -81,14 +81,14 @@ kotlin {
} }
} }
val linkWasmTask = skikoProjectContext.createWasmLinkTask()
if (supportJs) { if (supportWeb) {
js(IR) { skikoProjectContext.declareWasmTasks()
js {
moduleName = "skiko-kjs" // override the name to avoid name collision with a different skiko.js file moduleName = "skiko-kjs" // override the name to avoid name collision with a different skiko.js file
browser { browser {
testTask { testTask {
dependsOn(linkWasmTask!!)
useKarma { useKarma {
useChromeHeadless() useChromeHeadless()
useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("js")) useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("js"))
...@@ -101,32 +101,19 @@ kotlin { ...@@ -101,32 +101,19 @@ kotlin {
val test by compilations.getting val test by compilations.getting
project.tasks.named<Copy>(test.processResourcesTaskName) { project.tasks.named<Copy>(test.processResourcesTaskName) {
from(linkWasmTask!!) {
include("*.mjs")
include("*.wasm")
}
from(wasmImports) {
include("*.mjs")
}
dependsOn(test.compileTaskProvider, tasks["compileTestKotlinWasmJs"]) dependsOn(test.compileTaskProvider, tasks["compileTestKotlinWasmJs"])
} }
setupImportsGeneratorPlugin() setupImportsGeneratorPlugin()
} }
}
if (supportWasm) {
@OptIn(ExperimentalWasmDsl::class) @OptIn(ExperimentalWasmDsl::class)
wasmJs { wasmJs {
moduleName = "skiko-kjs-wasm" // override the name to avoid name collision with a different skiko.js file moduleName = "skiko-kjs-wasm" // override the name to avoid name collision with a different skiko.js file
browser { browser {
testTask { testTask {
dependsOn(linkWasmTask!!)
useKarma { useKarma {
this.webpackConfig.experiments.add("topLevelAwait")
useChromeHeadless() useChromeHeadless()
useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm")) useConfigDirectory(project.projectDir.resolve("karma.config.d").resolve("wasm"))
} }
...@@ -137,13 +124,6 @@ kotlin { ...@@ -137,13 +124,6 @@ kotlin {
val test by compilations.getting val test by compilations.getting
project.tasks.named<Copy>(test.processResourcesTaskName) { project.tasks.named<Copy>(test.processResourcesTaskName) {
from(linkWasmTask!!) {
include("*.mjs")
include("*.wasm")
}
from(skikoTestMjs)
dependsOn(test.compileTaskProvider, tasks["compileTestKotlinJs"]) dependsOn(test.compileTaskProvider, tasks["compileTestKotlinJs"])
} }
...@@ -237,7 +217,7 @@ kotlin { ...@@ -237,7 +217,7 @@ kotlin {
} }
} }
if (supportJs || supportWasm || supportAnyNative) { if (supportWeb || supportAnyNative) {
val nativeJsMain by creating { val nativeJsMain by creating {
dependsOn(commonMain) dependsOn(commonMain)
} }
...@@ -246,38 +226,41 @@ kotlin { ...@@ -246,38 +226,41 @@ kotlin {
dependsOn(commonTest) dependsOn(commonTest)
} }
if (supportJs || supportWasm) { if (supportWeb) {
val jsWasmMain by creating { val webMain by creating {
dependsOn(nativeJsMain) dependsOn(nativeJsMain)
} }
val jsWasmTest by creating { val webTest by creating {
dependsOn(nativeJsTest) dependsOn(nativeJsTest)
resources.srcDirs(
tasks.named("linkWasm"),
wasmImports
)
} }
if (supportJs) {
val jsMain by getting { val jsMain by getting {
dependsOn(jsWasmMain) dependsOn(webMain)
} }
val jsTest by getting { val jsTest by getting {
dependsOn(jsWasmTest) dependsOn(webTest)
}
} }
if (supportWasm) {
val wasmJsMain by getting { val wasmJsMain by getting {
dependsOn(jsWasmMain) dependsOn(webMain)
} }
val wasmJsTest by getting { val wasmJsTest by getting {
dependsOn(jsWasmTest) dependsOn(webTest)
dependencies { dependencies {
implementation(kotlin("test-wasm-js")) implementation(kotlin("test-wasm-js"))
} }
} }
} }
}
if (supportAnyNative) { if (supportAnyNative) {
all { all {
...@@ -597,7 +580,7 @@ publishing { ...@@ -597,7 +580,7 @@ publishing {
} }
} }
if (supportJs || supportWasm) { if (supportWeb) {
create<MavenPublication>("skikoWasmRuntime") { create<MavenPublication>("skikoWasmRuntime") {
pomNameForPublication[name] = "Skiko WASM Runtime" pomNameForPublication[name] = "Skiko WASM Runtime"
artifactId = SkikoArtifacts.jsWasmArtifactId artifactId = SkikoArtifacts.jsWasmArtifactId
......
...@@ -148,12 +148,9 @@ val Project.supportNativeLinux: Boolean ...@@ -148,12 +148,9 @@ val Project.supportNativeLinux: Boolean
val Project.supportAnyNative: Boolean val Project.supportAnyNative: Boolean
get() = supportAllNative || supportAnyNativeIos || supportNativeMac || supportNativeLinux get() = supportAllNative || supportAnyNativeIos || supportNativeMac || supportNativeLinux
val Project.supportWasm: Boolean val Project.supportWeb: Boolean
get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea
val Project.supportJs: Boolean
get() = findProperty("skiko.js.enabled") == "true" || supportWasm || isInIdea
fun Project.skiaVersion(target: String): String { fun Project.skiaVersion(target: String): String {
val platformSpecificVersion = "dependencies.skia.$target" val platformSpecificVersion = "dependencies.skia.$target"
......
...@@ -6,12 +6,11 @@ import SkiaBuildType ...@@ -6,12 +6,11 @@ import SkiaBuildType
import SkikoProperties import SkikoProperties
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.get
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool
import registerSkikoTask import registerSkikoTask
import supportAndroid import supportAndroid
import supportWasm import supportWeb
import toTitleCase import toTitleCase
import java.io.File import java.io.File
import skiaVersion import skiaVersion
...@@ -113,7 +112,7 @@ fun skiaPreprocessorFlags(os: OS, buildType: SkiaBuildType): Array<String> { ...@@ -113,7 +112,7 @@ fun skiaPreprocessorFlags(os: OS, buildType: SkiaBuildType): Array<String> {
} }
fun Project.configureSignAndPublishDependencies() { fun Project.configureSignAndPublishDependencies() {
if (supportWasm) { if (supportWeb) {
tasks.configureEach { tasks.configureEach {
val publishJs = "publishJsPublicationTo" val publishJs = "publishJsPublicationTo"
val publishWasm = "publishSkikoWasmRuntimePublicationTo" val publishWasm = "publishSkikoWasmRuntimePublicationTo"
......
...@@ -10,7 +10,6 @@ import compilerForTarget ...@@ -10,7 +10,6 @@ import compilerForTarget
import linkerForTarget import linkerForTarget
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getValue import org.gradle.kotlin.dsl.getValue
...@@ -24,37 +23,34 @@ import registerOrGetSkiaDirProvider ...@@ -24,37 +23,34 @@ import registerOrGetSkiaDirProvider
import setupMjs import setupMjs
import setupReexportMjs import setupReexportMjs
import skikoTestMjs import skikoTestMjs
import supportJs import supportWeb
import supportWasm
import java.io.File import java.io.File
fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? = with(this.project) { fun SkikoProjectContext.declareWasmTasks() {
if (!supportWasm && !supportJs) { if (!project.supportWeb) {
return null return
} }
val skiaWasmDir = registerOrGetSkiaDirProvider(OS.Wasm, Arch.Wasm, false) val skiaWasmDir = registerOrGetSkiaDirProvider(OS.Wasm, Arch.Wasm, false)
val compileWasm by tasks.registering(CompileSkikoCppTask::class) { val compileWasm by project.tasks.registering(CompileSkikoCppTask::class) {
val osArch = OS.Wasm to Arch.Wasm
dependsOn(skiaWasmDir) dependsOn(skiaWasmDir)
compiler.set(compilerForTarget(OS.Wasm, Arch.Wasm, isJvm = false)) compiler.set(compilerForTarget(OS.Wasm, Arch.Wasm, isJvm = false))
buildTargetOS.set(osArch.first) buildTargetOS.set(OS.Wasm)
buildTargetArch.set(osArch.second) buildTargetArch.set(Arch.Wasm)
buildVariant.set(buildType) buildVariant.set(buildType)
val srcDirs = projectDirs("src/commonMain/cpp/common", "src/jsWasmMain/cpp", "src/nativeJsMain/cpp") + val srcDirs = projectDirs("src/commonMain/cpp/common", "src/webMain/cpp", "src/nativeJsMain/cpp") +
if (skiko.includeTestHelpers) projectDirs("src/nativeJsTest/cpp") else emptyList() if (skiko.includeTestHelpers) projectDirs("src/nativeJsTest/cpp") else emptyList()
sourceRoots.set(srcDirs) sourceRoots.set(srcDirs)
includeHeadersNonRecursive(projectDir.resolve("src/nativeJsMain/cpp")) includeHeadersNonRecursive(project.projectDir.resolve("src/nativeJsMain/cpp"))
includeHeadersNonRecursive(projectDir.resolve("src/jsWasmMain/cpp")) includeHeadersNonRecursive(project.projectDir.resolve("src/webMain/cpp"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include")) includeHeadersNonRecursive(project.projectDir.resolve("src/commonMain/cpp/common/include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaWasmDir.get())) includeHeadersNonRecursive(skiaHeadersDirs(skiaWasmDir.get()))
flags.set( flags.set(
mutableListOf<String?>().apply { buildList {
addAll(skiaPreprocessorFlags(OS.Wasm, buildType)) addAll(skiaPreprocessorFlags(OS.Wasm, buildType))
addAll(buildType.clangFlags) addAll(buildType.clangFlags)
add("-fno-rtti") add("-fno-rtti")
...@@ -64,38 +60,27 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? = ...@@ -64,38 +60,27 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? =
) )
} }
val configureCommon: LinkSkikoWasmTask.(prefixPath: String, forD8: Boolean) -> Unit = { prefixPath, isForD8 -> fun LinkSkikoWasmTask.configureCommon(prefixPath: String) {
val osArch = OS.Wasm to Arch.Wasm
dependsOn(compileWasm) dependsOn(compileWasm)
dependsOn(skiaWasmDir) dependsOn(skiaWasmDir)
val unpackedSkia = skiaWasmDir.get()
linker.set(linkerForTarget(OS.Wasm, Arch.Wasm, isJvm = false)) linker.set(linkerForTarget(OS.Wasm, Arch.Wasm, isJvm = false))
buildTargetOS.set(osArch.first) buildTargetOS.set(OS.Wasm)
buildTargetArch.set(osArch.second) buildTargetArch.set(Arch.Wasm)
buildVariant.set(buildType) buildVariant.set(buildType)
if (isForD8) buildSuffix.set("d8") else buildSuffix.set("es6")
libFiles = project.fileTree(unpackedSkia) { include("**/*.a") } libFiles = project.fileTree(skiaWasmDir.get()) { include("**/*.a") }
objectFiles = project.fileTree(compileWasm.map { it.outDir.get() }) { objectFiles = project.fileTree(compileWasm.map { it.outDir.get() }) {
include("**/*.o") include("**/*.o")
} }
val wasmFileName = if (isForD8) "skikod8.wasm" else "skiko.wasm"
val jsFileName = if (isForD8) "skikod8.mjs" else "skiko.mjs"
libOutputFileName.set(wasmFileName) // emcc ignores this, it names .wasm file identically to js output
jsOutputFileName.set(jsFileName) // this determines the name .wasm file too
externPostJs.from( externPostJs.from(
// the order matters // the order matters
project.layout.projectDirectory.file("src/jsWasmMain/resources/skikoCallbacks.js"), project.layout.projectDirectory.file("src/webMain/resources/skikoCallbacks.js"),
project.layout.projectDirectory.file(prefixPath) project.layout.projectDirectory.file(prefixPath)
) )
@OptIn(kotlin.ExperimentalStdlibApi::class) flags.addAll(buildList {
flags.set(mutableListOf<String?>().apply {
addAll( addAll(
listOf( listOf(
"-l", "GL", "-l", "GL",
...@@ -107,85 +92,79 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? = ...@@ -107,85 +92,79 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? =
"-s", "MODULARIZE=1", "-s", "MODULARIZE=1",
"-s", "EXPORT_NAME=loadSkikoWASM", "-s", "EXPORT_NAME=loadSkikoWASM",
"-s", "EXPORTED_RUNTIME_METHODS=\"[GL, wasmExports]\"", "-s", "EXPORTED_RUNTIME_METHODS=\"[GL, wasmExports]\"",
"-s", "SUPPORT_LONGJMP=wasm",
"--bind", "--bind",
// -O2 saves 800kB for the output file, and ~100kB for transferred size. // -O2 saves 800kB for the output file, and ~100kB for transferred size.
// -O3 breaks the exports in js/mjs files. skiko.wasm size is the same though // -O3 breaks the exports in js/mjs files. skiko.wasm size is the same though
"-O2" "-O2"
) )
) )
addAll(listOf("-s", "SUPPORT_LONGJMP=wasm"))
if (isForD8) {
addAll(listOf("-s", "ENVIRONMENT=shell"))
}
if (skiko.isWasmBuildWithProfiling) add("--profiling") if (skiko.isWasmBuildWithProfiling) add("--profiling")
}) })
doLast { doLast {
// skiko.js (and skiko.mjs) files are directly referenced in karma.config.d/*/config.js // skiko.mjs is referenced in karma.config.d/*/config.js
// so symbols must be replaced right after linking // so symbols must be replaced right after linking
val jsFiles = outDir.asFile.get().walk() val jsFile = outDir.asFile.get().walk().first { it.name == jsOutputFileName.get() }
.filter { it.isFile && (it.name.endsWith(".js") || it.name.endsWith(".mjs")) }
val isEnvironmentNodeCheckRegex = Regex( val isEnvironmentNodeCheckRegex = Regex(
// spaces are different in release and debug builds // spacing is different in release and debug builds
"""if\s*\(ENVIRONMENT_IS_NODE\)\s*\{""" """if\s*\(ENVIRONMENT_IS_NODE\)\s*\{"""
) )
for (jsFile in jsFiles) {
val originalContent = jsFile.readText() val originalContent = jsFile.readText()
val newContent = originalContent.replace("_org_jetbrains", "org_jetbrains") val newContent = originalContent
.replace("skikod8.wasm", "skiko.wasm")
.replace(isEnvironmentNodeCheckRegex, "if (false) {") // to make webpack erase this part .replace(isEnvironmentNodeCheckRegex, "if (false) {") // to make webpack erase this part
jsFile.writeText(newContent) jsFile.writeText(newContent)
if (isForD8) {
// delete this file as its presence can be confusing.
// It's identical to skiko.wasm and we use skiko.wasm in `skikoWasmJar`task
outDir.file(wasmFileName).get().asFile.delete()
val renameTo = "skikod8.mjs"
outDir.file(jsFileName).get().asFile.renameTo(outDir.asFile.get().resolve(renameTo))
}
}
} }
} }
val linkWasm by tasks.registering(LinkSkikoWasmTask::class) { val linkWasm by project.tasks.registering(LinkSkikoWasmTask::class) {
dependsOn( dependsOn(
kotlin.wasmJs().compilations["main"].compileTaskProvider, kotlin.wasmJs().compilations["main"].compileTaskProvider,
kotlin.js().compilations["main"].compileTaskProvider kotlin.js().compilations["main"].compileTaskProvider
) )
configureCommon(setupMjs.normalize().absolutePath, false) buildSuffix.set("es6")
jsOutputFileName.set("skiko.mjs") // this determines the name .wasm file too
libOutputFileName.set("skiko.wasm")
configureCommon(project.setupMjs.normalize().absolutePath)
} }
val linkWasmD8WithES6 by tasks.registering(LinkSkikoWasmTask::class) { val linkWasmD8WithES6 by project.tasks.registering(LinkSkikoWasmTask::class) {
dependsOn( dependsOn(
kotlin.wasmJs().compilations["main"].compileTaskProvider, kotlin.wasmJs().compilations["main"].compileTaskProvider,
kotlin.js().compilations["main"].compileTaskProvider kotlin.js().compilations["main"].compileTaskProvider
) )
configureCommon(setupMjs.normalize().absolutePath, true)
buildSuffix.set("d8")
jsOutputFileName.set("skikod8.mjs") // this determines the name .wasm file too
libOutputFileName.set("skikod8.wasm")
flags.addAll(listOf("-s", "ENVIRONMENT=shell"))
configureCommon(project.setupMjs.normalize().absolutePath)
} }
// skikoWasmJar is used by task name // skikoWasmJar is used by task name
val skikoWasmJar by project.tasks.registering(Jar::class) { val skikoWasmJar by project.tasks.registering(Jar::class) {
dependsOn(linkWasm)
// We produce jar that contains .js of wrapper/bindings and .wasm with Skia + bindings. // We produce jar that contains .js of wrapper/bindings and .wasm with Skia + bindings.
val wasmEsOutDir = linkWasm.map { it.outDir } from(project.setupReexportMjs.parentFile) {
val wasmD8OutDir = linkWasmD8WithES6.map { it.outDir } include(project.setupReexportMjs.name)
from(setupReexportMjs.parentFile) {
include(setupReexportMjs.name)
} }
from(wasmEsOutDir) { from(linkWasm) {
include("*.js")
include("*.wasm") include("*.wasm")
include("*.mjs") include("*.mjs")
} }
from(wasmD8OutDir) {
from(linkWasmD8WithES6) {
include("*.mjs") include("*.mjs")
filesMatching("*.mjs") {
filter { it.replace("skikod8.wasm", "skiko.wasm") }
}
} }
archiveBaseName.set("skiko-wasm") archiveBaseName.set("skiko-wasm")
...@@ -193,8 +172,6 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? = ...@@ -193,8 +172,6 @@ fun SkikoProjectContext.createWasmLinkTask(): TaskProvider<LinkSkikoWasmTask>? =
println("Wasm and JS at: ${archiveFile.get().asFile.absolutePath}") println("Wasm and JS at: ${archiveFile.get().asFile.absolutePath}")
} }
} }
return linkWasm
} }
abstract class AbstractImportGeneratorCompilerPluginSupportPlugin( abstract class AbstractImportGeneratorCompilerPluginSupportPlugin(
...@@ -235,14 +212,14 @@ abstract class AbstractImportGeneratorCompilerPluginSupportPlugin( ...@@ -235,14 +212,14 @@ abstract class AbstractImportGeneratorCompilerPluginSupportPlugin(
class WasmImportsGeneratorCompilerPluginSupportPlugin : AbstractImportGeneratorCompilerPluginSupportPlugin( class WasmImportsGeneratorCompilerPluginSupportPlugin : AbstractImportGeneratorCompilerPluginSupportPlugin(
KotlinCompilation.MAIN_COMPILATION_NAME, KotlinCompilation.MAIN_COMPILATION_NAME,
{ it.setupMjs }, { it.setupMjs },
{ it.projectDir.resolve("src/jsWasmMain/resources/pre-setup.mjs") }, { it.projectDir.resolve("src/webMain/resources/pre-setup.mjs") },
{ it.setupReexportMjs } { it.setupReexportMjs }
) )
class WasmImportsGeneratorForTestCompilerPluginSupportPlugin : AbstractImportGeneratorCompilerPluginSupportPlugin( class WasmImportsGeneratorForTestCompilerPluginSupportPlugin : AbstractImportGeneratorCompilerPluginSupportPlugin(
KotlinCompilation.TEST_COMPILATION_NAME, KotlinCompilation.TEST_COMPILATION_NAME,
{ it.skikoTestMjs }, { it.skikoTestMjs },
{ it.projectDir.resolve("src/jsWasmMain/resources/pre-skiko-test.mjs") }, { it.projectDir.resolve("src/webMain/resources/pre-skiko-test.mjs") },
null null
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment