从GO编译WASM导出函数

huangapple go评论76阅读模式
英文:

Export function from GO compiling WASM

问题

嗨,我想将一个GO文件编译成WASM,并从一个Node服务器上运行它。

index.html中,我有以下代码:

    <script src="./path_to/wasm_exec.js"></script>
    <script>
      const go = new Go();
        WebAssembly.instantiateStreaming(fetch("./path_to/file.wasm"), go.importObject).then((result) => {
          go.run(result.instance);
          console.log(result);
          console.log(go);
        });

我编译成WASM的GO文件如下所示:

package main

import (
	"fmt"
)

//export FuncName
func FuncName(M int, durations []int) int {
	fmt.Println("[GO] Log file.go", M, durations)
	return 10	
}


func main() {
	fmt.Println("HELLO GO")
}

我目前使用以下命令进行编译:

GOOS=js GOARCH=wasm go build -o path_to/file.wasm path_to/file.go

我想在Go文件外部和HTML内部使用FuncName函数,但我无法导出它。

我尝试使用tinygo,像这样:tinygo build -o path_to/file.wasm path_to/file.go,但它也没有起作用。

英文:

Hi I want to make a compile a GO file intro WASM and run in from a node server.

In the index.html i have this:

    &lt;script src=&quot;./path_to/wasm_exec.js&quot; &gt;&lt;/script&gt;
    &lt;script&gt;
      const go = new Go();
        WebAssembly.instantiateStreaming(fetch(&quot;./path_to/file.wasm&quot;), go.importObject).then((result) =&gt; {
          go.run(result.instance);
          console.log(result);
          console.log(go);
        });

The GO file I compile to WASM is like this one:

package main

import (
	&quot;fmt&quot;
)

//export FuncName
func FuncName(M int, durations []int) int {
	fmt.Println(&quot;[GO] Log file.go&quot;, M, durations)
	return 10	
}


func main() {
	fmt.Println(&quot;HELLO GO&quot;)
}

And I compile Im currently compiling using this:

GOOS=js GOARCH=wasm go build -o path_to/file.wasm path_to/file.go

I want to use the funtion FuncName outside the Go file, and inside the html but i can export it.

I tried using tinygo like this: `tinygo build -o path_to/file.wasm path_to/file.go``but it didint work neather

答案1

得分: 1

纯Go的方法是使用syscall/js包将函数挂载在JavaScript全局对象上(通常是windowglobal):

js.Global().Set("myexport", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    //stuff
})

为了使导出的函数始终在页面上可用,Go程序不应该退出。否则,在调用导出的函数时,您将收到以下JavaScript错误:

Uncaught Error: Go program has already exited

请参阅wasm: re-use //export mechanism for exporting identifiers within wasm modules和https://stackoverflow.com/questions/67978442/go-wasm-export-functions。

这是一个更新的演示,可以正常工作(使用GOOS=js GOARCH=wasm go build -o main.wasm编译):

main.go:

package main

import (
	"fmt"
	"syscall/js"
)

func FuncName(M int, durations []int) int {
	fmt.Println("[GO] Log file.go", M, durations)
	return 10
}

func main() {
	fmt.Println("Hello, WebAssembly!")

	// 将函数挂载在JavaScript全局对象上。
	js.Global().Set("FuncName", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		if len(args) != 2 {
			fmt.Println("invalid number of args")
			return nil
		}
		if args[0].Type() != js.TypeNumber {
			fmt.Println("the first argument should be a number")
			return nil
		}

		arg := args[1]
		if arg.Type() != js.TypeObject {
			fmt.Println("the second argument should be an array")
			return nil
		}

		durations := make([]int, arg.Length())
		for i := 0; i < len(durations); i++ {
			item := arg.Index(i)
			if item.Type() != js.TypeNumber {
				fmt.Printf("the item at index %d should be a number\n", i)
				return nil
			}
			durations[i] = item.Int()
		}

		// 调用实际的函数。
		return FuncName(args[0].Int(), durations)
	}))

	// 防止程序退出。
	// 注意:如果不再需要导出的函数,应该释放它,并在此之后让程序退出。
	// 为了简化这个演示,这一步被省略了。有关更多信息,请参阅https://pkg.go.dev/syscall/js#Func.Release。
	select {}
}

index.html:

<html>
  <head>
    <meta charset="utf-8" />
    <script src="wasm_exec.js"></script>
    <script>
      const go = new Go();
      WebAssembly.instantiateStreaming(
        fetch('main.wasm'),
        go.importObject
      ).then((result) => {
        go.run(result.instance);
      });
    </script>
  </head>
  <body>
    <button id="btn">Call FuncName</button>
    <script>
      document.getElementById('btn').addEventListener('click', () => {
        console.log(FuncName(1, [1, 2, 3, 4, 5]));
      });
    </script>
  </body>
</html>
英文:

The pure Go way is to mount the function on the JavaScript global object (usually window or global) with the syscall/js package:

js.Global().Set(&quot;myexport&quot;, js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    //stuff
})

And to make the exported function always available on the page, the Go program should not exit. Otherwise, you will get this JavaScript error when calling the exported function:

Uncaught Error: Go program has already exited

See also wasm: re-use //export mechanism for exporting identifiers within wasm modules and https://stackoverflow.com/questions/67978442/go-wasm-export-functions.

Here is updated demo that works (compiled with GOOS=js GOARCH=wasm go build -o main.wasm):

main.go:

package main

import (
	&quot;fmt&quot;
	&quot;syscall/js&quot;
)

func FuncName(M int, durations []int) int {
	fmt.Println(&quot;[GO] Log file.go&quot;, M, durations)
	return 10
}

func main() {
	fmt.Println(&quot;Hello, WebAssembly!&quot;)

	// Mount the function on the JavaScript global object.
	js.Global().Set(&quot;FuncName&quot;, js.FuncOf(func(this js.Value, args []js.Value) any {
		if len(args) != 2 {
			fmt.Println(&quot;invalid number of args&quot;)
			return nil
		}
		if args[0].Type() != js.TypeNumber {
			fmt.Println(&quot;the first argument should be a number&quot;)
			return nil
		}

		arg := args[1]
		if arg.Type() != js.TypeObject {
			fmt.Println(&quot;the second argument should be an array&quot;)
			return nil
		}

		durations := make([]int, arg.Length())
		for i := 0; i &lt; len(durations); i++ {
			item := arg.Index(i)
			if item.Type() != js.TypeNumber {
				fmt.Printf(&quot;the item at index %d should be a number\n&quot;, i)
				return nil
			}
			durations[i] = item.Int()
		}

		// Call the actual func.
		return FuncName(args[0].Int(), durations)
	}))

	// Prevent the program from exiting.
	// Note: the exported func should be released if you don&#39;t need it any more,
	// and let the program exit after then. To simplify this demo, this is
	// omitted. See https://pkg.go.dev/syscall/js#Func.Release for more information.
	select {}
}

index.html:

&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;script src=&quot;wasm_exec.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      const go = new Go();
      WebAssembly.instantiateStreaming(
        fetch(&#39;main.wasm&#39;),
        go.importObject
      ).then((result) =&gt; {
        go.run(result.instance);
      });
    &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;button id=&quot;btn&quot;&gt;Call FuncName&lt;/button&gt;
    &lt;script&gt;
      document.getElementById(&#39;btn&#39;).addEventListener(&#39;click&#39;, () =&gt; {
        console.log(FuncName(1, [1, 2, 3, 4, 5]));
      });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;

huangapple
  • 本文由 发表于 2023年4月23日 03:29:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76081551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定