Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emscripten support #480

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ Refer to each lib's README.md for further usage intructions.
## Libraries
| Library | Latest version | Description |
|-------------------------------|----------------|----------------------------------------------------------------------------------------------------------------------------|
| **[zphysics](libs/zphysics)** | 0.0.6 | Zig build sys & bindings ontop of a [C API](https://github.com/zig-gamedev/zig-gamedev/tree/main/libs/zphysics/libs/JoltC) for [Jolt Physics](https://github.com/jrouwe/JoltPhysics) |
| **[zemscripten](libs/zemscripten)** | 0.1.0 | Zig build package for [Emscripten](https://emscripten.org) emsdk |
| **[zphysics](libs/zphysics)** | 0.0.6 | Zig build pacakge & bindings to [JoltC C API](https://github.com/zig-gamedev/zig-gamedev/tree/main/libs/zphysics/libs/JoltC) for [Jolt Physics](https://github.com/jrouwe/JoltPhysics) |
| **[zflecs](libs/zflecs)** | 0.0.1 | Zig bindings for [flecs](https://github.com/SanderMertens/flecs) ECS |
| **[zopengl](libs/zopengl)** | 0.2.0 | OpenGL loader (supports 4.0 Core Profile and ES 2.0 Profile) |
| **[zsdl](libs/zsdl)** | 0.0.1 | Bindings for SDL2 (wip) |
Expand Down
16 changes: 15 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ pub fn build(b: *std.Build) void {
) orelse false,
};

if (target.result.os.tag == .emscripten) {
zemscripten_pkg = zemscripten.package(b);
if (b.sysroot == null) {
b.sysroot = zemscripten_pkg.emsdk_sysroot;
std.log.info("sysroot set to \"{s}\"", .{zemscripten_pkg.emsdk_sysroot});
}
}

//
// Packages
//
Expand Down Expand Up @@ -95,7 +103,11 @@ pub fn build(b: *std.Build) void {
//
// Experiments
//
if (b.option(bool, "experiments", "Build our prototypes and experimental programs") orelse false) {
if (b.option(
bool,
"experiments",
"Build our prototypes and experimental programs",
) orelse false) {
@import("experiments/build.zig").build(b, options);
}
}
Expand Down Expand Up @@ -297,6 +309,7 @@ fn benchmarks(b: *std.Build, options: Options) void {
benchmark_step.dependOn(zmath.runBenchmarks(b, options.target, options.optimize));
}

pub var zemscripten_pkg: zemscripten.Package = undefined;
pub var zmath_pkg: zmath.Package = undefined;
pub var znoise_pkg: znoise.Package = undefined;
pub var zopengl_pkg: zopengl.Package = undefined;
Expand All @@ -322,6 +335,7 @@ pub var common_pkg: common.Package = undefined;
pub var common_d2d_pkg: common.Package = undefined;
pub var zd3d12_d2d_pkg: zd3d12.Package = undefined;

const zemscripten = @import("zemscripten");
const zsdl = @import("zsdl");
const zopengl = @import("zopengl");
const zmath = @import("zmath");
Expand Down
9 changes: 8 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@
.common = .{ .path = "libs/common" },
.zbullet = .{ .path = "libs/zbullet" },
.zgui = .{ .path = "libs/zgui" },
.zgpu = .{ .path = "libs/zgpu" },
.ztracy = .{ .path = "libs/ztracy" },
.zphysics = .{ .path = "libs/zphysics" },
.zaudio = .{ .path = "libs/zaudio" },
.zflecs = .{ .path = "libs/zflecs" },
.system_sdk = .{ .path = "libs/system-sdk" },

.zemscripten = .{ .path = "libs/zemscripten" },
.emsdk = .{
.url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.52.tar.gz",
.hash = "12202192726bf983ec243c7eea956d6107baf6f49d50b62f6a91f5d7471bc6daf53b",
},

.zgpu = .{ .path = "libs/zgpu" },
.dawn_x86_64_windows_gnu = .{
.url = "https://github.com/michal-z/webgpu_dawn-x86_64-windows-gnu/archive/d3a68014e6b6b53fd330a0ccba99e4dcfffddae5.tar.gz",
.hash = "1220f9448cde02ef3cd51bde2e0850d4489daa0541571d748154e89c6eb46c76a267",
Expand Down
1 change: 1 addition & 0 deletions libs/zemscripten/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# zemscripten v0.1.0 - Zig build package for [Emscripten](https://emscripten.org) emsdk
82 changes: 82 additions & 0 deletions libs/zemscripten/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const builtin = @import("builtin");
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_version = emsdk_ver_major ++ "." ++ emsdk_ver_minor ++ "." ++ emsdk_ver_tiny;

pub const Package = struct {
module: *std.Build.Module,
emsdk_sysroot: []const u8,
emsdk_path: []const u8,
emsdk_setup_step: *std.Build.Step,

pub fn emscStep(
pkg: Package,
compile_step: *std.Build.Step.Compile,
emcc_options: []const u8,
) *std.Build.Step {
compile_step.root_module.addImport("zemscripten", pkg.module);

const b = compile_step.step.owner;

const emcc = b.addSystemCommand(&.{
b.pathJoin(&.{ pkg.emsdk_path, "upstream/emscripten/emcc" }),
std.fmt.allocPrint(
b.allocator,
"-smalloc=emmalloc {s}",
.{emcc_options},
) catch |err| switch (err) {
error.OutOfMemory => @panic("Out of memory"),
},
});
emcc.step.dependOn(pkg.emsdk_setup_step);

emcc.addArtifactArg(compile_step);

return &emcc.step;
}
};

pub fn package(b: *std.Build) Package {
const module = b.addModule("root", .{
.root_source_file = .{ .path = thisDir() ++ "/src/root.zig" },
});

const emsdk_path = b.dependency("emsdk", .{}).path("").getPath(b);

const emsdk_bin_path = switch (builtin.target.os.tag) {
.windows => b.pathJoin(&.{ emsdk_path, "emsdk.bat" }),
else => b.pathJoin(&.{ emsdk_path, "emsdk" }),
};

var emsdk_install = b.addSystemCommand(&.{ emsdk_bin_path, "install", emsdk_version });

switch (builtin.target.os.tag) {
.linux, .macos => {
emsdk_install.step.dependOn(&b.addSystemCommand(&.{ "chmod", "+x", emsdk_bin_path }).step);
},
else => {},
}

var emsdk_activate = b.addSystemCommand(&.{ emsdk_bin_path, "activate", emsdk_version });
emsdk_activate.step.dependOn(&emsdk_install.step);

const sysroot = b.pathJoin(&.{ emsdk_path, "upstream/emscripten/cache/sysroot" });

return .{
.module = module,
.emsdk_sysroot = sysroot,
.emsdk_path = emsdk_path,
.emsdk_setup_step = &emsdk_activate.step,
};
}

pub fn build(b: *std.Build) void {
_ = package(b);
}

inline fn thisDir() []const u8 {
return comptime std.fs.path.dirname(@src().file) orelse ".";
}
16 changes: 16 additions & 0 deletions libs/zemscripten/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.{
.name = "zemsc",
.version = "0.1.0",
.dependencies = .{
.emsdk = .{
.url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.52.tar.gz",
.hash = "12202192726bf983ec243c7eea956d6107baf6f49d50b62f6a91f5d7471bc6daf53b",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"README.md",
"src",
},
}
90 changes: 90 additions & 0 deletions libs/zemscripten/src/root.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const std = @import("std");

extern "C" fn emmalloc_memalign(alignment: usize, size: usize) ?*anyopaque;
extern "C" fn emmalloc_realloc_try(ptr: ?*anyopaque, size: usize) ?*anyopaque;
extern "C" fn emmalloc_free(ptr: ?*anyopaque) void;

/// Zig Allocator that wraps emmalloc
/// use with linker flag -sMALLOC=emmalloc
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,
.free = &free,
},
};
}

fn alloc(
ctx: *anyopaque,
len: usize,
ptr_align_log2: u8,
return_address: usize,
) ?[*]u8 {
_ = ctx;
_ = return_address;
const ptr_align = @as(usize, 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 "C" fn emscripten_console_log([*c]const u8) void;
extern "C" fn emscripten_console_warn([*c]const u8) void;
extern "C" fn emscripten_console_error([*c]const u8) void;

/// std.log function that writes to dev-tools console
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 * 4]u8 = undefined;
const slice = std.fmt.bufPrint(buf[0 .. buf.len - 1], prefix ++ format, args) catch {
emscripten_console_error("zemsc: log message too long, skipped!");
return;
};
buf[slice.len] = 0;
switch (level) {
.err => emscripten_console_error(@ptrCast(slice.ptr)),
.warn => emscripten_console_warn(@ptrCast(slice.ptr)),
else => emscripten_console_log(@ptrCast(slice.ptr)),
}
}
14 changes: 11 additions & 3 deletions libs/zflecs/build.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const builtin = @import("builtin");
const std = @import("std");

pub const Package = struct {
Expand Down Expand Up @@ -34,12 +35,19 @@ pub fn package(
"-fno-sanitize=undefined",
"-DFLECS_NO_CPP",
"-DFLECS_USE_OS_ALLOC",
if (@import("builtin").mode == .Debug) "-DFLECS_SANITIZE" else "",
if (builtin.mode == .Debug) "-DFLECS_SANITIZE" else "",
},
});

if (target.result.os.tag == .windows) {
zflecs_c_cpp.linkSystemLibrary("ws2_32");
switch (target.result.os.tag) {
.windows => {
zflecs_c_cpp.linkSystemLibrary("ws2_32");
},
.emscripten => {
zflecs_c_cpp.defineCMacro("__EMSCRIPTEN__", "1");
zflecs_c_cpp.addIncludePath(.{ .path = b.pathJoin(&.{ b.sysroot.?, "include" }) });
},
else => {},
}

return .{
Expand Down
Loading
Loading