Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ All WASI APIs are also implemented.

All tests from the "wasmer" lib C repository are also reimplemented on zig. You can learn more about the API of this module through rich examples.

The current module works with Zig 0.15.x.
The current module works with Zig 0.16.x.

## Wasmer C API test examples [WIP]

Expand Down
13 changes: 7 additions & 6 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const std = @import("std");

pub fn build(b: *std.Build) !void {
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

Expand All @@ -18,15 +18,16 @@ pub fn build(b: *std.Build) !void {
});

if (build_examples_option) {
var examples_dir = try std.fs.cwd().openDir("examples", .{ .iterate = true });
defer examples_dir.close();
var examples_dir = b.build_root.handle.openDir(b.graph.io, "examples", .{ .iterate = true }) catch
@panic("failed to open examples directory");
defer examples_dir.close(b.graph.io);

var examples_dir_iter = examples_dir.iterate();

while (try examples_dir_iter.next()) |entry| {
while (examples_dir_iter.next(b.graph.io) catch @panic("failed to iterate examples")) |entry| {
if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".zig")) {
const exe_name = entry.name[0 .. entry.name.len - 4];
const exe_path = try std.fmt.allocPrint(b.allocator, "examples/{s}", .{entry.name});
const exe_path = std.fmt.allocPrint(b.allocator, "examples/{s}", .{entry.name}) catch @panic("OOM");

const example_exe = b.addExecutable(.{
.name = exe_name,
Expand Down Expand Up @@ -95,7 +96,7 @@ pub fn build(b: *std.Build) !void {

/// Attempt to resolve the Wasmer `lib` path, inserting a fail step if the base path is unknown
fn wasmerLibPath(b: *std.Build, path: ?[]const u8, step: *std.Build.Step) []const u8 {
const dir = path orelse std.process.getEnvVarOwned(b.allocator, "WASMER_DIR") catch null;
const dir = path orelse b.graph.environ_map.get("WASMER_DIR");

const fail_message = "Wasmer location not set. Use wasmer-dir or set WASMER_DIR in env";
if (dir == null) step.dependOn(&b.addFail(fail_message).step);
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.fingerprint = 0xadae4aecca466a13,
.name = .wasmer_zig_api,
.version = "0.4.0",
.minimum_zig_version = "0.15.0",
.minimum_zig_version = "0.16.0",
.paths = .{
"build.zig",
"build.zig.zon",
Expand Down
13 changes: 3 additions & 10 deletions src/wasm.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
const std = @import("std");
const testing = std.testing;
const meta = std.meta;
const trait = std.meta.trait;
const log = std.log.scoped(.wasm_zig);

const c_callconv: std.builtin.CallingConvention = .c;

var CALLBACK: usize = undefined;

Expand Down Expand Up @@ -75,11 +72,7 @@ pub const Module = opaque {
var byte_vec = ByteVec.initWithCapacity(bytes.len);
defer byte_vec.deinit();

var ptr = byte_vec.data;
var i: usize = 0;
while (i < bytes.len) : (i += 1) {
ptr[i] = bytes[i];
}
@memcpy(byte_vec.data[0..bytes.len], bytes);

return wasm_module_new(store, &byte_vec) orelse return Error.ModuleInit;
}
Expand All @@ -100,7 +93,7 @@ pub const Module = opaque {
extern "c" fn wasm_module_exports(?*const Module, *ExportTypeVec) void;
};

fn cb(params: ?*const Valtype, results: ?*Valtype) callconv(c_callconv) ?*Trap {
fn cb(params: ?*const Valtype, results: ?*Valtype) callconv(.c) ?*Trap {
_ = params;
_ = results;
const func = @as(*const fn () void, @ptrFromInt(CALLBACK));
Expand Down Expand Up @@ -662,7 +655,7 @@ pub const ExportTypeVec = extern struct {
extern "c" fn wasm_exporttype_vec_delete(*ExportTypeVec) void;
};

pub const Callback = fn (?*const Valtype, ?*Valtype) callconv(c_callconv) ?*Trap;
pub const Callback = fn (?*const Valtype, ?*Valtype) callconv(.c) ?*Trap;

pub const ByteVec = extern struct {
size: usize,
Expand Down
40 changes: 9 additions & 31 deletions src/wasmer.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const std = @import("std");
const builtin = @import("builtin");
pub const wasm = @import("./wasm.zig");

pub const wasi = @import("./wasi.zig");
Expand All @@ -24,40 +23,19 @@ pub const Memory = wasm.Memory;
pub const MemoryType = wasm.MemoryType;
pub const Limits = wasm.Limits;

const OS_PATH_MAX: usize = switch (builtin.os.tag) {
.windows => std.os.windows.MAX_PATH,
.linux, .macos => std.os.linux.PATH_MAX,
else => std.math.maxInt(usize),
};

/// Detect Wasmer library directory
pub fn detectWasmerLibDir(allocator: std.mem.Allocator) !?[]const u8 {
const argv = [_][]const u8{ "wasmer", "config", "--libdir" };

// By default, child will inherit stdout & stderr from its parents,
// this usually means that child's output will be printed to terminal.
// Here we change them to pipe and collect into `ArrayList`.
var child = std.process.Child.init(&argv, allocator);
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
var stdout = std.ArrayListUnmanaged(u8){};
var stderr = std.ArrayListUnmanaged(u8){};
pub fn detectWasmerLibDir(allocator: std.mem.Allocator, io: std.Io) !?[]const u8 {
const result = std.process.run(allocator, io, .{
.argv = &.{ "wasmer", "config", "--libdir" },
}) catch return null;
defer {
stdout.deinit(allocator);
stderr.deinit(allocator);
allocator.free(result.stdout);
allocator.free(result.stderr);
}

try child.spawn();
try child.collectOutput(allocator, &stdout, &stderr, OS_PATH_MAX);

const term = try child.wait();

if (stderr.items.len != 0 or term.Exited != 0) return null;

const stdout_res = try stdout.toOwnedSlice(allocator);
defer allocator.free(stdout_res);
if (result.stderr.len != 0 or result.term != .exited or result.term.exited != 0) return null;

return try allocator.dupe(u8, std.mem.trimRight(u8, stdout_res, "\r\n"));
return try allocator.dupe(u8, std.mem.trimEnd(u8, result.stdout, "\r\n"));
}

pub fn setupTracing(verbosity_level: usize, use_colors: usize) void {
Expand Down Expand Up @@ -91,7 +69,7 @@ pub fn watToWasm(wat: []const u8) !ByteVec {
extern "c" fn wat2wasm(*const wasm.ByteVec, *wasm.ByteVec) void;

test "detect wasmer lib directory" {
const result = try detectWasmerLibDir(std.testing.allocator) orelse "";
const result = try detectWasmerLibDir(std.testing.allocator, std.testing.io) orelse "";
defer std.testing.allocator.free(result);

try std.testing.expectStringEndsWith(result, ".wasmer/lib");
Expand Down