Building WASM library with Zig
This is written for Zig 0.14.1.
For my chromahack project I've used zig to implement the language. To integrate this into an interactive web app I had to compile it to WASM.
Function Definition
The original function I wanted to export as WASM has this signature:
pub fn render_point(program: []const u8, t: f32, x: f32, y: f32) [3]f32
This was a problem as the WASM target does not support the types []const u8
and [3]f32
as function parameter/return type. Therefore I've created a new function (creatively called render_point_2
) to wrap my original implementation:
export fn render_point_2(program: [*]const u8, len: usize, t: f32, x: f32, y: f32, result: [*]f32) void {
const r = render_point(program[0..len], t, x, y);
result[0] = r[0];
result[1] = r[1];
result[2] = r[2];
}
The program is now passed as a pointer to an array + its length. The function no longer has a return value, but writes the result to a provided array address. The caller has to ensure that the array can store 3 floating point values.
Also note the export
keyword. I've missed this and spent an hour wondering why my WASM file had no exported function.
Building WASM
To build the WASM file you can either use the zig build-exe
command or integrate it into your build.zig
file.
The command zig build-exe src/root.zig -target wasm32-freestanding -fno-entry -rdynamic -OReleaseFast
will create the WASM file in your project folder.
To build the WASM file via zig build
add the following block to your builg.zig
file. This will create the file in zig-out/bin
. (based on this gist from trasstaloch )
const wasm = b.addExecutable(.{
.name = "lib",
.root_source_file = b.path("src/root.zig"),
.target = b.resolveTargetQuery(std.Target.Query.parse(
.{ .arch_os_abi = "wasm32-freestanding" },
) catch unreachable),
.optimize = optimize,
});
wasm.entry = .disabled;
wasm.rdynamic = true;
b.installArtifact(wasm);
It is also possible to copy further assets into the output directoy, such as your HTML and JavaScript files.
// copy web stuff
b.installBinFile("index.html", "index.html");
b.installBinFile("assets/favicon.png", "favicon.png");