This commit is contained in:
peterino2 2025-12-30 13:55:35 -08:00
parent bb99e9025e
commit 97c8de24b9
8 changed files with 211 additions and 34 deletions

View File

@ -38,7 +38,7 @@ pub const InitOptions = struct {
pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem { pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem {
const buildOpts = declareBuildOptions(b); const buildOpts = declareBuildOptions(b);
var opts = bh.Options{ const opts = bh.Options{
.target = initOptions.target, .target = initOptions.target,
.optimize = initOptions.optimize, .optimize = initOptions.optimize,
.static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false, .static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false,
@ -48,8 +48,8 @@ pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem {
if (opts.target.result.os.tag == .linux) { if (opts.target.result.os.tag == .linux) {
// using a static build for linux... object loading hell is not fun... // using a static build for linux... object loading hell is not fun...
// i have skill issues in that realm right now // i have skill issues in that realm right now
std.debug.print("Important! only supporting static builds for linux", .{}); // std.debug.print("Important! only supporting static builds for linux", .{});
opts.static_build = true; // opts.static_build = true;
} }
const nwdep = b.dependency(initOptions.import_name, .{ const nwdep = b.dependency(initOptions.import_name, .{
@ -162,28 +162,6 @@ const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } =
.{ .dep = "ozz", .artifact = "ozz_cpp" }, .{ .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( pub fn addProgram(
self: *@This(), self: *@This(),
name: []const u8, name: []const u8,

View File

@ -30,6 +30,15 @@ pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
}), }),
}); });
const generateModApiExe = b.addExecutable(.{
.name = "backlog-generate-modapi",
.root_module = b.createModule(.{
.target = b.graph.host,
.optimize = .Debug,
.root_source_file = b.path("buildgen/generateModApi.zig"),
}),
});
const generateProgramSpecExe = b.addExecutable(.{ const generateProgramSpecExe = b.addExecutable(.{
.name = "backlog-generate-spec", .name = "backlog-generate-spec",
.root_module = b.createModule(.{ .root_module = b.createModule(.{
@ -71,6 +80,7 @@ pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
b.installArtifact(generateProgramSpecExe); b.installArtifact(generateProgramSpecExe);
b.installArtifact(generateShaders); b.installArtifact(generateShaders);
b.installArtifact(generateRcExe); b.installArtifact(generateRcExe);
b.installArtifact(generateModApiExe);
{ {
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{ const loadDynamicsStub = b.addModule("loadDynamicsStub", .{

View File

@ -4,6 +4,28 @@ pub const AddProgramOptions = struct {
root_source_file: std.Build.LazyPath, 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 { pub const GameModule = struct {
name: []const u8, name: []const u8,
enabled: bool = true, enabled: bool = true,
@ -16,10 +38,37 @@ pub const Program = struct {
// root_path: not used yet, we will create a second module that dynamically loads in to that root_path // root_path: not used yet, we will create a second module that dynamically loads in to that root_path
gameModules: std.ArrayListUnmanaged(GameModule) = .{}, gameModules: std.ArrayListUnmanaged(GameModule) = .{},
gameModulesMap: std.StringHashMapUnmanaged(bool) = .{},
buildSystem: *backlog.BuildSystem, buildSystem: *backlog.BuildSystem,
iconPath: ?std.Build.LazyPath = null, iconPath: ?std.Build.LazyPath = null,
allocator: std.mem.Allocator, // just set this to the build allocator 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 { pub fn setIconPath(self: *@This(), path: []const u8) void {
if (self.iconPath != null) { if (self.iconPath != null) {
return; return;
@ -50,17 +99,72 @@ pub const Program = struct {
return mod; 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 { pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
const bEngine = self.buildSystem.bEngine; const bEngine = self.buildSystem.bEngine;
const b = self.buildSystem.b; const b = self.buildSystem.b;
const core = self.buildSystem.nwdep.module("core"); const core = self.buildSystem.nwdep.module("core");
self.finalizeModules();
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 // 1. create the loader
const exe = bEngine.addExecutable(.{ const exe = bEngine.addExecutable(.{
@ -68,7 +172,7 @@ pub const Program = struct {
.root_module = bEngine.createModule(.{ .root_module = bEngine.createModule(.{
.target = self.opts.target, .target = self.opts.target,
.optimize = self.opts.optimize, .optimize = self.opts.optimize,
.root_source_file = bEngine.path("engine/main2.zig"), // this path sould be generated by generateTrampoline.zig .root_source_file = bEngine.path("engine/main2.zig"),
}), }),
}); });
@ -76,9 +180,12 @@ pub const Program = struct {
const spec = self.makeSpec(); const spec = self.makeSpec();
exe.root_module.addImport("gamespec", spec); exe.root_module.addImport("gamespec", spec);
exe.root_module.addImport("core", core); exe.root_module.addImport("core", core);
exe.root_module.addImport("trampoline", trampoline);
exe.root_module.addOptions("BacklogOptions", self.buildSystem.options); 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); const runArtifact = b.addRunArtifact(exe);
if (b.args) |args| { if (b.args) |args| {

View File

@ -0,0 +1,49 @@
const std = @import("std");
pub fn usage() void {
std.debug.print("generates a loader module which calls the start_modules for all the modules that the game module depends on.\ngenerate-mod-api <output file name> <module_name> <module list>\n", .{});
}
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Get output filename from build system
const args = try std.process.argsAlloc(allocator);
if (args.len < 3) {
usage();
@panic("Missing output filename\n");
}
const out_path = args[1];
const module_name = args[2];
const module_list = args[3..];
var writer = std.ArrayList(u8){};
try writer.print(allocator, "pub const moduleName:[]const u8 = \"{s}\";\n", .{module_name});
try writer.print(allocator, "pub const moduleList:[]const []const u8 = &.{{\n", .{});
for (module_list) |mod| {
try writer.print(allocator, "\"{s}\",\n", .{mod});
}
try writer.print(allocator, "}};\n", .{});
for (module_list) |mod| {
try writer.print(allocator, "pub const {s} = @import(\"{s}\").module;\n", .{ mod, mod });
}
try writer.append(allocator, 0);
const file = try std.fs.cwd().createFile(out_path, .{});
defer file.close();
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
// std.debug.print("output=\n{s}", .{writer.items[0 .. writer.items.len - 1]});
defer ast.deinit(allocator);
const out = try ast.renderAlloc(allocator);
// Write the content to the file
try file.writeAll(out);
}

View File

@ -46,6 +46,8 @@ pub fn main() !void {
\\ \\
); );
_ = try writer.print(allocator, "pub const programName = \"{s}\";", .{programName});
try writer.append(allocator, 0); try writer.append(allocator, 0);
// Write to specified output file // Write to specified output file

View File

@ -0,0 +1,14 @@
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
_ = allocator;
core.engine_logs("module started");
return true;
}
pub export fn shutdown_module() void {}
// const backlog = @import("backlog");
// const core = backlog.core;
const core = @import("core").module;

View File

@ -6,6 +6,7 @@ const panickers = core.panickers;
pub const gamespec = @import("gamespec"); pub const gamespec = @import("gamespec");
pub const options = @import("BacklogOptions"); pub const options = @import("BacklogOptions");
pub const std_options = std.Options{ pub const std_options = std.Options{
.enable_segfault_handler = true, .enable_segfault_handler = true,
}; };

View File

@ -0,0 +1,16 @@
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
_ = allocator;
core.engine_log("module started {s}", .{backlog.moduleName});
for (backlog.moduleList) |li| {
core.engine_log("mod: {s}", .{li});
}
return true;
}
pub export fn shutdown_module() void {}
const backlog = @import("backlog");
const core = backlog.core;