Skip to content
This repository was archived by the owner on Dec 1, 2025. It is now read-only.
Merged
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: 2 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ jobs:
run: cd template && zig build
- name: Build Template Windows
run: cd template && zig build -Dtarget=x86_64-windows
# - name: Build Template Web
# run: cd template && zig build -Dtarget=wasm32-emscripten
test:
name: Testing
runs-on: ubuntu-latest
Expand Down
28 changes: 25 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ pub fn build(b: *std.Build) !void {
"c_sdl_install_build_config_h",
"Additionally install 'SDL_build_config.h' when installing SDL (default: false)",
) orelse false;
const sdl_system_include_path = b.option(
std.Build.LazyPath,
"sdl_system_include_path",
"System include path for SDL",
);
const sdl_sysroot_path = b.option(
std.Build.LazyPath,
"sdl_sysroot_path",
"System include path for SDL",
);

if (sdl_sysroot_path) |val| {
b.sysroot = val.getPath(b);
}

const sdl_dep = b.dependency("sdl", .{
.target = target,
Expand All @@ -71,6 +85,8 @@ pub fn build(b: *std.Build) !void {
});

const sdl_dep_lib = sdl_dep.artifact("SDL3");
if (sdl_system_include_path) |val|
sdl_dep_lib.addSystemIncludePath(val);

// SDL options.
const extension_options = b.addOptions();
Expand Down Expand Up @@ -110,6 +126,8 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
});
translate_c.addIncludePath(sdl_dep.path("include"));
if (sdl_system_include_path) |val|
translate_c.addSystemIncludePath(val);

const c_module = translate_c.createModule();

Expand All @@ -122,6 +140,9 @@ pub fn build(b: *std.Build) !void {
},
});

if (sdl_system_include_path) |val|
sdl3.addSystemIncludePath(val);

const example_options = ExampleOptions{
.ext_image = ext_image,
.ext_net = ext_net,
Expand All @@ -130,23 +151,24 @@ pub fn build(b: *std.Build) !void {

sdl3.addOptions("extension_options", extension_options);
sdl3.linkLibrary(sdl_dep_lib);

if (ext_image) {
image.setup(b, sdl3, translate_c, sdl_dep_lib, c_sdl_preferred_linkage, .{
.optimize = optimize,
.target = target,
});
}, sdl_system_include_path);
}
if (ext_net) {
net.setup(b, sdl3, translate_c, sdl_dep_lib, c_sdl_preferred_linkage, .{
.optimize = optimize,
.target = target,
});
}, sdl_system_include_path);
}
if (ext_ttf) {
ttf.setup(b, sdl3, translate_c, sdl_dep_lib, c_sdl_preferred_linkage, .{
.optimize = optimize,
.target = target,
});
}, sdl_system_include_path);
}

_ = setupDocs(b, sdl3);
Expand Down
4 changes: 4 additions & 0 deletions build/image.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn setup(
sdl_dep_lib: *std.Build.Step.Compile,
linkage: std.builtin.LinkMode,
cfg: struct { optimize: std.builtin.OptimizeMode, target: std.Build.ResolvedTarget },
system_include_path: ?std.Build.LazyPath,
) void {
const upstream = b.lazyDependency("sdl_image", .{}) orelse return;

Expand All @@ -22,6 +23,9 @@ pub fn setup(
.link_libc = true,
}),
});
if (system_include_path) |val| {
lib.root_module.addSystemIncludePath(val);
}
lib.root_module.linkLibrary(sdl_dep_lib);

// Use stb_image for loading JPEG and PNG files. Native alternatives such as
Expand Down
5 changes: 5 additions & 0 deletions build/net.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub fn setup(
sdl_dep_lib: *std.Build.Step.Compile,
linkage: std.builtin.LinkMode,
cfg: struct { optimize: std.builtin.OptimizeMode, target: std.Build.ResolvedTarget },
system_include_path: ?std.Build.LazyPath,
) void {
const target = cfg.target;
const optimize = cfg.optimize;
Expand All @@ -30,6 +31,10 @@ pub fn setup(
.linkage = linkage,
});

if (system_include_path) |val| {
lib.addSystemIncludePath(val);
}

var lib_c_flags: std.ArrayListUnmanaged([]const u8) = .empty;
defer lib_c_flags.deinit(b.allocator);
lib_c_flags.appendSlice(b.allocator, &.{"-std=c99"}) catch @panic("OOM");
Expand Down
5 changes: 5 additions & 0 deletions build/ttf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub fn setup(
sdl_dep_lib: *std.Build.Step.Compile,
linkage: std.builtin.LinkMode,
cfg: struct { optimize: std.builtin.OptimizeMode, target: std.Build.ResolvedTarget },
system_include_path: ?std.Build.LazyPath,
) void {
const target = cfg.target;
const optimize: std.builtin.OptimizeMode = .ReleaseFast; // https://github.com/libsdl-org/SDL_ttf/issues/566 (ReleaseFast prevents UBSAN from running)
Expand All @@ -26,6 +27,10 @@ pub fn setup(
}),
});

if (system_include_path) |val| {
lib.addSystemIncludePath(val);
}

translate_c.addIncludePath(upstream.path("include"));
lib.addIncludePath(upstream.path("include"));
lib.addIncludePath(upstream.path("src"));
Expand Down
119 changes: 110 additions & 9 deletions template/build.zig
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
const std = @import("std");
const zemscripten = @import("zemscripten");

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

