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