╭ build.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 3 pub fn build(b: *std.Build) void { 4 const xit_dep = b.dependency("xit", .{}); 5 const ansi_art = ansiArtModule(b); 6 const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; 7 8 // wasm 9 const wasm_exe = blk: { 10 const wasm_target = b.resolveTargetQuery(.{ 11 .cpu_arch = .wasm32, 12 .os_tag = .freestanding, 13 }); 14 15 const exe = b.addExecutable(.{ 16 .name = "haxy", 17 .root_module = b.createModule(.{ 18 .root_source_file = b.path("src/main_wasm.zig"), 19 .target = wasm_target, 20 .optimize = .ReleaseSmall, 21 }), 22 }); 23 exe.root_module.addImport("xit", xit_dep.module("xit")); 24 25 exe.entry = .disabled; 26 exe.rdynamic = true; 27 exe.import_memory = false; 28 exe.export_memory = true; 29 exe.stack_size = std.wasm.page_size * 8; 30 31 // start small and let the allocator grow on demand up to wasm32's 32 // architectural ceiling (65536 pages = 4 GiB) 33 const initial_pages = 16; 34 const max_pages = 65536; 35 exe.initial_memory = std.wasm.page_size * initial_pages; 36 exe.max_memory = std.wasm.page_size * max_pages; 37 38 const install_exe = b.addInstallArtifact(exe, .{}); 39 40 const wasm_step = b.step("wasm", "Generate the wasm"); 41 wasm_step.dependOn(&install_exe.step); 42 43 break :blk exe; 44 }; 45 46 const target = b.standardTargetOptions(.{}); 47 const optimize = b.standardOptimizeOption(.{}); 48 49 // main 50 { 51 const exe = b.addExecutable(.{ 52 .name = "haxy", 53 .root_module = b.createModule(.{ 54 .root_source_file = b.path("src/main.zig"), 55 .target = target, 56 // default to ReleaseSafe unless an explicit -Doptimize is passed 57 .optimize = if (b.user_input_options.contains("optimize")) optimize else .ReleaseSafe, 58 }), 59 .use_llvm = true, 60 }); 61 exe.root_module.addImport("xit", xit_dep.module("xit")); 62 exe.root_module.addImport("ansi_art", ansi_art); 63 exe.root_module.addAnonymousImport("haxy.wasm", .{ 64 .root_source_file = wasm_exe.getEmittedBin(), 65 }); 66 67 const install_exe = b.addInstallArtifact(exe, .{}); 68 b.getInstallStep().dependOn(&install_exe.step); 69 } 70 71 // test 72 { 73 const unit_tests = b.addTest(.{ 74 .root_module = b.createModule(.{ 75 .root_source_file = b.path("src/test.zig"), 76 .target = target, 77 .optimize = optimize, 78 }), 79 .filters = test_filters, 80 }); 81 unit_tests.root_module.addImport("xit", xit_dep.module("xit")); 82 unit_tests.root_module.addImport("ansi_art", ansi_art); 83 84 const run_unit_tests = b.addRunArtifact(unit_tests); 85 run_unit_tests.has_side_effects = true; 86 const test_step = b.step("test", "Run unit tests"); 87 test_step.dependOn(&run_unit_tests.step); 88 } 89 90 // module for using haxy as a library 91 // (the commands below consume haxy this way) 92 const haxy = b.addModule("haxy", .{ 93 .root_source_file = b.path("src/lib.zig"), 94 }); 95 haxy.addImport("xit", xit_dep.module("xit")); 96 haxy.addImport("ansi_art", ansi_art); 97 haxy.addAnonymousImport("haxy.wasm", .{ 98 .root_source_file = wasm_exe.getEmittedBin(), 99 }); 100 101 // try 102 { 103 const exe = b.addExecutable(.{ 104 .name = "try", 105 .root_module = b.createModule(.{ 106 .root_source_file = b.path("src/try.zig"), 107 .target = target, 108 .optimize = optimize, 109 }), 110 }); 111 exe.root_module.addImport("haxy", haxy); 112 const try_install = b.addInstallArtifact(exe, .{}); 113 114 const run_cmd = b.addRunArtifact(exe); 115 run_cmd.step.dependOn(&try_install.step); 116 if (b.args) |args| { 117 run_cmd.addArgs(args); 118 } 119 120 const run_step = b.step("try", "Try the app"); 121 run_step.dependOn(&run_cmd.step); 122 } 123 124 // testnet 125 { 126 const server_exe = b.addExecutable(.{ 127 .name = "haxy", 128 .root_module = b.createModule(.{ 129 .root_source_file = b.path("src/main.zig"), 130 .target = target, 131 .optimize = .Debug, 132 }), 133 .use_llvm = true, 134 }); 135 server_exe.root_module.addImport("xit", xit_dep.module("xit")); 136 server_exe.root_module.addImport("ansi_art", ansi_art); 137 server_exe.root_module.addAnonymousImport("haxy.wasm", .{ 138 .root_source_file = wasm_exe.getEmittedBin(), 139 }); 140 const install_server_exe = b.addInstallArtifact(server_exe, .{}); 141 142 const unit_tests = b.addTest(.{ 143 .root_module = b.createModule(.{ 144 .root_source_file = b.path("src/testnet.zig"), 145 .target = target, 146 .optimize = optimize, 147 }), 148 .filters = test_filters, 149 }); 150 unit_tests.root_module.addImport("haxy", haxy); 151 152 const run_unit_tests = b.addRunArtifact(unit_tests); 153 run_unit_tests.has_side_effects = true; 154 run_unit_tests.step.dependOn(&install_server_exe.step); 155 const test_step = b.step("testnet", "Run network unit tests"); 156 test_step.dependOn(&run_unit_tests.step); 157 } 158 } 159 160 // reads every ANSI-art text file while configuring the build. sorting keeps 161 // the generated module stable when directory iteration order changes. 162 fn ansiArtModule(b: *std.Build) *std.Build.Module { 163 const io = b.graph.io; 164 var dir = b.build_root.handle.openDir(io, "src/embed/ansi", .{ .iterate = true }) catch |err| { 165 std.debug.panic("unable to open src/embed/ansi: {t}", .{err}); 166 }; 167 defer dir.close(io); 168 169 var names: std.ArrayList([]const u8) = .empty; 170 var iter = dir.iterate(); 171 while (iter.next(io) catch |err| std.debug.panic("unable to read src/embed/ansi: {t}", .{err})) |entry| { 172 if (entry.kind != .file or !std.mem.endsWith(u8, entry.name, ".txt")) continue; 173 names.append(b.allocator, b.dupe(entry.name)) catch @panic("OOM"); 174 } 175 std.mem.sort([]const u8, names.items, {}, struct { 176 fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool { 177 return std.mem.order(u8, lhs, rhs) == .lt; 178 } 179 }.lessThan); 180 if (names.items.len == 0) @panic("src/embed/ansi must contain at least one .txt file"); 181 182 const contents = b.allocator.alloc([]const u8, names.items.len) catch @panic("OOM"); 183 for (names.items, contents) |name, *content| { 184 content.* = dir.readFileAlloc(io, name, b.allocator, .limited(16 * 1024 * 1024)) catch |err| { 185 std.debug.panic("unable to read src/embed/ansi/{s}: {t}", .{ name, err }); 186 }; 187 } 188 189 const not_found = b.build_root.handle.readFileAlloc(io, "src/embed/not-found.txt", b.allocator, .limited(16 * 1024 * 1024)) catch unreachable; 190 191 const options = b.addOptions(); 192 options.addOption([]const []const u8, "art", contents); 193 options.addOption([]const u8, "not_found", not_found); 194 return options.createModule(); 195 } 196