authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-13 19:50:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
logdd51fc30f884aa1c3305793010a30d826689be89
tree9e6d744014ebe36593fa3874c5e9db2c83aa60c9
parentb998d71e939c304ba76860077b4483249f670b7d

maker: finish migrating compile step make logic


8 files changed, 308 insertions(+), 203 deletions(-)

lib/compiler/Maker.zig+42
......@@ -1084,6 +1084,7 @@ fn makeStep(
10841084 } else |err| switch (err) {
10851085 error.MakeFailed => .failure,
10861086 error.MakeSkipped => .skipped,
1087 error.Canceled => |e| return e,
10871088 };
10881089
10891090 @atomicStore(Step.State, &make_step.state, new_state, .monotonic);
......@@ -1764,6 +1765,10 @@ pub fn resolveLazyPathIndexAbs(
17641765 return resolveLazyPathAbs(maker, arena, lazy_path_index.get(c), asking_step_index);
17651766}
17661767
1768pub fn generatedPath(maker: *Maker, index: Configuration.GeneratedFileIndex) *Path {
1769 return &maker.generated_files[@intFromEnum(index)];
1770}
1771
17671772fn packagePath(
17681773 maker: *const Maker,
17691774 arena: Allocator,
......@@ -1783,3 +1788,40 @@ fn packagePath(
17831788 .sub_path = try Io.Dir.path.join(arena, &.{ pkg_root.sub_path, hash, sub_path }),
17841789 };
17851790}
1791
1792/// Wrapper around `Io.Dir.updateFile` that handles verbose and error output.
1793pub fn installFile(
1794 maker: *Maker,
1795 arena: Allocator,
1796 src_lazy_path: Configuration.LazyPath,
1797 dest_path: []const u8,
1798 asking_step_index: Configuration.Step.Index,
1799) !Io.Dir.PrevStatus {
1800 const graph = maker.graph;
1801 const io = graph.io;
1802 const src_path = try resolveLazyPath(maker, arena, src_lazy_path, asking_step_index);
1803 {
1804 const src_path_rendered = try src_path.toString(arena);
1805 defer arena.free(src_path_rendered);
1806 try graph.handleVerbose(.inherit, null, &.{ "install", "-C", src_path_rendered, dest_path });
1807 }
1808 return Io.Dir.updateFile(src_path.root_dir.handle, io, src_path.sub_path, .cwd(), dest_path, .{}) catch |err| {
1809 const s = stepByIndex(maker, asking_step_index);
1810 return s.fail(maker, "unable to update file from '{f}' to '{s}': {t}", .{ src_path, dest_path, err });
1811 };
1812}
1813
1814/// Wrapper around `Io.Dir.createDirPathStatus` that handles verbose and error output.
1815pub fn installDir(
1816 maker: *Maker,
1817 dest_path: []const u8,
1818 asking_step_index: Configuration.Step.Index,
1819) !Io.Dir.CreatePathStatus {
1820 const graph = maker.graph;
1821 const io = graph.io;
1822 try graph.handleVerbose(.inherit, null, &.{ "install", "-d", dest_path });
1823 return Io.Dir.cwd().createDirPathStatus(io, dest_path, .default_dir) catch |err| {
1824 const s = stepByIndex(maker, asking_step_index);
1825 return s.fail(maker, "unable to create dir '{s}': {t}", .{ dest_path, err });
1826 };
1827}
lib/compiler/Maker/Graph.zig+18
......@@ -47,3 +47,21 @@ sysroot: ?[]const u8 = null,
4747search_prefixes: std.ArrayList([]const u8) = .empty,
4848build_id: ?std.zig.BuildId = null,
4949error_limit: ?u32 = null,
50
51/// Intention of verbose is to print all sub-process command lines to stderr
52/// before spawning them.
53pub fn handleVerbose(
54 graph: *const Graph,
55 cwd: std.process.Child.Cwd,
56 opt_env: ?*const std.process.Environ.Map,
57 argv: []const []const u8,
58) error{OutOfMemory}!void {
59 if (!graph.verbose) return;
60 const arena = graph.arena;
61 const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{
62 .child = env,
63 .parent = &graph.environ_map,
64 } else null, argv);
65 defer arena.free(text);
66 std.log.scoped(.verbose).info("{s}", .{text});
67}
lib/compiler/Maker/Step.zig+134-154
......@@ -111,10 +111,9 @@ pub const Extended = union(enum) {
111111 progress_node: std.Progress.Node,
112112 ) Step.ExtendedMakeError!void {
113113 _ = todo;
114 _ = step_index;
115114 _ = maker;
116115 _ = progress_node;
117 @panic("TODO implement another step type");
116 std.debug.panic("TODO implement another step type (index {d})", .{step_index});
118117 }
119118 };
120119};
......@@ -146,7 +145,7 @@ pub const Inputs = struct {
146145 .table = .{},
147146 };
148147
149 pub const Table = std.ArrayHashMapUnmanaged(Cache.Path, Files, Cache.Path.TableAdapter, false);
148 pub const Table = std.ArrayHashMapUnmanaged(Path, Files, Path.TableAdapter, false);
150149 /// The special file name "." means any changes inside the directory.
151150 pub const Files = std.ArrayList([]const u8);
152151
......@@ -205,7 +204,7 @@ pub const MakeError = error{
205204 /// Indicates the error is already reported.
206205 MakeFailed,
207206 MakeSkipped,
208};
207} || Io.Cancelable;
209208
210209pub const ExtendedMakeError = MakeError || Allocator.Error;
211210
......@@ -215,7 +214,7 @@ pub fn make(
215214 progress_node: std.Progress.Node,
216215) MakeError!void {
217216 const graph = maker.graph;
218 const process_arena = graph.arena; // TODO don't leak into the process arena
217 const arena = graph.arena; // TODO don't leak into the process arena
219218 const io = graph.io;
220219 const c = &maker.scanned_config.configuration;
221220 const conf_step = step_index.ptr(c);
......@@ -248,6 +247,7 @@ pub fn make(
248247 s.result_oom = true;
249248 return error.MakeFailed;
250249 },
250 error.Canceled => |e| return e,
251251 };
252252
253253 if (!s.test_results.isSuccess()) {
......@@ -257,11 +257,11 @@ pub fn make(
257257 const max_rss = conf_step.max_rss.toBytes();
258258 if (max_rss != 0 and s.result_peak_rss > max_rss) {
259259 if (std.fmt.allocPrint(
260 process_arena,
260 arena,
261261 "memory usage peaked at {0B:.2} ({0d} bytes), exceeding the declared upper bound of {1B:.2} ({1d} bytes)",
262262 .{ s.result_peak_rss, max_rss },
263263 )) |msg| {
264 s.oomWrap(s.result_error_msgs.append(process_arena, msg));
264 s.oomWrap(s.result_error_msgs.append(arena, msg));
265265 } else |_| s.result_oom = true;
266266 }
267267}
......@@ -288,11 +288,12 @@ pub fn reset(step: *Step, gpa: Allocator) void {
288288/// Populates `s.result_failed_command`.
289289pub fn captureChildProcess(
290290 s: *Step,
291 gpa: Allocator,
291 maker: *Maker,
292292 progress_node: std.Progress.Node,
293293 argv: []const []const u8,
294294) !std.process.RunResult {
295 const graph = s.owner.graph;
295 const gpa = maker.gpa;
296 const graph = maker.graph;
296297 const arena = graph.arena;
297298 const io = graph.io;
298299
......@@ -300,14 +301,14 @@ pub fn captureChildProcess(
300301 assert(s.result_failed_command == null);
301302 s.result_failed_command = try std.zig.allocPrintCmd(gpa, .inherit, null, argv);
302303
303 try handleChildProcUnsupported(s);
304 try handleVerbose(s, .inherit, argv);
304 try handleChildProcUnsupported(s, maker);
305 try graph.handleVerbose(.inherit, null, argv);
305306
306307 const result = std.process.run(arena, io, .{
307308 .argv = argv,
308309 .environ_map = &graph.environ_map,
309310 .progress_node = progress_node,
310 }) catch |err| return s.fail("failed to run {s}: {t}", .{ argv[0], err });
311 }) catch |err| return s.fail(maker, "failed to run {s}: {t}", .{ argv[0], err });
311312
312313 if (result.stderr.len > 0) {
313314 try s.result_error_msgs.append(arena, result.stderr);
......@@ -316,7 +317,9 @@ pub fn captureChildProcess(
316317 return result;
317318}
318319
319pub fn fail(step: *Step, maker: *const Maker, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, MakeFailed } {
320pub const FailError = error{ OutOfMemory, MakeFailed };
321
322pub fn fail(step: *Step, maker: *const Maker, comptime fmt: []const u8, args: anytype) FailError {
320323 try step.addError(maker, fmt, args);
321324 return error.MakeFailed;
322325}
......@@ -351,15 +354,16 @@ pub const ZigProcess = struct {
351354/// is the zig compiler - the same version that compiled the build runner.
352355/// Populates `s.result_failed_command`.
353356pub fn evalZigProcess(
354 s: *Step,
357 step_index: Configuration.Step.Index,
358 maker: *Maker,
355359 argv: []const []const u8,
356360 prog_node: std.Progress.Node,
357361 watch: bool,
358 maker: *Maker,
359) !?Cache.Path {
362) (Step.ExtendedMakeError || error{NeedCompileErrorCheck})!?Path {
363 const s = maker.stepByIndex(step_index);
360364 const gpa = maker.gpa;
361 const b = s.owner;
362 const io = b.graph.io;
365 const graph = maker.graph;
366 const io = graph.io;
363367
364368 // If an error occurs, it's happened in this command:
365369 assert(s.result_failed_command == null);
......@@ -371,36 +375,33 @@ pub fn evalZigProcess(
371375 zp.progress_ipc_index = null;
372376 var exited = false;
373377 defer if (exited) {
374 s.cast(Compile).?.zig_process = null;
378 s.extended.compile.zig_process = null;
375379 zp.deinit(io);
376380 gpa.destroy(zp);
377381 } else zp.saveState(prog_node);
378 const result = zigProcessUpdate(s, zp, watch, maker) catch |err| switch (err) {
382 const result = zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {
379383 error.BrokenPipe, error.EndOfStream => |reason| {
380 std.log.info("{s} restart required: {t}", .{ argv[0], reason });
381384 // Process restart required.
382 const term = zp.child.wait(io) catch |e| {
383 return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
384 };
385 _ = term;
385 std.log.info("{s} restart required: {t}", .{ argv[0], reason });
386 _ = zp.child.wait(io) catch |e| return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });
386387 exited = true;
387388 break :update;
388389 },
389 else => |e| return e,
390 error.OutOfMemory, error.Canceled, error.MakeFailed => |e| return e,
391 else => |e| return s.fail(maker, "zig child process monitoring failed: {t}", .{e}),
390392 };
391393
392 if (s.result_error_bundle.errorMessageCount() > 0) {
393 return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
394 }
394 if (s.result_error_bundle.errorMessageCount() > 0)
395 return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
395396
396397 if (s.result_error_msgs.items.len > 0 and result == null) {
397398 // Crash detected.
398399 const term = zp.child.wait(io) catch |e| {
399 return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
400 return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });
400401 };
401402 s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
402403 exited = true;
403 try handleChildProcessTerm(s, term);
404 try handleChildProcessTerm(s, maker, term);
404405 return error.MakeFailed;
405406 }
406407
......@@ -408,31 +409,34 @@ pub fn evalZigProcess(
408409 }
409410 assert(argv.len != 0);
410411
411 try handleChildProcUnsupported(s);
412 try handleVerbose(s, .inherit, argv);
412 try handleChildProcUnsupported(s, maker);
413 try graph.handleVerbose(.inherit, null, argv);
413414
414415 const zp = try gpa.create(ZigProcess);
415416 defer if (!watch) gpa.destroy(zp);
416417
417418 zp.child = std.process.spawn(io, .{
418419 .argv = argv,
419 .environ_map = &b.graph.environ_map,
420 .environ_map = &graph.environ_map,
420421 .stdin = .pipe,
421422 .stdout = .pipe,
422423 .stderr = .pipe,
423424 .request_resource_usage_statistics = true,
424425 .progress_node = prog_node,
425 }) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
426 }) catch |err| return s.fail(maker, "failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
426427
427428 zp.multi_reader.init(gpa, io, zp.multi_reader_buffer.toStreams(), &.{
428429 zp.child.stdout.?, zp.child.stderr.?,
429430 });
430 if (watch) s.cast(Compile).?.zig_process = zp;
431 if (watch) s.extended.compile.zig_process = zp;
431432 defer if (!watch) zp.deinit(io);
432433
433434 const result = result: {
434435 defer if (watch) zp.saveState(prog_node);
435 break :result try zigProcessUpdate(s, zp, watch, maker);
436 break :result zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {
437 error.OutOfMemory, error.Canceled, error.MakeFailed => |e| return e,
438 else => |e| return s.fail(maker, "zig child process monitoring failed: {t}", .{e}),
439 };
436440 };
437441
438442 if (!watch) {
......@@ -441,56 +445,36 @@ pub fn evalZigProcess(
441445 zp.child.stdin = null;
442446
443447 const term = zp.child.wait(io) catch |err| {
444 return s.fail("unable to wait for {s}: {t}", .{ argv[0], err });
448 return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], err });
445449 };
446450 s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
447451
448 // Special handling for Compile step that is expecting compile errors.
449 if (s.cast(Compile)) |compile| switch (term) {
450 .exited => {
452 // Special handling for compile step that is expecting compile errors.
453 const conf = &maker.scanned_config.configuration;
454 if (term == .exited) switch (step_index.ptr(conf).extended.get(conf.extra)) {
455 .compile => |compile| if (compile.flags4.expect_errors != .none) {
451456 // Note that the exit code may be 0 in this case due to the
452457 // compiler server protocol.
453 if (compile.expect_errors != null) {
454 return error.NeedCompileErrorCheck;
455 }
458 return error.NeedCompileErrorCheck;
456459 },
457460 else => {},
458461 };
459
460 try handleChildProcessTerm(s, term);
462 try handleChildProcessTerm(s, maker, term);
461463 }
462464
463465 if (s.result_error_bundle.errorMessageCount() > 0) {
464 return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
466 return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
465467 }
466468
467469 return result;
468470}
469471
470/// Wrapper around `Io.Dir.updateFile` that handles verbose and error output.
471pub fn installFile(s: *Step, src_lazy_path: LazyPath, dest_path: []const u8) !Io.Dir.PrevStatus {
472 const b = s.owner;
473 const io = b.graph.io;
474 const src_path = src_lazy_path.getPath3(b, s);
475 try handleVerbose(s, .inherit, &.{ "install", "-C", b.fmt("{f}", .{src_path}), dest_path });
476 return Io.Dir.updateFile(src_path.root_dir.handle, io, src_path.sub_path, .cwd(), dest_path, .{}) catch |err|
477 return s.fail("unable to update file from '{f}' to '{s}': {t}", .{ src_path, dest_path, err });
478}
479
480/// Wrapper around `Io.Dir.createDirPathStatus` that handles verbose and error output.
481pub fn installDir(s: *Step, dest_path: []const u8) !Io.Dir.CreatePathStatus {
482 const b = s.owner;
483 const io = b.graph.io;
484 try handleVerbose(s, .inherit, &.{ "install", "-d", dest_path });
485 return Io.Dir.cwd().createDirPathStatus(io, dest_path, .default_dir) catch |err|
486 return s.fail("unable to create dir '{s}': {t}", .{ dest_path, err });
487}
488
489fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, maker: *Maker) !?Path {
472fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *ZigProcess, watch: bool) !?Path {
473 const s = maker.stepByIndex(step_index);
490474 const gpa = maker.gpa;
491 const b = s.owner;
492 const arena = b.allocator;
493 const io = b.graph.io;
475 const graph = maker.graph;
476 const arena = graph.arena; // TODO don't leak into the process arena
477 const io = graph.io;
494478
495479 const start_ts = Io.Clock.awake.now(io);
496480
......@@ -522,6 +506,7 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, maker: *Maker) !?Pat
522506 .zig_version => {
523507 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
524508 return s.fail(
509 maker,
525510 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
526511 .{ builtin.zig_version_string, body },
527512 );
......@@ -538,61 +523,65 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, maker: *Maker) !?Pat
538523 s.result_cached = emit_digest.flags.cache_hit;
539524 const digest = body[@sizeOf(EmitDigest)..][0..Cache.bin_digest_len];
540525 result = .{
541 .root_dir = b.cache_root,
542 .sub_path = try arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*)),
526 .root_dir = graph.local_cache_root,
527 .sub_path = try arena.dupe(u8, "o" ++ Io.Dir.path.sep_str ++ Cache.binToHex(digest.*)),
543528 };
544529 },
545530 .file_system_inputs => {
546 s.clearWatchInputs();
531 clearWatchInputs(s, maker);
532 const conf = &maker.scanned_config.configuration;
533 const conf_step = step_index.ptr(conf);
547534 var it = std.mem.splitScalar(u8, body, 0);
548535 while (it.next()) |prefixed_path| {
549536 const prefix_index: std.zig.Server.Message.PathPrefix = @enumFromInt(prefixed_path[0] - 1);
550537 const sub_path = try arena.dupe(u8, prefixed_path[1..]);
551 const sub_path_dirname = std.fs.path.dirname(sub_path) orelse "";
538 const sub_path_dirname = Io.Dir.path.dirname(sub_path) orelse "";
552539 switch (prefix_index) {
553540 .cwd => {
554 const path: Cache.Path = .{
555 .root_dir = Cache.Directory.cwd(),
541 const path: Path = .{
542 .root_dir = .cwd(),
556543 .sub_path = sub_path_dirname,
557544 };
558 try addWatchInputFromPath(s, path, std.fs.path.basename(sub_path));
545 try addWatchInputFromPath(s, maker, path, Io.Dir.path.basename(sub_path));
559546 },
560547 .zig_lib => zl: {
561 if (s.cast(Step.Compile)) |compile| {
562 if (compile.zig_lib_dir) |zig_lib_dir| {
563 const lp = try zig_lib_dir.join(arena, sub_path);
564 try addWatchInput(s, lp);
548 switch (conf_step.extended.get(conf.extra)) {
549 .compile => |compile| if (compile.zig_lib_dir.value) |zig_lib_dir| {
550 const resolved = try maker.resolveLazyPathIndex(arena, zig_lib_dir, step_index);
551 const appended = try resolved.join(arena, sub_path);
552 try addWatchInputPath(s, maker, appended);
565553 break :zl;
566 }
554 },
555 else => {},
567556 }
568 const path: Cache.Path = .{
569 .root_dir = s.owner.graph.zig_lib_directory,
557 const path: Path = .{
558 .root_dir = graph.zig_lib_directory,
570559 .sub_path = sub_path_dirname,
571560 };
572 try addWatchInputFromPath(s, path, std.fs.path.basename(sub_path));
561 try addWatchInputFromPath(s, maker, path, Io.Dir.path.basename(sub_path));
573562 },
574563 .local_cache => {
575 const path: Cache.Path = .{
576 .root_dir = b.cache_root,
564 const path: Path = .{
565 .root_dir = graph.local_cache_root,
577566 .sub_path = sub_path_dirname,
578567 };
579 try addWatchInputFromPath(s, path, std.fs.path.basename(sub_path));
568 try addWatchInputFromPath(s, maker, path, Io.Dir.path.basename(sub_path));
580569 },
581570 .global_cache => {
582 const path: Cache.Path = .{
583 .root_dir = s.owner.graph.global_cache_root,
571 const path: Path = .{
572 .root_dir = graph.global_cache_root,
584573 .sub_path = sub_path_dirname,
585574 };
586 try addWatchInputFromPath(s, path, std.fs.path.basename(sub_path));
575 try addWatchInputFromPath(s, maker, path, Io.Dir.path.basename(sub_path));
587576 },
588577 }
589578 }
590579 },
591 .time_report => if (maker.web_server) |ws| {
580 .time_report => if (maker.web_server) |*ws| {
592581 const TimeReport = std.zig.Server.Message.TimeReport;
593582 const tr: *align(1) const TimeReport = @ptrCast(body[0..@sizeOf(TimeReport)]);
594583 ws.updateTimeReportCompile(.{
595 .compile = s.cast(Step.Compile).?,
584 .compile_step = step_index,
596585 .use_llvm = tr.flags.use_llvm,
597586 .stats = tr.stats,
598587 .ns_total = @intCast(start_ts.untilNow(io, .awake).toNanoseconds()),
......@@ -636,46 +625,29 @@ fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
636625 };
637626}
638627
639pub fn handleVerbose(
640 s: *Step,
641 arena: Allocator,
642 cwd: std.process.Child.Cwd,
643 opt_env: ?*const std.process.Environ.Map,
644 argv: []const []const u8,
645) error{OutOfMemory}!void {
646 const graph = s.graph;
647 if (!graph.verbose) return;
648 // Intention of verbose is to print all sub-process command lines to
649 // stderr before spawning them.
650 const text = try std.zig.allocPrintCmd(arena, cwd, if (opt_env) |env| .{
651 .child = env,
652 .parent = &graph.environ_map,
653 } else null, argv);
654 std.log.scoped(.verbose).info("{s}", .{text});
655}
656
657628/// Asserts that the caller has already populated `s.result_failed_command`.
658pub inline fn handleChildProcUnsupported(s: *Step) error{ OutOfMemory, MakeFailed }!void {
629pub inline fn handleChildProcUnsupported(s: *Step, maker: *Maker) FailError!void {
630 assert(s.result_failed_command != null);
659631 if (!std.process.can_spawn) {
660 return s.fail("unable to spawn process: host cannot spawn child processes", .{});
632 return s.fail(maker, "unable to spawn process: host cannot spawn child processes", .{});
661633 }
662634}
663635
664636/// Asserts that the caller has already populated `s.result_failed_command`.
665pub fn handleChildProcessTerm(s: *Step, term: std.process.Child.Term) error{ MakeFailed, OutOfMemory }!void {
637pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.Term) FailError!void {
666638 assert(s.result_failed_command != null);
667639 return switch (term) {
668 .exited => |code| if (code != 0) s.fail("process exited with error code {d}", .{code}),
669 .signal => |sig| s.fail("process terminated with signal {t}", .{sig}),
670 .stopped => |sig| s.fail("process stopped with signal {t}", .{sig}),
671 .unknown => s.fail("process terminated unexpectedly", .{}),
640 .exited => |code| if (code != 0) s.fail(maker, "process exited with error code {d}", .{code}),
641 .signal => |sig| s.fail(maker, "process terminated with signal {t}", .{sig}),
642 .stopped => |sig| s.fail(maker, "process stopped with signal {t}", .{sig}),
643 .unknown => s.fail(maker, "process terminated unexpectedly", .{}),
672644 };
673645}
674646
675647/// Prefer `cacheHitAndWatch` unless you already added watch inputs
676648/// separately from using the cache system.
677pub fn cacheHit(s: *Step, man: *Cache.Manifest) !bool {
678 s.result_cached = man.hit() catch |err| return failWithCacheError(s, man, err);
649pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest) !bool {
650 s.result_cached = man.hit() catch |err| return failWithCacheError(s, maker, man, err);
679651 return s.result_cached;
680652}
681653
......@@ -683,36 +655,37 @@ pub fn cacheHit(s: *Step, man: *Cache.Manifest) !bool {
683655/// the full set of files picked up by the cache manifest.
684656///
685657/// Must be accompanied with `writeManifestAndWatch`.
686pub fn cacheHitAndWatch(s: *Step, man: *Cache.Manifest) !bool {
687 const is_hit = man.hit() catch |err| return failWithCacheError(s, man, err);
658pub fn cacheHitAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !bool {
659 const is_hit = man.hit() catch |err| return failWithCacheError(s, maker, man, err);
688660 s.result_cached = is_hit;
689661 // The above call to hit() populates the manifest with files, so in case of
690662 // a hit, we need to populate watch inputs.
691 if (is_hit) try setWatchInputsFromManifest(s, man);
663 if (is_hit) try setWatchInputsFromManifest(s, maker, man);
692664 return is_hit;
693665}
694666
695667fn failWithCacheError(
696668 s: *Step,
669 maker: *Maker,
697670 man: *const Cache.Manifest,
698671 err: Cache.Manifest.HitError,
699672) error{ OutOfMemory, Canceled, MakeFailed } {
700673 switch (err) {
701674 error.CacheCheckFailed => switch (man.diagnostic) {
702675 .none => unreachable,
703 .manifest_create, .manifest_read, .manifest_lock => |e| return s.fail("failed to check cache: {t} {t}", .{
676 .manifest_create, .manifest_read, .manifest_lock => |e| return s.fail(maker, "failed to check cache: {t} {t}", .{
704677 man.diagnostic, e,
705678 }),
706679 .file_open, .file_stat, .file_read, .file_hash => |op| {
707680 const pp = man.files.keys()[op.file_index].prefixed_path;
708681 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
709 return s.fail("failed to check cache: '{s}{c}{s}' {t} {t}", .{
710 prefix, std.fs.path.sep, pp.sub_path, man.diagnostic, op.err,
682 return s.fail(maker, "failed to check cache: '{s}{c}{s}' {t} {t}", .{
683 prefix, Io.Dir.path.sep, pp.sub_path, man.diagnostic, op.err,
711684 });
712685 },
713686 },
714687 error.OutOfMemory, error.Canceled => |e| return e,
715 error.InvalidFormat => return s.fail("failed to check cache: invalid manifest file format", .{}),
688 error.InvalidFormat => return s.fail(maker, "failed to check cache: invalid manifest file format", .{}),
716689 }
717690}
718691
......@@ -730,48 +703,48 @@ pub fn writeManifest(s: *Step, man: *Cache.Manifest) !void {
730703/// the full set of files picked up by the cache manifest.
731704///
732705/// Must be accompanied with `cacheHitAndWatch`.
733pub fn writeManifestAndWatch(s: *Step, man: *Cache.Manifest) !void {
706pub fn writeManifestAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
734707 try writeManifest(s, man);
735 try setWatchInputsFromManifest(s, man);
708 try setWatchInputsFromManifest(s, maker, man);
736709}
737710
738fn setWatchInputsFromManifest(s: *Step, man: *Cache.Manifest) !void {
739 const arena = s.owner.allocator;
711fn setWatchInputsFromManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
712 const graph = maker.graph;
713 const arena = graph.arena; // TODO don't leak into process arena
740714 const prefixes = man.cache.prefixes();
741 clearWatchInputs(s);
715 clearWatchInputs(s, maker);
742716 for (man.files.keys()) |file| {
743717 // The file path data is freed when the cache manifest is cleaned up at the end of `make`.
744718 const sub_path = try arena.dupe(u8, file.prefixed_path.sub_path);
745 try addWatchInputFromPath(s, .{
719 try addWatchInputFromPath(s, maker, .{
746720 .root_dir = prefixes[file.prefixed_path.prefix],
747 .sub_path = std.fs.path.dirname(sub_path) orelse "",
748 }, std.fs.path.basename(sub_path));
721 .sub_path = Io.Dir.path.dirname(sub_path) orelse "",
722 }, Io.Dir.path.basename(sub_path));
749723 }
750724}
751725
752726/// For steps that have a single input that never changes when re-running `make`.
753pub fn singleUnchangingWatchInput(step: *Step, lazy_path: LazyPath) Allocator.Error!void {
754 if (!step.inputs.populated()) try step.addWatchInput(lazy_path);
727pub fn singleUnchangingWatchInput(step: *Step, maker: *Maker, lazy_path: LazyPath) Allocator.Error!void {
728 if (!step.inputs.populated()) try step.addWatchInput(maker, lazy_path);
755729}
756730
757pub fn clearWatchInputs(step: *Step) void {
758 const gpa = step.owner.allocator;
759 step.inputs.clear(gpa);
731pub fn clearWatchInputs(step: *Step, maker: *Maker) void {
732 step.inputs.clear(maker.gpa);
760733}
761734
762735/// Places a *file* dependency on the path.
763pub fn addWatchInput(step: *Step, lazy_file: LazyPath) Allocator.Error!void {
736pub fn addWatchInput(step: *Step, maker: *Maker, lazy_file: LazyPath) Allocator.Error!void {
764737 switch (lazy_file) {
765738 .src_path => |src_path| try addWatchInputFromBuilder(step, src_path.owner, src_path.sub_path),
766739 .dependency => |d| try addWatchInputFromBuilder(step, d.dependency.builder, d.sub_path),
767740 .cwd_relative => |path_string| {
768 try addWatchInputFromPath(step, .{
741 try addWatchInputFromPath(step, maker, .{
769742 .root_dir = .{
770743 .path = null,
771744 .handle = Io.Dir.cwd(),
772745 },
773 .sub_path = std.fs.path.dirname(path_string) orelse "",
774 }, std.fs.path.basename(path_string));
746 .sub_path = Io.Dir.path.dirname(path_string) orelse "",
747 }, Io.Dir.path.basename(path_string));
775748 },
776749 // Nothing to watch because this dependency edge is modeled instead via `dependants`.
777750 .generated => {},
......@@ -780,7 +753,7 @@ pub fn addWatchInput(step: *Step, lazy_file: LazyPath) Allocator.Error!void {
780753
781754/// Any changes inside the directory will trigger invalidation.
782755///
783/// See also `addDirectoryWatchInputFromPath` which takes a `Cache.Path` instead.
756/// See also `addDirectoryWatchInputFromPath` which takes a `Path` instead.
784757///
785758/// Paths derived from this directory should also be manually added via
786759/// `addDirectoryWatchInputFromPath` if and only if this function returns
......@@ -812,15 +785,15 @@ pub fn addDirectoryWatchInput(step: *Step, lazy_directory: LazyPath) Allocator.E
812785/// dependency on `path` is not already accounted for by a `Step` dependency.
813786/// In other words, before calling this function, first check that the
814787/// `LazyPath` which this `path` is derived from is not `generated`.
815pub fn addDirectoryWatchInputFromPath(step: *Step, path: Cache.Path) !void {
816 return addWatchInputFromPath(step, path, ".");
788pub fn addDirectoryWatchInputFromPath(step: *Step, maker: *Maker, path: Path) !void {
789 return addWatchInputFromPath(step, maker, path, ".");
817790}
818791
819fn addWatchInputFromBuilder(step: *Step, package: Package, sub_path: []const u8) !void {
820 return addWatchInputFromPath(step, .{
792fn addWatchInputFromBuilder(step: *Step, maker: *Maker, package: Package, sub_path: []const u8) !void {
793 return addWatchInputFromPath(step, maker, .{
821794 .root_dir = package.build_root,
822 .sub_path = std.fs.path.dirname(sub_path) orelse "",
823 }, std.fs.path.basename(sub_path));
795 .sub_path = Io.Dir.path.dirname(sub_path) orelse "",
796 }, Io.Dir.path.basename(sub_path));
824797}
825798
826799fn addDirectoryWatchInputFromBuilder(step: *Step, package: Package, sub_path: []const u8) !void {
......@@ -830,9 +803,16 @@ fn addDirectoryWatchInputFromBuilder(step: *Step, package: Package, sub_path: []
830803 });
831804}
832805
833fn addWatchInputFromPath(step: *Step, path: Cache.Path, basename: []const u8) !void {
834 const gpa = step.owner.allocator;
835 const gop = try step.inputs.table.getOrPut(gpa, path);
806fn addWatchInputPath(step: *Step, maker: *Maker, path: Path) Allocator.Error!void {
807 return addWatchInputFromPath(step, maker, .{
808 .root_dir = path.root_dir,
809 .sub_path = Io.Dir.path.dirname(path.sub_path) orelse "",
810 }, Io.Dir.path.basename(path.sub_path));
811}
812
813fn addWatchInputFromPath(step: *Step, maker: *Maker, directory: Path, basename: []const u8) Allocator.Error!void {
814 const gpa = maker.gpa;
815 const gop = try step.inputs.table.getOrPut(gpa, directory);
836816 if (!gop.found_existing) gop.value_ptr.* = .empty;
837817 try gop.value_ptr.append(gpa, basename);
838818}
lib/compiler/Maker/Step/Compile.zig+59-28
......@@ -29,61 +29,91 @@ pub fn make(
2929) Step.ExtendedMakeError!void {
3030 const graph = maker.graph;
3131 const step = maker.stepByIndex(compile_index);
32 const conf = &maker.scanned_config.configuration;
33 const conf_step = compile_index.ptr(conf);
34 const conf_comp = conf_step.extended.get(conf.extra).compile;
3235
3336 // Reset / repopulate persistent state.
3437 compile.zig_args.clearRetainingCapacity();
3538
3639 try lowerZigArgs(compile, compile_index, maker, &compile.zig_args, false);
37 if (true) @panic("TODO implement compile.make()");
38 const process_arena = graph.arena; // TODO don't leak into the process_arena
3940
40 const maybe_output_dir = step.evalZigProcess(
41 const maybe_output_dir = Step.evalZigProcess(
42 compile_index,
43 maker,
4144 compile.zig_args.items,
4245 progress_node,
4346 (graph.incremental == true) and (maker.watch or maker.web_server != null),
44 maker,
4547 ) catch |err| switch (err) {
4648 error.NeedCompileErrorCheck => {
47 assert(compile.expect_errors != null);
4849 try checkCompileErrors(compile, maker);
4950 return;
5051 },
5152 else => |e| return e,
5253 };
5354
55 const root_module = conf_comp.root_module.get(conf);
56 const target = root_module.resolved_target.get(conf).?.result.get(conf);
57
5458 // Update generated files
5559 if (maybe_output_dir) |output_dir| {
56 if (compile.emit_directory) |lp| {
57 lp.path = try allocPrint(process_arena, "{f}", .{output_dir});
58 }
59
60 // zig fmt: off
61 if (compile.generated_bin) |lp| lp.path = compile.outputPath(output_dir, .bin);
62 if (compile.generated_pdb) |lp| lp.path = compile.outputPath(output_dir, .pdb);
63 // hack for stage2_x86_64 + coff
64 if (compile.generated_compiler_rt_dyn_lib) |lp| lp.path = compile.outputPath(output_dir, .compiler_rt_dyn_lib);
65 if (compile.generated_implib) |lp| lp.path = compile.outputPath(output_dir, .implib);
66 if (compile.generated_h) |lp| lp.path = compile.outputPath(output_dir, .h);
67 if (compile.generated_docs) |lp| lp.path = compile.outputPath(output_dir, .docs);
68 if (compile.generated_asm) |lp| lp.path = compile.outputPath(output_dir, .@"asm");
69 if (compile.generated_llvm_ir) |lp| lp.path = compile.outputPath(output_dir, .llvm_ir);
70 if (compile.generated_llvm_bc) |lp| lp.path = compile.outputPath(output_dir, .llvm_bc);
71 // zig fmt: on
60 if (conf_comp.emit_directory.value) |gf| maker.generatedPath(gf).* = output_dir;
61 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_bin.value, .bin);
62 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_pdb.value, .pdb);
63 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_implib.value, .implib);
64 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_h.value, .h);
65 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_docs.value, .docs);
66 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_asm.value, .@"asm");
67 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_llvm_ir.value, .llvm_ir);
68 try updateGeneratedFile(&conf_comp, maker, output_dir, &target, conf_comp.generated_llvm_bc.value, .llvm_bc);
7269 }
7370
74 if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic and
75 compile.version != null and compile.generated_bin != null and
76 std.Build.wantSharedLibSymLinks(compile.rootModuleTarget()))
71 if (conf_comp.flags3.kind == .lib and conf_comp.flags2.linkage == .dynamic and
72 conf_comp.version.value != null and conf_comp.generated_bin.value != null and
73 target.flags.os_tag != .windows)
7774 {
75 if (true) @panic("TODO");
7876 try doAtomicSymLinks(
7977 step,
80 compile.getEmittedBin().getPath2(step),
81 compile.major_only_filename.?,
82 compile.name_only_filename.?,
78 conf_comp.getEmittedBin().getPath2(step),
79 conf_comp.major_only_filename.?,
80 conf_comp.name_only_filename.?,
8381 );
8482 }
8583}
8684
85fn updateGeneratedFile(
86 conf_comp: *const Configuration.Step.Compile,
87 maker: *Maker,
88 out_path: std.Build.Cache.Path,
89 target: *const Configuration.TargetQuery,
90 opt_gf: ?Configuration.GeneratedFileIndex,
91 ea: std.zig.EmitArtifact,
92) Allocator.Error!void {
93 const gf = opt_gf orelse return;
94 const graph = maker.graph;
95 const conf = &maker.scanned_config.configuration;
96 const arena = graph.arena; // TODO don't leak into process arena
97 const name = try ea.cacheName(arena, .{
98 .root_name = conf_comp.root_name.slice(conf),
99 .cpu_arch = target.flags.cpu_arch.unwrap().?,
100 .os_tag = target.flags.os_tag.unwrap().?,
101 .ofmt = target.flags.object_format.unwrap().?,
102 .abi = target.flags.abi.unwrap().?,
103 .output_mode = switch (conf_comp.flags3.kind) {
104 .lib => .Lib,
105 .obj, .test_obj => .Obj,
106 .exe, .@"test" => .Exe,
107 },
108 .link_mode = conf_comp.flags2.linkage.unwrap(),
109 .version = if (conf_comp.version.value) |v|
110 std.SemanticVersion.parse(v.slice(conf)) catch unreachable
111 else
112 null,
113 });
114 maker.generatedPath(gf).* = try out_path.join(arena, name);
115}
116
87117/// List of importable modules in a compilation's module graph, including
88118/// the root module. The root module is guaranteed to be first.
89119const ModuleList = std.AutoArrayHashMapUnmanaged(Configuration.Module.Index, Configuration.String);
......@@ -154,7 +184,7 @@ fn lowerZigArgs(
154184 const root_module = conf_comp.root_module.get(conf);
155185
156186 if (root_module.resolved_target.get(conf).?.query.unwrap()) |query| {
157 if (query.get(conf).flags.object_format.get()) |ofmt| {
187 if (query.get(conf).flags.object_format.unwrap()) |ofmt| {
158188 try zig_args.append(gpa, try allocPrint(arena, "-ofmt={t}", .{ofmt}));
159189 }
160190 }
......@@ -1146,6 +1176,7 @@ fn runPkgConfig(compile: *const Compile, maker: *const Maker, lib_name: []const
11461176}
11471177
11481178fn checkCompileErrors(compile: *Compile, maker: *Maker) !void {
1179 if (true) @panic("TODO");
11491180 // Clear this field so that it does not get printed by the build runner.
11501181 const actual_eb = compile.step.result_error_bundle;
11511182 compile.step.result_error_bundle = .empty;
lib/compiler/Maker/WebServer.zig+8-4
......@@ -757,12 +757,16 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
757757 });
758758 return error.WasmCompilationFailed;
759759 };
760 const target = std.zig.system.resolveTargetQuery(io, std.Build.parseTargetQuery(.{
761 .arch_os_abi = arch_os_abi,
762 .cpu_features = cpu_features,
763 }) catch unreachable) catch unreachable;
760764 const bin_name = try std.zig.binNameAlloc(arena, .{
761765 .root_name = root_name,
762 .target = &(std.zig.system.resolveTargetQuery(io, std.Build.parseTargetQuery(.{
763 .arch_os_abi = arch_os_abi,
764 .cpu_features = cpu_features,
765 }) catch unreachable) catch unreachable),
766 .cpu_arch = target.cpu.arch,
767 .os_tag = target.os.tag,
768 .ofmt = target.ofmt,
769 .abi = target.abi,
766770 .output_mode = .Exe,
767771 });
768772 return base_path.join(arena, bin_name);
lib/std/Build/Configuration.zig+21-2
......@@ -768,6 +768,14 @@ pub const Step = extern struct {
768768 .dynamic => .dynamic,
769769 };
770770 }
771
772 pub fn unwrap(this: @This()) ?std.builtin.LinkMode {
773 return switch (this) {
774 .static => .static,
775 .dynamic => .dynamic,
776 .default => null,
777 };
778 }
771779 };
772780 pub const Kind = enum(u3) {
773781 exe,
......@@ -1838,6 +1846,12 @@ pub const TargetQuery = struct {
18381846 // TODO comptime assert the enums match
18391847 return @enumFromInt(@intFromEnum(x orelse return .default));
18401848 }
1849
1850 pub fn unwrap(this: @This()) ?std.Target.Cpu.Arch {
1851 // TODO comptime assert the enums match
1852 if (this == .default) return null;
1853 return @enumFromInt(@intFromEnum(this));
1854 }
18411855 };
18421856 pub const OsTag = enum(u6) {
18431857 freestanding,
......@@ -1913,7 +1927,7 @@ pub const TargetQuery = struct {
19131927 return @enumFromInt(@intFromEnum(x orelse return .default));
19141928 }
19151929
1916 pub fn get(this: @This()) ?std.Target.ObjectFormat {
1930 pub fn unwrap(this: @This()) ?std.Target.ObjectFormat {
19171931 return switch (this) {
19181932 .c => .c,
19191933 .coff => .coff,
......@@ -2018,11 +2032,16 @@ pub const Storage = enum {
20182032
20192033 pub const storage: Storage = .extended;
20202034
2035 pub fn tag(this: @This(), c: *const Configuration) @FieldType(BaseFlags, "tag") {
2036 const base_flags: BaseFlags = @bitCast(c.extra[@intFromEnum(this)]);
2037 return base_flags.tag;
2038 }
2039
20212040 pub fn get(this: @This(), buffer: []const u32) U {
20222041 var i: usize = @intFromEnum(this);
20232042 const base_flags: BaseFlags = @bitCast(buffer[i]);
20242043 return switch (base_flags.tag) {
2025 inline else => |tag| @unionInit(U, @tagName(tag), data(buffer, &i, @FieldType(U, @tagName(tag)))),
2044 inline else => |t| @unionInit(U, @tagName(t), data(buffer, &i, @FieldType(U, @tagName(t)))),
20262045 };
20272046 }
20282047 };
lib/std/Build/Step/Compile.zig+4-1
......@@ -384,7 +384,10 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
384384
385385 const out_filename = std.zig.binNameAlloc(arena, .{
386386 .root_name = name,
387 .target = target,
387 .cpu_arch = target.cpu.arch,
388 .os_tag = target.os.tag,
389 .ofmt = target.ofmt,
390 .abi = target.abi,
388391 .output_mode = switch (options.kind) {
389392 .lib => .Lib,
390393 .obj, .test_obj => .Obj,
lib/std/zig.zig+22-14
......@@ -146,7 +146,10 @@ pub fn lineDelta(source: []const u8, start: usize, end: usize) isize {
146146
147147pub const BinNameOptions = struct {
148148 root_name: []const u8,
149 target: *const std.Target,
149 cpu_arch: std.Target.Cpu.Arch,
150 os_tag: std.Target.Os.Tag,
151 ofmt: std.Target.ObjectFormat,
152 abi: std.Target.Abi,
150153 output_mode: std.builtin.OutputMode,
151154 link_mode: ?std.builtin.LinkMode = null,
152155 version: ?std.SemanticVersion = null,
......@@ -155,10 +158,12 @@ pub const BinNameOptions = struct {
155158/// Returns the standard file system basename of a binary generated by the Zig compiler.
156159pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
157160 const root_name = options.root_name;
158 const t = options.target;
159 switch (t.ofmt) {
161 switch (options.ofmt) {
160162 .coff => switch (options.output_mode) {
161 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, t.exeFileExt() }),
163 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{
164 root_name,
165 options.os_tag.exeFileExt(options.cpu_arch),
166 }),
162167 .Lib => {
163168 const suffix = switch (options.link_mode orelse .static) {
164169 .static => ".lib",
......@@ -173,16 +178,16 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
173178 .Lib => {
174179 switch (options.link_mode orelse .static) {
175180 .static => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
176 t.libPrefix(), root_name,
181 options.os_tag.libPrefix(options.abi), root_name,
177182 }),
178183 .dynamic => {
179184 if (options.version) |ver| {
180185 return std.fmt.allocPrint(allocator, "{s}{s}.so.{d}.{d}.{d}", .{
181 t.libPrefix(), root_name, ver.major, ver.minor, ver.patch,
186 options.os_tag.libPrefix(options.abi), root_name, ver.major, ver.minor, ver.patch,
182187 });
183188 } else {
184189 return std.fmt.allocPrint(allocator, "{s}{s}.so", .{
185 t.libPrefix(), root_name,
190 options.os_tag.libPrefix(options.abi), root_name,
186191 });
187192 }
188193 },
......@@ -195,16 +200,16 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
195200 .Lib => {
196201 switch (options.link_mode orelse .static) {
197202 .static => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
198 t.libPrefix(), root_name,
203 options.os_tag.libPrefix(options.abi), root_name,
199204 }),
200205 .dynamic => {
201206 if (options.version) |ver| {
202207 return std.fmt.allocPrint(allocator, "{s}{s}.{d}.{d}.{d}.dylib", .{
203 t.libPrefix(), root_name, ver.major, ver.minor, ver.patch,
208 options.os_tag.libPrefix(options.abi), root_name, ver.major, ver.minor, ver.patch,
204209 });
205210 } else {
206211 return std.fmt.allocPrint(allocator, "{s}{s}.dylib", .{
207 t.libPrefix(), root_name,
212 options.os_tag.libPrefix(options.abi), root_name,
208213 });
209214 }
210215 },
......@@ -213,11 +218,14 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
213218 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
214219 },
215220 .wasm => switch (options.output_mode) {
216 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, t.exeFileExt() }),
221 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{
222 root_name,
223 options.os_tag.exeFileExt(options.cpu_arch),
224 }),
217225 .Lib => {
218226 switch (options.link_mode orelse .static) {
219227 .static => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
220 t.libPrefix(), root_name,
228 options.os_tag.libPrefix(options.abi), root_name,
221229 }),
222230 .dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),
223231 }
......@@ -231,10 +239,10 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
231239 .plan9 => switch (options.output_mode) {
232240 .Exe => return allocator.dupe(u8, root_name),
233241 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
234 root_name, t.ofmt.fileExt(t.cpu.arch),
242 root_name, options.ofmt.fileExt(options.cpu_arch),
235243 }),
236244 .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
237 t.libPrefix(), root_name,
245 options.os_tag.libPrefix(options.abi), root_name,
238246 }),
239247 },
240248 }