@pkmn/engine 0.1.0-dev.b05836cd → 0.1.0-dev.b14f2221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +1 -3
  2. package/README.md +56 -21
  3. package/build/pkg/addon/browser.d.ts +3 -0
  4. package/build/pkg/addon/browser.js +47 -0
  5. package/build/pkg/addon/browser.js.map +1 -0
  6. package/build/pkg/addon/node.d.ts +3 -0
  7. package/build/pkg/addon/node.js +110 -0
  8. package/build/pkg/addon/node.js.map +1 -0
  9. package/build/pkg/addon/wasm.d.ts +2 -0
  10. package/build/pkg/addon/wasm.js +53 -0
  11. package/build/pkg/addon/wasm.js.map +1 -0
  12. package/build/pkg/addon.d.ts +26 -4
  13. package/build/pkg/addon.js +39 -71
  14. package/build/pkg/addon.js.map +1 -1
  15. package/build/pkg/data/layout.json +15 -2
  16. package/build/pkg/data/protocol.json +23 -9
  17. package/build/pkg/data.d.ts +27 -5
  18. package/build/pkg/data.js.map +1 -1
  19. package/build/pkg/gen1.d.ts +15 -18
  20. package/build/pkg/gen1.js +28 -19
  21. package/build/pkg/gen1.js.map +1 -1
  22. package/build/pkg/index.d.ts +42 -91
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +20 -1
  26. package/build/pkg/protocol.js +109 -107
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +69 -76
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +152 -0
  31. package/build/tools/display/debug.jsx.map +1 -0
  32. package/build/tools/display/index.js +152 -0
  33. package/build/tools/display/index.js.map +1 -0
  34. package/build/tools/display/ui.jsx +359 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +33 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +256 -122
  39. package/package.json +62 -134
  40. package/src/bin/install-pkmn-engine +47 -21
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +200 -0
  43. package/src/lib/{binding → bindings}/node.zig +15 -32
  44. package/src/lib/bindings/wasm.zig +50 -0
  45. package/src/lib/common/array.zig +70 -0
  46. package/src/lib/common/data.zig +4 -4
  47. package/src/lib/common/debug.zig +32 -11
  48. package/src/lib/common/js.zig +3 -7
  49. package/src/lib/common/optional.zig +12 -18
  50. package/src/lib/common/options.zig +6 -0
  51. package/src/lib/common/protocol.zig +209 -178
  52. package/src/lib/common/rational.zig +340 -253
  53. package/src/lib/common/rng.zig +7 -9
  54. package/src/lib/common/util.zig +33 -1
  55. package/src/lib/gen1/calc.zig +724 -175
  56. package/src/lib/gen1/chance.zig +453 -291
  57. package/src/lib/gen1/data/moves.zig +2 -4
  58. package/src/lib/gen1/data/species.zig +2 -4
  59. package/src/lib/gen1/data/types.zig +3 -4
  60. package/src/lib/gen1/data.zig +29 -32
  61. package/src/lib/gen1/helpers.zig +91 -549
  62. package/src/lib/gen1/mechanics.zig +417 -294
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +85 -503
  65. package/src/lib/gen2/data/items.zig +1 -3
  66. package/src/lib/gen2/data/moves.zig +2 -4
  67. package/src/lib/gen2/data/species.zig +1 -3
  68. package/src/lib/gen2/data/types.zig +7 -5
  69. package/src/lib/gen2/data.zig +27 -29
  70. package/src/lib/gen2/generated.zig +19 -26
  71. package/src/lib/gen2/helpers.zig +45 -26
  72. package/src/lib/gen2/mechanics.zig +234 -180
  73. package/src/lib/napi.h +2 -0
  74. package/src/lib/node.zig +14 -0
  75. package/src/lib/pkmn.zig +125 -29
  76. package/src/lib/wasm.zig +13 -0
  77. package/src/tools/display/dom.ts +93 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -400
  80. package/build/test/display.js.map +0 -1
  81. package/src/lib/binding/wasm.zig +0 -12
  82. package/src/lib/gen1/README.md +0 -894
  83. package/src/lib/gen2/README.md +0 -329
  84. package/src/test/display/pkmn.html.tmpl +0 -368
package/build.zig CHANGED
@@ -1,5 +1,9 @@
1
- const std = @import("std");
2
1
  const builtin = @import("builtin");
