]> gitweb.ps.run Git - sporegirl/blob - build.zig
add stb_image
[sporegirl] / build.zig
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
9 pub fn build(b: *Build) !void {
10     const target = b.standardTargetOptions(.{});
11     const optimize = b.standardOptimizeOption(.{});
12
13     const opt_docking = b.option(bool, "docking", "Build with docking support") orelse false;
14
15     // Get the matching Zig module name, C header search path and C library for
16     // vanilla imgui vs the imgui docking branch.
17     const cimgui_conf = cimgui.getConfig(opt_docking);
18
19     // note that the sokol dependency is built with `.with_sokol_imgui = true`
20     const dep_sokol = b.dependency("sokol", .{
21         .target = target,
22         .optimize = optimize,
23         .with_sokol_imgui = true,
24     });
25     const dep_cimgui = b.dependency("cimgui", .{
26         .target = target,
27         .optimize = optimize,
28     });
29
30     // inject the cimgui header search path into the sokol C library compile step
31     dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir));
32
33     // shaders
34     dep_sokol.artifact("sokol_clib").addIncludePath(b.path("ext/cimgui"));
35     const dep_shdc = dep_sokol.builder.dependency("shdc", .{});
36     const shdc_step = try sokol.shdc.createSourceFile(b, .{
37         .shdc_dep = dep_shdc,
38         .input = "src/shader/quad.glsl",
39         .output = "src/shader/quad.glsl.zig",
40         .slang = .{ .glsl430 = true },
41     });
42
43     // main module with sokol and cimgui imports
44     const mod_main = b.createModule(.{
45         .root_source_file = b.path("src/main.zig"),
46         .target = target,
47         .optimize = optimize,
48         .imports = &.{
49             .{ .name = "sokol", .module = dep_sokol.module("sokol") },
50             .{ .name = cimgui_conf.module_name, .module = dep_cimgui.module(cimgui_conf.module_name) },
51         },
52     });
53     const mod_options = b.addOptions();
54     mod_options.addOption(bool, "docking", opt_docking);
55     mod_main.addOptions("build_options", mod_options);
56
57     // from here on different handling for native vs wasm builds
58     if (target.result.cpu.arch.isWasm()) {
59         try buildWasm(b, .{
60             .mod_main = mod_main,
61             .dep_sokol = dep_sokol,
62             .dep_cimgui = dep_cimgui,
63             .cimgui_clib_name = cimgui_conf.clib_name,
64         });
65     } else {
66         const exe = try buildNative(b, mod_main);
67         exe.step.dependOn(shdc_step);
68     }
69 }
70
71 fn buildNative(b: *Build, mod: *Build.Module) !*Build.Step.Compile {
72     const exe = b.addExecutable(.{
73         .name = "demo",
74         .root_module = mod,
75     });
76     b.installArtifact(exe);
77     b.step("run", "Run demo").dependOn(&b.addRunArtifact(exe).step);
78     return exe;
79 }
80
81 const BuildWasmOptions = struct {
82     mod_main: *Build.Module,
83     dep_sokol: *Dependency,
84     dep_cimgui: *Dependency,
85     cimgui_clib_name: []const u8,
86 };
87
88 fn buildWasm(b: *Build, opts: BuildWasmOptions) !void {
89     // build the main file into a library, this is because the WASM 'exe'
90     // needs to be linked in a separate build step with the Emscripten linker
91     const demo = b.addLibrary(.{
92         .name = "demo",
93         .root_module = opts.mod_main,
94     });
95
96     // get the Emscripten SDK dependency from the sokol dependency
97     const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{});
98
99     // need to inject the Emscripten system header include path into
100     // the cimgui C library otherwise the C/C++ code won't find
101     // C stdlib headers
102     const emsdk_incl_path = dep_emsdk.path("upstream/emscripten/cache/sysroot/include");
103     opts.dep_cimgui.artifact(opts.cimgui_clib_name).addSystemIncludePath(emsdk_incl_path);
104
105     // all C libraries need to depend on the sokol library, when building for
106     // WASM this makes sure that the Emscripten SDK has been setup before
107     // C compilation is attempted (since the sokol C library depends on the
108     // Emscripten SDK setup step)
109     opts.dep_cimgui.artifact(opts.cimgui_clib_name).step.dependOn(&opts.dep_sokol.artifact("sokol_clib").step);
110
111     // create a build step which invokes the Emscripten linker
112     const link_step = try sokol.emLinkStep(b, .{
113         .lib_main = demo,
114         .target = opts.mod_main.resolved_target.?,
115         .optimize = opts.mod_main.optimize.?,
116         .emsdk = dep_emsdk,
117         .use_webgl2 = true,
118         .use_emmalloc = true,
119         .use_filesystem = false,
120         .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
121     });
122     // attach to default target
123     b.getInstallStep().dependOn(&link_step.step);
124     // ...and a special run step to start the web build output via 'emrun'
125     const run = sokol.emRunStep(b, .{ .name = "demo", .emsdk = dep_emsdk });
126     run.step.dependOn(&link_step.step);
127     b.step("run", "Run demo").dependOn(&run.step);
128 }