Reputation: 30009
I have a Zig codebase that I'm compiling to WebAssembly with a build.zig like this:
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
const mode = b.standardReleaseOptions();
const lib = b.addSharedLibrary("main", "src/main.zig", b.version(0, 0, 0));
lib.setBuildMode(mode);
lib.setTarget(.{.cpu_arch = .wasm32, .os_tag = .freestanding});
lib.setOutputDir("web/dist");
b.default_step.dependOn(&lib.step);
}
Inside src/main.zig
there's an extern
that marks a function provided through the WebAssembly imports.
extern fn printString(message: [*]u8, length: usize) void;
This works fine when running in the browser, but I'm trying to add tests to the project, but whenever I attempt to run zig test
on main.zig
(or any file with extern
) I get the following linker error.
MachO Flush... error(link): undefined reference to symbol '_printString'
It might be worth pointing out that nothing in my test "..." {}
blocks actually touches any of these extern
functions.
Is there a sane way to link to alternate implementations of these externs during tests? Or any other workarounds that would allow me to write tests?
Upvotes: 0
Views: 689
Reputation: 30009
You can use combine @import("builtin").is_test
and usingnamespace
to create stubs for extern functions during tests.
const builtin = @import("builtin");
pub usingnamespace if (!builtin.is_test) struct {
pub extern fn printString(message: [*]u8, length: usize) void;
} else struct {
pub fn printString(message: [*]u8, length: usize) void {
_ = message;
_ = length;
}
}
pub usingnamespace
makes all the members of the struct part of the module's public struct, and during tests we just use a different struct that doesn't rely on any external functions.
Credit to mitchellh/zig-js.
Upvotes: 0