const std = @import("std"); const builtin = @import("builtin"); const HEAD_location = ".git/HEAD"; const commit_location = ".git/refs/heads/master"; const common_c_files = &[_][]const u8 { "src/utils/stringBuilder.c", "src/utils/arena.c", "src/wren_inter/wren_inter.c", "src/resources/resources.c", "src/resources/config.c", "src/ui_elements/UI.c", "src/ui_elements/TextEditor.c", "src/ui_elements/Button.c", "src/scenes/sceneManager.c", "src/scenes/mainMenu.c", "src/scenes/resultView.c", "src/scenes/puzzleScene.c", "src/scenes/distractionScene.c", "src/scenes/collectionScene.c", "src/puzzles/puzzle.c", "src/puzzles/parser.c", "src/puzzles/distractions.c", }; pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // ========== Building a game ========== var game_root = b.addModule("game-mod", .{ .optimize = optimize, .target = target, .link_libc = true, }); FillModule(b, game_root, optimize); // The entry point. This is put there separatly to separate from tests entry point game_root.addCSourceFile(.{ .file = b.path("src/main.c") }); const exe = b.addExecutable(.{ .name = "game", .root_module = game_root, }); b.installArtifact(exe); // ========== Running a game ========== const run_step = b.step("run", "Run the app"); const run_cmd = b.addRunArtifact(exe); run_step.dependOn(&run_cmd.step); if (b.args) |args| { run_cmd.addArgs(args); } // ========== Building and running tests ========== const test_runner_root = b.addModule("test-runner-mod", .{ .optimize = optimize, .target = target, .link_libc = true, }); FillModule(b, test_runner_root, optimize); // The only difference is the additional files test_runner_root.addCSourceFiles(.{ .files = &[_][]const u8 { "src/tests/runner.c", "src/tests/arena_tests.c", "src/tests/difficulty_calc.c", } }); const test_runner_exe = b.addExecutable(.{ .name = "game_tests", .root_module = test_runner_root, }); const test_run_step = b.step("test", "Run the test app"); const test_run_cmd = b.addRunArtifact(test_runner_exe); test_run_step.dependOn(&test_run_cmd.step); if (b.args) |args| { test_run_cmd.addArgs(args); } } fn FillModule(b: *std.Build, mod: *std.Build.Module, opt: std.builtin.OptimizeMode) void { // Adding a build version const build_ver = GetVersionString(b, opt) catch "Build UNTRACKED"; if (build_ver.len > 0) mod.addCMacro("BUILD_VERSION", build_ver); mod.addCSourceFiles(.{ .files = common_c_files, }); // Linking raylib if (builtin.target.os.tag == .windows) { // If you are building on windows you need to provide your own // raylib. Put it in the raylib dir mod.addLibraryPath(b.path("raylib/lib/")); mod.addIncludePath(b.path("raylib/include/")); } mod.linkSystemLibrary("raylib", .{.needed = true}); mod.addIncludePath(b.path("include/")); // Linking wren. They do not provide system-wide libraries so you have to // provide them yourself mod.addIncludePath(b.path("wren/src/include/")); mod.addLibraryPath(b.path("wren/lib/")); mod.linkSystemLibrary("wren", .{ .needed = true, .preferred_link_mode = .static, }); } // Returns a build version. Returns an empty string if build in release mode fn GetVersionString(b: *std.Build, optimization: std.builtin.OptimizeMode) ![]u8 { if (optimization != .Debug) { return ""; } const allocator = b.allocator; var threaded = std.Io.Threaded.init(allocator, .{}); defer threaded.deinit(); const headContents = try std.Io.Dir.cwd().readFileAlloc(threaded.io(), HEAD_location, allocator, .limited(std.math.maxInt(usize))); var headIter = std.mem.tokenizeAny(u8, headContents[0..headContents.len - 1], "/"); var branchName: []const u8 = ""; while (headIter.next()) |token| { branchName = token; } const commitContents = try std.Io.Dir.cwd().readFileAlloc(threaded.io(), commit_location, allocator, .limited(std.math.maxInt(usize))); return try std.fmt.allocPrint(allocator, "\"Build {s}:{s}\"", .{ branchName, commitContents[0..@min(commitContents.len-1, 10)] }); }