pub const AddProgramOptions = struct { name: []const u8, opt: bh.Options, root_source_file: std.Build.LazyPath, }; // all other modules are disabled by default pub const defaultEnabledModules: []const []const u8 = &.{ "core", "assets", "platform", "rend", }; pub const moduleOrder: []const []const u8 = &.{ "core", "sys", "assets", "platform", "net", "physics", "audio", "rend", "ui", "imgui", "papyrus", }; pub const GameModule = struct { name: []const u8, enabled: bool = true, }; pub const Program = struct { name: []const u8, opts: bh.Options, // root_path: not used yet, we will create a second module that dynamically loads in to that root_path gameModules: std.ArrayListUnmanaged(GameModule) = .{}, gameModulesMap: std.StringHashMapUnmanaged(bool) = .{}, buildSystem: *backlog.BuildSystem, iconPath: ?std.Build.LazyPath = null, allocator: std.mem.Allocator, // just set this to the build allocator pub fn setModuleEnabled(self: *@This(), name: []const u8, enabled: bool) void { const r = self.gameModulesMap.getOrPut(self.allocator, name); r.value_ptr.* = enabled; } fn finalizeModules(self: *@This()) void { self.gameModules.clearRetainingCapacity(); for (moduleOrder) |mod| { var enabled: bool = false; for (defaultEnabledModules) |default| { if (std.mem.eql(u8, default, mod)) { enabled = true; } } if (self.gameModulesMap.get(mod)) |value| { enabled = value; } if (enabled) { self.gameModules.append(self.allocator, .{ .name = mod, .enabled = enabled }) catch unreachable; } } } pub fn setIconPath(self: *@This(), path: []const u8) void { if (self.iconPath != null) { return; } self.iconPath = self.buildSystem.generateRc(self.name, path) catch return; } pub fn makeSpec(self: *@This()) *std.Build.Module { const b = self.buildSystem.b; const run = b.addRunArtifact(self.buildSystem.specGen); const pfile = run.addOutputFileArg(b.fmt("{s}-spec.zig", .{self.name})); run.addArg(self.name); for (self.gameModules.items) |mod| { if (mod.enabled) run.addArg(mod.name); } const mod = b.createModule(.{ .target = self.opts.target, .optimize = self.opts.optimize, .root_source_file = pfile, }); const core = self.buildSystem.nwdep.module("core"); mod.addImport("core", core); return mod; } pub fn makeGameApi(self: *@This()) *std.Build.Module { const b = self.buildSystem.b; const apigen = self.buildSystem.nwdep.artifact("backlog-generate-modapi"); const run = b.addRunArtifact(apigen); const pfile = run.addOutputFileArg(b.fmt("{s}-api.zig", .{self.name})); run.addArg(self.name); for (self.gameModules.items) |mod| { if (mod.enabled) { run.addArg(mod.name); } } const api = b.createModule(.{ .target = self.opts.target, .optimize = self.opts.optimize, .root_source_file = pfile, }); for (self.gameModules.items) |mod| { if (mod.enabled) { api.addImport(mod.name, self.buildSystem.nwdep.module(mod.name)); } } return api; } pub fn makeGameModule(self: *@This()) *std.Build.Step.Compile { const b = self.buildSystem.b; const bEngine = self.buildSystem.bEngine; const opts = self.opts; // 1. generate the main launch codeset. const lib = b.addLibrary(.{ .name = self.name, .linkage = if (opts.static_build) .static else .dynamic, .root_module = b.createModule(.{ .target = opts.target, .optimize = opts.optimize, .root_source_file = bEngine.path("engine/modulelaunch.zig"), }), }); lib.root_module.addImport("core", self.buildSystem.nwdep.module("core")); if (opts.static_build) { // b.installArtifact(lib); } else { const installExtern = b.addInstallArtifact(lib, .{ .dest_dir = .{ .override = .{ .custom = "modules" } }, }); b.getInstallStep().dependOn(&installExtern.step); } return lib; } // spec is linked in both the base trampoline pub fn compileInstall(self: *@This()) *std.Build.Step.Compile { const bEngine = self.buildSystem.bEngine; const b = self.buildSystem.b; const core = self.buildSystem.nwdep.module("core"); self.finalizeModules(); // 1. create the loader const exe = bEngine.addExecutable(.{ .name = self.name, .root_module = bEngine.createModule(.{ .target = self.opts.target, .optimize = self.opts.optimize, .root_source_file = bEngine.path("engine/main2.zig"), }), }); // link core const spec = self.makeSpec(); exe.root_module.addImport("gamespec", spec); exe.root_module.addImport("core", core); exe.root_module.addOptions("BacklogOptions", self.buildSystem.options); const gameModule = self.makeGameModule(); const gameApi = self.makeGameApi(); gameModule.root_module.addImport("backlog", gameApi); { const runArtifact = b.addRunArtifact(exe); if (b.args) |args| { runArtifact.addArgs(args); } const run_exe = b.step(b.fmt("run-{s}", .{self.name}), "runs the program"); run_exe.dependOn(&runArtifact.step); } // 2. create the actual library that the loader will try to load // 3. set up linking, if static then we will link against the loader self.buildSystem.b.installArtifact(exe); // return the actual library not the loader return exe; } // const b = self.b; // const exe = self.nw_builder.addExecutable(.{ // .name = opts.name, // .target = self.target, // .optimize = self.optimize, // .root_source_file = self.nw_builder.path("engine/main.zig"), // }); // b.installArtifact(exe); // const runArtifact = b.addRunArtifact(exe); // if (b.args) |args| { // runArtifact.addArgs(args); // } // const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc); // run_exe.dependOn(&runArtifact.step); // // main path = name/main.zig // const mod = b.addModule(opts.name, .{ // .target = self.target, // .optimize = self.optimize, // .root_source_file = opts.root_source_file, // .imports = opts.imports, // }); // exe.root_module.addImport("main", mod); // // todo.. remove this one and see what happens // exe.root_module.addImport("core", self.nwdep.module("core")); // // mod.addImport("Backlog", self.nw_mod); // exe.root_module.addOptions("BacklogOptions", self.options); // if (self.cookShaders) { // const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot}); // const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"}); // cookShadersCommand.addArg(cookShadersScript); // run_exe.dependOn(&cookShadersCommand.step); // } // b.getInstallStep().dependOn(self.nw_builder.getInstallStep()); // // run_exe.dependOn(b.getInstallStep()); // return mod; }; const std = @import("std"); const bh = @import("bh"); const backlog = @import("../build.zig");