[Go] WASM ๋นŒ๋“œํ•˜๊ธฐ

go๋Š” wasm์„ ๊ทธ๋Ÿญ์ €๋Ÿญ ์ง€์›ํ•˜๋Š” ํŽธ์ด๋‹ค.
์„ฑ๋Šฅ์ด ํŠน์ถœ๋‚˜๊ฑฐ๋‚˜ ์ง€์› ์ˆ˜์ค€์ด ์—„์ฒญ ์ข‹์€๊ฑด ์•„๋‹Œ๋ฐ, ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ตฌํ˜„ํ•˜๊ธฐ ๋‚œ๊ฐํ•œ ๊ฒƒ๋“ค์„ ๋Œ€ํ–‰ํ• ๋•Œ ๊ฐ€๋”์€ ์“ธ๋งŒํ•  ๊ฒƒ์ด๋‹ค.

์™ธ๋ถ€ ์ข…์†์„ฑ์ด ๋”ฐ๋กœ ํ•„์š”ํ•˜์ง„ ์•Š๋‹ค.




js ๋ณธ๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ

wasm์˜ ํ•œ๊ณ„์ƒ, ๋…๋ฆฝ์ ์œผ๋กœ๋Š” ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  js๋ฅผ ๊ฑฐ์ณ์„œ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
์•„๋ž˜์™€ ๊ฐ™์€ ํŠน์ˆ˜ํ•œ ๊ฒฝ๋กœ์— ์ค€๋น„๋˜์–ด์žˆ๋Š” wasm ๋ณธ๋“œ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๊ฑธ ๋ณต์‚ฌํ•ด์„œ ๊ฐ€์ ธ์˜จ๋‹ค.

cp $(go env GOROOT)/misc/wasm/wasm_exec.js .

๋‚ด์šฉ์€ ์ด๋Ÿฐ๋ฐ, ๊ตณ์ด ๋ณผ ํ•„์š”๋Š” ์—†๋‹ค. ๊ณ ์น ์ผ๋„ ์—†๊ณ 




Go ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

์ด์ œ wasm์„ ์ƒ์„ฑํ•  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ฒ ๋‹ค.
๊ฐ„๋‹จํ•˜๊ฒŒ ๋ง์…ˆ ํ•จ์ˆ˜๋งŒ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ด์„œ ๋Œ๋ ค๋ณด๋ ค ํ•œ๋‹ค.

์šฐ์„  syscall/js๋ผ๋Š” ๊ธฐ๋ณธ ํŒจํ‚ค์ง€๋ฅผ importํ•œ๋‹ค.
์ด๊ฑด ํŠน์ • ํƒ€๊ฒŸ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ˆ˜ ํŒจํ‚ค์ง€๋‹ค. ๋นจ๊ฐ„์ค„์€ ๊ทธ๋ž˜์„œ ๋œจ๋Š”๊ฑฐ๋‹ค.

๊ทธ๋ฆฌ๊ณ  js์—์„œ ์‚ฌ์šฉํ•  ๋ง์…ˆ ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์คฌ๋‹ค.

js์— ๋‚ด๋ณด๋‚ผ ํ•จ์ˆ˜๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜ ์‹œ๊ทธ๋„ˆ์ฒ˜๋ฅผ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.
์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ํ•จ์ˆ˜ ์ž์ฒด์˜ this ์ปจํ…์ŠคํŠธ๊ณ , ๋‚˜๋จธ์ง€๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋‹ค.
์—ฌ๊ธฐ์„œ๋Š” Int๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค์Œ์— ๋ง์…ˆ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋ฐ˜ํ™˜ํ•ด์ฃผ๋„๋ก ํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ € ํ•จ์ˆ˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ js ์ „์—ญ ์ƒํƒœ์— ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

main ํ•จ์ˆ˜๋งŒ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋์ด๋‹ค.

์—ฌ๊ธฐ์„œ ์ดˆ๊ธฐํ™” ๊ด€๋ จ ๋กœ์ง๋“ค์„ ํ• ๋‹นํ•  ์ˆ˜๋„ ์žˆ๊ณ , ํ•จ์ˆ˜ ๋“ฑ๋ก๋„ ์—ฌ๊ธฐ์„œ ํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ด main ํ•จ์ˆ˜๋Š” ์ข…๋ฃŒ๋˜์ง€ ์•Š์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฑ„๋„๋กœ ๋ธ”๋ฝ์„ ๊ฑธ์–ด์ค€๋‹ค.

main์ด ๋๋‚˜๋ฉด ์—ฌ๊ธฐ์„œ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๊ฐ€ ์—†๋”๋ผ. IPC ์Šคํƒ€์ผ์ธ๊ฑฐ๊ฐ™๋‹ค.

์ „์ฒด ์ฝ”๋“œ๋‹ค.

// main.go
package main

import (
	"log"
	"syscall/js"
)

//export add
func add(this js.Value, args []js.Value) any {
	result := args[0].Int() + args[1].Int()
	return js.ValueOf(result)
}

func registerCallbacks() {
	js.Global().Set("add", js.FuncOf(add))
}

func main() {
	waiter := make(chan struct{}, 0)

	println("Hello, WASM!")
	log.Println("WASM Go Initialized")
	registerCallbacks()

	<-waiter
}



html๊ณผ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

์šฐ์„  wasm ๋นŒ๋“œ๋ฅผ ํ•œ๋‹ค.
์ด๋Ÿฐ์‹์œผ๋กœ ์˜ต์…˜์„ ์ฃผ๋ฉด ๋œ๋‹ค.

GOOS=js GOARCH=wasm go build -o static/main.wasm cmd/main.go

๊ฒฐ๊ณผ๋ฌผ๋“ค์„ ํ•œ๊ณณ์— ๋ชฐ์•„๋„ฃ๊ณ 

๊ฐ„๋‹จํ•œ ์ •์ ์„œ๋ฒ„ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ 

const express = require("express");
const path = require("path");

const app = express();
const port = 8000;
const root = path.join(__dirname, "static");

app.get("*", (req, res) => {
  const filePath = path.join(root, req.url);
  res.sendFile(filePath, (err) => {
    if (err) {
      res.status(404).send("Not Found");
    }
  });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

๋ธŒ๋ผ์šฐ์ € ์ฝ”๋“œ๋Š” ์ด๋ž˜ ์งฐ๋‹ค.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Go+Wasm</title>

  <script src="wasm_exec.js"></script>
  <script>
    const go = new Go();
    WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
            .then((wasmModule) => {
              // ์›น ์–ด์…ˆ๋ธ”๋ฆฌ ๋กœ๋”ฉ
              go.run(wasmModule.instance);

              // ์›น ์–ด์…ˆ๋ธ”๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” add ํ•จ์ˆ˜ ํ˜ธ์ถœ
              console.log(wasmModule.instance.exports);
            });
  </script>
</head>
<body></body>
</html>

js ๋ณธ๋“œ importํ•œ ๋‹ค์Œ์— ์ €๋Ÿฐ ์‹์œผ๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•ด๋ณด๋ฉด

์ด๋Ÿฐ์‹์œผ๋กœ ๊ฐ–๋‹ค์“ธ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.



์ฐธ์กฐ
https://golangbot.com/webassembly-using-go/