diff --git a/README.md b/README.md index 2a52def..c3d9276 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,24 @@ Add zemscripten's "root" module to your wasm compile target., then create an `em b.getInstallStep().dependOn(emcc_step); ``` +To use a custom html file emccStep() accepts a shell_file_path option: +```zig + const emcc_step = @import("zemscripten").emccStep( + b, + wasm, + .{ + .optimize = optimize, + .flags = emcc_flags, + .settings = emcc_settings, + .use_preload_plugins = true, + .embed_paths = &.{}, + .preload_paths = &.{}, + .install_dir = .{ .custom = "web" }, + .shell_file_path = "path/to/file" + }, + ); +``` + Now you can use the provided Zig panic and log overrides in your wasm's root module and define the entry point that invoked by the js output of `emcc` (by default it looks for a symbol named `main`). For example: ```zig const std = @import("std"); @@ -85,3 +103,4 @@ You can also define a run step that invokes `emrun`. This will serve the html lo b.step("emrun", "Build and open the web app locally using emrun").dependOn(emrun_step); ``` See the [emrun documentation](https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html) for the difference args that can be used. + diff --git a/build.zig b/build.zig index a41c751..526aa86 100644 --- a/build.zig +++ b/build.zig @@ -3,7 +3,7 @@ const std = @import("std"); pub const emsdk_ver_major = "3"; pub const emsdk_ver_minor = "1"; -pub const emsdk_ver_tiny = "52"; +pub const emsdk_ver_tiny = "73"; pub const emsdk_version = emsdk_ver_major ++ "." ++ emsdk_ver_minor ++ "." ++ emsdk_ver_tiny; pub fn build(b: *std.Build) void { @@ -32,6 +32,13 @@ pub fn emrunPath(b: *std.Build) []const u8 { }) catch unreachable; } +pub fn htmlPath(b: *std.Build) []const u8 { + return std.fs.path.join(b.allocator, &.{ + b.dependency("emsdk", .{}).path("").getPath(b), + "upstream/emscripten/src/shell.html", + }) catch unreachable; +} + pub fn activateEmsdkStep(b: *std.Build) *std.Build.Step { const emsdk_script_path = std.fs.path.join(b.allocator, &.{ b.dependency("emsdk", .{}).path("").getPath(b), @@ -77,9 +84,14 @@ pub const EmccFlags = std.StringHashMap(void); pub fn emccDefaultFlags(allocator: std.mem.Allocator, optimize: std.builtin.OptimizeMode) EmccFlags { var args = EmccFlags.init(allocator); - if (optimize == .Debug) { - args.put("-Og", {}) catch unreachable; - args.put("-gsource-map", {}) catch unreachable; + switch (optimize) { + .Debug => { + args.put("-gsource-map", {}) catch unreachable; + }, + .ReleaseSmall, .ReleaseFast => { + args.put("-O3", {}) catch unreachable; + }, + else => {}, } return args; } diff --git a/src/zemscripten.zig b/src/zemscripten.zig index faa60e4..b864f34 100644 --- a/src/zemscripten.zig +++ b/src/zemscripten.zig @@ -6,10 +6,7 @@ comptime { _ = std.testing.refAllDeclsRecursive(@This()); } -extern fn emscripten_err([*c]const u8) void; -extern fn emscripten_console_error([*c]const u8) void; -extern fn emscripten_console_warn([*c]const u8) void; -extern fn emscripten_console_log([*c]const u8) void; +pub extern fn emscripten_sleep(ms: u32) void; pub const MainLoopCallback = *const fn () callconv(.C) void; extern fn emscripten_set_main_loop(MainLoopCallback, c_int, c_int) void; @@ -21,6 +18,123 @@ pub const AnimationFrameCallback = *const fn (f64, ?*anyopaque) callconv(.C) c_i extern fn emscripten_request_animation_frame_loop(AnimationFrameCallback, ?*anyopaque) void; pub const requestAnimationFrameLoop = emscripten_request_animation_frame_loop; +pub const EmscriptenResult = enum(i16) { + success = 0, + deferred = 1, + not_supported = -1, + failed_not_deferred = -2, + invalid_target = -3, + unknown_target = -4, + invalid_param = -5, + failed = -6, + no_data = -7, + timed_out = -8, +}; +pub const CanvasSizeChangedCallback = *const fn ( + i16, + *anyopaque, + ?*anyopaque, +) callconv(.C) c_int; +pub fn setResizeCallback( + cb: CanvasSizeChangedCallback, + use_capture: bool, + user_data: ?*anyopaque, +) EmscriptenResult { + const result = emscripten_set_resize_callback_on_thread( + "2", + user_data, + @intFromBool(use_capture), + cb, + 2, + ); + return @enumFromInt(result); +} +extern fn emscripten_set_resize_callback_on_thread( + [*:0]const u8, + ?*anyopaque, + c_int, + CanvasSizeChangedCallback, + c_int, +) c_int; + +pub fn getElementCssSize( + target_id: [:0]const u8, + width: *f64, + height: *f64, +) EmscriptenResult { + return @enumFromInt(emscripten_get_element_css_size( + target_id, + width, + height, + )); +} +extern fn emscripten_get_element_css_size([*:0]const u8, *f64, *f64) c_int; + +// EmmalocAllocator allocator +// use with linker flag -sMALLOC=emmalloc +// for details see docs: https://github.com/emscripten-core/emscripten/blob/main/system/lib/emmalloc.c +extern fn emmalloc_memalign(u32, u32) ?*anyopaque; +extern fn emmalloc_realloc_try(?*anyopaque, u32) ?*anyopaque; +extern fn emmalloc_free(?*anyopaque) void; +pub const EmmalocAllocator = struct { + const Self = @This(); + dummy: u32 = undefined, + + pub fn allocator(self: *Self) std.mem.Allocator { + return .{ + .ptr = self, + .vtable = &.{ + .alloc = &alloc, + .resize = &resize, + .free = &free, + }, + }; + } + + fn alloc( + ctx: *anyopaque, + len: usize, + ptr_align_log2: u8, + return_address: usize, + ) ?[*]u8 { + _ = ctx; + _ = return_address; + const ptr_align: u32 = @as(u32, 1) << @as(u5, @intCast(ptr_align_log2)); + if (!std.math.isPowerOfTwo(ptr_align)) unreachable; + const ptr = emmalloc_memalign(ptr_align, len) orelse return null; + return @ptrCast(ptr); + } + + fn resize( + ctx: *anyopaque, + buf: []u8, + buf_align_log2: u8, + new_len: usize, + return_address: usize, + ) bool { + _ = ctx; + _ = return_address; + _ = buf_align_log2; + return emmalloc_realloc_try(buf.ptr, new_len) != null; + } + + fn free( + ctx: *anyopaque, + buf: []u8, + buf_align_log2: u8, + return_address: usize, + ) void { + _ = ctx; + _ = buf_align_log2; + _ = return_address; + return emmalloc_free(buf.ptr); + } +}; + +extern fn emscripten_err([*c]const u8) void; +extern fn emscripten_console_error([*c]const u8) void; +extern fn emscripten_console_warn([*c]const u8) void; +extern fn emscripten_console_log([*c]const u8) void; /// std.panic impl pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { _ = error_return_trace;