Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active November 28, 2023 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterhellberg/6593423646b7c7094a02ca931d34341e to your computer and use it in GitHub Desktop.
Save peterhellberg/6593423646b7c7094a02ca931d34341e to your computer and use it in GitHub Desktop.
Compiling Zig to WASI, then calling it from Go using Wazero (https://ziglang.org, https://go.dev, https://wazero.io)
zig-cache
bin
const std = @import("std");
export fn add(a: i64, b: i64) i64 {
return a + b;
}
test "add 1+2=3" {
try std.testing.expectEqual(add(1, 2), 3);
}
test "add 4+5=9" {
try std.testing.expectEqual(add(4, 5), 9);
}
const std = @import("std");
pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.single_threaded = true,
.name = "add",
.root_source_file = .{ .path = "add.zig" },
.target = .{ .cpu_arch = .wasm32, .os_tag = .wasi },
.optimize = .ReleaseSmall,
});
exe.entry = .disabled;
exe.export_table = true;
exe.export_symbol_names = &[_][]const u8{"add"};
b.installArtifact(exe);
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "add.zig" },
.target = .{ .cpu_arch = .wasm32, .os_tag = .wasi },
.optimize = .ReleaseSmall,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
}
module experiments/gists/go-zig-wasm-add
go 1.21.4
require github.com/tetratelabs/wazero v1.5.0
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
package main
import (
"context"
"flag"
"fmt"
"log"
"strconv"
_ "embed"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)
//go:generate zig build -p . --cache-dir /tmp/go-zig-wasm-add
// addWasm was generated by the following:
//
// go generate
//
// Run the Zig tests like this:
//
// zig build test -fwasmtime
//
//go:embed bin/add.wasm
var addWasm []byte
func main() {
flag.Parse()
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
wasi_snapshot_preview1.MustInstantiate(ctx, r)
mod, err := r.Instantiate(ctx, addWasm)
if err != nil {
log.Panicf("failed to instantiate module: %v", err)
}
x, y, err := readTwoArgs(flag.Arg(0), flag.Arg(1))
if err != nil {
log.Panicf("failed to read arguments: %v", err)
}
add := mod.ExportedFunction("add")
results, err := add.Call(ctx, uint64(x), uint64(y))
if err != nil {
log.Panicf("failed to call add: %v", err)
}
fmt.Printf("%d + %d = %d\n", x, y, int64(results[0]))
}
func readTwoArgs(xs, ys string) (int64, int64, error) {
if xs == "" || ys == "" {
return 0, 0, fmt.Errorf("must specify two command line arguments")
}
x, err := strconv.ParseInt(xs, 10, 64)
if err != nil {
return 0, 0, fmt.Errorf("argument X: %v", err)
}
y, err := strconv.ParseInt(ys, 10, 64)
if err != nil {
return 0, 0, fmt.Errorf("argument Y: %v", err)
}
return x, y, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment