WebAssembly

Zig supports building for WebAssembly out of the box.

Freestanding

For host environments like the web browser and nodejs, build as a dynamic library using the freestanding OS target. Here’s an example of running Zig code compiled to WebAssembly with nodejs.

math.zig

  1. extern fn print(i32) void;
  2. export fn add(a: i32, b: i32) void {
  3. print(a + b);
  4. }

Shell

  1. $ zig build-lib math.zig -target wasm32-freestanding -dynamic -rdynamic

test.js

  1. const fs = require('fs');
  2. const source = fs.readFileSync("./math.wasm");
  3. const typedArray = new Uint8Array(source);
  4. WebAssembly.instantiate(typedArray, {
  5. env: {
  6. print: (result) => { console.log(`The result is ${result}`); }
  7. }}).then(result => {
  8. const add = result.instance.exports.add;
  9. add(1, 2);
  10. });

Shell

  1. $ node test.js
  2. The result is 3

WASI

Zig’s support for WebAssembly System Interface (WASI) is under active development. Example of using the standard library and reading command line arguments:

wasi_args.zig

  1. const std = @import("std");
  2. pub fn main() !void {
  3. var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
  4. const gpa = general_purpose_allocator.allocator();
  5. const args = try std.process.argsAlloc(gpa);
  6. defer std.process.argsFree(gpa, args);
  7. for (args, 0..) |arg, i| {
  8. std.debug.print("{}: {s}\n", .{ i, arg });
  9. }
  10. }

Shell

  1. $ zig build-exe wasi_args.zig -target wasm32-wasi

Shell

  1. $ wasmtime wasi_args.wasm 123 hello
  2. 0: wasi_args.wasm
  3. 1: 123
  4. 2: hello

A more interesting example would be extracting the list of preopens from the runtime. This is now supported in the standard library via std.fs.wasi.PreopenList:

wasi_preopens.zig

  1. const std = @import("std");
  2. const fs = std.fs;
  3. pub fn main() !void {
  4. var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
  5. const gpa = general_purpose_allocator.allocator();
  6. var arena_instance = std.heap.ArenaAllocator.init(gpa);
  7. defer arena_instance.deinit();
  8. const arena = arena_instance.allocator();
  9. const preopens = try fs.wasi.preopensAlloc(arena);
  10. for (preopens.names, 0..) |preopen, i| {
  11. std.debug.print("{}: {s}\n", .{ i, preopen });
  12. }
  13. }

Shell

  1. $ zig build-exe wasi_preopens.zig -target wasm32-wasi

Shell

  1. $ wasmtime --dir=. wasi_preopens.wasm
  2. 0: stdin
  3. 1: stdout
  4. 2: stderr
  5. 3: .