wasmerio / wasmer-go

🐹🕸️ WebAssembly runtime for Go
https://pkg.go.dev/github.com/wasmerio/wasmer-go
MIT License
2.84k stars 161 forks source link

Can this compile to wasm? #275

Open AskAlice opened 3 years ago

AskAlice commented 3 years ago

Summary

I'm looking to import a ffmpeg wasm module and use it in combination with another go module moshpit, then compile that combination to webassembly.

Is that the right approach? Is this possible? Is there a way to do this with go's native webassembly library?

My first thought was to create an i/o layer in javascript to send commands to/from the ffmpeg and moshpit, but this seems tedious to create and not easily extensible unless I create an exec implementation that works with this i/o layer.

I also saw this in the go source https://go-review.googlesource.com/c/go/+/290112/

but it seems it's limited and I can't import modules.

This module seems like it could be useful, but I doubt it would compile to wasm.

How should I approach this?

Hywan commented 3 years ago

Hello,

Answering this kind of questions is out of the scope of this project, but let's give it a try because I'm curious!

So, ffmpeg.wasm is already a Wasm module, nothing to do on that side. moshpit is a Go project. To get a Wasm module, we need to compile Go to Wasm. The Wasm backend of the Go compiler produces a Wasm with the WASI ABI but only tailored for the Web, i.e. to be consumed by JavaScript. It's an issue if you want to use it with wasmer-go because we support WASI but not the WASI-ish ABI produced by Go. However, Tinygo can also be used to compile Go to Wasm with a correct WASI ABI. I therefore encourage you to use Tinygo.

Once you've both your modules, you've 2 ways to use them:

Both approaches sound good to me. To link multiple modules into a single one, I would recommend lld from LLVM. In the future, the Module Linking WebAssembly Proposal might be a thing, and then a third option will be availble to you.

After that, you can use wasmer-go to compile the Wasm modules, and then get instances from them.

How does it sound?

soulteary commented 3 years ago

Hi, @AskAlice .

Looking at this question again at the end of 2021, the answer has actually changed a bit. You can use tinygo and wasmer-go to solve this problem.

Regarding the solution, I submitted a simple demo, the code is very simple, so there is no need to describe too much: https://github.com/wasmerio/wasmer-go/pull/315

If you want to know more details, you can read this technical blog, but it needs to be translated because I use Chinese for content writing. https://soulteary.com/2021/11/21/use-docker-and-golang-to-quickly-get-started-with-webassembly.html

AskAlice commented 2 years ago

thanks for pointing me in the right direction, i appreciate it

AntonioND commented 1 year ago

@soulteary I've followed your instructions, but it looks like something has changed since you wrote your article.

main.go

package main

func main() {}

//export multiply
func multiply(a int, b int) int {
  return a * b
}
tinygo build --no-debug -o simple.wasm -target=wasi -scheduler=none main.go

When I try to run it with wasmer-go I get:

Missing import: `wasi_snapshot_preview1`.`fd_write`

This is what I get with tinygo version:

tinygo version 0.26.0 linux/amd64 (using go version go1.18.1 and LLVM version 14.0.0)
AntonioND commented 1 year ago

I think it's because of the comment in this article: https://wazero.io/languages/tinygo/

Why does my wasm import WASI functions even when I don’t use it?

TinyGo has a wasm target (for browsers) and a wasi target for runtimes that support WASI. This document is written only about the wasi target.

Some users are surprised to see imports from WASI (wasi_snapshot_preview1), when their neither has a main function nor uses memory. At least implementing panic requires writing to the console, and fd_write is used for this.

A bare or standalone WebAssembly target doesn’t yet exist, but if interested, you can follow this issue.

AntonioND commented 1 year ago

Ah, that was the tip I needed, I can build it now with this:

tinygo build --no-debug -o simple.wasm -target=wasi -panic=trap -scheduler=none main.go

By doing -panic=trap it stops requiring painc() to do something clever. It just traps execution instead.