From 3648615829f31b54dfcc8792b0d2bc7eb7961267 Mon Sep 17 00:00:00 2001 From: peterino2 Date: Sun, 7 Dec 2025 14:35:58 -0800 Subject: [PATCH] new build system who dis --- build.archive.zig | 696 ++++++++++++++++++ build.zig | 254 +++++++ build.zig.zon | 47 +- build/Program-old.zig | 84 +++ build/engineDeps.zig | 128 ++++ build/modules-old.zig | 182 +++++ build/program.zig | 117 +++ build/resources.zig | 3 + build/utils.zig | 125 +++- {build => buildgen}/generateApi.zig | 0 .../generateEmbeddedShaders.zig | 0 {build => buildgen}/generateFwd.zig | 0 {build => buildgen}/generateLoadDynamics.zig | 0 {build => buildgen}/generateRc.zig | 0 buildgen/utils.zig | 19 + engine/main2.zig | 7 +- projects/build.zig | 29 +- projects/test-trampoline.zig | 8 + todo.txt | 8 +- 19 files changed, 1638 insertions(+), 69 deletions(-) create mode 100644 build.archive.zig create mode 100644 build/Program-old.zig create mode 100644 build/engineDeps.zig create mode 100644 build/modules-old.zig create mode 100644 build/program.zig create mode 100644 build/resources.zig rename {build => buildgen}/generateApi.zig (100%) rename {build => buildgen}/generateEmbeddedShaders.zig (100%) rename {build => buildgen}/generateFwd.zig (100%) rename {build => buildgen}/generateLoadDynamics.zig (100%) rename {build => buildgen}/generateRc.zig (100%) create mode 100644 buildgen/utils.zig create mode 100644 projects/test-trampoline.zig diff --git a/build.archive.zig b/build.archive.zig new file mode 100644 index 0000000..27330e4 --- /dev/null +++ b/build.archive.zig @@ -0,0 +1,696 @@ +// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac +b: *std.Build, +nw_builder: *std.Build, +target: std.Build.ResolvedTarget, +optimize: std.builtin.Mode, +nw_mod: *std.Build.Module, +spirvReflect: SpirvReflect.SpirvGenerator2, +gltf2ozz: ozz.GltfToOzz, +options: *std.Build.Step.Options, +cookShaders: bool, + +backlogRoot: []const u8, +// list of all shaders discovered under +// content/_shaders/def +reflectShaderPathList: [][]u8 = undefined, + +staticBuild: bool = false, + +nwdep: *std.Build.Dependency, +apigen: *std.Build.Step.Compile, +shaderEmbedGen: *std.Build.Step.Compile, +loadDynamicsGen: *std.Build.Step.Compile, +rcGen: *std.Build.Step.Compile, +generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{}, + +const engineDepList = [_][]const u8{ + "assets", + "audio", + "core", + "net", + "papyrus", + "platform", + "rend", + "ui", + "imgui", + "physics", + "sys", +}; + +const BuildSystem = @This(); +const std = @import("std"); +const Build = std.Build; +const LazyPath = Build.LazyPath; + +const SpirvReflect = @import("SpirvReflect"); +const ozz = @import("ozz"); + +pub const InitOptions = struct { + import_name: []const u8 = "Backlog", + backlogRoot: []const u8 = "./BacklogEngine", + staticBuild: bool = false, + target: Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +}; + +pub fn init(b: *std.Build, opts: InitOptions) BuildSystem { + var buildOpts = declareBuildOptions(b); + + if (opts.target.result.os.tag == .linux) { + // using a static build for linux... object loading hell is not fun + std.debug.print("Important! only supporting static builds for linux", .{}); + buildOpts.static_build = true; + } + + const nwdep = b.dependency(opts.import_name, .{ + .target = opts.target, + .optimize = opts.optimize, + .static_build = buildOpts.static_build, + }); + + var self = BuildSystem{ + .b = b, + .nw_builder = nwdep.builder, + .target = opts.target, + .optimize = opts.optimize, + .nw_mod = nwdep.module("Backlog"), + .backlogRoot = opts.backlogRoot, + .spirvReflect = SpirvReflect.SpirvGenerator2.init(nwdep.builder, .{}), + .options = createGameOptions(b, buildOpts), + .gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}), + .cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false, + + .staticBuild = buildOpts.static_build, + .nwdep = nwdep, + .apigen = nwdep.artifact("backlog-apigen"), + .loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"), + .rcGen = nwdep.artifact("backlog-generate-rc"), + .shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"), + }; + + const exeList = [2]*std.Build.Step.Compile{ self.gltf2ozz.exe, self.spirvReflect.reflect }; + const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine"); + for (exeList) |exe| { + const toolsInstall = b.addInstallArtifact(exe, .{ + .dest_dir = .{ .override = .{ .custom = "tools" } }, + }); + + install_tools.dependOn(&toolsInstall.step); + } + + { + const runArtifact = b.addRunArtifact(self.gltf2ozz.exe); + if (b.args) |args| { + runArtifact.addArgs(args); + } + + const run_exe = b.step("gltf2ozz", "runs the gltf animation converter."); + run_exe.dependOn(&runArtifact.step); + } + + { + const runArtifact = b.addRunArtifact(self.spirvReflect.reflect); + if (b.args) |args| { + runArtifact.addArgs(args); + } + + const run_exe = b.step("spv-reflect", "runs the gltf animation converter."); + run_exe.dependOn(&runArtifact.step); + } + + self.addDependencyInstalls(self.b, .ReleaseFast); + + return self; +} + +pub const AddProgramOptions = struct { + name: []const u8, + desc: []const u8, + root_source_file: LazyPath, + imports: []const Build.Module.Import = &.{}, +}; + +pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module { + 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; +} + +pub const BuildOptions = struct { + mutex_job_queue: bool, + static_build: bool, + zero_logging: bool, + slow_logging: bool, + force_mailbox: bool, +}; + +pub fn declareBuildOptions(b: *std.Build) BuildOptions { + return .{ + .mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false, + .static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false, + .zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false, + .slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false, + .force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false, + }; +} + +pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options { + const opts = b.addOptions(); + + inline for (@typeInfo(BuildOptions).@"struct".fields) |field| { + opts.addOption(bool, field.name, @field(options, field.name)); + } + + // build options for core.zig + // opts.addOption( + // bool, + // "mutex_job_queue", + // ); + + // opts.addOption( + // bool, + // "static_build", + // ); + + // opts.addOption( + // bool, + // "zero_logging", + // ); + // opts.addOption( + // bool, + // "slow_logging", + // ); + // opts.addOption( + // bool, + // "force_mailbox", + // ); + + return opts; +} + +pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void { + const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild }); + mod.addImport(moduleName, dep.module(moduleName)); +} + +pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void { + //if (self.staticBuild) { + //return; + // } + + inline for (DynamicDepList) |d| { + b.installArtifact(b.dependency( + d.dep, + .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild }, + ).artifact(d.artifact)); + } + + // b.installArtifact(b.dependency( + // "sdl3", + // .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild }, + // ).artifact("SDL3")); +} + +const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{ + .{ .dep = "sdl3", .artifact = "SDL3" }, + .{ .dep = "spng", .artifact = "spng_c" }, + .{ .dep = "lua", .artifact = "luac" }, + // .{ .dep = "miniaudio", .artifact = "miniaudio_c" }, + .{ .dep = "zphysics", .artifact = "joltc" }, + // .{ .dep = "enet", .artifact = "enet_c" }, + .{ .dep = "ozz", .artifact = "ozz_cpp" }, +}; + +// 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 DynamicModule = struct { + name: []const u8, + allocator: std.mem.Allocator, + buildSystem: *BuildSystem, + programName: []const u8, + opts: AddProgramOptions, + + extras: std.ArrayListUnmanaged(GameModule) = .{}, + gameModules: std.ArrayListUnmanaged(GameModule) = .{}, + + library: ?*std.Build.Step.Compile = null, + + pub fn addExtraModule(self: *@This(), module: []const u8) void { + self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory"); + } + + pub fn init(name: []const u8, p: *Program) *@This() { + var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory"); + + self.* = .{ + .opts = p.opts, + .programName = p.opts.name, + .buildSystem = p.buildSystem, + .allocator = p.allocator, + .name = name, + }; + + for (p.gameModules.items) |module| { + self.gameModules.append(self.allocator, module) catch @panic("out of memory"); + } + + for (p.extras.items) |module| { + self.extras.append(self.allocator, module) catch @panic("out of memory"); + } + + return self; + } + + pub fn compileInstall(self: *@This()) *std.Build.Step.Compile { + if (self.library) |lib| { + return lib; + } + + const b = self.buildSystem.b; + const static = self.buildSystem.staticBuild; + const lib = if (static) + b.addStaticLibrary(.{ + .root_source_file = self.opts.root_source_file, + .link_libc = true, + .optimize = self.buildSystem.optimize, + .target = self.buildSystem.target, + .name = self.name, + }) + else + b.addSharedLibrary(.{ + .root_source_file = self.opts.root_source_file, + .link_libc = true, + .optimize = self.buildSystem.optimize, + .target = self.buildSystem.target, + .name = self.name, + }); + + var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator); + + for (self.gameModules.items) |mod| { + if (mod.enabled) { + modlist.append(mod.name) catch @panic("out of memory"); + } + } + + for (self.extras.items) |extra| { + self.buildSystem.addExtraModule(lib.root_module, extra.name); + } + + lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null)); + lib.root_module.addOptions("BacklogOptions", self.buildSystem.options); + + if (static) { + // generateApi should create static callers for the main program + } else { + const installExtern = b.addInstallArtifact(lib, .{ + .dest_dir = .{ .override = .{ .custom = "modules" } }, + }); + b.getInstallStep().dependOn(&installExtern.step); + } + + return lib; + } +}; + +pub const GameModule = struct { + name: []const u8, + enabled: bool = true, +}; + +pub const Program = struct { + allocator: std.mem.Allocator, + opts: AddProgramOptions, + gameModules: std.ArrayListUnmanaged(GameModule) = .{}, + extras: std.ArrayListUnmanaged(GameModule) = .{}, + dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{}, + buildSystem: *BuildSystem, + + iconPath: ?std.Build.LazyPath = null, + + pub fn setIconPath(self: *@This(), path: []const u8) void { + if (self.iconPath != null) { + return; + } + + self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return; + } + + pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void { + for (self.gameModules.items) |*m| { + if (std.mem.eql(u8, m.name, module)) { + m.enabled = enable; + return; + } + } + + // module not found, add it here. + self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory"); + } + + pub fn addExtraModule(self: *@This(), module: []const u8) void { + self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory"); + } + + pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule { + const dynamicModule = DynamicModule.init(module, self); + dynamicModule.opts.root_source_file = root_source_file; + self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory"); + + return dynamicModule; + } + + pub fn compileInstall(self: *@This()) *std.Build.Module { + const exe = self.buildSystem.addProgram(self.opts); + var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator); + + for (self.gameModules.items) |mod| { + if (mod.enabled) { + modlist.append(mod.name) catch @panic("out of memory"); + } + } + + for (self.extras.items) |extra| { + self.buildSystem.addExtraModule(exe, extra.name); + } + + exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items)); + + if (self.buildSystem.target.result.os.tag == .windows) { + if (self.iconPath) |ip| { + exe.addWin32ResourceFile(.{ + .file = ip, + .flags = &.{}, + }); + } + } + + return exe; + } +}; + +pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program { + const prog = self.b.allocator.create(Program) catch unreachable; + + prog.* = .{ + .allocator = self.b.allocator, + .opts = opts, + .buildSystem = self, + }; + + for (moduleOrder) |module| { + prog.setModuleEnabled(module, false); + } + + for (defaultEnabledModules) |module| { + prog.setModuleEnabled(module, true); + } + + return prog; +} + +// ========= standalone build instance ======= +// maybe the default should be like an engine launcher/project launcher or something +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false; + + const spirvDep = b.dependency("SpirvReflect", .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }); + _ = spirvDep; + + const fwdGeneratorExe = b.addExecutable(.{ + .name = "backlog-generate-fwd", + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("build/generateFwd.zig"), + }); + + const generateExe = b.addExecutable(.{ + .name = "backlog-apigen", + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("build/generateApi.zig"), + }); + + const generateShaders = b.addExecutable(.{ + .name = "backlog-shaderEmbedGen", + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("build/generateEmbeddedShaders.zig"), + }); + + const generateRcExe = b.addExecutable(.{ + .name = "backlog-generate-rc", + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("build/generateRc.zig"), + }); + + const generateLoadDynamicsExe = b.addExecutable(.{ + .name = "backlog-generate-loadDynamics", + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("build/generateLoadDynamics.zig"), + }); + + b.installArtifact(generateLoadDynamicsExe); + b.installArtifact(generateExe); + b.installArtifact(generateShaders); + b.installArtifact(generateRcExe); + + { + const loadDynamicsStub = b.addModule("loadDynamicsStub", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/loadDynamicsStub.zig"), + }); + + _ = loadDynamicsStub; + + const mod = b.addModule("Backlog", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/backlog.zig"), + }); + + for (engineDepList) |depName| { + const dep = b.dependency( + depName, + .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }, + ); + + const run = b.addRunArtifact(fwdGeneratorExe); + const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName})); + + const modFwd = b.addModule(depName, .{ + .target = target, + .optimize = optimize, + .root_source_file = output, + }); + + mod.addImport(b.fmt("{s}", .{depName}), modFwd); + modFwd.addImport("module", dep.module(depName)); + + // mod.addImport(depName, dep.module(depName)); + } + + // link in large platform support functions... special case. + { + const dep = b.dependency("sdl3", .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }); + const lib = dep.module("SDL3"); + + mod.addImport("sdl3_fwd", lib); + } + } +} + +pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module { + // std.debug.print("GENERATE API:: {s}\n", .{programName}); + + for (moduleList) |mod| { + _ = mod; + // std.debug.print("{s}\n", .{mod}); + } + // + if (self.generatedApis.get(programName)) |m| { + return m; + } + + const run = self.b.addRunArtifact(self.apigen); + const pfile = self.b.fmt("{s}Api.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + for (moduleList) |modName| { + run.addArg(modName); + } + + const mod = self.b.addModule(pfile, .{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = output, + }); + for (moduleList) |modName| { + mod.addImport(modName, self.nwdep.module(modName)); + } + + const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable; + mod.addImport("staticShaderLoader", loadStatics); + + // deal with dynamics + if (dynamicModules) |dynamics| { + const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown"); + mod.addImport("loadDynamics", loadDynamics); + } else { + mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub")); + } + + self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory"); + + return mod; +} + +pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath { + const run = self.b.addRunArtifact(self.rcGen); + const pfile = self.b.fmt("{s}.rc", .{programName}); + const output = run.addOutputFileArg(pfile); + run.addArg(iconPath); + + return output; +} + +pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module { + const run = self.b.addRunArtifact(self.loadDynamicsGen); + const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + if (self.staticBuild) { + run.addArg("static"); + } else { + run.addArg("dynamic"); + } + + for (dynamics) |dyn| { + run.addArg(dyn.name); + } + + const mod = self.b.addModule(pfile, .{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = output, + }); + + mod.addImport("core", self.nwdep.module("core")); + for (dynamics) |dyn| { + const dynmod = dyn.compileInstall(); + mod.addImport(dyn.name, dynmod.root_module); + } + + return mod; +} + +pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module { + const run = self.b.addRunArtifact(self.shaderEmbedGen); + const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + run.addArg(shadersPath); + + const b = self.b; + const mod = self.b.addModule(pfile, .{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = output, + }); + mod.addImport("core", self.nwdep.module("core")); + + var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true }); + defer dir.close(); + + var walker = dir.iterate(); + while (try walker.next()) |shaderType| { + if (shaderType.kind == .directory) { + var d2 = try dir.openDir(shaderType.name, .{ .iterate = true }); + defer d2.close(); + var w2 = d2.iterate(); + while (try w2.next()) |shaderName| { + const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name }); + mod.addAnonymousImport(shaderName.name, .{ + .root_source_file = b.path(shaderPath), + }); + } + } + } + + return mod; +} diff --git a/build.zig b/build.zig index e69de29..3efa854 100644 --- a/build.zig +++ b/build.zig @@ -0,0 +1,254 @@ +// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac +b: *std.Build, +bEngine: *std.Build, // used to resolve executable paths from within the engine's root directory +opts: bh.Options, +nw_mod: *std.Build.Module, +gltf2ozz: ozz.GltfToOzz, +options: *std.Build.Step.Options, +cookShaders: bool, + +backlogRoot: []const u8, + +// list of all shaders discovered under +// content/_shaders/def +reflectShaderPathList: [][]u8 = undefined, + +nwdep: *std.Build.Dependency, +apigen: *std.Build.Step.Compile, +shaderEmbedGen: *std.Build.Step.Compile, +loadDynamicsGen: *std.Build.Step.Compile, +rcGen: *std.Build.Step.Compile, +generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{}, + +pub const BuildSystem = @This(); +const std = @import("std"); +const Build = std.Build; +const LazyPath = Build.LazyPath; + +const ozz = @import("ozz"); + +pub const InitOptions = struct { + import_name: []const u8 = "Backlog", + backlogRoot: []const u8 = "./BacklogEngine", + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, +}; + +pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem { + const buildOpts = declareBuildOptions(b); + + var opts = bh.Options{ + .target = initOptions.target, + .optimize = initOptions.optimize, + .static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false, + .tracy = b.option(bool, "tracy", "builds with tracy support") orelse false, + }; + + if (opts.target.result.os.tag == .linux) { + // using a static build for linux... object loading hell is not fun... + // i have skill issues in that realm right now + std.debug.print("Important! only supporting static builds for linux", .{}); + opts.static_build = true; + } + + const nwdep = b.dependency(initOptions.import_name, .{ + .target = opts.target, + .optimize = opts.optimize, + .static_build = opts.static_build, + }); + + var self = BuildSystem{ + .b = b, + .bEngine = nwdep.builder, + .opts = opts, + .nw_mod = nwdep.module("Backlog"), + .backlogRoot = initOptions.backlogRoot, + .options = createGameOptions(b, buildOpts, opts), + .gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}), + .cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false, + + .nwdep = nwdep, + .apigen = nwdep.artifact("backlog-apigen"), + .loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"), + .rcGen = nwdep.artifact("backlog-generate-rc"), + .shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"), + }; + + const exeList = [1]*std.Build.Step.Compile{self.gltf2ozz.exe}; + const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine"); + for (exeList) |exe| { + const toolsInstall = b.addInstallArtifact(exe, .{ + .dest_dir = .{ .override = .{ .custom = "tools" } }, + }); + + install_tools.dependOn(&toolsInstall.step); + } + + { + const runArtifact = b.addRunArtifact(self.gltf2ozz.exe); + if (b.args) |args| { + runArtifact.addArgs(args); + } + + const run_exe = b.step("gltf2ozz", "runs the gltf animation converter."); + run_exe.dependOn(&runArtifact.step); + } + + self.addDependencyInstalls(self.b, .ReleaseFast); + + return self; +} + +// Build Options for the engine, +// should generally be written as false = default +// true = enabling something +const BuildOptions = struct { + mutex_job_queue: bool, + zero_logging: bool, + slow_logging: bool, + force_mailbox: bool, +}; + +fn declareBuildOptions(b: *std.Build) BuildOptions { + return .{ + .mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false, + .zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false, + .slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false, + .force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false, + }; +} + +fn createGameOptions(b: *std.Build, options: BuildOptions, bhopts: bh.Options) *std.Build.Step.Options { + const opts = b.addOptions(); + + inline for (@typeInfo(BuildOptions).@"struct".fields) |field| { + opts.addOption(bool, field.name, @field(options, field.name)); + } + + // forward the options to the build options + opts.addOption(bool, "tracy", bhopts.tracy); + opts.addOption(bool, "static_build", bhopts.static_build); + + return opts; +} + +pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void { + const dep = self.b.dependency(moduleName, .{ .target = self.opts.target, .optimize = self.opts.optimize, .static_build = self.opts.static_build }); + mod.addImport(moduleName, dep.module(moduleName)); +} + +fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void { + if (self.opts.static_build) { + return; + } + + inline for (DynamicDepList) |d| { + b.installArtifact(b.dependency( + d.dep, + .{ .target = self.opts.target, .optimize = optimize, .static_build = self.opts.static_build }, + ).artifact(d.artifact)); + } +} + +const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{ + .{ .dep = "sdl3", .artifact = "SDL3" }, + .{ .dep = "spng", .artifact = "spng_c" }, + .{ .dep = "lua", .artifact = "luac" }, + .{ .dep = "miniaudio", .artifact = "miniaudio_c" }, + .{ .dep = "zphysics", .artifact = "joltc" }, + // .{ .dep = "enet", .artifact = "enet_c" }, + .{ .dep = "ozz", .artifact = "ozz_cpp" }, +}; + +// 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 fn addProgram( + self: *@This(), + name: []const u8, +) *Program { + const p = self.b.allocator.create(Program) catch unreachable; + p.* = .{ + .name = name, + .opts = self.opts, + .buildSystem = self, + .allocator = self.b.allocator, + }; + + return p; +} + +pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath { + const run = self.b.addRunArtifact(self.rcGen); + const pfile = self.b.fmt("{s}.rc", .{programName}); + const output = run.addOutputFileArg(pfile); + run.addArg(iconPath); + + return output; +} + +pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module { + const run = self.b.addRunArtifact(self.shaderEmbedGen); + const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + run.addArg(shadersPath); + + const b = self.b; + const mod = self.b.addModule(pfile, .{ + .target = self.opts.target, + .optimize = self.opts.optimize, + .root_source_file = output, + }); + mod.addImport("core", self.nwdep.module("core")); + + var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true }); + defer dir.close(); + + var walker = dir.iterate(); + while (try walker.next()) |shaderType| { + if (shaderType.kind == .directory) { + var d2 = try dir.openDir(shaderType.name, .{ .iterate = true }); + defer d2.close(); + var w2 = d2.iterate(); + while (try w2.next()) |shaderName| { + const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name }); + mod.addAnonymousImport(shaderName.name, .{ + .root_source_file = b.path(shaderPath), + }); + } + } + } + + return mod; +} + +// ========= standalone build instance ======= +// maybe the default should be like an engine launcher/project launcher or something +pub fn build(b: *std.Build) void { + const opts = bh.declareOptions(b); + engineDeps.buildGenerators(b, opts); +} + +const bh = @import("bh"); +const engineDeps = @import("build/engineDeps.zig"); +const program = @import("build/program.zig"); +const Program = program.Program; diff --git a/build.zig.zon b/build.zig.zon index ad5dea2..8bc699b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,28 +1,23 @@ -.{ - .name = .Backlog, - .version = "0.0.0", - .dependencies = .{ - .assets = .{ .path = "engine/assets" }, - .audio = .{ .path = "engine/audio" }, - .core = .{ .path = "engine/core" }, - .net = .{ .path = "engine/net" }, - .papyrus = .{ .path = "engine/papyrus" }, - .physics = .{ .path = "engine/physics" }, - .platform = .{ .path = "engine/platform" }, - .imgui = .{ .path = "engine/imgui" }, - .ui = .{ .path = "engine/ui" }, - .sys = .{ .path = "engine/sys" }, - .rend = .{.path = "engine/rend" }, +.{ .name = .Backlog, .version = "0.0.0", .dependencies = .{ + .assets = .{ .path = "engine/assets" }, + .audio = .{ .path = "engine/audio" }, + .core = .{ .path = "engine/core" }, + .net = .{ .path = "engine/net" }, + .papyrus = .{ .path = "engine/papyrus" }, + .physics = .{ .path = "engine/physics" }, + .platform = .{ .path = "engine/platform" }, + .imgui = .{ .path = "engine/imgui" }, + .ui = .{ .path = "engine/ui" }, + .sys = .{ .path = "engine/sys" }, + .rend = .{ .path = "engine/rend" }, - .ozz = .{ .path = "lib/ozz" }, - .spng = .{ .path = "lib/spng" }, - .zphysics = .{ .path = "lib/zphysics" }, + .ozz = .{ .path = "lib/ozz" }, + .spng = .{ .path = "lib/spng" }, + .zphysics = .{ .path = "lib/zphysics" }, - .sdl3 = .{ .path = "lib/sdl3" }, - .enet = .{ .path = "lib/enet" }, - }, - .paths = .{ - "", - }, - .fingerprint = 0xcf9bab998abe37e3 -} + .sdl3 = .{ .path = "lib/sdl3" }, + .enet = .{ .path = "lib/enet" }, + .bh = .{ .path = "lib/bh" }, +}, .paths = .{ + "", +}, .fingerprint = 0xcf9bab998abe37e3 } diff --git a/build/Program-old.zig b/build/Program-old.zig new file mode 100644 index 0000000..14c3ba4 --- /dev/null +++ b/build/Program-old.zig @@ -0,0 +1,84 @@ +pub const AddProgramOptions = struct { + name: []const u8, + desc: []const u8, + root_source_file: LazyPath, + imports: []const Build.Module.Import = &.{}, +}; + +pub const Program = struct { + allocator: std.mem.Allocator, + opts: AddProgramOptions, + gameModules: std.ArrayListUnmanaged(GameModule) = .{}, + extras: std.ArrayListUnmanaged(GameModule) = .{}, + dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{}, + buildSystem: *BuildSystem, + + iconPath: ?std.Build.LazyPath = null, + + pub fn setIconPath(self: *@This(), path: []const u8) void { + if (self.iconPath != null) { + return; + } + + self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return; + } + + pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void { + for (self.gameModules.items) |*m| { + if (std.mem.eql(u8, m.name, module)) { + m.enabled = enable; + return; + } + } + + // module not found, add it here. + self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory"); + } + + pub fn addExtraModule(self: *@This(), module: []const u8) void { + self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory"); + } + + pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule { + const dynamicModule = DynamicModule.init(module, self); + dynamicModule.opts.root_source_file = root_source_file; + self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory"); + + return dynamicModule; + } + + pub fn compileInstall(self: *@This()) *std.Build.Module { + const exe = self.buildSystem.addProgram(self.opts); + const allocator = self.buildSystem.b.allocator; + + var modlist = std.ArrayList([]const u8){}; + + for (self.gameModules.items) |mod| { + if (mod.enabled) { + modlist.append(allocator, mod.name) catch @panic("out of memory"); + } + } + + for (self.extras.items) |extra| { + self.buildSystem.addExtraModule(exe, extra.name); + } + + exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items)); + + if (self.buildSystem.target.result.os.tag == .windows) { + if (self.iconPath) |ip| { + exe.addWin32ResourceFile(.{ + .file = ip, + .flags = &.{}, + }); + } + } + + return exe; + } +}; + +const std = @import("std"); +const Build = std.Build; +const LazyPath = Build.LazyPath; + diff --git a/build/engineDeps.zig b/build/engineDeps.zig new file mode 100644 index 0000000..83f32c9 --- /dev/null +++ b/build/engineDeps.zig @@ -0,0 +1,128 @@ +const engineDepList = [_][]const u8{ + "assets", + "audio", + "core", + "net", + "papyrus", + "platform", + "rend", + "ui", + "imgui", + "physics", + "sys", +}; + +pub fn depList() []const []const u8 { + return &engineDepList; +} + +pub fn buildGenerators(b: *std.Build, opts: bh.Options) void { + const target = opts.target; + const optimize = opts.optimize; + const static_build = opts.static_build; + + const fwdGeneratorExe = b.addExecutable(.{ + .name = "backlog-generate-fwd", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateFwd.zig"), + }), + }); + + const generateExe = b.addExecutable(.{ + .name = "backlog-apigen", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateApi.zig"), + }), + }); + + const generateShaders = b.addExecutable(.{ + .name = "backlog-shaderEmbedGen", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"), + }), + }); + + const generateRcExe = b.addExecutable(.{ + .name = "backlog-generate-rc", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateRc.zig"), + }), + }); + + const generateLoadDynamicsExe = b.addExecutable(.{ + .name = "backlog-generate-loadDynamics", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateLoadDynamics.zig"), + }), + }); + + b.installArtifact(fwdGeneratorExe); + b.installArtifact(generateLoadDynamicsExe); + b.installArtifact(generateExe); + b.installArtifact(generateShaders); + b.installArtifact(generateRcExe); + + { + const loadDynamicsStub = b.addModule("loadDynamicsStub", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/loadDynamicsStub.zig"), + }); + + _ = loadDynamicsStub; + + const mod = b.addModule("Backlog", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/backlog.zig"), + }); + + for (depList()) |depName| { + const dep = b.dependency( + depName, + .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }, + ); + + const run = b.addRunArtifact(fwdGeneratorExe); + const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName})); + + const modFwd = b.addModule(depName, .{ + .target = target, + .optimize = optimize, + .root_source_file = output, + }); + + mod.addImport(b.fmt("{s}", .{depName}), modFwd); + modFwd.addImport("module", dep.module(depName)); + } + + // link in large platform support functions... special case. + { + const dep = b.dependency("sdl3", .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }); + const lib = dep.module("SDL3"); + + mod.addImport("sdl3_fwd", lib); + } + } +} + +const std = @import("std"); +const bh = @import("bh"); diff --git a/build/modules-old.zig b/build/modules-old.zig new file mode 100644 index 0000000..141822d --- /dev/null +++ b/build/modules-old.zig @@ -0,0 +1,182 @@ +// legacy code, kept here as reference +pub const GameModule = struct { + name: []const u8, + enabled: bool = true, +}; + +pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program { + const prog = self.b.allocator.create(Program) catch unreachable; + + prog.* = .{ + .allocator = self.b.allocator, + .opts = opts, + .buildSystem = self, + }; + + for (moduleOrder) |module| { + prog.setModuleEnabled(module, false); + } + + for (defaultEnabledModules) |module| { + prog.setModuleEnabled(module, true); + } + + return prog; +} + +pub const DynamicModule = struct { + name: []const u8, + allocator: std.mem.Allocator, + buildSystem: *BuildSystem, + programName: []const u8, + opts: Program.AddProgramOptions, + + extras: std.ArrayListUnmanaged(Program.GameModule) = .{}, + gameModules: std.ArrayListUnmanaged(Program.GameModule) = .{}, + + library: ?*std.Build.Step.Compile = null, + + pub fn addExtraModule(self: *@This(), module: []const u8) void { + self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory"); + } + + pub fn init(name: []const u8, p: *Program) *@This() { + var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory"); + + self.* = .{ + .opts = p.opts, + .programName = p.opts.name, + .buildSystem = p.buildSystem, + .allocator = p.allocator, + .name = name, + }; + + for (p.gameModules.items) |module| { + self.gameModules.append(self.allocator, module) catch @panic("out of memory"); + } + + for (p.extras.items) |module| { + self.extras.append(self.allocator, module) catch @panic("out of memory"); + } + + return self; + } + + pub fn compileInstall(self: *@This()) *std.Build.Step.Compile { + if (self.library) |lib| { + return lib; + } + + const b = self.buildSystem.b; + const static = self.buildSystem.staticBuild; + const lib = b.addLibrary(.{ + .name = self.name, + .linkage = if (static) .static else .dynamic, + .root_module = b.createModule(.{ + .root_source_file = self.opts.root_source_file, + .link_libc = true, + .optimize = self.buildSystem.optimize, + .target = self.buildSystem.target, + }), + }); + + const allocator = self.buildSystem.b.allocator; + + var modlist = std.ArrayList([]const u8){}; + + for (self.gameModules.items) |mod| { + if (mod.enabled) { + modlist.append(allocator, mod.name) catch @panic("out of memory"); + } + } + + for (self.extras.items) |extra| { + self.buildSystem.addExtraModule(lib.root_module, extra.name); + } + + lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null)); + lib.root_module.addOptions("BacklogOptions", self.buildSystem.options); + + if (!static) { + const installExtern = b.addInstallArtifact(lib, .{ + .dest_dir = .{ .override = .{ .custom = "modules" } }, + }); + b.getInstallStep().dependOn(&installExtern.step); + } + + return lib; + } +}; + +pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule,) *std.Build.Module { + // std.debug.print("GENERATE API:: {s}\n", .{programName}); + + for (moduleList) |mod| { + _ = mod; + // std.debug.print("{s}\n", .{mod}); + } + // + if (self.generatedApis.get(programName)) |m| { + return m; + } + + const run = self.b.addRunArtifact(self.apigen); + const pfile = self.b.fmt("{s}Api.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + for (moduleList) |modName| { + run.addArg(modName); + } + + const mod = self.b.addModule(pfile, .{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = output, + }); + for (moduleList) |modName| { + mod.addImport(modName, self.nwdep.module(modName)); + } + + const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable; + mod.addImport("staticShaderLoader", loadStatics); + + // deal with dynamics + if (dynamicModules) |dynamics| { + const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown"); + mod.addImport("loadDynamics", loadDynamics); + } else { + mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub")); + } + + self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory"); + + return mod; +} + +pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module { + const run = self.b.addRunArtifact(self.loadDynamicsGen); + const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName}); + const output = run.addOutputFileArg(pfile); + if (self.staticBuild) { + run.addArg("static"); + } else { + run.addArg("dynamic"); + } + + for (dynamics) |dyn| { + run.addArg(dyn.name); + } + + const mod = self.b.addModule(pfile, .{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = output, + }); + + mod.addImport("core", self.nwdep.module("core")); + for (dynamics) |dyn| { + const dynmod = dyn.compileInstall(); + mod.addImport(dyn.name, dynmod.root_module); + } + + return mod; +} diff --git a/build/program.zig b/build/program.zig new file mode 100644 index 0000000..3bb7595 --- /dev/null +++ b/build/program.zig @@ -0,0 +1,117 @@ +pub const AddProgramOptions = struct { + name: []const u8, + opt: bh.Options, + root_source_file: std.Build.LazyPath, +}; + +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) = .{}, + buildSystem: *backlog.BuildSystem, + iconPath: ?std.Build.LazyPath = null, + allocator: std.mem.Allocator, // just set this to the build allocator + + 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 compileInstall(self: *@This()) *std.Build.Step.Compile { + const bEngine = self.buildSystem.bEngine; + const b = self.buildSystem.b; + const core = self.buildSystem.nwdep.module("core"); + + const trampoline = b.createModule(.{ + .target = self.opts.target, + .optimize = self.opts.optimize, + .root_source_file = b.path("test-trampoline.zig"), + }); + trampoline.addImport("core", core); + + // 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"), // this path sould be generated by generateTrampoline.zig + }), + }); + + exe.root_module.addImport("core", core); + exe.root_module.addImport("trampoline", trampoline); + exe.root_module.addOptions("BacklogOptions", self.buildSystem.options); + + // link core + + // 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"); diff --git a/build/resources.zig b/build/resources.zig new file mode 100644 index 0000000..7a0c3d5 --- /dev/null +++ b/build/resources.zig @@ -0,0 +1,3 @@ +const std = @import("std"); +const Build = std.Build; +const LazyPath = Build.LazyPath; diff --git a/build/utils.zig b/build/utils.zig index c373dbf..b1a96de 100644 --- a/build/utils.zig +++ b/build/utils.zig @@ -1,19 +1,114 @@ -pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 { - var file = try std.fs.cwd().openFile(filename, .{}); - defer file.close(); - const filesize = (try file.stat()).size + 1; // add null byte - const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize); - errdefer allocator.free(buffer); - try file.reader().readNoEof(buffer[0 .. buffer.len - 1]); - buffer[buffer.len - 1] = 0; - return buffer; + +pub fn buildGenerators(b: *std.Build, opts: bh.Options) void { + const target = opts.target; + const optimize = opts.optimize; + const static_build = opts.static_build; + + const fwdGeneratorExe = b.addExecutable(.{ + .name = "backlog-generate-fwd", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateFwd.zig"), + }), + }); + + const generateExe = b.addExecutable(.{ + .name = "backlog-apigen", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateApi.zig"), + }), + }); + + const generateShaders = b.addExecutable(.{ + .name = "backlog-shaderEmbedGen", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"), + }), + }); + + const generateRcExe = b.addExecutable(.{ + .name = "backlog-generate-rc", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateRc.zig"), + }), + }); + + const generateLoadDynamicsExe = b.addExecutable(.{ + .name = "backlog-generate-loadDynamics", + .root_module = b.createModule(.{ + .target = b.graph.host, + .optimize = .Debug, + .root_source_file = b.path("buildgen/generateLoadDynamics.zig"), + }), + }); + + b.installArtifact(fwdGeneratorExe); + b.installArtifact(generateLoadDynamicsExe); + b.installArtifact(generateExe); + b.installArtifact(generateShaders); + b.installArtifact(generateRcExe); + + { + const loadDynamicsStub = b.addModule("loadDynamicsStub", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/loadDynamicsStub.zig"), + }); + + _ = loadDynamicsStub; + + const mod = b.addModule("Backlog", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("engine/backlog.zig"), + }); + + for (depList()) |depName| { + const dep = b.dependency( + depName, + .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }, + ); + + const run = b.addRunArtifact(fwdGeneratorExe); + const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName})); + + const modFwd = b.addModule(depName, .{ + .target = target, + .optimize = optimize, + .root_source_file = output, + }); + + mod.addImport(b.fmt("{s}", .{depName}), modFwd); + modFwd.addImport("module", dep.module(depName)); + + // mod.addImport(depName, dep.module(depName)); + } + + // link in large platform support functions... special case. + { + const dep = b.dependency("sdl3", .{ + .target = target, + .optimize = optimize, + .static_build = static_build, + }); + const lib = dep.module("SDL3"); + + mod.addImport("sdl3_fwd", lib); + } + } } -pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 { - var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig); - const out = try ast.render(allocator); - - return out; -} const std = @import("std"); +const bh = @import("bh"); diff --git a/build/generateApi.zig b/buildgen/generateApi.zig similarity index 100% rename from build/generateApi.zig rename to buildgen/generateApi.zig diff --git a/build/generateEmbeddedShaders.zig b/buildgen/generateEmbeddedShaders.zig similarity index 100% rename from build/generateEmbeddedShaders.zig rename to buildgen/generateEmbeddedShaders.zig diff --git a/build/generateFwd.zig b/buildgen/generateFwd.zig similarity index 100% rename from build/generateFwd.zig rename to buildgen/generateFwd.zig diff --git a/build/generateLoadDynamics.zig b/buildgen/generateLoadDynamics.zig similarity index 100% rename from build/generateLoadDynamics.zig rename to buildgen/generateLoadDynamics.zig diff --git a/build/generateRc.zig b/buildgen/generateRc.zig similarity index 100% rename from build/generateRc.zig rename to buildgen/generateRc.zig diff --git a/buildgen/utils.zig b/buildgen/utils.zig new file mode 100644 index 0000000..c373dbf --- /dev/null +++ b/buildgen/utils.zig @@ -0,0 +1,19 @@ +pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 { + var file = try std.fs.cwd().openFile(filename, .{}); + defer file.close(); + const filesize = (try file.stat()).size + 1; // add null byte + const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize); + errdefer allocator.free(buffer); + try file.reader().readNoEof(buffer[0 .. buffer.len - 1]); + buffer[buffer.len - 1] = 0; + return buffer; +} + +pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 { + var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig); + const out = try ast.render(allocator); + + return out; +} + +const std = @import("std"); diff --git a/engine/main2.zig b/engine/main2.zig index faa6bcc..829b39d 100644 --- a/engine/main2.zig +++ b/engine/main2.zig @@ -2,7 +2,9 @@ const std = @import("std"); const core = @import("core").module; const panickers = core.panickers; -const realMain = @import("main"); +// const realMain = @import("main"); + +pub const trampoline = @import("trampoline"); pub const options = @import("BacklogOptions"); @@ -46,6 +48,7 @@ pub fn main() !void { core.engine_log("Working Dir set: {s}", .{try std.fs.cwd().realpath(".", &BUFFER)}); } + trampoline.launch(); // panickers.attachSegfaultHandler(); - try realMain.main(); + // try realMain.main(); } diff --git a/projects/build.zig b/projects/build.zig index bfd8987..646fffd 100644 --- a/projects/build.zig +++ b/projects/build.zig @@ -5,32 +5,15 @@ pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - var blbuild = Backlog.init(b, .{ + var buildSystem = Backlog.init(b, .{ .target = target, .optimize = optimize, .backlogRoot = "../", }); - const sampleGame = blbuild.program(.{ - .name = "sampleGame", - .desc = "sample game with hot reloading", - .root_source_file = b.path("sampleGame/sampleGame.zig"), - }); - - sampleGame.setModuleEnabled("imgui", true); - sampleGame.setModuleEnabled("audio", true); - sampleGame.setModuleEnabled("physics", true); - sampleGame.setModuleEnabled("ui", true); - sampleGame.setModuleEnabled("sys", true); - sampleGame.setModuleEnabled("net", true); - - sampleGame.addExtraModule("gameExtras"); - sampleGame.addExtraModule("videoplayer"); - sampleGame.addExtraModule("doomplayer"); - sampleGame.addExtraModule("bsp"); - - sampleGame.setIconPath("icons/icon.ico"); - - const sampleGameExe = sampleGame.compileInstall(); - _ = sampleGameExe; + const coreTest = buildSystem.addProgram( + "coreTest", + ); + coreTest.setIconPath("projects/content/icons/icon.ico"); + _ = coreTest.compileInstall(); } diff --git a/projects/test-trampoline.zig b/projects/test-trampoline.zig new file mode 100644 index 0000000..2c26c25 --- /dev/null +++ b/projects/test-trampoline.zig @@ -0,0 +1,8 @@ +// This is a trampoline file, it only depends on core. +// Then calls LoadModule on the target module + +const core = @import("core").module; + +pub fn launch() void { + core.engine_log("This is where my modules would be loaded!", .{}); +} diff --git a/todo.txt b/todo.txt index 7b4458d..435ec56 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,7 @@ -how the fuck do i do this +I think before i can do anything else -1. change it so that the core executable only links core +I need to clean up build.zig -actual issues we need to fix. +engineDepList should be discovered from the filesystem + +many functions should be moved into build/ scripts