const std = @import("std"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // https://ziglang.org/learn/build-system/#conditional-compilation const options = b.addOptions(); const do_hotload = b.option(bool, "hotload", "build with hotload") orelse true; options.addOption(bool, "hotload", do_hotload); const do_shaders = b.option(bool, "shaders", "build the GPU shaders") orelse false; options.options.addOption(bool, "shaders", do_shaders); const c_mod = buildClibs(b, target, optimize); const game_mod = buildGame(b, target, optimize, do_hotload); const shaders_mod = buildShaders(b, optimize, game_mod, do_shaders); const engine_mod = b.createModule(.{ .root_source_file = b.path("src/engine/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "c", .module = c_mod }, .{ .name = "game", .module = game_mod }, .{ .name = "shaders", .module = shaders_mod }, }, }); engine_mod.addOptions("options", options); // Game executable const exe = b.addExecutable(.{ .name = "sadira", .root_module = engine_mod, // TODO remove this in the future when Zig's backend works with LLDB .use_llvm = true, }); b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); run_cmd.addPassthruArgs(); run_cmd.step.dependOn(b.getInstallStep()); const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); } fn buildGame( b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, do_hotload: bool, ) *std.Build.Module { // The game module MUST NOT depend on any C libraries const game_mod = b.addModule("game", .{ .root_source_file = b.path("src/game/root.zig"), .target = target, .optimize = optimize, }); const tests = b.addTest(.{ .root_module = game_mod, }); const run_game_tests = b.addRunArtifact(tests); const test_step = b.step("test", "Run tests"); test_step.dependOn(&run_game_tests.step); if (do_hotload) { const game_lib = b.addLibrary(.{ .name = "sadira", .root_module = game_mod, .linkage = .dynamic, .use_llvm = true, }); b.installArtifact(game_lib); } return game_mod; } fn buildClibs( b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, ) *std.Build.Module { const tsl_c = b.addTranslateC(.{ .root_source_file = b.path("src/include.h"), .target = target, .optimize = optimize, .link_libc = true, }); tsl_c.linkSystemLibrary("sdl3", .{}); tsl_c.linkSystemLibrary("sqlite3", .{}); const mod = tsl_c.createModule(); // mod.addObjectFile(b.path("/how/get/to/libtcl9.0.a")); // mod.addObjectFile(b.path("/how/get/to/libtcl9.0tk9.0.a")); return mod; } fn buildShaders( b: *std.Build, optimize: std.builtin.OptimizeMode, game_mod: *std.Build.Module, do_shaders: bool, ) *std.Build.Module { const shader_mod = b.addModule("shaders", .{ .root_source_file = b.path("src/shaders/root.zig"), .imports = &.{.{ .name = "game", .module = game_mod }}, }); if (do_shaders) { const frag_name = "fragment.spv"; const vert_name = "vertex.spv"; const frag_shader = buildShader(b, frag_name, .{ .root_source_file = b.path("src/shaders/fragment.zig"), .optimize = optimize, .imports = &.{.{ .name = "game", .module = game_mod }}, }); const vert_shader = buildShader(b, vert_name, .{ .root_source_file = b.path("src/shaders/vertex.zig"), .optimize = optimize, }); // https://ziglang.org/learn/build-system/#embed-file shader_mod.addAnonymousImport(frag_name, .{ .root_source_file = frag_shader.getEmittedBin(), }); shader_mod.addAnonymousImport(vert_name, .{ .root_source_file = vert_shader.getEmittedBin(), }); } return shader_mod; } // https://gist.github.com/alichraghi/cc4b1db0a0a556de4f85cf06f0e7a400 fn buildShader( b: *std.Build, name: []const u8, options: std.Build.Module.CreateOptions, ) *std.Build.Step.Compile { // https://ziglang.org/documentation/0.16.0/std/#std.Target.Query const target = b.resolveTargetQuery(.{ .cpu_arch = .spirv64, .cpu_model = .{ .explicit = &std.Target.spirv.cpu.vulkan_v1_2 }, .abi = .none, .os_tag = .vulkan, .ofmt = .spirv, // .cpu_features_add = std.Target.spirv.Feature.int64 }); // Copy the options and overwrite the target var opts = options; opts.target = opts.target orelse target; const shader = b.addObject(.{ .name = name, .root_module = b.createModule(opts), }); return shader; }