export CGO_ENABLED=1; export CC=gcc; go install github.com/wasmerio/go-ext-wasm/wasmer
import "github.com/wasmerio/go-ext-wasm/wasmer"
construction is used import "github.com/wasmerio/go-ext-wasm/wasmer"
.
#[no_mangle] pub extern fn sum(x: i32, y: i32) -> i32 { x + y }
simple.rs
, as a result of the compilation of this program, the file simple.wasm is obtained .
sum
from a wasm file, passing in the form of arguments the numbers 5 and 37:
package main import ( "fmt" wasm "github.com/wasmerio/go-ext-wasm/wasmer" ) func main() { // WebAssembly. bytes, _ := wasm.ReadBytes("simple.wasm") // WebAssembly. instance, _ := wasm.NewInstance(bytes) defer instance.Close() // `sum` WebAssembly. sum := instance.Exports["sum"] // Go. // , , . result, _ := sum(5, 37) fmt.Println(result) // 42! }
extern { fn sum(x: i32, y: i32) -> i32; } #[no_mangle] pub extern fn add1(x: i32, y: i32) -> i32 { unsafe { sum(x, y) } + 1 }
import.rs
file with it import.rs
. As a result of its compilation in WebAssembly, you get code that can be found here .
add1
calls the function sum
. There is no implementation of this function, only its signature is defined in the file. This is the so-called extern-function. For WebAssembly, this is an imported function. Its implementation must be imported.
sum
function using Go. For this we need to use cgo . Here is the resulting code. Some comments, which are descriptions of the main code fragments, are numbered. Below we talk about them in more detail.
package main // // 1. `sum` ( cgo). // // #include <stdlib.h> // // extern int32_t sum(void *context, int32_t x, int32_t y); import "C" import ( "fmt" wasm "github.com/wasmerio/go-ext-wasm/wasmer" "unsafe" ) // 2. `sum` ( cgo). //export sum func sum(context unsafe.Pointer, x int32, y int32) int32 { return x + y } func main() { // WebAssembly. bytes, _ := wasm.ReadBytes("import.wasm") // 3. WebAssembly. imports, _ := wasm.NewImports().Append("sum", sum, C.sum) // 4. WebAssembly . instance, _ := wasm.NewInstanceWithImports(bytes, imports) // WebAssembly. defer instance.Close() // `add1` WebAssembly. add1 := instance.Exports["add1"] // . result, _ := add1(1, 2) fmt.Println(result) // add1(1, 2) // = sum(1 + 2) + 1 // = 1 + 2 + 1 // = 4 // QED }
sum
function is defined in C (see the comment above the import "C"
command).sum
function is defined in Go (note the //export
line — such a mechanism cgo uses to link the code written in Go to the code written in C).NewImports
is the API used to create WebAssembly imports. In this code, "sum"
is the name of the function imported by WebAssembly, sum
is the pointer to the Go function, and C.sum
is the pointer to the cgo function.NewInstanceWithImports
is a constructor designed to initialize the module WebAssembly with imports.memory.rs
.
#[no_mangle] pub extern fn return_hello() -> *const u8 { b"Hello, World!\0".as_ptr() }
memory.wasm
file, which is used below.
return_hello
function returns a pointer to a string. The line ends, as in C, with a null character.
bytes, _ := wasm.ReadBytes("memory.wasm") instance, _ := wasm.NewInstance(bytes) defer instance.Close() // `return_hello`. // . result, _ := instance.Exports["return_hello"]() // . pointer := result.ToI32() // . memory := instance.Memory.Data() fmt.Println(string(memory[pointer : pointer+13])) // Hello, World!
return_hello
function returns a pointer as an i32
value. We get this value by calling ToI32
. Then we retrieve the data from memory using instance.Memory.Data()
.
memory[pointer : pointer+13]
. Then the read data is converted to a string.
Source: https://habr.com/ru/post/454518/