Unverified Commit b8510b66 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

JS compilation (#157)

parent f794e4bb
......@@ -36,12 +36,25 @@ repositories {
}
val skiaZip = run {
val zipName = skiko.skiaReleaseForTargetOS + ".zip"
val zipName = skiko.skiaReleaseFor(targetOs, targetArch) + ".zip"
val zipFile = skiko.dependenciesDir.resolve("skia/${zipName.substringAfterLast('/')}")
tasks.register("downloadSkia", Download::class) {
onlyIf { skiko.skiaDir == null && !zipFile.exists() }
inputs.property("skia.release.for.target.os", skiko.skiaReleaseForTargetOS)
inputs.property("skia.release.for.target.os", skiko.skiaReleaseFor(targetOs, targetArch))
src("https://github.com/JetBrains/skia-pack/releases/download/$zipName")
dest(zipFile)
onlyIfModified(true)
}.map { zipFile }
}
val skiaWasmZip = run {
val release = skiko.skiaReleaseFor(OS.Wasm, Arch.Wasm)
val zipName = "$release.zip"
val zipFile = skiko.dependenciesDir.resolve("skia/${zipName.substringAfterLast('/')}")
tasks.register("downloadSkiaWasm", Download::class) {
onlyIf { skiko.skiaDir == null && !zipFile.exists() }
inputs.property("skia.release.for.wasm", release)
src("https://github.com/JetBrains/skia-pack/releases/download/$zipName")
dest(zipFile)
onlyIfModified(true)
......@@ -70,6 +83,24 @@ val skiaDir = run {
}
}
val skiaWasmDir = run {
if (skiko.skiaDir != null) {
tasks.register("skiaWasmDir", DefaultTask::class) {
// dummy task to simplify usage of the resulting provider (see `else` branch)
// if a file provider is not created from a task provider,
// then it cannot be used instead of a task in `dependsOn` clauses of other tasks.
// e.g. the resulting `skiaDir` could not be used in `dependsOn` of CppCompile configuration
enabled = false
}.map { skiko.skiaDir!! }
} else {
val targetDir = skiko.dependenciesDir.resolve("skia/skia-wasm")
tasks.register("unzipSkiaWasm", Copy::class) {
from(skiaWasmZip.map { zipTree(it) })
configureSkiaCopy(targetDir)
}.map { targetDir }
}
}
val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
val Project.supportNative: Boolean
......@@ -82,6 +113,11 @@ kotlin {
}
}
js(IR) {
browser()
binaries.executable()
}
if (supportNative) {
val nativeTarget = when (target) {
"macos-x64", "macos-arm64" -> macosX64()
......@@ -243,6 +279,7 @@ tasks.withType(CppCompile::class.java).configureEach {
)
)
}
OS.Wasm -> throw GradleException("Should not reach here")
}
}
......@@ -275,6 +312,33 @@ project.tasks.register<Exec>("objcCompile") {
outputs.files(outs)
}
project.tasks.register<Exec>("wasmCompile") {
dependsOn(skiaWasmDir)
val inputDir = "$projectDir/src/jsMain/cpp"
val outDir = "$buildDir/wasm"
val names = File(inputDir).listFiles()!!.map { it.name.removeSuffix(".cc") }
val srcs = names.map { "$inputDir/$it.cc" }.toTypedArray()
val outJs = "$outDir/skiko.js"
val outWasm = "$outDir/skiko.wasm"
val skiaDir = skiaWasmDir.get().absolutePath
workingDir = File(outDir)
val libs = fileTree("$skiaDir/out/Release-wasm-wasm").filter { it.name.endsWith(".a") }
commandLine = listOf(
"emcc",
*Arch.Wasm.clangFlags,
"-I$skiaDir",
"-I$skiaDir/include",
"-I$skiaDir/include/gpu",
"-std=c++17",
"-o", outJs,
*libs.files.map { it.absolutePath }.toTypedArray(),
*srcs
)
file(outDir).mkdirs()
inputs.files(srcs)
outputs.files(outJs, outWasm)
}
fun localSign(signer: String, lib: File): File {
println("Local signing $lib as $signer")
val proc = ProcessBuilder("codesign", "-f", "-s", signer, lib.absolutePath)
......@@ -393,6 +457,9 @@ tasks.withType(LinkSharedLibrary::class.java).configureEach {
)
)
}
OS.Wasm -> {
throw GradleException("This task shalln't be used with WASM")
}
}
}
......@@ -489,6 +556,17 @@ val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) {
from(createChecksums.get().outputs.files)
}
project.tasks.register<Jar>("skikoJsJar") {
// We produce jar that contains .js of wrapper/bindings and .wasm with Skia + bindings.
from(kotlin.js().compilations["main"].output.allOutputs)
from(project.tasks.named("wasmCompile").get().outputs)
from(project.tasks.named("jsJar").get().outputs)
archiveBaseName.set("skiko-wasm")
doLast {
println("output at ${outputs.files.files.single()}")
}
}
project.tasks.register<JavaExec>("run") {
main = "org.jetbrains.skiko.MainKt"
classpath = files(skikoJvmRuntimeJar.map { it.archiveFile })
......
......@@ -4,7 +4,8 @@ import java.io.File
enum class OS(val id: String) {
Linux("linux"),
Windows("windows"),
MacOS("macos")
MacOS("macos"),
Wasm("wasm")
;
val isWindows
......@@ -13,7 +14,8 @@ enum class OS(val id: String) {
enum class Arch(val id: String, val clangFlags: Array<String>) {
X64("x64", arrayOf("-arch", "x86_64")),
Arm64("arm64", arrayOf("-arch", "arm64"))
Arm64("arm64", arrayOf("-arch", "arm64")),
Wasm("wasm", emptyArray())
}
enum class SkiaBuildType(
......@@ -51,12 +53,14 @@ fun findTargetOs() = when (System.getProperty("skiko.target.os.name")) {
"linux" -> OS.Linux
"macos" -> OS.MacOS
"windows" -> OS.Windows
"wasm" -> OS.Wasm
else -> null
}
fun findTargetArch() = when (System.getProperty("skiko.target.os.arch")) {
"x64" -> Arch.X64
"arm64" -> Arch.Arm64
"wasm" -> Arch.Wasm
else -> null
}
......@@ -86,15 +90,11 @@ class SkikoProperties(private val myProject: Project) {
val buildType: SkiaBuildType
get() = if (myProject.findProperty("skiko.debug") == "true") SkiaBuildType.DEBUG else SkiaBuildType.RELEASE
val skiaReleaseForTargetOS: String
get() {
fun skiaReleaseFor(os: OS, arch: Arch): String {
val target = "${os.id}-${arch.id}"
val tag = myProject.property("dependencies.skia.$target") as String
val suffix = if (targetOs == OS.Linux && targetArch == Arch.X64) {
"-ubuntu14"
} else {
""
}
return "${tag}/Skia-${tag}-${targetOs.id}-${buildType.id}-${targetArch.id}$suffix"
val suffix = if (os == OS.Linux && arch == Arch.X64) "-ubuntu14" else ""
return "${tag}/Skia-${tag}-${os.id}-${buildType.id}-${arch.id}$suffix"
}
val releaseGithubVersion: String
......
......@@ -7,3 +7,4 @@ dependencies.skia.linux-x64=m93-87e8842e8c
dependencies.skia.macos-x64=m93-87e8842e8c
dependencies.skia.linux-arm64=m93-87e8842e8c
dependencies.skia.macos-arm64=m93-87e8842e8c
dependencies.skia.wasm-wasm=m93-87e8842e8c
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.ImageFilter.Companion.makeDropShadowOnly
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import kotlin.jvm.JvmStatic
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
package org.jetbrains.skia
enum class PathEllipseArc {
/** Smaller of arc pair. */
SMALLER,
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.*
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.*
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.impl
import org.jetbrains.skia.ByteBuffer
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.shaper
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.shaper
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.shaper
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.shaper
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
@file:Suppress("NESTED_EXTERNAL_DECLARATION")
package org.jetbrains.skia.shaper
import org.jetbrains.skia.impl.Library.Companion.staticLoad
......
#include "GrBackendSurface.h"
#include "GrDirectContext.h"
void* init_surface() {
return nullptr;
}
int main() {
printf("Hello from WASM\n");
//void* ctx = GrDirectContext::MakeGL().release();
//printf("Context is %p\n");
return 0;
}
package org.jetbrains.skia
actual abstract class ByteBuffer
actual fun <R> commonSynchronized(lock: Any, block: () -> R) {
block()
}
actual fun String.intCodePoints(): IntArray = TODO()
actual class Pattern {
actual fun split(input: CharSequence): Array<String?>? = TODO()
actual fun matcher(input: CharSequence): Matcher = TODO()
}
actual class Matcher {
actual fun group(name: String): String? = TODO()
actual fun matches(): Boolean = TODO()
}
actual fun defaultLanguageTag(): String = TODO()
actual fun compilePattern(regex: String): Pattern = TODO()
\ No newline at end of file
package org.jetbrains.skia.impl
actual class Library {
actual companion object {
actual fun staticLoad() {
TODO()
}
}
}
package org.jetbrains.skia.impl
actual abstract class Managed actual constructor(ptr: Long, finalizer: Long, managed: Boolean) : Native(ptr) {
actual open fun close(): Unit = TODO()
}
\ No newline at end of file
package org.jetbrains.skia.impl
actual abstract class Native actual constructor(ptr: Long) {
actual var _ptr: Long
actual open fun _nativeEquals(other: Native?): Boolean = TODO()
actual companion object {
actual fun getPtr(n: Native?): Long {
return n?._ptr ?: 0
}
}
init {
if (ptr == 0L) throw RuntimeException("Can't wrap nullptr")
_ptr = ptr
}
}
actual fun reachabilityBarrier(obj: Any?) {
TODO()
}
\ No newline at end of file
package org.jetbrains.skia.impl
actual abstract class RefCnt : Managed {
actual protected constructor(ptr: Long): super(ptr, 0L, false) { TODO() }
actual protected constructor(ptr: Long, allowClose: Boolean): super(ptr, 0, allowClose) { TODO() }
}
\ No newline at end of file
package org.jetbrains.skia.impl
actual object Stats {
actual fun onNativeCall() {
TODO()
}
actual fun onAllocated(className: String) {
TODO()
}
actual fun onDeallocated(className: String) {
TODO()
}
}
\ No newline at end of file
package org.jetbrains.skiko.wasm
import kotlinx.dom.createElement
import kotlinx.browser.document
import org.w3c.dom.HTMLCanvasElement
@JsExport
fun createSkikoCanvas(): HTMLCanvasElement {
return document.createElement("canvas") {} as HTMLCanvasElement
}
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