2
+ const std = @import("std");
3
+
4
+ fn ArrayList(comptime T: type) type {
5
+ return std.array_list.Aligned(T, null);
6
+ }
3
7
 
4
8
  pub const Options = struct {
5
9
  showdown: ?bool = null,
@@ -9,16 +13,16 @@ pub const Options = struct {
9
13
  };
10
14
 
11
15
  pub fn module(b: *std.Build, options: Options) *std.Build.Module {
12
- const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
13
16
  const build_options = b.addOptions();
14
17
  build_options.addOption(?bool, "showdown", options.showdown);
15
18
  build_options.addOption(?bool, "log", options.log);
16
19
  build_options.addOption(?bool, "chance", options.chance);
17
20
  build_options.addOption(?bool, "calc", options.calc);
18
- return b.createModule(.{
19
- .source_file = .{ .path = dirname ++ "/src/lib/pkmn.zig" },
20
- .dependencies = &.{.{ .name = "build_options", .module = build_options.createModule() }},
21
- });
21
+
22
+ const root_source_file = b.path("src/lib/pkmn.zig");
23
+ const imports: []const std.Build.Module.Import =
24
+ &.{.{ .name = "build_options", .module = build_options.createModule() }};
25
+ return b.createModule(.{ .root_source_file = root_source_file, .imports = imports });
22
26
  }
23
27
 
24
28
  pub fn build(b: *std.Build) !void {
@@ -28,12 +32,16 @@ pub fn build(b: *std.Build) !void {
28
32
  const node_headers = b.option([]const u8, "node-headers", "Path to node-headers");
29
33
  const node_import_lib =
30
34
  b.option([]const u8, "node-import-library", "Path to node import library (Windows)");
35
+ const demo = if (try exists(b, "src/tools/demo.zig"))
36
+ b.option(bool, "demo", "Build the demo library") orelse false
37
+ else
38
+ false;
31
39
  const wasm = b.option(bool, "wasm", "Build a WASM library") orelse false;
32
40
  const wasm_stack_size =
33
41
  b.option(u64, "wasm-stack-size", "The size of WASM stack") orelse std.wasm.page_size;
34
42
  const dynamic = b.option(bool, "dynamic", "Build a dynamic library") orelse false;
35
- const strip = b.option(bool, "strip", "Strip debugging symbols from binary") orelse false;
36
- const pic = b.option(bool, "pic", "Force position independent code") orelse false;
43
+ const strip = b.option(bool, "strip", "Strip debugging symbols from binary");
44
+ const pic = b.option(bool, "pic", "Force position independent code");
37
45
  const emit_asm = b.option(bool, "emit-asm", "Output .s (assembly code)") orelse false;
38
46
  const emit_ll = b.option(bool, "emit-ll", "Output .ll (LLVM IR)") orelse false;
39
47
 
@@ -44,7 +52,7 @@ pub fn build(b: *std.Build) !void {
44
52
  defer parsed.deinit();
45
53
  const version = parsed.value.object.get("version").?.string;
46
54
  const description = parsed.value.object.get("description").?.string;
47
- var repository = std.mem.split(u8, parsed.value.object.get("repository").?.string, ":");
55
+ var repository = std.mem.splitScalar(u8, parsed.value.object.get("repository").?.string, ':');
48
56
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
49
57
 
50
58
  const showdown =
@@ -52,6 +60,7 @@ pub fn build(b: *std.Build) !void {
52
60
  const log = b.option(bool, "log", "Enable protocol message logging") orelse false;
53
61
  const chance = b.option(bool, "chance", "Enable update probability tracking") orelse false;
54
62
  const calc = b.option(bool, "calc", "Enable damage calculator support") orelse false;
63
+ const extra = b.option([]const []const u8, "option", "Enable extra option");
55
64
 
56
65
  const options = b.addOptions();
57
66
  options.addOption(?bool, "showdown", showdown);
@@ -59,32 +68,67 @@ pub fn build(b: *std.Build) !void {
59
68
  options.addOption(?bool, "chance", chance);
60
69
  options.addOption(?bool, "calc", calc);
61
70
 
71
+ if (extra) |opts| {
72
+ for (opts) |opt| {
73
+ if (std.mem.indexOfScalar(u8, opt, '=')) |i| {
74
+ options.addOption(?bool, opt[0..i], if (std.mem.eql(u8, opt[i + 1 ..], "true"))
75
+ true
76
+ else if (std.mem.eql(u8, opt[i + 1 ..], "false"))
77
+ false
78
+ else {
79
+ std.log.err("Invalid option: {s}\n", .{opt});
80
+ return error.InvalidOption;
81
+ });
82
+ } else {
83
+ options.addOption(?bool, opt, true);
84
+ }
85
+ }
86
+ }
87
+
62
88
  const name = if (showdown) "pkmn-showdown" else "pkmn";
63
89
 
90
+ const pkmn: *std.Build.Module = b.addModule("pkmn", .{
91
+ .root_source_file = b.path("src/lib/pkmn.zig"),
92
+ .optimize = optimize,
93
+ .target = target,
94
+ .imports = &.{.{ .name = "build_options", .module = options.createModule() }},
95
+ });
96
+
64
97
  var c = false;
65
98
  if (node_headers) |headers| {
99
+ const translate_c = b.addTranslateC(.{
100
+ .root_source_file = b.path("src/lib/napi.h"),
101
+ .target = target,
102
+ .optimize = optimize,
103
+ });
104
+ translate_c.addSystemIncludePath(b.path(headers));
66
105
  const addon = b.fmt("{s}.node", .{name});
67
- const lib = b.addSharedLibrary(.{
106
+ const path = b.path("src/lib/node.zig");
107
+ const lib = b.addLibrary(.{
108
+ .linkage = .dynamic,
68
109
  .name = addon,
69
- .main_pkg_path = .{ .path = "." },
70
- .root_source_file = .{ .path = "src/lib/binding/node.zig" },
71
- .optimize = optimize,
72
- .target = target,
110
+ .root_module = b.createModule(.{
111
+ .root_source_file = path,
112
+ .optimize = optimize,
113
+ .target = target,
114
+ .strip = strip,
115
+ .pic = pic,
116
+ }),
73
117
  });
74
- lib.addOptions("build_options", options);
75
- lib.addSystemIncludePath(.{ .path = headers });
76
- lib.linkLibC();
118
+ lib.root_module.addOptions("build_options", options);
119
+ lib.root_module.addImport("napi", translate_c.createModule());
120
+ lib.root_module.link_libc = true;
77
121
  if (node_import_lib) |il| {
78
- lib.addObjectFile(.{ .path = il });
79
- } else if ((try std.zig.system.NativeTargetInfo.detect(target)).target.os.tag == .windows) {
80
- try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
122
+ lib.root_module.addObjectFile(b.path(il));
123
+ } else if (target.result.os.tag == .windows) {
124
+ var err = std.Io.File.stderr().writer(b.graph.io, &.{});
125
+ try err.interface.writeAll("Must provide --node-import-library path on Windows\n");
81
126
  std.process.exit(1);
82
127
  }
83
128
  lib.linker_allow_shlib_undefined = true;
84
129
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
85
- if (pic) lib.force_pic = pic;
86
130
  // Always emit to build/lib because this is where the driver code expects to find it
87
- // TODO(ziglang/zig#2231): using the following used to work (though was hacky):
131
+ // TODO: ziglang/zig#2231 - using the following used to work (though was hacky):
88
132
  //
89
133
  // lib.emit_bin = .{ .emit_to = b.fmt("build/lib/{s}", .{addon}) };
90
134
  // b.getInstallStep().dependOn(&lib.step);
@@ -93,70 +137,48 @@ pub fn build(b: *std.Build) !void {
93
137
  // rename the file ourself in install-pkmn-engine
94
138
  b.installArtifact(lib);
95
139
  } else if (wasm) {
96
- const exe = b.addExecutable(.{
97
- .name = name,
98
- .main_pkg_path = .{ .path = "." },
99
- .root_source_file = .{ .path = "src/lib/binding/wasm.zig" },
100
- .optimize = switch (optimize) {
101
- .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
102
- else => optimize,
103
- },
104
- .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
105
- });
106
- exe.addOptions("build_options", options);
107
- exe.export_symbol_names = &[_][]const u8{
108
- "SHOWDOWN",
109
- "LOG",
110
- "CHANCE",
111
- "CALC",
112
- "GEN1_CHOICES_SIZE",
113
- "GEN1_LOGS_SIZE",
114
- };
115
- exe.entry = .disabled;
116
- exe.stack_size = wasm_stack_size;
117
- exe.strip = strip;
118
- if (pic) exe.force_pic = pic;
119
- const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
120
- if (optimize != .Debug and opt != null) {
121
- const out = b.fmt("build/lib/{s}.wasm", .{name});
122
- const sh = b.addSystemCommand(&.{ opt.?, "-O4" });
123
- sh.addArtifactArg(exe);
124
- sh.addArg("-o");
125
- sh.addFileSourceArg(.{ .path = out });
126
- b.getInstallStep().dependOn(&sh.step);
127
- } else {
128
- b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
129
- .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
130
- }).step);
131
- }
140
+ const path = "src/lib/wasm.zig";
141
+ try buildWasm(b, name, path, optimize, strip, pic, wasm_stack_size, null, options);
142
+ } else if (demo) {
143
+ const path = "src/tools/demo.zig";
144
+ const n = if (showdown) "demo-showdown" else "demo";
145
+ const mod = pkmn;
146
+ try buildWasm(b, n, path, optimize, strip, pic, wasm_stack_size, mod, options);
132
147
  } else if (dynamic) {
133
- const lib = b.addSharedLibrary(.{
148
+ const path = b.path("src/lib/c.zig");
149
+ const lib = b.addLibrary(.{
150
+ .linkage = .dynamic,
134
151
  .name = name,
135
- .main_pkg_path = .{ .path = "." },
136
- .root_source_file = .{ .path = "src/lib/binding/c.zig" },
137
- .version = try std.SemanticVersion.parse(version),
138
- .optimize = optimize,
139
- .target = target,
152
+ .root_module = b.createModule(.{
153
+ .root_source_file = path,
154
+ .optimize = optimize,
155
+ .target = target,
156
+ .strip = strip,
157
+ .pic = pic,
158
+ }),
140
159
  });
141
- lib.addOptions("build_options", options);
142
- lib.addIncludePath(.{ .path = "src/include" });
160
+ lib.root_module.addOptions("build_options", options);
161
+ lib.root_module.addIncludePath(b.path("src/include"));
143
162
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
144
- if (pic) lib.force_pic = pic;
145
163
  b.installArtifact(lib);
146
164
  c = true;
147
165
  } else {
148
- const lib = b.addStaticLibrary(.{
166
+ const path = b.path("src/lib/c.zig");
167
+ const lib = b.addLibrary(.{
168
+ .linkage = .static,
149
169
  .name = name,
150
- .main_pkg_path = .{ .path = "." },
151
- .root_source_file = .{ .path = "src/lib/binding/c.zig" },
152
- .optimize = optimize,
153
- .target = target,
170
+ .root_module = b.createModule(.{
171
+ .root_source_file = path,
172
+ .optimize = optimize,
173
+ .target = target,
174
+ .strip = strip,
175
+ .pic = pic,
176
+ }),
154
177
  });
155
- lib.addOptions("build_options", options);
156
- lib.addIncludePath(.{ .path = "src/include" });
178
+ lib.root_module.addOptions("build_options", options);
179
+ lib.root_module.addIncludePath(b.path("src/include"));
157
180
  lib.bundle_compiler_rt = true;
158
181
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
159
- if (pic) lib.force_pic = pic;
160
182
  if (emit_asm) {
161
183
  b.getInstallStep().dependOn(&b.addInstallFileWithDir(
162
184
  lib.getEmittedAsm(),
@@ -176,20 +198,25 @@ pub fn build(b: *std.Build) !void {
176
198
  }
177
199
 
178
200
  if (c) {
179
- const header = b.addInstallFileWithDir(
180
- .{ .path = "src/include/pkmn.h" },
181
- .header,
182
- "pkmn.h",
183
- );
201
+ const path = b.path("src/include/pkmn.h");
202
+ const header = b.addInstallFileWithDir(path, .header, "pkmn.h");
184
203
  b.getInstallStep().dependOn(&header.step);
185
204
 
186
205
  const pc = b.fmt("lib{s}.pc", .{name});
187
- const file = try b.cache_root.join(b.allocator, &.{pc});
188
- const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
206
+ const cwd = try std.process.currentPathAlloc(b.graph.io, b.allocator);
207
+ const file = try std.Io.Dir.path.relative(
208
+ b.allocator,
209
+ cwd,
210
+ &b.graph.environ_map,
211
+ cwd,
212
+ try b.cache_root.join(b.allocator, &.{pc}),
213
+ );
214
+ const pkgconfig_file = try std.Io.Dir.cwd().createFile(b.graph.io, file, .{});
215
+ defer pkgconfig_file.close(b.graph.io);
189
216
 
190
217
  const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
191
- const writer = pkgconfig_file.writer();
192
- try writer.print(
218
+ var writer = pkgconfig_file.writer(b.graph.io, &.{});
219
+ try writer.interface.print(
193
220
  \\prefix={0s}/{1s}
194
221
  \\includedir=${{prefix}}/include
195
222
  \\libdir=${{prefix}}/lib
@@ -201,12 +228,11 @@ pub fn build(b: *std.Build) !void {
201
228
  \\Cflags: -I${{includedir}}
202
229
  \\Libs: -L${{libdir}} -l{2s}
203
230
  , .{ dirname, b.install_path, name, repository.next().?, description, version });
204
- defer pkgconfig_file.close();
205
231
 
206
232
  b.installFile(file, b.fmt("share/pkgconfig/{s}", .{pc}));
207
233
  }
208
234
 
209
- const config = .{
235
+ const config: Config = .{
210
236
  .target = target,
211
237
  .optimize = optimize,
212
238
  .pic = pic,
@@ -217,7 +243,7 @@ pub fn build(b: *std.Build) !void {
217
243
  // TODO: tests can be run multiple times due to @imports
218
244
  const tests = TestStep.create(b, options, config);
219
245
 
220
- var exes = std.ArrayList(*std.Build.CompileStep).init(b.allocator);
246
+ var exes: ArrayList(*std.Build.Step.Compile) = .empty;
221
247
  const tools: ToolConfig = .{
222
248
  .options = .{
223
249
  .showdown = showdown,
@@ -225,6 +251,7 @@ pub fn build(b: *std.Build) !void {
225
251
  .chance = chance,
226
252
  .calc = calc,
227
253
  },
254
+ .module = pkmn,
228
255
  .general = config,
229
256
  .tool = .{
230
257
  .tests = if (tests.build) tests else null,
@@ -263,15 +290,93 @@ pub fn build(b: *std.Build) !void {
263
290
  }
264
291
  }
265
292
 
293
+ fn buildWasm(
294
+ b: *std.Build,
295
+ name: []const u8,
296
+ root_src_file: []const u8,
297
+ optimize: std.builtin.OptimizeMode,
298
+ strip: ?bool,
299
+ pic: ?bool,
300
+ wasm_stack_size: u64,
301
+ import: ?*std.Build.Module,
302
+ options: anytype,
303
+ ) !void {
304
+ const mode = switch (optimize) {
305
+ .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
306
+ else => optimize,
307
+ };
308
+ // https://webassembly.org/features/
309
+ var features = std.Target.wasm.featureSet(&.{
310
+ .atomics,
311
+ .bulk_memory,
312
+ // .exception_handling,
313
+ .extended_const,
314
+ // .half_precision,
315
+ // .multimemory,
316
+ .mutable_globals,
317
+ .nontrapping_fptoint,
318
+ .reference_types,
319
+ // .relaxed_simd,
320
+ .sign_ext,
321
+ .simd128,
322
+ // .tail_call,
323
+ });
324
+ if (builtin.zig_version.order(try std.SemanticVersion.parse("0.12.0")) != .lt) {
325
+ features.addFeature(@intFromEnum(std.Target.wasm.Feature.multivalue));
326
+ }
327
+ const freestanding = b.resolveTargetQuery(.{
328
+ .cpu_arch = .wasm32,
329
+ .os_tag = .freestanding,
330
+ .cpu_features_add = features,
331
+ });
332
+ const path = b.path(root_src_file);
333
+ const exe = b.addExecutable(.{
334
+ .name = name,
335
+ .root_module = b.createModule(.{
336
+ .root_source_file = path,
337
+ .optimize = mode,
338
+ .target = freestanding,
339
+ .strip = strip,
340
+ .pic = pic,
341
+ }),
342
+ });
343
+
344
+ var file = try std.Io.Dir.cwd().openFile(b.graph.io, root_src_file, .{});
345
+ defer file.close(b.graph.io);
346
+ var reader = file.reader(b.graph.io, &.{});
347
+ const bytes = try reader.interface.allocRemaining(b.allocator, .unlimited);
348
+ exe.root_module.export_symbol_names = try exports(b, bytes);
349
+ exe.entry = .disabled;
350
+
351
+ if (import) |i| {
352
+ exe.root_module.addImport("pkmn", i);
353
+ }
354
+ exe.stack_size = wasm_stack_size;
355
+ exe.root_module.addOptions("build_options", options);
356
+
357
+ const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
358
+ if (optimize != .Debug and opt != null) {
359
+ const out = b.fmt("build/lib/{s}.wasm", .{name});
360
+ const sh = b.addSystemCommand(&.{ opt.?, "--enable-bulk-memory", "--enable-simd", "-O4" });
361
+ sh.addArtifactArg(exe);
362
+ sh.addArg("-o");
363
+ sh.addFileArg(b.path(out));
364
+ b.getInstallStep().dependOn(&sh.step);
365
+ } else {
366
+ b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
367
+ .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
368
+ }).step);
369
+ }
370
+ }
371
+
266
372
  fn maybeStrip(
267
373
  b: *std.Build,
268
- artifact: *std.Build.CompileStep,
374
+ artifact: *std.Build.Step.Compile,
269
375
  step: *std.Build.Step,
270
- strip: bool,
376
+ strip: ?bool,
271
377
  cmd: ?[]const u8,
272
378
  ) void {
273
- artifact.strip = strip;
274
- if (!strip or cmd == null) return;
379
+ if (!(strip orelse false) or cmd == null) return;
275
380
  // Using `strip -r -u` for dynamic libraries is supposed to work on macOS but doesn't...
276
381
  const mac = builtin.os.tag == .macos;
277
382
  if (mac and artifact.isDynamicLibrary()) return;
@@ -283,10 +388,10 @@ fn maybeStrip(
283
388
  }
284
389
 
285
390
  const Config = struct {
286
- target: std.zig.CrossTarget,
391
+ target: std.Build.ResolvedTarget,
287
392
  optimize: std.builtin.OptimizeMode,
288
- pic: bool,
289
- strip: bool,
393
+ pic: ?bool,
394
+ strip: ?bool,
290
395
  cmd: ?[]const u8,
291
396
  };
292
397
 
@@ -294,9 +399,8 @@ const TestStep = struct {
294
399
  step: std.Build.Step,
295
400
  build: bool,
296
401
 
297
- pub fn create(b: *std.Build, options: *std.Build.OptionsStep, config: Config) *TestStep {
402
+ pub fn create(b: *std.Build, options: *std.Build.Step.Options, config: Config) *TestStep {
298
403
  const coverage = b.option([]const u8, "test-coverage", "Generate test coverage");
299
- const test_file = b.option([]const u8, "test-file", "Input file for test");
300
404
  const test_filter =
301
405
  b.option([]const u8, "test-filter", "Skip tests that do not match filter");
302
406
 
@@ -304,22 +408,21 @@ const TestStep = struct {
304
408
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
305
409
  self.* = .{ .step = step, .build = test_filter == null };
306
410
 
307
- const path = test_file orelse "src/lib/test.zig";
411
+ const path = b.path("src/lib/test.zig");
308
412
  const tests = b.addTest(.{
309
- .name = b.fmt("{s}-{s}", .{
310
- std.fs.path.basename(std.fs.path.dirname(path).?),
311
- std.fs.path.stem(std.fs.path.basename(path)),
413
+ .root_module = b.createModule(.{
414
+ .root_source_file = path,
415
+ .optimize = config.optimize,
416
+ .target = config.target,
417
+ .single_threaded = true,
418
+ .strip = config.strip,
419
+ .pic = config.pic,
312
420
  }),
313
- .main_pkg_path = .{ .path = "." },
314
- .root_source_file = .{ .path = path },
315
- .optimize = config.optimize,
316
- .target = config.target,
317
- .filter = test_filter,
421
+ .filters = if (test_filter) |filter| &.{filter} else &.{},
318
422
  });
319
- tests.addOptions("build_options", options);
320
- tests.single_threaded = true;
423
+ tests.root_module.addOptions("build_options", options);
424
+
321
425
  maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
322
- if (config.pic) tests.force_pic = config.pic;
323
426
  if (coverage) |c| {
324
427
  tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
325
428
  }
@@ -331,19 +434,17 @@ const TestStep = struct {
331
434
 
332
435
  const ToolConfig = struct {
333
436
  options: Options,
437
+ module: ?*std.Build.Module,
334
438
  general: Config,
335
439
  tool: struct {
336
440
  tests: ?*TestStep,
337
441
  name: ?[]const u8 = null,
338
- exes: *std.ArrayList(*std.Build.CompileStep),
442
+ exes: *ArrayList(*std.Build.Step.Compile),
339
443
  },
340
444
  };
341
445
 
342
- fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunStep {
343
- std.fs.cwd().access(path, .{}) catch |err| switch (err) {
344
- error.FileNotFound => return null,
345
- else => |e| return e,
346
- };
446
+ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.Run {
447
+ if (!try exists(b, path)) return null;
347
448
  var name = config.tool.name orelse std.fs.path.basename(path);
348
449
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
349
450
  if (index) |i| name = name[0..i];
@@ -351,16 +452,23 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunSte
351
452
 
352
453
  const exe = b.addExecutable(.{
353
454
  .name = name,
354
- .root_source_file = .{ .path = path },
355
- .target = config.general.target,
356
- .optimize = config.general.optimize,
455
+ .root_module = b.createModule(.{
456
+ .root_source_file = b.path(path),
457
+ .target = config.general.target,
458
+ .optimize = config.general.optimize,
459
+ .strip = config.general.strip,
460
+ .pic = config.general.pic,
461
+ }),
357
462
  });
358
- exe.addModule("pkmn", module(b, config.options));
359
463
 
360
- exe.single_threaded = true;
361
- if (config.general.pic) exe.force_pic = config.general.pic;
464
+ const import = if (config.module) |m| m else module(b, config.options);
465
+ exe.root_module.addImport("pkmn", import);
466
+ if (config.general.target.result.os.tag == .windows) {
467
+ exe.root_module.linkSystemLibrary("advapi32", .{});
468
+ }
469
+
362
470
  if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
363
- config.tool.exes.append(exe) catch @panic("OOM");
471
+ config.tool.exes.append(b.allocator, exe) catch @panic("OOM");
364
472
 
365
473
  const run = b.addRunArtifact(exe);
366
474
  maybeStrip(b, exe, &run.step, config.general.strip, config.general.cmd);
@@ -369,10 +477,18 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.RunSte
369
477
  return run;
370
478
  }
371
479
 
480
+ fn exists(b: *std.Build, path: []const u8) !bool {
481
+ std.Io.Dir.cwd().access(b.graph.io, path, .{}) catch |err| switch (err) {
482
+ error.FileNotFound => return false,
483
+ else => |e| return e,
484
+ };
485
+ return true;
486
+ }
487
+
372
488
  const ToolsStep = struct {
373
489
  step: std.Build.Step,
374
490
 
375
- pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.CompileStep)) *ToolsStep {
491
+ pub fn create(b: *std.Build, exes: *ArrayList(*std.Build.Step.Compile)) *ToolsStep {
376
492
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
377
493
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
378
494
  self.* = .{ .step = step };
@@ -380,3 +496,21 @@ const ToolsStep = struct {
380
496
  return self;
381
497
  }
382
498
  };
499
+
500
+ pub fn exports(b: *std.Build, bytes: []const u8) ![][]const u8 {
501
+ var symbols: ArrayList([]const u8) = .empty;
502
+
503
+ var it = std.mem.splitSequence(u8, bytes, "export ");
504
+ _ = it.next();
505
+ while (it.next()) |s| {
506
+ if (std.mem.startsWith(u8, s, "const ")) {
507
+ const i = std.mem.indexOf(u8, s[6..], " ").?;
508
+ try symbols.append(b.allocator, s[6 .. 6 + i]);
509
+ } else { // "fn "
510
+ const i = std.mem.indexOf(u8, s[3..], "(").?;
511
+ try symbols.append(b.allocator, s[3 .. 3 + i]);
512
+ }
513
+ }
514
+
515
+ return symbols.items;
516
+ }