diff --git a/build.zig b/build.zig
index 21e88be8..8500f88d 100644
--- a/build.zig
+++ b/build.zig
@@ -10,8 +10,7 @@ const earcut = @import("libs/earcut/build.zig");
const gamemode = @import("libs/gamemode/build.zig");
const model3d = @import("libs/model3d/build.zig");
const dusk = @import("libs/dusk/build.zig");
-// TODO: get wasmserve working
-// const wasmserve = @import("tools/wasmserve/wasmserve.zig");
+const wasmserve = @import("tools/wasmserve/wasmserve.zig");
pub const gpu_dawn = @import("libs/gpu-dawn/sdk.zig").Sdk(.{
.glfw_include_dir = sdkPath("/libs/glfw/upstream/glfw/include"),
.system_sdk = system_sdk,
@@ -28,8 +27,7 @@ const core = @import("libs/core/sdk.zig").Sdk(.{
.gpu_dawn = gpu_dawn,
.glfw = glfw,
.gamemode = gamemode,
- // TODO: get wasmserve working
- // .wasmserve = wasmserve,
+ .wasmserve = wasmserve,
.sysjs = sysjs,
});
diff --git a/libs/core/sdk.zig b/libs/core/sdk.zig
index 39636be6..2f1b6636 100644
--- a/libs/core/sdk.zig
+++ b/libs/core/sdk.zig
@@ -91,7 +91,7 @@ pub fn Sdk(comptime deps: anytype) type {
pub const LinkError = deps.glfw.LinkError;
pub const RunError = error{
ParsingIpFailed,
- } || std.fmt.ParseIntError;
+ } || deps.wasmserve.Error || std.fmt.ParseIntError;
pub const Platform = enum {
native,
@@ -129,7 +129,12 @@ pub fn Sdk(comptime deps: anytype) type {
const step = blk: {
if (platform == .web) {
- const lib = b.addSharedLibrary(.{ .name = options.name, .root_source_file = .{ .path = sdkPath("/src/main.zig") }, .target = options.target, .optimize = options.optimize });
+ const lib = b.addSharedLibrary(.{
+ .name = options.name,
+ .root_source_file = .{ .path = sdkPath("/src/entry.zig") },
+ .target = options.target,
+ .optimize = options.optimize,
+ });
lib.rdynamic = true;
lib.addModule("sysjs", deps.sysjs.module(b));
@@ -182,7 +187,7 @@ pub fn Sdk(comptime deps: anytype) type {
// Set install directory to '{prefix}/www'
app.getInstallStep().?.dest_dir = web_install_dir;
- inline for (.{ "/src/platform/wasm/mach.js", "/libs/sysjs/src/mach-sysjs.js" }) |js| {
+ inline for (.{ "/src/platform/wasm/mach.js", "/libs/mach-sysjs/src/mach-sysjs.js" }) |js| {
const install_js = app.b.addInstallFileWithDir(
.{ .path = sdkPath(js) },
web_install_dir,
@@ -191,15 +196,9 @@ pub fn Sdk(comptime deps: anytype) type {
app.getInstallStep().?.step.dependOn(&install_js.step);
}
- const html_generator = app.b.addExecutable(.{
- .name = "html-generator",
- .root_source_file = .{ .path = sdkPath("/tools/html-generator/main.zig") },
- });
- const run_html_generator = html_generator.run();
- run_html_generator.addArgs(&.{ "index.html", app.name });
-
- run_html_generator.cwd = app.b.getInstallPath(web_install_dir, "");
- app.getInstallStep().?.step.dependOn(&run_html_generator.step);
+ genHtml(app.b.allocator, app.b.getInstallPath(web_install_dir, "index.html"), app.name) catch |err| {
+ std.log.err("unable to generate html: {s}", .{@errorName(err)});
+ };
}
// Install resources
@@ -218,20 +217,19 @@ pub fn Sdk(comptime deps: anytype) type {
pub fn run(app: *const App) RunError!*std.build.Step {
if (app.platform == .web) {
- @panic("TODO: wasmserve is broken! sorry");
- // TODO: get wasmserve working
- // const address = std.process.getEnvVarOwned(app.b.allocator, "MACH_ADDRESS") catch try app.b.allocator.dupe(u8, "127.0.0.1");
- // const port = std.process.getEnvVarOwned(app.b.allocator, "MACH_PORT") catch try app.b.allocator.dupe(u8, "8080");
- // const address_parsed = std.net.Address.parseIp4(address, try std.fmt.parseInt(u16, port, 10)) catch return error.ParsingIpFailed;
- // const serve_step = try deps.wasmserve.serve(
- // app.step,
- // .{
- // .install_dir = web_install_dir,
- // .watch_paths = app.watch_paths,
- // .listen_address = address_parsed,
- // },
- // );
- // return &serve_step.step;
+ const address = std.process.getEnvVarOwned(app.b.allocator, "MACH_ADDRESS") catch try app.b.allocator.dupe(u8, "127.0.0.1");
+ const port = std.process.getEnvVarOwned(app.b.allocator, "MACH_PORT") catch try app.b.allocator.dupe(u8, "8080");
+ const address_parsed = std.net.Address.parseIp4(address, try std.fmt.parseInt(u16, port, 10)) catch return error.ParsingIpFailed;
+ const serve_step = try deps.wasmserve.serve(
+ app.b,
+ .{
+ // .step_name =
+ .install_dir = web_install_dir,
+ .watch_paths = app.watch_paths,
+ .listen_address = address_parsed,
+ },
+ );
+ return &serve_step.step;
} else {
return &app.step.run().step;
}
@@ -241,5 +239,72 @@ pub fn Sdk(comptime deps: anytype) type {
return app.step.install_step;
}
};
+
+ pub fn genHtml(allocator: std.mem.Allocator, output_name: []const u8, app_name: []const u8) !void {
+ const file = try std.fs.cwd().createFile(output_name, .{});
+ defer file.close();
+
+ var buf = try std.fmt.allocPrint(allocator, html_template, .{ .app_name = app_name });
+ defer allocator.free(buf);
+
+ _ = try file.write(buf);
+ }
+
+ const html_template =
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\ {[app_name]s}
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ ;
};
}
diff --git a/tools/html-generator/main.zig b/tools/html-generator/main.zig
deleted file mode 100644
index 9dcba5dd..00000000
--- a/tools/html-generator/main.zig
+++ /dev/null
@@ -1,29 +0,0 @@
-const std = @import("std");
-
-const source = @embedFile("template.html");
-const app_name_needle = "{ app_name }";
-
-pub fn main() !void {
- var gpa = std.heap.GeneralPurposeAllocator(.{}){};
- const allocator = gpa.allocator();
- defer _ = gpa.deinit();
-
- const args = try std.process.argsAlloc(allocator);
- defer std.process.argsFree(allocator, args);
-
- if (args.len < 3) {
- std.debug.print("Usage: html-generator \n", .{});
- return;
- }
-
- const output_name = args[1];
- const app_name = args[2];
-
- const file = try std.fs.cwd().createFile(output_name, .{});
- defer file.close();
- var buf = try allocator.alloc(u8, std.mem.replacementSize(u8, source, app_name_needle, app_name));
- defer allocator.free(buf);
-
- _ = std.mem.replace(u8, source, app_name_needle, app_name, buf);
- _ = try file.write(buf);
-}
diff --git a/tools/html-generator/template.html b/tools/html-generator/template.html
deleted file mode 100644
index 3a34470d..00000000
--- a/tools/html-generator/template.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- { app_name }
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tools/wasmserve/wasmserve.zig b/tools/wasmserve/wasmserve.zig
index 3e0b81fc..6e0a5c10 100644
--- a/tools/wasmserve/wasmserve.zig
+++ b/tools/wasmserve/wasmserve.zig
@@ -19,6 +19,7 @@ const esc = struct {
};
pub const Options = struct {
+ step_name: []const u8 = "install",
install_dir: ?build.InstallDir = null,
watch_paths: ?[]const []const u8 = null,
listen_address: ?net.Address = null,
@@ -26,30 +27,30 @@ pub const Options = struct {
pub const Error = error{CannotOpenDirectory} || mem.Allocator.Error;
-pub fn serve(step: *build.CompileStep, options: Options) Error!*Wasmserve {
- const self = try step.step.owner.allocator.create(Wasmserve);
+pub fn serve(b: *std.Build.Builder, options: Options) Error!*Wasmserve {
+ const self = try b.allocator.create(Wasmserve);
const install_dir = options.install_dir orelse build.InstallDir{ .lib = {} };
- const install_dir_iter = fs.cwd().makeOpenPathIterable(step.step.owner.getInstallPath(install_dir, ""), .{}) catch
+ const install_dir_iter = fs.cwd().makeOpenPathIterable(b.getInstallPath(install_dir, ""), .{}) catch
return error.CannotOpenDirectory;
self.* = Wasmserve{
- .step = build.Step.init(.run, "wasmserve", step.step.owner.allocator, Wasmserve.make),
- .b = step.step.owner,
- .exe_step = step,
+ .b = b,
+ .step = build.Step.init(.{ .id = .run, .name = "wasmserve", .owner = b, .makeFn = Wasmserve.make }),
+ .step_name = options.step_name,
.install_dir = install_dir,
.install_dir_iter = install_dir_iter,
.address = options.listen_address orelse net.Address.initIp4([4]u8{ 127, 0, 0, 1 }, 8080),
.subscriber = null,
- .watch_paths = options.watch_paths orelse &.{step.root_src.?.path},
- .mtimes = std.AutoHashMap(fs.File.INode, i128).init(step.step.owner.allocator),
+ .watch_paths = options.watch_paths orelse &.{"src"},
+ .mtimes = std.AutoHashMap(fs.File.INode, i128).init(b.allocator),
.notify_msg = null,
};
return self;
}
const Wasmserve = struct {
- step: build.Step,
b: *build.Builder,
- exe_step: *build.CompileStep,
+ step: build.Step,
+ step_name: []const u8,
install_dir: build.InstallDir,
install_dir_iter: fs.IterableDir,
address: net.Address,
@@ -69,11 +70,13 @@ const Wasmserve = struct {
data: []const u8,
};
- pub fn make(step: *build.Step) !void {
+ pub fn make(step: *build.Step, prog_node: *std.Progress.Node) !void {
+ std.debug.print("Really!\n", .{});
+
const self = @fieldParentPtr(Wasmserve, "step", step);
- self.compile();
- std.debug.assert(mem.eql(u8, fs.path.extension(self.exe_step.out_filename), ".wasm"));
+ try self.compile();
+ // std.debug.assert(mem.eql(u8, fs.path.extension(self.compile_step.out_filename), ".wasm"));
var www_dir = try fs.cwd().openIterableDir(www_dir_path, .{});
defer www_dir.close();
@@ -86,7 +89,7 @@ const Wasmserve = struct {
self.install_dir,
file.name,
);
- try install_www.step.make();
+ try install_www.step.make(prog_node);
}
const watch_thread = try std.Thread.spawn(.{}, watch, .{self});
@@ -134,7 +137,12 @@ const Wasmserve = struct {
const url = dropFragment(uri)[1..];
if (mem.eql(u8, url, "notify")) {
- _ = try conn.stream.write("HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: text/event-stream\r\nCache-Control: No-Cache\r\n\r\n");
+ _ = try conn.stream.write(
+ "HTTP/1.1 200 OK\r\n" ++
+ "Connection: Keep-Alive\r\n" ++
+ "Content-Type: text/event-stream\r\n" ++
+ "Cache-Control: No-Cache\r\n\r\n",
+ );
self.subscriber = try self.b.allocator.create(net.StreamServer.Connection);
self.subscriber.?.* = conn;
if (self.notify_msg) |msg|
@@ -232,7 +240,7 @@ const Wasmserve = struct {
const entry = try self.mtimes.getOrPut(stat.inode);
if (entry.found_existing and stat.mtime > entry.value_ptr.*) {
std.log.info(esc.yellow ++ esc.underline ++ "{s}" ++ esc.reset ++ " updated", .{path});
- self.compile();
+ try self.compile();
entry.value_ptr.* = stat.mtime;
return true;
}
@@ -253,14 +261,10 @@ const Wasmserve = struct {
}
}
- fn compile(self: *Wasmserve) void {
+ fn compile(self: *Wasmserve) !void {
std.log.info("Building...", .{});
- const argv = getExecArgs(self.exe_step) catch |err| {
- logErr(err, @src());
- return;
- };
- defer self.b.allocator.free(argv);
- var res = std.ChildProcess.exec(.{ .argv = argv, .allocator = self.b.allocator }) catch |err| {
+
+ var res = std.ChildProcess.exec(.{ .argv = &.{ self.b.zig_exe, "build", self.step_name, "-Dtarget=wasm32-freestanding-none" }, .allocator = self.b.allocator }) catch |err| {
logErr(err, @src());
return;
};
@@ -307,8 +311,8 @@ fn dropFragment(input: []const u8) []const u8 {
}
fn logErr(err: anyerror, src: std.builtin.SourceLocation) void {
- if (@errorReturnTrace()) |bt| {
- std.log.err(esc.red ++ esc.bold ++ "{s}" ++ esc.reset ++ " >>>\n{s}", .{ @errorName(err), bt });
+ if (@errorReturnTrace()) |et| {
+ std.log.err(esc.red ++ esc.bold ++ "{s}" ++ esc.reset ++ " >>>\n{s}", .{ @errorName(err), et });
} else {
var file_name_buf: [1024]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&file_name_buf);
@@ -333,28 +337,3 @@ fn sdkPath(comptime suffix: []const u8) []const u8 {
break :blk root_dir ++ suffix;
};
}
-
-// copied from CompileStep.make()
-// TODO: this is very tricky
-// TODO(wasmserve): wasmserve is broken after recent Zig build changes, need to expose
-// this from Zig stdlib or something instead of copying this huge function out of stdlib
-// like this (nasty!)
-fn getExecArgs(_: *build.CompileStep) ![]const []const u8 {
- @panic("wasmserve is currently not working");
-}
-
-fn makePackageCmd(self: *std.build.CompileStep, pkg: std.build.Pkg, zig_args: *std.ArrayList([]const u8)) error{OutOfMemory}!void {
- const builder = self.builder;
-
- try zig_args.append("--pkg-begin");
- try zig_args.append(pkg.name);
- try zig_args.append(builder.pathFromRoot(pkg.source.getPath(self.builder)));
-
- if (pkg.dependencies) |dependencies| {
- for (dependencies) |sub_pkg| {
- try makePackageCmd(self, sub_pkg, zig_args);
- }
- }
-
- try zig_args.append("--pkg-end");
-}