Gitignore zig crap
This commit is contained in:
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 zig-gamedev contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,105 @@
|
||||
# [zemscripten](https://github.com/zig-gamedev/zemscripten)
|
||||
|
||||
Zig build package and shims for [Emscripten](https://emscripten.org) emsdk
|
||||
|
||||
## How to use it
|
||||
|
||||
Add `zemscripten` and (optionally) `emsdk` to your build.zig.zon dependencies
|
||||
```sh
|
||||
zig fetch --save https://github.com/emscripten-core/emsdk/archive/refs/tags/4.0.3.tar.gz
|
||||
```
|
||||
|
||||
Emsdk must be activated before it can be used. You can use `activateEmsdkStep` to create a build step for that:
|
||||
```zig
|
||||
const activate_emsdk_step = @import("zemscripten").activateEmsdkStep(b);
|
||||
```
|
||||
|
||||
Add zemscripten's "root" module to your wasm compile target., then create an `emcc` build step. We use zemscripten's default flags and settings which can be overridden for your project specific requirements. Refer to the [emcc documentation](https://emscripten.org/docs/tools_reference/emcc.html). Example build.zig code:
|
||||
```zig
|
||||
const wasm = b.addStaticLibrary(.{
|
||||
.name = "MyGame",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const zemscripten = b.dependency("zemscripten", .{});
|
||||
wasm.root_module.addImport("zemscripten", zemscripten.module("root"));
|
||||
|
||||
const emcc_flags = @import("zemscripten").emccDefaultFlags(b.allocator, optimize);
|
||||
|
||||
var emcc_settings = @import("zemscripten").emccDefaultSettings(b.allocator, .{
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
try emcc_settings.put("ALLOW_MEMORY_GROWTH", "1");
|
||||
|
||||
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" },
|
||||
},
|
||||
);
|
||||
emcc_step.dependOn(activate_emsdk_step);
|
||||
|
||||
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 = b.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");
|
||||
|
||||
const zemscripten = @import("zemscripten");
|
||||
pub const panic = zemscripten.panic;
|
||||
|
||||
pub const std_options = std.Options{
|
||||
.logFn = zemscripten.log,
|
||||
};
|
||||
|
||||
export fn main() c_int {
|
||||
std.log.info("hello, world.", .{});
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
You can also define a run step that invokes `emrun`. This will serve the html locally over HTTP and try to open it using your default browser. Example build.zig code:
|
||||
```zig
|
||||
const html_filename = try std.fmt.allocPrint(b.allocator, "{s}.html", .{wasm.name});
|
||||
|
||||
const emrun_args = .{};
|
||||
const emrun_step = @import("zemscripten").emrunStep(
|
||||
b,
|
||||
b.getInstallPath(.{ .custom = "web" }, html_filename),
|
||||
&emrun_args,
|
||||
);
|
||||
|
||||
emrun_step.dependOn(emcc_step);
|
||||
|
||||
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.
|
||||
@ -0,0 +1,290 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
pub const emsdk_ver_major = "4";
|
||||
pub const emsdk_ver_minor = "0";
|
||||
pub const emsdk_ver_tiny = "3";
|
||||
pub const emsdk_version = emsdk_ver_major ++ "." ++ emsdk_ver_minor ++ "." ++ emsdk_ver_tiny;
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
_ = b.addModule("root", .{ .root_source_file = b.path("src/zemscripten.zig") });
|
||||
}
|
||||
|
||||
pub fn emccPath(b: *std.Build) []const u8 {
|
||||
return std.fs.path.join(b.allocator, &.{
|
||||
b.dependency("emsdk", .{}).path("").getPath(b),
|
||||
"upstream",
|
||||
"emscripten",
|
||||
switch (builtin.target.os.tag) {
|
||||
.windows => "emcc.bat",
|
||||
else => "emcc",
|
||||
},
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn emrunPath(b: *std.Build) []const u8 {
|
||||
return std.fs.path.join(b.allocator, &.{
|
||||
b.dependency("emsdk", .{}).path("").getPath(b),
|
||||
"upstream",
|
||||
"emscripten",
|
||||
switch (builtin.target.os.tag) {
|
||||
.windows => "emrun.bat",
|
||||
else => "emrun",
|
||||
},
|
||||
}) 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),
|
||||
switch (builtin.target.os.tag) {
|
||||
.windows => "emsdk.bat",
|
||||
else => "emsdk",
|
||||
},
|
||||
}) catch unreachable;
|
||||
|
||||
var emsdk_install = b.addSystemCommand(&.{ emsdk_script_path, "install", emsdk_version });
|
||||
|
||||
switch (builtin.target.os.tag) {
|
||||
.linux, .macos => {
|
||||
emsdk_install.step.dependOn(&b.addSystemCommand(&.{ "chmod", "+x", emsdk_script_path }).step);
|
||||
},
|
||||
.windows => {
|
||||
emsdk_install.step.dependOn(&b.addSystemCommand(&.{ "takeown", "/f", emsdk_script_path }).step);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var emsdk_activate = b.addSystemCommand(&.{ emsdk_script_path, "activate", emsdk_version });
|
||||
emsdk_activate.step.dependOn(&emsdk_install.step);
|
||||
|
||||
const step = b.allocator.create(std.Build.Step) catch unreachable;
|
||||
step.* = std.Build.Step.init(.{
|
||||
.id = .custom,
|
||||
.name = "Activate EMSDK",
|
||||
.owner = b,
|
||||
.makeFn = &struct {
|
||||
fn make(_: *std.Build.Step, _: std.Build.Step.MakeOptions) anyerror!void {}
|
||||
}.make,
|
||||
});
|
||||
|
||||
switch (builtin.target.os.tag) {
|
||||
.linux, .macos => {
|
||||
const chmod_emcc = b.addSystemCommand(&.{ "chmod", "+x", emccPath(b) });
|
||||
chmod_emcc.step.dependOn(&emsdk_activate.step);
|
||||
step.dependOn(&chmod_emcc.step);
|
||||
|
||||
const chmod_emrun = b.addSystemCommand(&.{ "chmod", "+x", emrunPath(b) });
|
||||
chmod_emrun.step.dependOn(&emsdk_activate.step);
|
||||
step.dependOn(&chmod_emrun.step);
|
||||
},
|
||||
.windows => {
|
||||
const takeown_emcc = b.addSystemCommand(&.{ "takeown", "/f", emccPath(b) });
|
||||
takeown_emcc.step.dependOn(&emsdk_activate.step);
|
||||
step.dependOn(&takeown_emcc.step);
|
||||
|
||||
const takeown_emrun = b.addSystemCommand(&.{ "takeown", "/f", emrunPath(b) });
|
||||
takeown_emrun.step.dependOn(&emsdk_activate.step);
|
||||
step.dependOn(&takeown_emrun.step);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
pub const EmccFlags = std.StringHashMap(void);
|
||||
|
||||
pub const EmccDefaultFlagsOverrides = struct {
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
fsanitize: bool,
|
||||
};
|
||||
|
||||
pub fn emccDefaultFlags(allocator: std.mem.Allocator, options: EmccDefaultFlagsOverrides) EmccFlags {
|
||||
var args = EmccFlags.init(allocator);
|
||||
switch (options.optimize) {
|
||||
.Debug => {
|
||||
args.put("-O0", {}) catch unreachable;
|
||||
args.put("-gsource-map", {}) catch unreachable;
|
||||
if (options.fsanitize)
|
||||
args.put("-fsanitize=undefined", {}) catch unreachable;
|
||||
},
|
||||
.ReleaseSafe => {
|
||||
args.put("-O3", {}) catch unreachable;
|
||||
if (options.fsanitize) {
|
||||
args.put("-fsanitize=undefined", {}) catch unreachable;
|
||||
args.put("-fsanitize-minimal-runtime", {}) catch unreachable;
|
||||
}
|
||||
},
|
||||
.ReleaseFast => {
|
||||
args.put("-O3", {}) catch unreachable;
|
||||
},
|
||||
.ReleaseSmall => {
|
||||
args.put("-Oz", {}) catch unreachable;
|
||||
},
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
pub const EmccSettings = std.StringHashMap([]const u8);
|
||||
|
||||
pub const EmsdkAllocator = enum {
|
||||
none,
|
||||
dlmalloc,
|
||||
emmalloc,
|
||||
@"emmalloc-debug",
|
||||
@"emmalloc-memvalidate",
|
||||
@"emmalloc-verbose",
|
||||
mimalloc,
|
||||
};
|
||||
|
||||
pub const EmccDefaultSettingsOverrides = struct {
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
emsdk_allocator: EmsdkAllocator = .emmalloc,
|
||||
shell_file: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub fn emccDefaultSettings(allocator: std.mem.Allocator, options: EmccDefaultSettingsOverrides) EmccSettings {
|
||||
var settings = EmccSettings.init(allocator);
|
||||
switch (options.optimize) {
|
||||
.Debug, .ReleaseSafe => {
|
||||
settings.put("SAFE_HEAP", "1") catch unreachable;
|
||||
settings.put("STACK_OVERFLOW_CHECK", "1") catch unreachable;
|
||||
settings.put("ASSERTIONS", "1") catch unreachable;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
settings.put("USE_OFFSET_CONVERTER", "1") catch unreachable;
|
||||
settings.put("MALLOC", @tagName(options.emsdk_allocator)) catch unreachable;
|
||||
return settings;
|
||||
}
|
||||
|
||||
pub const EmccFilePath = struct {
|
||||
src_path: []const u8,
|
||||
virtual_path: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub const StepOptions = struct {
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
flags: EmccFlags,
|
||||
settings: EmccSettings,
|
||||
use_preload_plugins: bool = false,
|
||||
embed_paths: ?[]const EmccFilePath = null,
|
||||
preload_paths: ?[]const EmccFilePath = null,
|
||||
shell_file_path: ?std.Build.LazyPath = null,
|
||||
install_dir: std.Build.InstallDir,
|
||||
};
|
||||
|
||||
pub fn emccStep(
|
||||
b: *std.Build,
|
||||
wasm: *std.Build.Step.Compile,
|
||||
options: StepOptions,
|
||||
) *std.Build.Step {
|
||||
var emcc = b.addSystemCommand(&.{emccPath(b)});
|
||||
|
||||
var iterFlags = options.flags.iterator();
|
||||
while (iterFlags.next()) |kvp| {
|
||||
emcc.addArg(kvp.key_ptr.*);
|
||||
}
|
||||
|
||||
var iterSettings = options.settings.iterator();
|
||||
while (iterSettings.next()) |kvp| {
|
||||
emcc.addArg(std.fmt.allocPrint(
|
||||
b.allocator,
|
||||
"-s{s}={s}",
|
||||
.{ kvp.key_ptr.*, kvp.value_ptr.* },
|
||||
) catch unreachable);
|
||||
}
|
||||
|
||||
emcc.addArtifactArg(wasm);
|
||||
{
|
||||
for (wasm.root_module.getGraph().modules) |module| {
|
||||
for (module.link_objects.items) |link_object| {
|
||||
switch (link_object) {
|
||||
.other_step => |compile_step| {
|
||||
switch (compile_step.kind) {
|
||||
.lib => {
|
||||
emcc.addArtifactArg(compile_step);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emcc.addArg("-o");
|
||||
const out_file = emcc.addOutputFileArg(b.fmt("{s}.html", .{wasm.name}));
|
||||
|
||||
if (options.use_preload_plugins) {
|
||||
emcc.addArg("--use-preload-plugins");
|
||||
}
|
||||
|
||||
if (options.embed_paths) |embed_paths| {
|
||||
for (embed_paths) |path| {
|
||||
const path_arg = if (path.virtual_path) |virtual_path|
|
||||
std.fmt.allocPrint(
|
||||
b.allocator,
|
||||
"{s}@{s}",
|
||||
.{ path.src_path, virtual_path },
|
||||
) catch unreachable
|
||||
else
|
||||
path.src_path;
|
||||
emcc.addArgs(&.{ "--embed-file", path_arg });
|
||||
}
|
||||
}
|
||||
|
||||
if (options.preload_paths) |preload_paths| {
|
||||
for (preload_paths) |path| {
|
||||
const path_arg = if (path.virtual_path) |virtual_path|
|
||||
std.fmt.allocPrint(
|
||||
b.allocator,
|
||||
"{s}@{s}",
|
||||
.{ path.src_path, virtual_path },
|
||||
) catch unreachable
|
||||
else
|
||||
path.src_path;
|
||||
emcc.addArgs(&.{ "--preload-file", path_arg });
|
||||
}
|
||||
}
|
||||
|
||||
if (options.shell_file_path) |shell_file_path| {
|
||||
emcc.addArg("--shell-file");
|
||||
emcc.addFileArg(shell_file_path);
|
||||
emcc.addFileInput(shell_file_path);
|
||||
}
|
||||
|
||||
const install_step = b.addInstallDirectory(.{
|
||||
.source_dir = out_file.dirname(),
|
||||
.install_dir = options.install_dir,
|
||||
.install_subdir = "",
|
||||
});
|
||||
install_step.step.dependOn(&emcc.step);
|
||||
|
||||
return &install_step.step;
|
||||
}
|
||||
|
||||
pub fn emrunStep(
|
||||
b: *std.Build,
|
||||
html_path: []const u8,
|
||||
extra_args: []const []const u8,
|
||||
) *std.Build.Step {
|
||||
var emrun = b.addSystemCommand(&.{emrunPath(b)});
|
||||
emrun.addArgs(extra_args);
|
||||
emrun.addArg(html_path);
|
||||
// emrun.addArg("--");
|
||||
|
||||
return &emrun.step;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
.{
|
||||
.name = .zemscripten,
|
||||
.fingerprint = 0x2de6d80ca84319b1, // Changing this has security and trust implications.
|
||||
.version = "0.2.0-dev",
|
||||
.minimum_zig_version = "0.14.0",
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
},
|
||||
}
|
||||
@ -0,0 +1,223 @@
|
||||
//! Zig bindings and glue for Emscripten
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
comptime {
|
||||
_ = std.testing.refAllDeclsRecursive(@This());
|
||||
}
|
||||
|
||||
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;
|
||||
pub fn setMainLoop(cb: MainLoopCallback, maybe_fps: ?i16, simulate_infinite_loop: bool) void {
|
||||
emscripten_set_main_loop(cb, if (maybe_fps) |fps| fps else -1, @intFromBool(simulate_infinite_loop));
|
||||
}
|
||||
|
||||
extern fn emscripten_cancel_main_loop() void;
|
||||
pub fn cancelMainLoop() void {
|
||||
emscripten_cancel_main_loop();
|
||||
}
|
||||
|
||||
pub const MainLoopArgCallback = *const fn (arg: *anyopaque) callconv(.c) void;
|
||||
extern fn emscripten_set_main_loop_arg(MainLoopArgCallback, arg: *anyopaque, c_int, c_int) void;
|
||||
pub fn setMainLoopArg(cb: MainLoopArgCallback, arg: *anyopaque, maybe_fps: ?i16, simulate_infinite_loop: bool) void {
|
||||
emscripten_set_main_loop_arg(cb, arg, if (maybe_fps) |fps| fps else -1, @intFromBool(simulate_infinite_loop));
|
||||
}
|
||||
|
||||
pub const AnimationFrameCallback = *const fn (f64, ?*anyopaque) callconv(.c) c_int;
|
||||
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;
|
||||
|
||||
// EmmallocAllocator 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 EmmallocAllocator = struct {
|
||||
const Self = @This();
|
||||
dummy: u32 = undefined,
|
||||
|
||||
pub fn allocator(self: *Self) std.mem.Allocator {
|
||||
return .{
|
||||
.ptr = self,
|
||||
.vtable = &.{
|
||||
.alloc = &alloc,
|
||||
.resize = &resize,
|
||||
.remap = &remap,
|
||||
.free = &free,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn alloc(
|
||||
ctx: *anyopaque,
|
||||
len: usize,
|
||||
ptr_align_log2: std.mem.Alignment,
|
||||
return_address: usize,
|
||||
) ?[*]u8 {
|
||||
_ = ctx;
|
||||
_ = return_address;
|
||||
const ptr_align: u32 = @as(u32, 1) << @as(u5, @intFromEnum(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: std.mem.Alignment,
|
||||
new_len: usize,
|
||||
return_address: usize,
|
||||
) bool {
|
||||
_ = ctx;
|
||||
_ = return_address;
|
||||
_ = buf_align_log2;
|
||||
return emmalloc_realloc_try(buf.ptr, new_len) != null;
|
||||
}
|
||||
|
||||
fn remap(
|
||||
ctx: *anyopaque,
|
||||
buf: []u8,
|
||||
buf_align_log2: std.mem.Alignment,
|
||||
new_len: usize,
|
||||
return_address: usize,
|
||||
) ?[*]u8 {
|
||||
return if (resize(ctx, buf, buf_align_log2, new_len, return_address)) buf.ptr else null;
|
||||
}
|
||||
|
||||
fn free(
|
||||
ctx: *anyopaque,
|
||||
buf: []u8,
|
||||
buf_align_log2: std.mem.Alignment,
|
||||
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;
|
||||
_ = ret_addr;
|
||||
|
||||
var buf: [1024]u8 = undefined;
|
||||
const error_msg: [:0]u8 = std.fmt.bufPrintZ(&buf, "PANIC! {s}", .{msg}) catch unreachable;
|
||||
emscripten_err(error_msg.ptr);
|
||||
|
||||
while (true) {
|
||||
@breakpoint();
|
||||
}
|
||||
}
|
||||
|
||||
/// std.log impl
|
||||
pub fn log(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @TypeOf(.EnumLiteral),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
const level_txt = comptime level.asText();
|
||||
const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||
const prefix = level_txt ++ prefix2;
|
||||
|
||||
var buf: [1024]u8 = undefined;
|
||||
const msg = std.fmt.bufPrintZ(buf[0 .. buf.len - 1], prefix ++ format, args) catch |err| {
|
||||
switch (err) {
|
||||
error.NoSpaceLeft => {
|
||||
emscripten_console_error("log message too long, skipped.");
|
||||
return;
|
||||
},
|
||||
}
|
||||
};
|
||||
switch (level) {
|
||||
.err => emscripten_console_error(@ptrCast(msg.ptr)),
|
||||
.warn => emscripten_console_warn(@ptrCast(msg.ptr)),
|
||||
else => emscripten_console_log(@ptrCast(msg.ptr)),
|
||||
}
|
||||
}
|
||||
|
||||
// Networking
|
||||
extern fn emscripten_wget(url: [*c]const u8, file: [*c]const u8) c_int;
|
||||
extern fn emscripten_wget_data(url: [*c]const u8, pbuffer: **anyopaque, pnum: *c_int, perror: *c_int) void;
|
||||
|
||||
pub fn wget(url: [:0]const u8, file: [:0]const u8) !void {
|
||||
if (emscripten_wget(url.ptr, file.ptr) != 0) {
|
||||
return error.WgetError;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wget_data(url: [:0]const u8) ![]u8 {
|
||||
var buffer_ptr: *anyopaque = undefined;
|
||||
var len: c_int = undefined;
|
||||
var err: c_int = undefined;
|
||||
|
||||
emscripten_wget_data(url.ptr, &buffer_ptr, &len, &err);
|
||||
|
||||
if (err != 0) {
|
||||
return error.WgetError;
|
||||
}
|
||||
|
||||
return @as([*]u8, @ptrCast(buffer_ptr))[0..@intCast(len)];
|
||||
}
|
||||
Reference in New Issue
Block a user