fn buildBin(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !void {
const exe_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
Expand Down Expand Up @@ -32,13 +30,116 @@ pub fn build(b: *std.Build) void {

const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

const exe_unit_tests = b.addTest(.{
.root_module = exe_mod,
fn buildWeb(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !void {
const activateEmsdk = zemscripten.activateEmsdkStep(b);
b.default_step.dependOn(activateEmsdk);

const wasm = b.addLibrary(.{
.name = "template",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
.linkage = .static,
});

const zemscripten_dep = b.dependency("zemscripten", .{});
wasm.root_module.addImport("zemscripten", zemscripten_dep.module("root"));

const emsdk_dep = b.dependency("emsdk", .{});
const emsdk_sysroot_path = emsdk_dep.path("upstream/emscripten/cache/sysroot");
const emsdk_sysroot_include_path = emsdk_dep.path("upstream/emscripten/cache/sysroot/include");

const sdl3 = b.dependency("sdl3", .{
.target = target,
.optimize = optimize,
.callbacks = true,
.ext_image = true,
.sdl_system_include_path = emsdk_sysroot_include_path,
.sdl_sysroot_path = emsdk_sysroot_path,
});

const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
wasm.root_module.addSystemIncludePath(emsdk_sysroot_include_path);

const sdl_module = sdl3.module("sdl3");
sdl_module.addSystemIncludePath(emsdk_sysroot_include_path);
wasm.root_module.addImport("sdl3", sdl3.module("sdl3"));
wasm.addSystemIncludePath(emsdk_sysroot_include_path);

const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_unit_tests.step);
const emcc_flags = zemscripten.emccDefaultFlags(b.allocator, .{
.optimize = optimize,
.fsanitize = true,
});

var emcc_settings = zemscripten.emccDefaultSettings(b.allocator, .{
.optimize = optimize,
});
try emcc_settings.put("ALLOW_MEMORY_GROWTH", "1");
emcc_settings.put("USE_SDL", "3") catch unreachable;

const emcc_step = zemscripten.emccStep(
b,
wasm,
.{
.optimize = optimize,
.flags = emcc_flags, // Pass the modified flags
.settings = emcc_settings,
.use_preload_plugins = true,
.embed_paths = &.{},
.preload_paths = &.{},
.install_dir = .{ .custom = "web" },
.shell_file_path = b.path("src/html/shell.html"),
},
);

b.getInstallStep().dependOn(emcc_step);

const base_name = if (wasm.name_only_filename) |n| n else wasm.name;

// Create filename with extension
const html_file = try std.fmt.allocPrint(b.allocator, "{s}.html", .{base_name});
defer b.allocator.free(html_file);

std.debug.print("HTML FILE: {s}\n", .{html_file});

// output set in emcc_step
const html_path = b.pathJoin(&.{ "zig-out", "web", html_file });

std.debug.print("HTML PATH: {s}\n", .{html_path});

// Absolute path to emrun
const emrun_path = emsdk_dep.path("upstream/emscripten/emrun");

// System command
const emrun_cmd = b.addSystemCommand(&.{
emrun_path.getPath(b),
"--port",
b.fmt("{d}", .{b.option(u16, "port", "Port to run the webapp on (default: 8080)") orelse 8080}),
html_path,
});

emrun_cmd.step.dependOn(b.getInstallStep());

const run_step = b.step("run", "Run the app (via emrun)");
run_step.dependOn(&emrun_cmd.step);

if (b.args) |args| {
emrun_cmd.addArgs(args);
}
}

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

const os = target.result.os.tag;
if (os == .emscripten) {
try buildWeb(b, target, optimize);
} else {
try buildBin(b, target, optimize);
}
}
8 changes: 8 additions & 0 deletions template/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
.name = .sdl3_template,
.version = "0.0.0",
.dependencies = .{
.emsdk = .{
.url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/4.0.3.tar.gz",
.hash = "N-V-__8AAOG3BQCJ9cn-N2swm2o5cLmDhmdHmtwNngOChK78",
},
.sdl3 = .{
// .url = "git+https://github.com/Gota7/zig-sdl3#v0.1.0",
// .hash = "sdl3-0.0.1-NmT1Q5LaIAC1lVdodEX_pnLOI44bfRvW1ZuOlqrMY17E"
.path = "../",
},
.zemscripten = .{
.url = "git+https://github.com/zig-gamedev/zemscripten#00da03b188220374a57cb34cda6230b8d53737ea",
.hash = "zemscripten-0.2.0-dev-sRlDqFJSAAB8hgnRt5DDMKP3zLlDtMnUDwYRJVCa5lGY",
},
},
.paths = .{
"build.zig",
Expand Down
34 changes: 34 additions & 0 deletions template/src/html/shell.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> </title>
<style>
html, body {
margin: 0;
height: 100%;
background: #112;
display: flex;
justify-content: center; /* horizontal center */
align-items: center; /* vertical center */
}
canvas {
background: black;
display: block;
/* Use fixed size */
width: 1280px;
height: 720px;
}
</style>
</head>
<body>
<canvas id="canvas" width="1280" height="720"></canvas>

{{{ SCRIPT }}}

<script>
console.log("Hello World!");
</script>
</body>
</html>

3 changes: 2 additions & 1 deletion template/src/main.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const sdl3 = @import("sdl3");
const std = @import("std");
const builtin = @import("builtin");

// Use main callbacks.
comptime {
Expand All @@ -18,7 +19,7 @@ pub const _start = void;
pub const WinMainCRTStartup = void;

/// Allocator we will use.
const allocator = std.heap.smp_allocator;
const allocator = if (builtin.os.tag != .emscripten) std.heap.smp_allocator else std.heap.c_allocator;

/// For logging system messages.
const log_app = sdl3.log.Category.application;
Expand Down