const std = @import("std"); const Build = std.Build; const OptimizeMode = std.builtin.OptimizeMode; const ResolvedTarget = Build.ResolvedTarget; const Dependency = Build.Dependency; const sokol = @import("sokol"); const cimgui = @import("cimgui"); pub fn build(b: *Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const opt_docking = b.option(bool, "docking", "Build with docking support") orelse false; // Get the matching Zig module name, C header search path and C library for // vanilla imgui vs the imgui docking branch. const cimgui_conf = cimgui.getConfig(opt_docking); // note that the sokol dependency is built with `.with_sokol_imgui = true` const dep_sokol = b.dependency("sokol", .{ .target = target, .optimize = optimize, .with_sokol_imgui = true, }); const dep_cimgui = b.dependency("cimgui", .{ .target = target, .optimize = optimize, }); // inject the cimgui header search path into the sokol C library compile step dep_sokol.artifact("sokol_clib").addIncludePath(dep_cimgui.path(cimgui_conf.include_dir)); // shaders dep_sokol.artifact("sokol_clib").addIncludePath(b.path("ext/cimgui")); const dep_shdc = dep_sokol.builder.dependency("shdc", .{}); const shdc_step = try sokol.shdc.createSourceFile(b, .{ .shdc_dep = dep_shdc, .input = "src/shader/quad.glsl", .output = "src/shader/quad.glsl.zig", .slang = .{ .glsl430 = true }, }); // main module with sokol and cimgui imports const mod_main = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "sokol", .module = dep_sokol.module("sokol") }, .{ .name = cimgui_conf.module_name, .module = dep_cimgui.module(cimgui_conf.module_name) }, }, }); const mod_options = b.addOptions(); mod_options.addOption(bool, "docking", opt_docking); mod_main.addOptions("build_options", mod_options); // from here on different handling for native vs wasm builds if (target.result.cpu.arch.isWasm()) { try buildWasm(b, .{ .mod_main = mod_main, .dep_sokol = dep_sokol, .dep_cimgui = dep_cimgui, .cimgui_clib_name = cimgui_conf.clib_name, }); } else { const exe = try buildNative(b, mod_main); exe.step.dependOn(shdc_step); } } fn buildNative(b: *Build, mod: *Build.Module) !*Build.Step.Compile { const exe = b.addExecutable(.{ .name = "demo", .root_module = mod, }); b.installArtifact(exe); b.step("run", "Run demo").dependOn(&b.addRunArtifact(exe).step); return exe; } const BuildWasmOptions = struct { mod_main: *Build.Module, dep_sokol: *Dependency, dep_cimgui: *Dependency, cimgui_clib_name: []const u8, }; fn buildWasm(b: *Build, opts: BuildWasmOptions) !void { // build the main file into a library, this is because the WASM 'exe' // needs to be linked in a separate build step with the Emscripten linker const demo = b.addLibrary(.{ .name = "demo", .root_module = opts.mod_main, }); // get the Emscripten SDK dependency from the sokol dependency const dep_emsdk = opts.dep_sokol.builder.dependency("emsdk", .{}); // need to inject the Emscripten system header include path into // the cimgui C library otherwise the C/C++ code won't find // C stdlib headers const emsdk_incl_path = dep_emsdk.path("upstream/emscripten/cache/sysroot/include"); opts.dep_cimgui.artifact(opts.cimgui_clib_name).addSystemIncludePath(emsdk_incl_path); // all C libraries need to depend on the sokol library, when building for // WASM this makes sure that the Emscripten SDK has been setup before // C compilation is attempted (since the sokol C library depends on the // Emscripten SDK setup step) opts.dep_cimgui.artifact(opts.cimgui_clib_name).step.dependOn(&opts.dep_sokol.artifact("sokol_clib").step); // create a build step which invokes the Emscripten linker const link_step = try sokol.emLinkStep(b, .{ .lib_main = demo, .target = opts.mod_main.resolved_target.?, .optimize = opts.mod_main.optimize.?, .emsdk = dep_emsdk, .use_webgl2 = true, .use_emmalloc = true, .use_filesystem = false, .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"), }); // attach to default target b.getInstallStep().dependOn(&link_step.step); // ...and a special run step to start the web build output via 'emrun' const run = sokol.emRunStep(b, .{ .name = "demo", .emsdk = dep_emsdk }); run.step.dependOn(&link_step.step); b.step("run", "Run demo").dependOn(&run.step); }