1 const std = @import("std");
2 const Build = std.Build;
3 const OptimizeMode = std.builtin.OptimizeMode;
4 const ResolvedTarget = Build.ResolvedTarget;
5 const Dependency = Build.Dependency;
6 const sokol = @import("sokol");
7 const cimgui = @import("cimgui");
8 const shdc = @import("shdc");
10 pub fn build(b: *Build) !void {
11 const target = b.standardTargetOptions(.{});
12 const optimize = b.standardOptimizeOption(.{});
14 // Get the matching Zig module name, C header search path and C library for
15 // vanilla imgui vs the imgui docking branch.
16 const cimgui_conf = cimgui.getConfig(true);
18 // note that the sokol dependency is built with `.with_sokol_imgui = true`
19 const dep_sokol = b.dependency("sokol", .{
22 .with_sokol_imgui = true,
24 const dep_cimgui = b.dependency("cimgui", .{
29 // inject the cimgui header search path into the sokol C library compile step
30 dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir));
33 dep_sokol.artifact("sokol_clib").addIncludePath(b.path("ext/cimgui"));
34 const dep_shdc = b.dependency("shdc", .{});
35 const shdc_step = try shdc.createSourceFile(b, .{
37 .input = "shd/main.glsl",
38 .output = "src/shd/main.glsl.zig",
39 .slang = .{ .glsl430 = true },
42 // main module with sokol and cimgui imports
43 const mod_main = b.createModule(.{
44 .root_source_file = b.path("src/main.zig"),
48 .{ .name = "sokol", .module = dep_sokol.module("sokol") },
49 .{ .name = cimgui_conf.module_name, .module = dep_cimgui.module(cimgui_conf.module_name) },
54 mod_main.addIncludePath(b.path("src"));
55 mod_main.addCSourceFile(.{.file = b.path("src/stb_image.c")});
57 // from here on different handling for native vs wasm builds
58 if (target.result.cpu.arch.isWasm()) {
61 .dep_sokol = dep_sokol,
62 .dep_cimgui = dep_cimgui,
63 .cimgui_clib_name = cimgui_conf.clib_name,
66 const exe = try buildNative(b, mod_main);
67 exe.step.dependOn(shdc_step);
69 exe.root_module.link_libc = true;
70 exe.root_module.linkSystemLibrary("X11", .{ .needed = true });
71 exe.root_module.linkSystemLibrary("Xcursor", .{ .needed = true });
73 const exe_check = b.addExecutable(.{
75 .root_module = mod_main,
77 const check = b.step("check", "Check");
78 check.dependOn(&exe_check.step);
82 fn buildNative(b: *Build, mod: *Build.Module) !*Build.Step.Compile {
83 const exe = b.addExecutable(.{
87 b.installArtifact(exe);
88 b.step("run", "Run Sporegirl").dependOn(&b.addRunArtifact(exe).step);
92 const BuildWasmOptions = struct {
93 mod_main: *Build.Module,
94 dep_sokol: *Dependency,
95 dep_cimgui: *Dependency,
96 cimgui_clib_name: []const u8,
99 fn buildWasm(b: *Build, opts: BuildWasmOptions) !void {
100 // build the main file into a library, this is because the WASM 'exe'
101 // needs to be linked in a separate build step with the Emscripten linker
102 const demo = b.addLibrary(.{
104 .root_module = opts.mod_main,
107 // get the Emscripten SDK dependency from the sokol dependency
108 const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
110 // need to inject the Emscripten system header include path into
111 // the cimgui C library otherwise the C/C++ code won't find
113 const emsdk_incl_path = dep_emsdk.path("upstream/emscripten/cache/sysroot/include");
114 opts.dep_cimgui.artifact(opts.cimgui_clib_name).addSystemIncludePath(emsdk_incl_path);
116 // all C libraries need to depend on the sokol library, when building for
117 // WASM this makes sure that the Emscripten SDK has been setup before
118 // C compilation is attempted (since the sokol C library depends on the
119 // Emscripten SDK setup step)
120 opts.dep_cimgui.artifact(opts.cimgui_clib_name).step.dependOn(&opts.dep_sokol.artifact("sokol_clib").step);
122 // create a build step which invokes the Emscripten linker
123 const link_step = try sokol.emLinkStep(b, .{
125 .target = opts.mod_main.resolved_target.?,
126 .optimize = opts.mod_main.optimize.?,
129 .use_emmalloc = true,
130 .use_filesystem = false,
131 .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
133 // attach to default target
134 b.getInstallStep().dependOn(&link_step.step);
135 // ...and a special run step to start the web build output via 'emrun'
136 const run = sokol.emRunStep(b, .{ .name = "demo", .emsdk = dep_emsdk });
137 run.step.dependOn(&link_step.step);
138 b.step("run", "Run demo").dependOn(&run.step);