Skip to content

Commit 280e7fc

Browse files
committed
wasmtime support
1 parent 8b9945c commit 280e7fc

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ To build and run the application:
3434
`./gradlew wasmWasiWasmEdgeTest`
3535
<br>&nbsp;<br>
3636

37+
* **Run the program with Wasmtime:**
38+
39+
`./gradlew wasmWasiWasmtimeRun`
40+
41+
> **Note:**
42+
> The Exception Handling proposal [is not yet implemented](https://github.com/bytecodealliance/wasmtime/issues/3427)
43+
44+
* **Run tests with Wasmtime:**
45+
46+
`./gradlew wasmWasiWasmtimeTest`
47+
3748
* **Run the program with NodeJs:**
3849

3950
`./gradlew wasmWasiNodeRun`

build.gradle.kts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import org.gradle.internal.os.OperatingSystem
44
import de.undercouch.gradle.tasks.download.Download
5+
import org.gradle.api.internal.file.archive.compression.*
56
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
67
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExec
78
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
89
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport
10+
import java.io.*
11+
import java.net.*
912
import java.nio.file.Files
1013
import java.util.Locale
1114

@@ -14,6 +17,13 @@ plugins {
1417
alias(libs.plugins.undercouchDownload) apply false
1518
}
1619

20+
buildscript {
21+
dependencies {
22+
// to extract `tar.xz`
23+
classpath("org.tukaani:xz:1.9")
24+
}
25+
}
26+
1727
repositories {
1828
mavenCentral()
1929
}
@@ -352,3 +362,134 @@ tasks.withType<NodeJsExec>().all {
352362
)
353363
}
354364
}
365+
366+
// Wasmtime tasks
367+
val wasmtimeVersion = "dev" // only `dev` supports GC
368+
369+
val wasmtimeSuffix = when (currentOsType) {
370+
OsType(OsName.LINUX, OsArch.X86_64) -> "x86_64-linux"
371+
OsType(OsName.LINUX, OsArch.ARM64) -> "aarch64-linux"
372+
OsType(OsName.MAC, OsArch.X86_64) -> "x86_64-macos"
373+
OsType(OsName.MAC, OsArch.ARM64) -> "aarch64-macos"
374+
OsType(OsName.WINDOWS, OsArch.X86_32),
375+
OsType(OsName.WINDOWS, OsArch.X86_64) -> "x86_64-windows"
376+
377+
else -> error("unsupported os type $currentOsType")
378+
}
379+
380+
val wasmtimeArtifactName = "wasmtime-$wasmtimeVersion-$wasmtimeSuffix"
381+
382+
val unzipWasmtime = run {
383+
val wasmtimeDirectory = "https://github.com/bytecodealliance/wasmtime/releases/download/$wasmtimeVersion"
384+
val archiveType = if (currentOsType.name == OsName.WINDOWS) "zip" else "tar.xz"
385+
val wasmtimeArchiveName = "$wasmtimeArtifactName.$archiveType"
386+
val wasmtimeLocation = "$wasmtimeDirectory/$wasmtimeArchiveName"
387+
388+
val downloadedTools = File(layout.buildDirectory.asFile.get(), "tools")
389+
390+
val downloadWasmtime = tasks.register("wasmtimeDownload", Download::class) {
391+
src(wasmtimeLocation)
392+
dest(File(downloadedTools, wasmtimeArchiveName))
393+
overwrite(false)
394+
}
395+
396+
tasks.register("wasmtimeUnzip", Copy::class) {
397+
dependsOn(downloadWasmtime)
398+
399+
val archive = downloadWasmtime.get().dest
400+
401+
from(if (archive.extension == "zip") zipTree(archive) else tarTree(XzArchiver(archive)))
402+
403+
into(downloadedTools)
404+
}
405+
}
406+
407+
private class XzArchiver(private val file: File) : CompressedReadableResource {
408+
override fun read(): InputStream = org.tukaani.xz.XZInputStream(file.inputStream().buffered())
409+
override fun getURI(): URI = URIBuilder(file.toURI()).schemePrefix("xz:").build()
410+
override fun getBackingFile(): File = file
411+
override fun getBaseName(): String = file.name
412+
override fun getDisplayName(): String = file.path
413+
}
414+
415+
fun Project.createWasmtimeExec(
416+
nodeMjsFile: RegularFileProperty,
417+
taskName: String,
418+
taskGroup: String?,
419+
startFunction: String
420+
): TaskProvider<Exec> {
421+
val outputDirectory = nodeMjsFile.map { it.asFile.parentFile }
422+
val wasmFileName = nodeMjsFile.map { "${it.asFile.nameWithoutExtension}.wasm" }
423+
424+
return tasks.register(taskName, Exec::class) {
425+
dependsOn(unzipWasmtime)
426+
inputs.property("wasmFileName", wasmFileName)
427+
428+
taskGroup?.let { group = it }
429+
430+
description = "Executes tests with Wasmtime"
431+
432+
val wasmtimeDirectory = unzipWasmtime.get().destinationDir.resolve(wasmtimeArtifactName)
433+
434+
val executableName = when (currentOsType.name) {
435+
OsName.WINDOWS -> "wasmtime.exe"
436+
else -> "wasmtime"
437+
}
438+
executable = wasmtimeDirectory.resolve(executableName).absolutePath
439+
440+
doFirst {
441+
val newArgs = mutableListOf<String>()
442+
443+
newArgs.add("-W")
444+
newArgs.add("function-references,gc")
445+
446+
newArgs.add("-D")
447+
newArgs.add("logging=y")
448+
449+
newArgs.add("--invoke")
450+
newArgs.add(startFunction)
451+
452+
newArgs.add(wasmFileName.get())
453+
454+
args(newArgs)
455+
workingDir(outputDirectory)
456+
457+
// to show stacktraces
458+
environment("RUST_BACKTRACE", "full")
459+
}
460+
}
461+
}
462+
463+
tasks.withType<KotlinJsTest>().all {
464+
val wasmtimeRunTask = createWasmtimeExec(
465+
inputFileProperty,
466+
name.replace("Node", "Wasmtime"),
467+
group,
468+
"startUnitTests"
469+
)
470+
471+
wasmtimeRunTask.configure {
472+
dependsOn(
473+
project.provider { this@all.taskDependencies }
474+
)
475+
}
476+
477+
tasks.withType<KotlinTestReport> {
478+
dependsOn(wasmtimeRunTask)
479+
}
480+
}
481+
482+
tasks.withType<NodeJsExec>().all {
483+
val wasmtimeRunTask = createWasmtimeExec(
484+
inputFileProperty,
485+
name.replace("Node", "Wasmtime"),
486+
group,
487+
"dummy"
488+
)
489+
490+
wasmtimeRunTask.configure {
491+
dependsOn(
492+
project.provider { this@all.taskDependencies }
493+
)
494+
}
495+
}

0 commit comments

Comments
 (0)