@pkmn/engine 0.1.0-dev.683fba11 → 0.1.0-dev.6b383c80

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 (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +22 -16
  3. package/build/pkg/addon/browser.js +6 -3
  4. package/build/pkg/addon/browser.js.map +1 -1
  5. package/build/pkg/addon/node.js +23 -10
  6. package/build/pkg/addon/node.js.map +1 -1
  7. package/build/pkg/addon/wasm.js +23 -14
  8. package/build/pkg/addon/wasm.js.map +1 -1
  9. package/build/pkg/addon.d.ts +5 -5
  10. package/build/pkg/addon.js.map +1 -1
  11. package/build/pkg/data.js.map +1 -1
  12. package/build/pkg/gen1.d.ts +2 -1
  13. package/build/pkg/gen1.js +22 -9
  14. package/build/pkg/gen1.js.map +1 -1
  15. package/build/pkg/index.d.ts +2 -0
  16. package/build/pkg/index.js +17 -7
  17. package/build/pkg/index.js.map +1 -1
  18. package/build/pkg/protocol.d.ts +11 -2
  19. package/build/pkg/protocol.js.map +1 -1
  20. package/build/tools/debug.js +54 -11
  21. package/build/tools/debug.js.map +1 -1
  22. package/build/tools/display/debug.jsx +19 -94
  23. package/build/tools/display/debug.jsx.map +1 -1
  24. package/build/tools/display/index.js +18 -7
  25. package/build/tools/display/index.js.map +1 -1
  26. package/build/tools/display/ui.jsx +20 -9
  27. package/build/tools/display/ui.jsx.map +1 -1
  28. package/build/tools/display/util.js +140 -1
  29. package/build/tools/display/util.js.map +1 -1
  30. package/build.zig +255 -313
  31. package/package.json +29 -131
  32. package/src/bin/install-pkmn-engine +24 -22
  33. package/src/lib/bindings/c.zig +201 -0
  34. package/src/lib/bindings/node.zig +117 -0
  35. package/src/lib/bindings/wasm.zig +51 -0
  36. package/src/lib/common/array.zig +9 -16
  37. package/src/lib/common/data.zig +8 -8
  38. package/src/lib/common/debug.zig +46 -61
  39. package/src/lib/common/js.zig +3 -9
  40. package/src/lib/common/optional.zig +20 -25
  41. package/src/lib/common/protocol.zig +224 -189
  42. package/src/lib/common/rational.zig +275 -284
  43. package/src/lib/common/rng.zig +4 -4
  44. package/src/lib/common/util.zig +34 -31
  45. package/src/lib/gen1/calc.zig +141 -119
  46. package/src/lib/gen1/chance.zig +162 -101
  47. package/src/lib/gen1/data/types.zig +2 -2
  48. package/src/lib/gen1/data.zig +27 -24
  49. package/src/lib/gen1/helpers.zig +36 -26
  50. package/src/lib/gen1/mechanics.zig +45 -49
  51. package/src/lib/gen2/calc.zig +3 -6
  52. package/src/lib/gen2/chance.zig +55 -43
  53. package/src/lib/gen2/data/types.zig +6 -3
  54. package/src/lib/gen2/data.zig +20 -16
  55. package/src/lib/gen2/helpers.zig +27 -19
  56. package/src/lib/gen2/mechanics.zig +17 -17
  57. package/src/lib/napi.h +2 -0
  58. package/src/lib/node.zig +3 -118
  59. package/src/lib/pkmn.zig +94 -19
  60. package/src/lib/wasm.zig +9 -44
  61. package/src/tools/display/dom.ts +43 -31
package/build.zig CHANGED
@@ -1,73 +1,44 @@
1
- const builtin = @import("builtin");
2
1
  const std = @import("std");
3
2
 
4
- pub const Options = struct {
5
- showdown: ?bool = null,
6
- log: ?bool = null,
7
- chance: ?bool = null,
8
- calc: ?bool = null,
9
- };
10
-
11
- const Step = if (@hasDecl(std.Build, "Step")) std.Build.Step else .{
12
- .Compile = std.Build.CompileStep,
13
- .Options = std.Build.OptionsStep,
14
- .Run = std.Build.RunStep,
15
- };
16
- const has_path = @hasField(std.Build.LazyPath, "path");
17
- const root_module = @hasField(Step.Compile, "root_module");
18
- const force_pic = !@hasField(std.Build.SharedLibraryOptions, "pic");
19
- const ResolvedTarget =
20
- if (@hasDecl(std.Build, "ResolvedTarget")) std.Build.ResolvedTarget else std.zig.CrossTarget;
21
-
22
- pub fn module(b: *std.Build, options: Options) *std.Build.Module {
23
- const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
24
- const build_options = b.addOptions();
25
- build_options.addOption(?bool, "showdown", options.showdown);
26
- build_options.addOption(?bool, "log", options.log);
27
- build_options.addOption(?bool, "chance", options.chance);
28
- build_options.addOption(?bool, "calc", options.calc);
29
-
30
- const root_source_file = .{ .cwd_relative = dirname ++ "/src/lib/pkmn.zig" };
31
- const imports = &.{.{ .name = "build_options", .module = build_options.createModule() }};
32
- return b.createModule(if (@hasDecl(std.Build, "CreateModuleOptions"))
33
- .{ .source_file = root_source_file, .dependencies = imports }
34
- else
35
- .{ .root_source_file = root_source_file, .imports = imports });
36
- }
3
+ const Debug: std.builtin.OptimizeMode =
4
+ if (@hasDecl(std.builtin.OptimizeMode, "Debug")) .debug else .Debug;
5
+ const ReleaseSafe: std.builtin.OptimizeMode =
6
+ if (@hasDecl(std.builtin.OptimizeMode, "ReleaseSafe")) .safe else .ReleaseSafe;
7
+ const ReleaseFast: std.builtin.OptimizeMode =
8
+ if (@hasDecl(std.builtin.OptimizeMode, "ReleaseFast")) .fast else .ReleaseFast;
9
+ const ReleaseSmall: std.builtin.OptimizeMode =
10
+ if (@hasDecl(std.builtin.OptimizeMode, "ReleaseSmall")) .small else .ReleaseSmall;
37
11
 
38
12
  pub fn build(b: *std.Build) !void {
39
13
  const target = b.standardTargetOptions(.{});
40
14
  const optimize = b.standardOptimizeOption(.{});
41
15
 
42
- const default: ?bool = if (force_pic) false else null;
43
16
  const node_headers = b.option([]const u8, "node-headers", "Path to node-headers");
44
17
  const node_import_lib =
45
18
  b.option([]const u8, "node-import-library", "Path to node import library (Windows)");
19
+ const demo = if (try exists(b, "src/tools/demo.zig"))
20
+ b.option(bool, "demo", "Build the demo library") orelse false
21
+ else
22
+ false;
46
23
  const wasm = b.option(bool, "wasm", "Build a WASM library") orelse false;
47
24
  const wasm_stack_size =
48
25
  b.option(u64, "wasm-stack-size", "The size of WASM stack") orelse std.wasm.page_size;
49
26
  const dynamic = b.option(bool, "dynamic", "Build a dynamic library") orelse false;
50
- const strip = b.option(bool, "strip", "Strip debugging symbols from binary") orelse default;
51
- const pic = b.option(bool, "pic", "Force position independent code") orelse default;
27
+ const strip = b.option(bool, "strip", "Strip debugging symbols from binary");
28
+ const unwind_tables: ?std.builtin.UnwindTables =
29
+ if ((strip orelse false) and target.result.os.tag != .windows) .none else null;
30
+ const pic = b.option(bool, "pic", "Force position independent code");
52
31
  const emit_asm = b.option(bool, "emit-asm", "Output .s (assembly code)") orelse false;
53
32
  const emit_ll = b.option(bool, "emit-ll", "Output .ll (LLVM IR)") orelse false;
54
33
 
55
- const cmd = b.findProgram(&.{"strip"}, &.{}) catch null;
56
-
57
34
  const json = @embedFile("package.json");
58
35
  var parsed = try std.json.parseFromSlice(std.json.Value, b.allocator, json, .{});
59
36
  defer parsed.deinit();
60
37
  const version = parsed.value.object.get("version").?.string;
61
38
  const description = parsed.value.object.get("description").?.string;
62
- var repository = std.mem.splitSequence(u8, parsed.value.object.get("repository").?.string, ":");
39
+ var repository = std.mem.splitScalar(u8, parsed.value.object.get("repository").?.string, ':');
63
40
  std.debug.assert(std.mem.eql(u8, repository.first(), "github"));
64
41
 
65
- const fast = try std.SemanticVersion.parse("0.12.0-dev.866+3a47bc715");
66
- if (optimize != .Debug and fast.order(builtin.zig_version) == .lt) {
67
- std.log.warn("Release builds are ~10-20% slower than before Zig " ++
68
- "v0.12.0-dev.866+3a47bc715 due to ziglang/zig#17768", .{});
69
- }
70
-
71
42
  const showdown =
72
43
  b.option(bool, "showdown", "Enable Pokémon Showdown compatibility mode") orelse false;
73
44
  const log = b.option(bool, "log", "Enable protocol message logging") orelse false;
@@ -100,99 +71,98 @@ pub fn build(b: *std.Build) !void {
100
71
 
101
72
  const name = if (showdown) "pkmn-showdown" else "pkmn";
102
73
 
103
- const pkmn = if (@hasDecl(std.Build, "CreateModuleOptions")) null else b.addModule("pkmn", .{
104
- .root_source_file = if (has_path)
105
- .{ .path = "src/lib/pkmn.zig" }
106
- else
107
- b.path("src/lib/pkmn.zig"),
108
- .optimize = optimize,
109
- .target = target,
74
+ const pkmn = b.addModule("pkmn", .{
75
+ .root_source_file = b.path("src/lib/pkmn.zig"),
110
76
  .imports = &.{.{ .name = "build_options", .module = options.createModule() }},
111
77
  });
112
78
 
113
79
  var c = false;
114
80
  if (node_headers) |headers| {
115
- const addon = b.fmt("{s}.node", .{name});
116
- const path = if (has_path) .{ .path = "src/lib/node.zig" } else b.path("src/lib/node.zig");
117
- const lib = b.addSharedLibrary(if (force_pic) .{
118
- .name = addon,
119
- .root_source_file = path,
120
- .optimize = optimize,
81
+ const translate_c = b.addTranslateC(.{
82
+ .root_source_file = b.path("src/lib/napi.h"),
121
83
  .target = target,
122
- } else .{
84
+ // TODO: workaround for ziglang/zig#35515
85
+ .optimize = Debug,
86
+ });
87
+ translate_c.addSystemIncludePath(b.path(headers));
88
+ const addon = b.fmt("{s}.node", .{name});
89
+ const path = b.path("src/lib/node.zig");
90
+ const lib = b.addLibrary(.{
91
+ .linkage = .dynamic,
123
92
  .name = addon,
124
- .root_source_file = path,
125
- .optimize = optimize,
126
- .target = target,
127
- .strip = strip,
128
- .pic = pic,
93
+ .root_module = b.createModule(.{
94
+ .root_source_file = path,
95
+ .optimize = optimize,
96
+ .target = target,
97
+ .strip = strip,
98
+ .unwind_tables = unwind_tables,
99
+ .pic = pic,
100
+ }),
129
101
  });
130
- (if (root_module) lib.root_module else lib).addOptions("build_options", options);
131
- lib.addSystemIncludePath(if (has_path) .{ .path = headers } else b.path(headers));
132
- lib.linkLibC();
102
+ lib.discard_local_symbols = strip orelse false;
103
+ lib.root_module.addOptions("build_options", options);
104
+ lib.root_module.addImport("napi", translate_c.createModule());
105
+ lib.root_module.link_libc = true;
133
106
  if (node_import_lib) |il| {
134
- lib.addObjectFile(if (has_path) .{ .path = il } else b.path(il));
135
- } else if (detect(target).os.tag == .windows) {
136
- try std.io.getStdErr().writeAll("Must provide --node-import-library path on Windows\n");
107
+ lib.root_module.addObjectFile(b.path(il));
108
+ } else if (target.result.os.tag == .windows) {
109
+ var err = std.Io.File.stderr().writer(b.graph.io, &.{});
110
+ try err.interface.writeAll("Must provide --node-import-library path on Windows\n");
137
111
  std.process.exit(1);
138
112
  }
139
113
  lib.linker_allow_shlib_undefined = true;
140
- maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
141
- if (force_pic and pic orelse false) lib.force_pic = pic;
142
- // Always emit to build/lib because this is where the driver code expects to find it
143
- // TODO: ziglang/zig#2231 - using the following used to work (though was hacky):
144
- //
145
- // lib.emit_bin = .{ .emit_to = b.fmt("build/lib/{s}", .{addon}) };
146
- // b.getInstallStep().dependOn(&lib.step);
147
- //
148
- // But ziglang/zig#14647 broke this so we now need to do an install() and then manually
149
- // rename the file ourself in install-pkmn-engine
150
- b.installArtifact(lib);
114
+ b.getInstallStep().dependOn(&b.addInstallArtifact(lib, .{
115
+ .dest_dir = .{ .override = .lib },
116
+ .dest_sub_path = addon,
117
+ .implib_dir = .disabled,
118
+ .pdb_dir = .disabled,
119
+ }).step);
151
120
  } else if (wasm) {
152
- try buildWasm(b, name, "src/lib/wasm.zig", optimize, strip, pic, wasm_stack_size, options);
121
+ const path = "src/lib/wasm.zig";
122
+ try buildWasm(b, name, path, optimize, strip, pic, wasm_stack_size, null, options);
123
+ } else if (demo) {
124
+ const path = "src/tools/demo.zig";
125
+ const n = if (showdown) "demo-showdown" else "demo";
126
+ try buildWasm(b, n, path, optimize, strip, pic, wasm_stack_size, pkmn, options);
153
127
  } else if (dynamic) {
154
- const path = if (has_path) .{ .path = "src/lib/c.zig" } else b.path("src/lib/c.zig");
155
- const lib = b.addSharedLibrary(if (force_pic) .{
128
+ const path = b.path("src/lib/c.zig");
129
+ const lib = b.addLibrary(.{
130
+ .linkage = .dynamic,
156
131
  .name = name,
157
- .root_source_file = path,
158
- .version = try std.SemanticVersion.parse(version),
159
- .optimize = optimize,
160
- .target = target,
161
- } else .{
162
- .name = name,
163
- .root_source_file = path,
164
- .version = try std.SemanticVersion.parse(version),
165
- .optimize = optimize,
166
- .target = target,
167
- .strip = strip,
168
- .pic = pic,
132
+ .root_module = b.createModule(.{
133
+ .root_source_file = path,
134
+ .optimize = optimize,
135
+ .target = target,
136
+ .strip = strip,
137
+ .unwind_tables = unwind_tables,
138
+ .pic = pic,
139
+ }),
169
140
  });
170
- (if (root_module) lib.root_module else lib).addOptions("build_options", options);
171
- lib.addIncludePath(if (has_path) .{ .path = "src/include" } else b.path("src/include"));
172
- maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
173
- if (force_pic and pic orelse false) lib.force_pic = pic;
141
+ lib.discard_local_symbols = strip orelse false;
142
+ lib.root_module.addOptions("build_options", options);
143
+ lib.root_module.addIncludePath(b.path("src/include"));
174
144
  b.installArtifact(lib);
175
145
  c = true;
176
146
  } else {
177
- const path = if (has_path) .{ .path = "src/lib/c.zig" } else b.path("src/lib/c.zig");
178
- const lib = b.addStaticLibrary(if (force_pic) .{
179
- .name = name,
180
- .root_source_file = path,
181
- .optimize = optimize,
182
- .target = target,
183
- } else .{
147
+ const path = b.path("src/lib/c.zig");
148
+ const lib = b.addLibrary(.{
149
+ .linkage = .static,
184
150
  .name = name,
185
- .root_source_file = path,
186
- .optimize = optimize,
187
- .target = target,
188
- .strip = strip,
189
- .pic = pic,
151
+ .root_module = b.createModule(.{
152
+ .root_source_file = path,
153
+ .optimize = optimize,
154
+ .target = target,
155
+ .strip = strip,
156
+ .unwind_tables = unwind_tables,
157
+ .pic = pic,
158
+ }),
190
159
  });
191
- (if (root_module) lib.root_module else lib).addOptions("build_options", options);
192
- lib.addIncludePath(if (has_path) .{ .path = "src/include" } else b.path("src/include"));
193
- lib.bundle_compiler_rt = true;
194
- maybeStrip(b, lib, b.getInstallStep(), strip, cmd);
195
- if (force_pic and pic orelse false) lib.force_pic = pic;
160
+ lib.discard_local_symbols = strip orelse false;
161
+ lib.root_module.addOptions("build_options", options);
162
+ lib.root_module.addIncludePath(b.path("src/include"));
163
+ if (target.result.os.tag != .macos) {
164
+ lib.bundle_compiler_rt = true;
165
+ }
196
166
  if (emit_asm) {
197
167
  b.getInstallStep().dependOn(&b.addInstallFileWithDir(
198
168
  lib.getEmittedAsm(),
@@ -212,72 +182,64 @@ pub fn build(b: *std.Build) !void {
212
182
  }
213
183
 
214
184
  if (c) {
215
- const path =
216
- if (has_path) .{ .path = "src/include/pkmn.h" } else b.path("src/include/pkmn.h");
185
+ const path = b.path("src/include/pkmn.h");
217
186
  const header = b.addInstallFileWithDir(path, .header, "pkmn.h");
218
187
  b.getInstallStep().dependOn(&header.step);
219
188
 
220
- const pc = b.fmt("lib{s}.pc", .{name});
221
- const file = try std.fs.path.relative(
222
- b.allocator,
223
- try std.process.getCwdAlloc(b.allocator),
224
- try b.cache_root.join(b.allocator, &.{pc}),
225
- );
226
- const pkgconfig_file = try std.fs.cwd().createFile(file, .{});
227
-
228
- const dirname = comptime std.fs.path.dirname(@src().file) orelse ".";
229
- const writer = pkgconfig_file.writer();
230
- try writer.print(
231
- \\prefix={0s}/{1s}
189
+ const content = try std.fmt.allocPrint(b.allocator,
190
+ \\prefix=${{pcfiledir}}/../..
232
191
  \\includedir=${{prefix}}/include
233
192
  \\libdir=${{prefix}}/lib
234
193
  \\
235
- \\Name: lib{2s}
236
- \\URL: https://github.com/{3s}
237
- \\Description: {4s}
238
- \\Version: {5s}
194
+ \\Name: lib{0s}
195
+ \\URL: https://github.com/{1s}
196
+ \\Description: {2s}
197
+ \\Version: {3s}
239
198
  \\Cflags: -I${{includedir}}
240
- \\Libs: -L${{libdir}} -l{2s}
241
- , .{ dirname, b.install_path, name, repository.next().?, description, version });
242
- defer pkgconfig_file.close();
199
+ \\Libs: -L${{libdir}} -l{0s}
200
+ , .{ name, repository.next().?, description, version });
243
201
 
244
- b.installFile(file, b.fmt("share/pkgconfig/{s}", .{pc}));
202
+ const pc = b.fmt("lib{s}.pc", .{name});
203
+ const write_file = b.addWriteFiles();
204
+ const pkgconfig = write_file.add(pc, content);
205
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
206
+ pkgconfig,
207
+ .prefix,
208
+ b.fmt("share/pkgconfig/{s}", .{pc}),
209
+ ).step);
245
210
  }
246
211
 
247
- const config = .{
212
+ const config: Config = .{
248
213
  .target = target,
249
214
  .optimize = optimize,
250
215
  .pic = pic,
251
216
  .strip = strip,
252
- .cmd = cmd,
217
+ .unwind_tables = unwind_tables,
253
218
  };
254
219
 
255
220
  // TODO: tests can be run multiple times due to @imports
256
221
  const tests = TestStep.create(b, options, config);
257
222
 
258
- var exes = std.ArrayList(*Step.Compile).init(b.allocator);
223
+ var exes: std.ArrayList(*std.Build.Step.Compile) = .empty;
259
224
  const tools: ToolConfig = .{
260
- .options = .{
261
- .showdown = showdown,
262
- .log = log,
263
- .chance = chance,
264
- .calc = calc,
265
- },
225
+ .showdown = showdown,
266
226
  .module = pkmn,
267
227
  .general = config,
268
228
  .tool = .{
269
- .tests = if (tests.build) tests else null,
229
+ .tests = if (tests.build) tests.step else null,
270
230
  .exes = &exes,
271
231
  },
272
232
  };
273
233
 
274
234
  var benchmark_config = tools;
275
- benchmark_config.general.optimize = .ReleaseFast;
235
+ benchmark_config.general.optimize = ReleaseFast;
276
236
  benchmark_config.general.strip = true;
237
+ benchmark_config.general.unwind_tables = if (target.result.os.tag != .windows) .none else null;
277
238
  const benchmark = try tool(b, "src/test/benchmark.zig", benchmark_config);
278
239
 
279
240
  var fuzz_config = tools;
280
241
  fuzz_config.general.strip = false;
242
+ fuzz_config.general.unwind_tables = null;
281
243
  fuzz_config.tool.name = "fuzz";
282
244
  const fuzz = try tool(b, "src/test/fuzz.zig", fuzz_config);
283
245
 
@@ -287,7 +249,7 @@ pub fn build(b: *std.Build) !void {
287
249
 
288
250
  // FIXME: serde randomly fails to build in some release configurations
289
251
  var hack = tools;
290
- if (optimize != .Debug) hack.tool.tests = null;
252
+ if (optimize != Debug) hack.tool.tests = null;
291
253
  const serde = try tool(b, "src/tools/serde.zig", hack);
292
254
 
293
255
  if (analyze) |t| b.step("analyze", "Run LLVM analysis tool").dependOn(&t.step);
@@ -295,8 +257,9 @@ pub fn build(b: *std.Build) !void {
295
257
  if (dump) |t| b.step("dump", "Run protocol dump tool").dependOn(&t.step);
296
258
  if (fuzz) |t| b.step("fuzz", "Run fuzz tester").dependOn(&t.step);
297
259
  if (serde) |t| b.step("serde", "Run serialization/deserialization tool").dependOn(&t.step);
298
- b.step("test", "Run all tests").dependOn(&tests.step);
299
- b.step("tools", "Install tools").dependOn(&ToolsStep.create(b, &exes).step);
260
+ b.step("test", "Run all tests").dependOn(tests.step);
261
+ const install_tools = b.step("tools", "Install tools");
262
+ for (exes.items) |t| install_tools.dependOn(&b.addInstallArtifact(t, .{}).step);
300
263
  if (transitions) |t| {
301
264
  b.step("transitions", "Visualize transitions algorithm search").dependOn(&t.step);
302
265
  }
@@ -310,229 +273,208 @@ fn buildWasm(
310
273
  strip: ?bool,
311
274
  pic: ?bool,
312
275
  wasm_stack_size: u64,
313
- options: anytype,
276
+ import: ?*std.Build.Module,
277
+ options: *std.Build.Step.Options,
314
278
  ) !void {
315
- const entry = @hasDecl(Step.Compile, "Entry");
316
279
  const mode = switch (optimize) {
317
- .ReleaseFast, .ReleaseSafe => .ReleaseSmall,
280
+ ReleaseFast, ReleaseSafe => ReleaseSmall,
318
281
  else => optimize,
319
282
  };
320
- const freestanding = if (@hasDecl(std.Build, "resolveTargetQuery"))
321
- b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding })
322
- else
323
- ResolvedTarget{ .cpu_arch = .wasm32, .os_tag = .freestanding };
324
- const path = if (has_path) .{ .path = root_src_file } else b.path(root_src_file);
325
- const bin = if (entry) bin: {
326
- const exe = b.addExecutable(if (force_pic) .{
327
- .name = name,
328
- .root_source_file = path,
329
- .optimize = mode,
330
- .target = freestanding,
331
- } else .{
332
- .name = name,
283
+ // https://webassembly.org/features/
284
+ const features = std.Target.wasm.featureSet(&.{
285
+ .atomics,
286
+ .bulk_memory,
287
+ // .exception_handling,
288
+ .extended_const,
289
+ // .half_precision,
290
+ // .multimemory,
291
+ .multivalue,
292
+ .mutable_globals,
293
+ .nontrapping_fptoint,
294
+ .reference_types,
295
+ // .relaxed_simd,
296
+ .sign_ext,
297
+ .simd128,
298
+ // .tail_call,
299
+ });
300
+ const freestanding = b.resolveTargetQuery(.{
301
+ .cpu_arch = .wasm32,
302
+ .os_tag = .freestanding,
303
+ .cpu_features_add = features,
304
+ });
305
+ const path = b.path(root_src_file);
306
+ const exe = b.addExecutable(.{
307
+ .name = name,
308
+ .root_module = b.createModule(.{
333
309
  .root_source_file = path,
334
310
  .optimize = mode,
335
311
  .target = freestanding,
336
312
  .strip = strip,
313
+ .unwind_tables = if (strip orelse false) .none else null,
337
314
  .pic = pic,
315
+ }),
316
+ });
317
+ exe.discard_local_symbols = strip orelse false;
318
+
319
+ if (@hasDecl(std.Build, "FindProgramOptions")) b.dependOnFileContents(path);
320
+ const root = if (@hasField(std.Build, "root")) b.root.root_dir.handle else b.build_root.handle;
321
+ var file = try root.openFile(b.graph.io, root_src_file, .{});
322
+ defer file.close(b.graph.io);
323
+ var reader = file.reader(b.graph.io, &.{});
324
+ const bytes = try reader.interface.allocRemaining(b.allocator, .unlimited);
325
+ exe.root_module.export_symbol_names = try exports(b, bytes);
326
+ exe.entry = .disabled;
327
+
328
+ if (import) |i| {
329
+ exe.root_module.addImport("pkmn", i);
330
+ } else {
331
+ exe.root_module.addOptions("build_options", options);
332
+ }
333
+ exe.stack_size = wasm_stack_size;
334
+
335
+ const opt = if (optimize == Debug)
336
+ null
337
+ else if (@hasDecl(std.Build, "FindProgramOptions")) blk: {
338
+ if (exists(b, "./node_modules/.bin/wasm-opt") catch false) {
339
+ break :blk "./node_modules/.bin/wasm-opt";
340
+ }
341
+ break :blk b.findProgram(.{ .names = &.{"wasm-opt"} });
342
+ } else b.findProgram(&.{"wasm-opt"}, &.{"./node_modules/.bin"}) catch null;
343
+ if (opt) |wasm_opt| {
344
+ const out = b.fmt("{s}.wasm", .{name});
345
+ const sh = b.addSystemCommand(&.{
346
+ wasm_opt,
347
+ "--enable-bulk-memory",
348
+ "--enable-simd",
349
+ "-O4",
338
350
  });
339
- (if (root_module) exe.root_module else exe).export_symbol_names = try exports(b);
340
- exe.entry = .disabled;
341
- break :bin exe;
342
- } else bin: {
343
- const lib = b.addSharedLibrary(.{
344
- .name = name,
345
- .root_source_file = path,
346
- .optimize = mode,
347
- .target = freestanding,
348
- });
349
- lib.rdynamic = true;
350
- break :bin lib;
351
- };
352
- bin.stack_size = wasm_stack_size;
353
- if (@hasDecl(@TypeOf(bin.*), "strip")) bin.strip = strip orelse false;
354
- if (force_pic and pic orelse false) bin.force_pic = pic;
355
- (if (root_module) bin.root_module else bin).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.?, "-O4" });
361
- sh.addArtifactArg(bin);
351
+ sh.addArtifactArg(exe);
362
352
  sh.addArg("-o");
363
- if (@hasDecl(@TypeOf(sh.*), "addFileSourceArg")) {
364
- sh.addFileSourceArg(if (has_path) .{ .path = out } else b.path(out));
365
- } else {
366
- sh.addFileArg(if (has_path) .{ .path = out } else b.path(out));
367
- }
368
- b.getInstallStep().dependOn(&sh.step);
369
- if (!entry) b.installArtifact(bin);
370
- } else if (entry) {
371
- b.getInstallStep().dependOn(&b.addInstallArtifact(bin, .{
372
- .dest_dir = .{ .override = std.Build.InstallDir{ .lib = {} } },
353
+ b.getInstallStep().dependOn(&b.addInstallFileWithDir(
354
+ sh.addOutputFileArg(out),
355
+ .lib,
356
+ out,
357
+ ).step);
358
+ } else {
359
+ b.getInstallStep().dependOn(&b.addInstallArtifact(exe, .{
360
+ .dest_dir = .{ .override = .lib },
373
361
  }).step);
374
362
  }
375
363
  }
376
364
 
377
- fn maybeStrip(
378
- b: *std.Build,
379
- artifact: *Step.Compile,
380
- step: *std.Build.Step,
381
- strip: ?bool,
382
- cmd: ?[]const u8,
383
- ) void {
384
- if (@hasDecl(@TypeOf(artifact.*), "strip")) artifact.strip = strip orelse false;
385
- if (!(strip orelse false) or cmd == null) return;
386
- // Using `strip -r -u` for dynamic libraries is supposed to work on macOS but doesn't...
387
- const mac = builtin.os.tag == .macos;
388
- if (mac and artifact.isDynamicLibrary()) return;
389
- // Assuming GNU strip, which complains "illegal pathname found in archive member"...
390
- if (!mac and artifact.isStaticLibrary()) return;
391
- const sh = b.addSystemCommand(&.{ cmd.?, if (mac) "-x" else "-s" });
392
- sh.addArtifactArg(artifact);
393
- step.dependOn(&sh.step);
394
- }
395
-
396
365
  const Config = struct {
397
- target: ResolvedTarget,
366
+ target: std.Build.ResolvedTarget,
398
367
  optimize: std.builtin.OptimizeMode,
399
368
  pic: ?bool,
400
369
  strip: ?bool,
401
- cmd: ?[]const u8,
370
+ unwind_tables: ?std.builtin.UnwindTables,
402
371
  };
403
372
 
404
373
  const TestStep = struct {
405
- step: std.Build.Step,
374
+ step: *std.Build.Step,
406
375
  build: bool,
407
376
 
408
- pub fn create(b: *std.Build, options: *Step.Options, config: Config) *TestStep {
377
+ pub fn create(b: *std.Build, options: *std.Build.Step.Options, config: Config) TestStep {
409
378
  const coverage = b.option([]const u8, "test-coverage", "Generate test coverage");
410
379
  const test_filter =
411
380
  b.option([]const u8, "test-filter", "Skip tests that do not match filter");
412
381
 
413
- const self = b.allocator.create(TestStep) catch @panic("OOM");
414
- const step = std.Build.Step.init(.{ .id = .custom, .name = "Run all tests", .owner = b });
415
- self.* = .{ .step = step, .build = test_filter == null };
416
-
417
- const path = if (has_path) .{ .path = "src/lib/test.zig" } else b.path("src/lib/test.zig");
418
- const tests = b.addTest(if (force_pic) .{
419
- .root_source_file = path,
420
- .optimize = config.optimize,
421
- .target = config.target,
422
- .filter = test_filter,
423
- } else .{
424
- .root_source_file = path,
425
- .optimize = config.optimize,
426
- .target = config.target,
427
- .filter = test_filter,
428
- .single_threaded = true,
429
- .strip = config.strip,
430
- .pic = config.pic,
382
+ const path = b.path("src/lib/test.zig");
383
+ const tests = b.addTest(.{
384
+ .root_module = b.createModule(.{
385
+ .root_source_file = path,
386
+ .optimize = config.optimize,
387
+ .target = config.target,
388
+ .single_threaded = true,
389
+ .strip = config.strip,
390
+ .unwind_tables = config.unwind_tables,
391
+ .pic = config.pic,
392
+ }),
393
+ .filters = if (test_filter) |filter| &.{filter} else &.{},
431
394
  });
432
- (if (root_module) tests.root_module else tests).addOptions("build_options", options);
395
+ tests.discard_local_symbols = config.strip orelse false;
396
+ tests.root_module.addOptions("build_options", options);
433
397
 
434
- maybeStrip(b, tests, &tests.step, config.strip, config.cmd);
435
- if (force_pic) {
436
- tests.single_threaded = true;
437
- if (config.pic orelse false) tests.force_pic = config.pic;
438
- }
439
398
  if (coverage) |c| {
440
- tests.setExecCmd(&.{ "kcov", "--include-pattern=src/lib", c, null });
399
+ const kcov_run = b.addSystemCommand(&.{ "kcov", "--include-pattern=src/lib", c });
400
+ kcov_run.addArtifactArg(tests);
401
+ kcov_run.enableTestRunnerMode();
402
+ return .{ .step = &kcov_run.step, .build = test_filter == null };
403
+ } else {
404
+ const run_step = b.addRunArtifact(tests);
405
+ return .{ .step = &run_step.step, .build = test_filter == null };
441
406
  }
442
- self.step.dependOn(&b.addRunArtifact(tests).step);
443
-
444
- return self;
445
407
  }
446
408
  };
447
409
 
448
410
  const ToolConfig = struct {
449
- options: Options,
450
- module: ?*std.Build.Module,
411
+ showdown: ?bool,
412
+ module: *std.Build.Module,
451
413
  general: Config,
452
414
  tool: struct {
453
- tests: ?*TestStep,
415
+ tests: ?*std.Build.Step,
454
416
  name: ?[]const u8 = null,
455
- exes: *std.ArrayList(*Step.Compile),
417
+ exes: *std.ArrayList(*std.Build.Step.Compile),
456
418
  },
457
419
  };
458
420
 
459
- fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*Step.Run {
460
- std.fs.cwd().access(path, .{}) catch |err| switch (err) {
461
- error.FileNotFound => return null,
462
- else => |e| return e,
463
- };
421
+ fn tool(b: *std.Build, path: []const u8, config: ToolConfig) !?*std.Build.Step.Run {
422
+ if (!try exists(b, path)) return null;
464
423
  var name = config.tool.name orelse std.fs.path.basename(path);
465
424
  const index = std.mem.lastIndexOfScalar(u8, name, '.');
466
425
  if (index) |i| name = name[0..i];
467
- if (config.options.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
426
+ if (config.showdown orelse false) name = b.fmt("{s}-showdown", .{name});
468
427
 
469
- const exe = b.addExecutable(if (force_pic) .{
470
- .name = name,
471
- .root_source_file = if (has_path) .{ .path = path } else b.path(path),
472
- .target = config.general.target,
473
- .optimize = config.general.optimize,
474
- } else .{
428
+ const exe = b.addExecutable(.{
475
429
  .name = name,
476
- .root_source_file = if (has_path) .{ .path = path } else b.path(path),
477
- .target = config.general.target,
478
- .optimize = config.general.optimize,
479
- .single_threaded = true,
480
- .strip = config.general.strip,
481
- .pic = config.general.pic,
430
+ .root_module = b.createModule(.{
431
+ .root_source_file = b.path(path),
432
+ .target = config.general.target,
433
+ .optimize = config.general.optimize,
434
+ .single_threaded = true,
435
+ .strip = config.general.strip,
436
+ .unwind_tables = config.general.unwind_tables,
437
+ .pic = config.general.pic,
438
+ }),
482
439
  });
440
+ exe.discard_local_symbols = config.general.strip orelse false;
441
+ exe.root_module.addImport("pkmn", config.module);
483
442
 
484
- if (root_module) {
485
- const import = if (config.module) |m| m else module(b, config.options);
486
- exe.root_module.addImport("pkmn", import);
487
- } else {
488
- exe.addModule("pkmn", module(b, config.options));
489
- }
490
-
491
- if (force_pic) {
492
- exe.single_threaded = true;
493
- if (config.general.pic orelse false) exe.force_pic = config.general.pic;
494
- }
495
- if (config.tool.tests) |ts| ts.step.dependOn(&exe.step);
496
- config.tool.exes.append(exe) catch @panic("OOM");
443
+ if (config.tool.tests) |ts| ts.dependOn(&exe.step);
444
+ config.tool.exes.append(b.allocator, exe) catch @panic("OOM");
497
445
 
498
446
  const run = b.addRunArtifact(exe);
499
- maybeStrip(b, exe, &run.step, config.general.strip, config.general.cmd);
500
- if (b.args) |args| run.addArgs(args);
447
+ if (@hasDecl(std.Build, "FindProgramOptions")) {
448
+ run.addPassthruArgs();
449
+ } else {
450
+ if (b.args) |args| run.addArgs(args);
451
+ }
501
452
 
502
453
  return run;
503
454
  }
504
455
 
505
- const ToolsStep = struct {
506
- step: std.Build.Step,
507
-
508
- pub fn create(b: *std.Build, exes: *std.ArrayList(*Step.Compile)) *ToolsStep {
509
- const self = b.allocator.create(ToolsStep) catch @panic("OOM");
510
- const step = std.Build.Step.init(.{ .id = .custom, .name = "Install tools", .owner = b });
511
- self.* = .{ .step = step };
512
- for (exes.items) |t| self.step.dependOn(&b.addInstallArtifact(t, .{}).step);
513
- return self;
514
- }
515
- };
516
-
517
- fn detect(target: anytype) std.Target {
518
- if (@hasField(@TypeOf(target), "result")) return target.result;
519
- return (std.zig.system.NativeTargetInfo.detect(target) catch unreachable).target;
456
+ fn exists(b: *std.Build, path: []const u8) !bool {
457
+ const root = if (@hasField(std.Build, "root")) b.root.root_dir.handle else b.build_root.handle;
458
+ root.access(b.graph.io, path, .{}) catch |err| switch (err) {
459
+ error.FileNotFound => return false,
460
+ else => |e| return e,
461
+ };
462
+ if (@hasDecl(std.Build, "FindProgramOptions")) b.dependOnFileMetadata(b.path(path));
463
+ return true;
520
464
  }
521
465
 
522
- const WASM = @embedFile("src/lib/wasm.zig");
523
-
524
- fn exports(b: *std.Build) ![][]const u8 {
525
- var symbols = std.ArrayList([]const u8).init(b.allocator);
466
+ pub fn exports(b: *std.Build, bytes: []const u8) ![][]const u8 {
467
+ var symbols: std.ArrayList([]const u8) = .empty;
526
468
 
527
- var it = std.mem.splitSequence(u8, WASM, "export ");
469
+ var it = std.mem.splitSequence(u8, bytes, "export ");
528
470
  _ = it.next();
529
471
  while (it.next()) |s| {
530
472
  if (std.mem.startsWith(u8, s, "const ")) {
531
473
  const i = std.mem.indexOf(u8, s[6..], " ").?;
532
- try symbols.append(s[6 .. 6 + i]);
474
+ try symbols.append(b.allocator, s[6 .. 6 + i]);
533
475
  } else { // "fn "
534
476
  const i = std.mem.indexOf(u8, s[3..], "(").?;
535
- try symbols.append(s[3 .. 3 + i]);
477
+ try symbols.append(b.allocator, s[3 .. 3 + i]);
536
478
  }
537
479
  }
538
480