@pkmn/engine 0.1.0-dev.62399ed5 → 0.1.0-dev.62eefbc0

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 (81) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +24 -14
  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 +34 -65
  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 +23 -1
  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 +40 -90
  23. package/build/pkg/index.js +23 -70
  24. package/build/pkg/index.js.map +1 -1
  25. package/build/pkg/protocol.d.ts +29 -1
  26. package/build/pkg/protocol.js +105 -103
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +83 -73
  29. package/build/tools/debug.js.map +1 -1
  30. package/build/tools/display/debug.jsx +66 -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 +360 -0
  35. package/build/tools/display/ui.jsx.map +1 -0
  36. package/build/tools/display/util.js +157 -0
  37. package/build/tools/display/util.js.map +1 -0
  38. package/build.zig +266 -103
  39. package/package.json +59 -138
  40. package/src/bin/install-pkmn-engine +25 -7
  41. package/src/bin/pkmn-debug +1 -1
  42. package/src/lib/bindings/c.zig +200 -0
  43. package/src/lib/bindings/node.zig +117 -0
  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 +8 -8
  47. package/src/lib/common/debug.zig +33 -28
  48. package/src/lib/common/js.zig +3 -7
  49. package/src/lib/common/optional.zig +11 -17
  50. package/src/lib/common/options.zig +4 -0
  51. package/src/lib/common/protocol.zig +196 -160
  52. package/src/lib/common/rational.zig +303 -310
  53. package/src/lib/common/rng.zig +5 -7
  54. package/src/lib/common/util.zig +33 -1
  55. package/src/lib/gen1/calc.zig +569 -190
  56. package/src/lib/gen1/chance.zig +412 -249
  57. package/src/lib/gen1/data/moves.zig +2 -4
  58. package/src/lib/gen1/data/species.zig +1 -3
  59. package/src/lib/gen1/data/types.zig +3 -4
  60. package/src/lib/gen1/data.zig +40 -43
  61. package/src/lib/gen1/helpers.zig +17 -556
  62. package/src/lib/gen1/mechanics.zig +317 -221
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +91 -510
  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 +33 -35
  70. package/src/lib/gen2/generated.zig +18 -23
  71. package/src/lib/gen2/helpers.zig +9 -20
  72. package/src/lib/gen2/mechanics.zig +105 -132
  73. package/src/lib/napi.h +2 -0
  74. package/src/lib/node.zig +4 -121
  75. package/src/lib/pkmn.zig +103 -22
  76. package/src/lib/wasm.zig +9 -9
  77. package/src/tools/display/dom.ts +108 -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/test/display/pkmn.html.tmpl +0 -368
package/build.zig CHANGED
@@ -1,5 +1,39 @@
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
+ }
7
+
8
+ pub const Options = struct {
9
+ showdown: ?bool = null,
10
+ log: ?bool = null,
11
+ chance: ?bool = null,
12
+ calc: ?bool = null,
13
+ };
14
+
15
+ pub fn module(
16
+ b: *std.Build,
17
+ options: Options,
18
+ target: std.Build.ResolvedTarget,
19
+ optimize: std.builtin.OptimizeMode,
20
+ ) *std.Build.Module {
21
+ const build_options = b.addOptions();
22
+ build_options.addOption(?bool, "showdown", options.showdown);
23
+ build_options.addOption(?bool, "log", options.log);
24
+ build_options.addOption(?bool, "chance", options.chance);
25
+ build_options.addOption(?bool, "calc", options.calc);
26
+
27
+ const root_source_file = b.path("src/lib/pkmn.zig");
28
+ const imports: []const std.Build.Module.Import =
29
+ &.{.{ .name = "build_options", .module = build_options.createModule() }};
30
+ return b.createModule(.{
31
+ .root_source_file = root_source_file,
32
+ .target = target,
33
+ .optimize = optimize,
34
+ .imports = imports,
35
+ });
36
+ }
3
37
 
