@pkmn/engine 0.1.0-dev.b01cb48c → 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 (81) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +21 -11
  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 +20 -1
  26. package/build/pkg/protocol.js +105 -103
  27. package/build/pkg/protocol.js.map +1 -1
  28. package/build/tools/debug.js +68 -74
  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 +255 -102
  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 +30 -9
  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 +195 -159
  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 +324 -180
  56. package/src/lib/gen1/chance.zig +536 -140
  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 -29
  62. package/src/lib/gen1/mechanics.zig +240 -187
  63. package/src/lib/gen2/calc.zig +35 -28
  64. package/src/lib/gen2/chance.zig +88 -74
  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 +98 -98
  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 +93 -0
  78. package/src/tools/display/ui.css +354 -0
  79. package/build/test/display.js +0 -405
  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,29 @@
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(b: *std.Build, options: Options) *std.Build.Module {
16
+ const build_options = b.addOptions();
17
+ build_options.addOption(?bool, "showdown", options.showdown);
18
+ build_options.addOption(?bool, "log", options.log);
19
+ build_options.addOption(?bool, "chance", options.chance);
20
+ build_options.addOption(?bool, "calc", options.calc);
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 });
26
+ }
3
27
 
4
28
  pub fn build(b: *std.Build) !void {
5
29
  const target = b.standardTargetOptions(.{});
@@ -8,6 +32,10 @@ pub fn build(b: *std.Build) !void {
8
32
  const node_headers = b.option([]const u8, "node-headers", "Path to node-headers");
9
33
  const node_import_lib =
10
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;
11
39
  const wasm = b.option(bool, "wasm", "Build a WASM library") orelse false;
12
40
  const wasm_stack_size =
13
41
  b.option(u64, "wasm-stack-size", "The size of WASM stack") orelse std.wasm.page_size;
@@ -24,7 +52,7 @@ pub fn build(b: *std.Build) !void {
24
52
  defer parsed.deinit();
25
53
  const version = parsed.value.object.get("version").?.string;
26
54
  const description = parsed.value.object.get("description").?.string;
27
- var repository = std.mem.splitSequence(u8, parsed.value.object.get("repository").?.string, ":");
55
+ var repository = std.mem.splitScalar(u8, parsed.value.object.get("repository").?.string, ':');
28
56
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
29
57
 
30
58
  const showdown =
@@ -32,6 +60,7 @@ pub fn build(b: *std.Build) !void {
32
60
  const log = b.option(bool, "log", "Enable protocol message logging") orelse false;
33
61
  const chance = b.option(bool, "chance", "Enable update probability tracking") orelse false;
34
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");
35
64
 
36
65
  const options = b.addOptions();
37
66
  options.addOption(?bool, "showdown", showdown);
@@ -39,9 +68,26 @@ pub fn build(b: *std.Build) !void {
39
68
  options.addOption(?bool, "chance", chance);
40
69
  options.addOption(?bool, "calc", calc);
41
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
+
42
88
  const name = if (showdown) "pkmn-showdown" else "pkmn";
43
89
 
44
- const module = b.addModule("pkmn", .{
90
+ const pkmn: *std.Build.Module = b.addModule("pkmn", .{
45
91
  .root_source_file = b.path("src/lib/pkmn.zig"),
46
92
  .optimize = optimize,
47
93
  .target = target,
@@ -50,22 +96,33 @@ pub fn build(b: *std.Build) !void {
50
96
 
51
97
  var c = false;
52
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));
53
105
  const addon = b.fmt("{s}.node", .{name});
54
- const lib = b.addSharedLibrary(.{
106
+ const path = b.path("src/lib/node.zig");
107
+ const lib = b.addLibrary(.{
108
+ .linkage = .dynamic,
55
109
  .name = addon,
56
- .root_source_file = b.path("src/lib/node.zig"),
57
- .optimize = optimize,
58
- .target = target,
59
- .strip = strip,
60
- .pic = pic,
110
+ .root_module = b.createModule(.{
111
+ .root_source_file = path,
112
+ .optimize = optimize,
113
+ .target = target,
114
+ .strip = strip,
115
+ .pic = pic,
116
+ }),
61
117
  });
62
118
  lib.root_module.addOptions("build_options", options);
63
- lib.addSystemIncludePath(b.path(headers));
64
- lib.linkLibC();
119
+ lib.root_module.addImport("napi", translate_c.createModule());
120
+ lib.root_module.link_libc = true;
65
121
  if (node_import_lib) |il| {
66
- lib.addObjectFile(b.path(il));
122
+ lib.root_module.addObjectFile(b.path(il));
67
123
  } else if (target.result.os.tag == .windows) {
68
- try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
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");
69
126
  std.process.exit(1);
70
127
  }
71
128
  lib.linker_allow_shlib_undefined = true;
@@ -80,67 +137,46 @@ pub fn build(b: *std.Build) !void {
80
137
  // rename the file ourself in install-pkmn-engine
81
138
  b.installArtifact(lib);
82
139
  } 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
- }
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);
118
147
  } else if (dynamic) {
119
- const lib = b.addSharedLibrary(.{
148
+ const path = b.path("src/lib/c.zig");
149
+ const lib = b.addLibrary(.{
150
+ .linkage = .dynamic,
120
151
  .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,
152
+ .root_module = b.createModule(.{
153
+ .root_source_file = path,
154
+ .optimize = optimize,
155
+ .target = target,
156
+ .strip = strip,
157
+ .pic = pic,
158
+ }),
127
159
  });
128
160
  lib.root_module.addOptions("build_options", options);
129
- lib.addIncludePath(b.path("src/include"));
161
+ lib.root_module.addIncludePath(b.path("src/include"));
130
162
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
131
163
  b.installArtifact(lib);
132
164
  c = true;
133
165
  } else {
134
- const lib = b.addStaticLibrary(.{
166
+ const path = b.path("src/lib/c.zig");
167
+ const lib = b.addLibrary(.{
168
+ .linkage = .static,
135
169
  .name = name,
136
- .root_source_file = b.path("src/lib/c.zig"),
137
- .optimize = optimize,
138
- .target = target,
139
- .strip = strip,
140
- .pic = pic,
170
+ .root_module = b.createModule(.{
171
+ .root_source_file = path,
172
+ .optimize = optimize,
173
+ .target = target,
174
+ .strip = strip,
175
+ .pic = pic,
176
+ }),
141
177
  });
142
178
  lib.root_module.addOptions("build_options", options);
143
- lib.addIncludePath(b.path("src/include"));
179
+ lib.root_module.addIncludePath(b.path("src/include"));
144
180
  lib.bundle_compiler_rt = true;
145
181
  maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
146
182
  if (emit_asm) {
@@ -162,24 +198,25 @@ pub fn build(b: *std.Build) !void {
162
198
  }
163
199
 
164
200
  if (c) {
165
- const header = b.addInstallFileWithDir(
166
- b.path("src/include/pkmn.h"),
167
- .header,
168
- "pkmn.h",
169
- );
201
+ const path = b.path("src/include/pkmn.h");
202
+ const header = b.addInstallFileWithDir(path, .header, "pkmn.h");
170
203
  b.getInstallStep().dependOn(&header.step);
171
204
 
172
205
  const pc = b.fmt("lib{s}.pc", .{name});
173
- const file = try std.fs.path.relative(
206
+ const cwd = try std.process.currentPathAlloc(b.graph.io, b.allocator);
207
+ const file = try std.Io.Dir.path.relative(
174
208
  b.allocator,
175
- try std.process.getCwdAlloc(b.allocator),
209
+ cwd,
210
+ &b.graph.environ_map,
211
+ cwd,
176
212
  try b.cache_root.join(b.allocator, &.{pc}),
177
213
  );
178
- const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
214
+ const pkgconfig_file = try std.Io.Dir.cwd().createFile(b.graph.io, file, .{});
215
+ defer pkgconfig_file.close(b.graph.io);
179
216
 
180
217
  const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
181
- const writer = pkgconfig_file.writer();
182
- try writer.print(
218
+ var writer = pkgconfig_file.writer(b.graph.io, &.{});
219
+ try writer.interface.print(
183
220
  \\prefix={0s}/{1s}
184
221
  \\includedir=${{prefix}}/include
185
222
  \\libdir=${{prefix}}/lib
@@ -191,12 +228,11 @@ pub fn build(b: *std.Build) !void {
191
228
  \\Cflags: -I${{includedir}}
192
229
  \\Libs: -L${{libdir}} -l{2s}
193
230
  , .{ dirname, b.install_path, name, repository.next().?, description, version });
194
- defer pkgconfig_file.close();
195
231
 
196
232
  b.installFile(file, b.fmt("share/pkgconfig/{s}", .{pc}));
197
233
  }
198
234
 
199
- const config = .{
235
+ const config: Config = .{
200
236
  .target = target,
201
237
  .optimize = optimize,
202
238
  .pic = pic,
@@ -207,10 +243,15 @@ pub fn build(b: *std.Build) !void {
207
243
  // TODO: tests can be run multiple times due to @imports
208
244
  const tests = TestStep.create(b, options, config);
209
245
 
210
- var exes = std.ArrayList(*std.Build.Step.Compile).init(b.allocator);
246
+ var exes: ArrayList(*std.Build.Step.Compile) = .empty;
211
247
  const tools: ToolConfig = .{
212
- .showdown = showdown,
213
- .module = module,
248
+ .options = .{
249
+ .showdown = showdown,
250
+ .log = log,
251
+ .chance = chance,
252
+ .calc = calc,
253
+ },
254
+ .module = pkmn,
214
255
  .general = config,
215
256
  .tool = .{
216
257
  .tests = if (tests.build) tests else null,
@@ -249,6 +290,85 @@ pub fn build(b: *std.Build) !void {
249
290
  }
250
291
  }
251
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
+
252
372
  fn maybeStrip(
253
373
  b: *std.Build,
254
374
  artifact: *std.Build.Step.Compile,
@@ -288,16 +408,20 @@ const TestStep = struct {
288
408
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
289
409
  self.* = .{ .step = step, .build = test_filter == null };
290
410
 
411
+ const path = b.path("src/lib/test.zig");
291
412
  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,
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,
420
+ }),
421
+ .filters = if (test_filter) |filter| &.{filter} else &.{},
299
422
  });
300
423
  tests.root_module.addOptions("build_options", options);
424
+
301
425
  maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
302
426
  if (coverage) |c| {
303
427
  tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
@@ -309,39 +433,42 @@ const TestStep = struct {
309
433
  };
310
434
 
311
435
  const ToolConfig = struct {
312
- showdown: ?bool,
313
- module: *std.Build.Module,
436
+ options: Options,
437
+ module: ?*std.Build.Module,
314
438
  general: Config,
315
439
  tool: struct {
316
440
  tests: ?*TestStep,
317
441
  name: ?[]const u8 = null,
318
- exes: *std.ArrayList(*std.Build.Step.Compile),
442
+ exes: *ArrayList(*std.Build.Step.Compile),
319
443
  },
320
444
  };
321
445
 
322
446
  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
- };
447
+ if (!try exists(b, path)) return null;
327
448
  var name = config.tool.name orelse std.fs.path.basename(path);
328
449
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
329
450
  if (index) |i| name = name[0..i];
330
- if (config.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
451
+ if (config.options.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
331
452
 
332
453
  const exe = b.addExecutable(.{
333
454
  .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,
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
+ }),
340
462
  });
341
- exe.root_module.addImport("pkmn", config.module);
463
+
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
+ }
342
469
 
343
470
  if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
344
- config.tool.exes.append(exe) catch @panic("OOM");
471
+ config.tool.exes.append(b.allocator, exe) catch @panic("OOM");
345
472
 
346
473
  const run = b.addRunArtifact(exe);
347
474
  maybeStrip(b, exe, &run.step, config.general.strip, config.general.cmd);
@@ -350,10 +477,18 @@ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.R
350
477
  return run;
351
478
  }
352
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
+
353
488
  const ToolsStep = struct {
354
489
  step: std.Build.Step,
355
490
 
356
- pub fn create(b: *std.Build, exes: *std.ArrayList(*std.Build.Step.Compile)) *ToolsStep {
491
+ pub fn create(b: *std.Build, exes: *ArrayList(*std.Build.Step.Compile)) *ToolsStep {
357
492
  const self = b.allocator.create(ToolsStep) catch @panic("OOM");
358
493
  const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
359
494
  self.* = .{ .step = step };
@@ -361,3 +496,21 @@ const ToolsStep = struct {
361
496
  return self;
362
497
  }
363
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
+ }