4
38
  pub fn build(b: *std.Build) !void {
5
39
  const target = b.standardTargetOptions(.{});
@@ -8,6 +42,10 @@ pub fn build(b: *std.Build) !void {
8
42
  const node_headers = b.option([]const u8, "node-headers", "Path to node-headers");
9
43
  const node_import_lib =
10
44
  b.option([]const u8, "node-import-library", "Path to node import library (Windows)");
45
+ const demo = if (try exists(b, "src/tools/demo.zig"))
46
+ b.option(bool, "demo", "Build the demo library") orelse false
47
+ else
48
+ false;
11
49
  const wasm = b.option(bool, "wasm", "Build a WASM library") orelse false;
12
50
  const wasm_stack_size =
13
51
  b.option(u64, "wasm-stack-size", "The size of WASM stack") orelse std.wasm.page_size;
@@ -24,7 +62,7 @@ pub fn build(b: *std.Build) !void {
24
62
  defer parsed.deinit();
25
63
  const version = parsed.value.object.get("version").?.string;
26
64
  const description = parsed.value.object.get("description").?.string;
27
- var repository = std.mem.splitSequence(u8, parsed.value.object.get("repository").?.string, ":");
65
+ var repository = std.mem.splitScalar(u8, parsed.value.object.get("repository").?.string, ':');
28
66
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
29
67
 
30
68
  const showdown =
@@ -32,6 +70,7 @@ pub fn build(b: *std.Build) !void {
32
70
  const log = b.option(bool, "log", "Enable protocol message logging") orelse false;
33
71
  const chance = b.option(bool, "chance", "Enable update probability tracking") orelse false;
34
72
  const calc = b.option(bool, "calc", "Enable damage calculator support") orelse false;
73
+ const extra = b.option([]const []const u8, "option", "Enable extra option");
35
74
 
36
75
  const options = b.addOptions();
37
76
  options.addOption(?bool, "showdown", showdown);
@@ -39,9 +78,26 @@ pub fn build(b: *std.Build) !void {
39
78
  options.addOption(?bool, "chance", chance);
40
79
  options.addOption(?bool, "calc", calc);
41
80
 
81
+ if (extra) |opts| {
82
+ for (opts) |opt| {
83
+ if (std.mem.indexOfScalar(u8, opt, '=')) |i| {
84
+ options.addOption(?bool, opt[0..i], if (std.mem.eql(u8, opt[i + 1 ..], "true"))
85
+ true
86
+ else if (std.mem.eql(u8, opt[i + 1 ..], "false"))
87
+ false
88
+ else {
89
+ std.log.err("Invalid option: {s}\n", .{opt});
90
+ return error.InvalidOption;
91
+ });
92
+ } else {
93
+ options.addOption(?bool, opt, true);
94
+ }
95
+ }
96
+ }
97
+
42
98
  const name = if (showdown) "pkmn-showdown" else "pkmn";
43
99
 
44
- const module = b.addModule("pkmn", .{
100
+ const pkmn: *std.Build.Module = b.addModule("pkmn", .{
45
101
  .root_source_file = b.path("src/lib/pkmn.zig"),
46
102
  .optimize = optimize,
47
103
  .target = target,
@@ -50,22 +106,33 @@ pub fn build(b: *std.Build) !void {
50
106
 
51
107
  var c = false;
52
108
  if (node_headers) |headers| {
109
+ const translate_c = b.addTranslateC(.{
110
+ .root_source_file = b.path("src/lib/napi.h"),
111
+ .target = target,
112
+ .optimize = optimize,
113
+ });
114
+ translate_c.addSystemIncludePath(b.path(headers));
53
115
  const addon = b.fmt("{s}.node", .{name});
54
- const lib = b.addSharedLibrary(.{
116
+ const path = b.path("src/lib/node.zig");
117
+ const lib = b.addLibrary(.{
118
+ .linkage = .dynamic,
55
119
  .name = addon,
56
- .root_source_file = b.path("src/lib/node.zig"),
57
- .optimize = optimize,
58
- .target = target,
59
- .strip = strip,
60
- .pic = pic,
120
+ .root_module = b.createModule(.{
121
+ .root_source_file = path,
122
+ .optimize = optimize,
123
+ .target = target,
124
+ .strip = strip,
125
+ .pic = pic,
126
+ }),
61
127
  });
62
128
  lib.root_module.addOptions("build_options", options);
63
- lib.addSystemIncludePath(b.path(headers));
64
- lib.linkLibC();
129
+ lib.root_module.addImport("napi", translate_c.createModule());
130
+ lib.root_module.link_libc = true;
65
131
  if (node_import_lib) |il| {
66
- lib.addObjectFile(b.path(il));
132
+ lib.root_module.addObjectFile(b.path(il));
67
133
  } else if (target.result.os.tag == .windows) {
68
- try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
134
+ var err = std.Io.File.stderr().writer(b.graph.io, &.{});
135
+ try err.interface.writeAll("Must provide --node-import-library path on Windows\n");
69
136
  std.process.exit(1);
70
137
  }
71
138
  lib.linker_allow_shlib_undefined = true;
@@ -80,68 +147,49 @@ pub fn build(b: *std.Build) !void {
80
147
  // rename the file ourself in install-pkmn-engine
81
148
  b.installArtifact(lib);
82
149
  } else if (wasm) {
83
- const exe = b.addExecutable(.{
84
- .name = name,
85
- .root_source_file = b.path("src/lib/wasm.zig"),
86
- .optimize = switch (optimize) {
87
- .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
88
- else => optimize,
89
- },
90
- .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
91
- .strip = strip,
92
- .pic = pic,
93
- });
94
- exe.root_module.addOptions("build_options", options);
95
- exe.root_module.export_symbol_names = &[_][]const u8{
96
- "SHOWDOWN",
97
- "LOG",
98
- "CHANCE",
99
- "CALC",
100
- "GEN1_CHOICES_SIZE",
101
- "GEN1_LOGS_SIZE",
102
- };
103
- exe.entry = .disabled;
104
- exe.stack_size = wasm_stack_size;
105
- const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
106
- if (optimize != .Debug and opt != null) {
107
- const out = b.fmt("build/lib/{s}.wasm", .{name});
108
- const sh = b.addSystemCommand(&.{ opt.?, "-O4" });
109
- sh.addArtifactArg(exe);
110
- sh.addArg("-o");
111
- sh.addFileArg(b.path(out));
112
- b.getInstallStep().dependOn(&sh.step);
113
- } else {
114
- b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
115
- .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
116
- }).step);
117
- }
150
+ const path = "src/lib/wasm.zig";
151
+ try buildWasm(b, name, path, optimize, strip, pic, wasm_stack_size, null, options);
152
+ } else if (demo) {
153
+ const path = "src/tools/demo.zig";
154
+ const n = if (showdown) "demo-showdown" else "demo";
155
+ const mod = pkmn;
156
+ try buildWasm(b, n, path, optimize, strip, pic, wasm_stack_size, mod, options);
118
157
  } else if (dynamic) {
119
- const lib = b.addSharedLibrary(.{
158
+ const path = b.path("src/lib/c.zig");
159
+ const lib = b.addLibrary(.{
160
+ .linkage = .dynamic,
120
161
  .name = name,
121
- .root_source_file = b.path("src/lib/c.zig"),
122
- .version = try std.SemanticVersion.parse(version),
123
- .optimize = optimize,
124
- .target = target,
125
- .strip = strip,
126
- .pic = pic,
162
+ .root_module = b.createModule(.{
163
+ .root_source_file = path,
164
+ .optimize = optimize,
165
+ .target = target,
166
+ .strip = strip,
167
+ .pic = pic,
168
+ }),
127
169
  });
128
170
  lib.root_module.addOptions("build_options", options);
129
- lib.addIncludePath(b.path("src/include"));
171
+ lib.root_module.addIncludePath(b.path("src/include"));
130
172
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
131
173
  b.installArtifact(lib);
132
174
  c = true;
133
175
  } else {
134
- const lib = b.addStaticLibrary(.{
176
+ const path = b.path("src/lib/c.zig");
177
+ const lib = b.addLibrary(.{
178
+ .linkage = .static,
135
179
  .name = name,
136
- .root_source_file = b.path("src/lib/c.zig"),
137
- .optimize = optimize,
138
- .target = target,
139
- .strip = strip,
140
- .pic = pic,
180
+ .root_module = b.createModule(.{
181
+ .root_source_file = path,
182
+ .optimize = optimize,
183
+ .target = target,
184
+ .strip = strip,
185
+ .pic = pic,
186
+ }),
141
187
  });
142
188
  lib.root_module.addOptions("build_options", options);
143
- lib.addIncludePath(b.path("src/include"));
144
- lib.bundle_compiler_rt = true;
189
+ lib.root_module.addIncludePath(b.path("src/include"));
190
+ if (target.result.os.tag != .macos) {
191
+ lib.bundle_compiler_rt = true;
192
+ }
145
193
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
146
194
  if (emit_asm) {
147
195
  b.getInstallStep().dependOn(&b.addInstallFileWithDir(
@@ -162,24 +210,25 @@ pub fn build(b: *std.Build) !void {
162
210
  }
163
211
 
164
212
  if (c) {
165
- const header = b.addInstallFileWithDir(
166
- b.path("src/include/pkmn.h"),
167
- .header,
168
- "pkmn.h",
169
- );
213
+ const path = b.path("src/include/pkmn.h");
214
+ const header = b.addInstallFileWithDir(path, .header, "pkmn.h");
170
215
  b.getInstallStep().dependOn(&header.step);
171
216
 
172
217
  const pc = b.fmt("lib{s}.pc", .{name});
173
- const file = try std.fs.path.relative(
218
+ const cwd = try std.process.currentPathAlloc(b.graph.io, b.allocator);
219
+ const file = try std.Io.Dir.path.relative(
174
220
  b.allocator,
175
- try std.process.getCwdAlloc(b.allocator),
221
+ cwd,
222
+ &b.graph.environ_map,
223
+ cwd,
176
224
  try b.cache_root.join(b.allocator, &.{pc}),
177
225
  );
178
- const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
226
+ const pkgconfig_file = try std.Io.Dir.cwd().createFile(b.graph.io, file, .{});
227
+ defer pkgconfig_file.close(b.graph.io);
179
228
 
180
229
  const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
181
- const writer = pkgconfig_file.writer();
182
- try writer.print(
230
+ var writer = pkgconfig_file.writer(b.graph.io, &.{});
231
+ try writer.interface.print(
183
232
  \\prefix={0s}/{1s}
184
233
  \\includedir=${{prefix}}/include
185
234
  \\libdir=${{prefix}}/lib
@@ -191,12 +240,11 @@ pub fn build(b: *std.Build) !void {
191
240
  \\Cflags: -I${{includedir}}
192
241
  \\Libs: -L${{libdir}} -l{2s}
193
242
  , .{ dirname, b.install_path, name, repository.next().?, description, version });
194
- defer pkgconfig_file.close();
195
243
 
196
244
  b.installFile(file, b.fmt("share/pkgconfig/{s}", .{pc}));
197
245
  }
198
246
 
199
- const config = .{
247
+ const config: Config = .{
200
248
  .target = target,
201
249
  .optimize = optimize,
202
250
  .pic = pic,
@@ -207,10 +255,14 @@ pub fn build(b: *std.Build) !void {
207
255
  // TODO: tests can be run multiple times due to @imports
208
256
  const tests = TestStep.create(b, options, config);
209
257
 
210
- var exes = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
258
+ var exes: ArrayList(*std.Build.Step.Compile) = .empty;
211
259
  const tools: ToolConfig = .{
212
- .showdown = showdown,
213
- .module = module,
260
+ .options = .{
261
+ .showdown = showdown,
262
+ .log = log,
263
+ .chance = chance,
264
+ .calc = calc,
265
+ },
214
266
  .general = config,
215
267
  .tool = .{
216
268
  .tests = if (tests.build) tests else null,
@@ -249,6 +301,85 @@ pub fn build(b: *std.Build) !void {
249
301
  }
250
302
  }
251
303
 
304
+ fn buildWasm(
305
+ b: *std.Build,
306
+ name: []const u8,
307
+ root_src_file: []const u8,
308
+ optimize: std.builtin.OptimizeMode,
309
+ strip: ?bool,
310
+ pic: ?bool,
311
+ wasm_stack_size: u64,
312
+ import: ?*std.Build.Module,
313
+ options: anytype,
314
+ ) !void {
315
+ const mode = switch (optimize) {
316
+ .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
317
+ else => optimize,
318
+ };
319
+ // https://webassembly.org/features/
320
+ var features = std.Target.wasm.featureSet(&.{
321
+ .atomics,
322
+ .bulk_memory,
323
+ // .exception_handling,
324
+ .extended_const,
325
+ // .half_precision,
326
+ // .multimemory,
327
+ .mutable_globals,
328
+ .nontrapping_fptoint,
329
+ .reference_types,
330
+ // .relaxed_simd,
331
+ .sign_ext,
332
+ .simd128,
333
+ // .tail_call,
334
+ });
335
+ if (builtin.zig_version.order(try std.SemanticVersion.parse("0.12.0")) != .lt) {
336
+ features.addFeature(@intFromEnum(std.Target.wasm.Feature.multivalue));
337
+ }
338
+ const freestanding = b.resolveTargetQuery(.{
339
+ .cpu_arch = .wasm32,
340
+ .os_tag = .freestanding,
341
+ .cpu_features_add = features,
342
+ });
343
+ const path = b.path(root_src_file);
344
+ const exe = b.addExecutable(.{
345
+ .name = name,
346
+ .root_module = b.createModule(.{
347
+ .root_source_file = path,
348
+ .optimize = mode,
349
+ .target = freestanding,
350
+ .strip = strip,
351
+ .pic = pic,
352
+ }),
353
+ });
354
+
355
+ var file = try std.Io.Dir.cwd().openFile(b.graph.io, root_src_file, .{});
356
+ defer file.close(b.graph.io);
357
+ var reader = file.reader(b.graph.io, &.{});
358
+ const bytes = try reader.interface.allocRemaining(b.allocator, .unlimited);
359
+ exe.root_module.export_symbol_names = try exports(b, bytes);
360
+ exe.entry = .disabled;
361
+
362
+ if (import) |i| {
363
+ exe.root_module.addImport("pkmn", i);
364
+ }
365
+ exe.stack_size = wasm_stack_size;
366
+ exe.root_module.addOptions("build_options", options);
367
+
368
+ const opt = b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
369
+ if (optimize != .Debug and opt != null) {
370
+ const out = b.fmt("build/lib/{s}.wasm", .{name});
371
+ const sh = b.addSystemCommand(&.{ opt.?, "--enable-bulk-memory", "--enable-simd", "-O4" });
372
+ sh.addArtifactArg(exe);
373
+ sh.addArg("-o");
374
+ sh.addFileArg(b.path(out));
375
+ b.getInstallStep().dependOn(&sh.step);
376
+ } else {
377
+ b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
378
+ .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
379
+ }).step);
380
+ }
381
+ }
382
+
252
383
  fn maybeStrip(
253
384
  b: *std.Build,
254
385
  artifact: *std.Build.Step.Compile,
@@ -288,16 +419,20 @@ const TestStep = struct {
288
419
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
289
420
  self.* = .{ .step = step, .build = test_filter == null };
290
421
 
422
+ const path = b.path("src/lib/test.zig");
291
423
  const tests = b.addTest(.{
292
- .root_source_file = b.path("src/lib/test.zig"),
293
- .optimize = config.optimize,
294
- .target = config.target,
295
- .filter = test_filter,
296
- .single_threaded = true,
297
- .strip = config.strip,
298
- .pic = config.pic,
424
+ .root_module = b.createModule(.{
425
+ .root_source_file = path,
426
+ .optimize = config.optimize,
427
+ .target = config.target,
428
+ .single_threaded = true,
429
+ .strip = config.strip,
430
+ .pic = config.pic,
431
+ }),
432
+ .filters = if (test_filter) |filter| &.{filter} else &.{},
299
433
  });
300
434
  tests.root_module.addOptions("build_options", options);
435
+
301
436
  maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
302
437
  if (coverage) |c| {
303
438
  tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
@@ -309,39 +444,41 @@ const TestStep = struct {
309
444
  };
310
445
 
311
446
  const ToolConfig = struct {
312
- showdown: ?bool,
313
- module: *std.Build.Module,
447
+ options: Options,
314
448
  general: Config,
315
449
  tool: struct {
316
450
  tests: ?*TestStep,
317
451
  name: ?[]const u8 = null,
318
- exes: *std.ArrayList(*std.Build.Step.Compile),
452
+ exes: *ArrayList(*std.Build.Step.Compile),
319
453
  },
320
454
  };
321
455
 
322
456
  fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.Run {
323
- std.fs.cwd().access(path, .{}) catch |err| switch (err) {
324
- error.FileNotFound => return null,
325
- else => |e| return e,
326
- };
457
+ if (!try exists(b, path)) return null;
327
458
  var name = config.tool.name orelse std.fs.path.basename(path);
328
459
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
329
460
  if (index) |i| name = name[0..i];
330
- if (config.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
461
+ if (config.options.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
331
462
 
332
463
  const exe = b.addExecutable(.{
333
464
  .name = name,
334
- .root_source_file = b.path(path),
335
- .target = config.general.target,
336
- .optimize = config.general.optimize,
337
- .single_threaded = true,
338
- .strip = config.general.strip,
339
- .pic = config.general.pic,
465
+ .root_module = b.createModule(.{
466
+ .root_source_file = b.path(path),
467
+ .target = config.general.target,
468
+ .optimize = config.general.optimize,
469
+ .strip = config.general.strip,
470
+ .pic = config.general.pic,
471
+ }),
340
472
  });
341
- exe.root_module.addImport("pkmn", config.module);
473
+
474
+ const import = module(b, config.options, config.general.target, config.general.optimize);
475
+ exe.root_module.addImport("pkmn", import);
476
+ if (config.general.target.result.os.tag == .windows) {
477
+ exe.root_module.linkSystemLibrary("advapi32", .{});
478
+ }
342
479
 
343
480
  if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
344
- config.tool.exes.append(exe) catch @panic("OOM");
481
+ config.tool.exes.append(b.allocator, exe) catch @panic("OOM");
345
482
 
346
483
  const run = b.addRunArtifact(exe);
347
484
  maybeStrip(b, exe, &run.step, config.general.strip, config.general.cmd);
@@ -350,10 +487,18 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.R
350
487
  return run;
351
488
  }
352
489
 
490
+ fn exists(b: *std.Build, path: []const u8) !bool {
491
+ std.Io.Dir.cwd().access(b.graph.io, path, .{}) catch |err| switch (err) {
492
+ error.FileNotFound => return false,
493
+ else => |e| return e,
494
+ };
495
+ return true;
496
+ }
497
+
353
498
  const ToolsStep = struct {
354
499
  step: std.Build.Step,
355
500
 
356
- pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.Step.Compile)) *ToolsStep {
501
+ pub fn create(b: *std.Build, exes: *ArrayList(*std.Build.Step.Compile)) *ToolsStep {
357
502
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
358
503
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
359
504
  self.* = .{ .step = step };
@@ -361,3 +506,21 @@ const ToolsStep = struct {
361
506
  return self;
362
507
  }
363
508
  };
509
+
510
+ pub fn exports(b: *std.Build, bytes: []const u8) ![][]const u8 {
511
+ var symbols: ArrayList([]const u8) = .empty;
512
+
513
+ var it = std.mem.splitSequence(u8, bytes, "export ");
514
+ _ = it.next();
515
+ while (it.next()) |s| {
516
+ if (std.mem.startsWith(u8, s, "const ")) {
517
+ const i = std.mem.indexOf(u8, s[6..], " ").?;
518
+ try symbols.append(b.allocator, s[6 .. 6 + i]);
519
+ } else { // "fn "
520
+ const i = std.mem.indexOf(u8, s[3..], "(").?;
521
+ try symbols.append(b.allocator, s[3 .. 3 + i]);
522
+ }
523
+ }
524
+
525
+ return symbols.items;
526
+ }