authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-01 22:56:37-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:13-07:00
log58edefc6d1716c0731ee2fe672ec8d073651aafb
tree9de4d030be9f44d3bc953d114eaef0812bd11cf4
parentd0f675827c28b1d50e8aea6a7d29cb45ad8d4e67

zig build: many enhancements related to parallel building

Rework std.Build.Step to have an `owner: *Build` field. This simplified the implementation of installation steps, as well as provided some much-needed common API for the new parallelized build system. --verbose is now defined very concretely: it prints to stderr just before spawning a child process. Child process execution is updated to conform to the new parallel-friendly make() function semantics. DRY up the failWithCacheError handling code. It now integrates properly with the step graph instead of incorrectly dumping to stderr and calling process exit. In the main CLI, fix `zig fmt` crash when there are no errors and stdin is used. Deleted steps: * EmulatableRunStep - this entire thing can be removed in favor of a flag added to std.Build.RunStep called `skip_foreign_checks`. * LogStep - this doesn't really fit with a multi-threaded build runner and is effectively superseded by the new build summary output. build runner: * add -fsummary and -fno-summary to override the default behavior, which is to print a summary if any of the build steps fail. * print the dep prefix when emitting error messages for steps. std.Build.FmtStep: * This step now supports exclude paths as well as a check flag. * The check flag decides between two modes, modify mode, and check mode. These can be used to update source files in place, or to fail the build, respectively. Zig's own build.zig: * The `test-fmt` step will do all the `zig fmt` checking that we expect to be done. Since the `test` step depends on this one, we can simply remove the explicit call to `zig fmt` in the CI. * The new `fmt` step will actually perform `zig fmt` and update source files in place. std.Build.RunStep: * expose max_stdio_size is a field (previously an unchangeable hard-coded value). * rework the API. Instead of configuring each stream independently, there is a `stdio` field where you can choose between `infer_from_args`, `inherit`, or `check`. These determine whether the RunStep is considered to have side-effects or not. The previous field, `condition` is gone. * when stdio mode is set to `check` there is a slice of any number of checks to make, which include things like exit code, stderr matching, or stdout matching. * remove the ill-defined `print` field. * when adding an output arg, it takes the opportunity to give itself a better name. * The flag `skip_foreign_checks` is added. If this is true, a RunStep which is configured to check the output of the executed binary will not fail the build if the binary cannot be executed due to being for a foreign binary to the host system which is running the build graph. Command-line arguments such as -fqemu and -fwasmtime may affect whether a binary is detected as foreign, as well as system configuration such as Rosetta (macOS) and binfmt_misc (Linux). - This makes EmulatableRunStep no longer needed. * Fix the child process handling to properly integrate with the new bulid API and to avoid deadlocks in stdout/stderr streams by polling if necessary. std.Build.RemoveDirStep now uses the open build_root directory handle instead of an absolute path.

23 files changed, 1113 insertions(+), 1167 deletions(-)

build.zig+18-6
......@@ -61,8 +61,6 @@ pub fn build(b: *std.Build) !void {
6161 test_cases.stack_size = stack_size;
6262 test_cases.single_threaded = single_threaded;
6363
64 const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
65
6664 const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false;
6765 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
6866 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
......@@ -386,10 +384,24 @@ pub fn build(b: *std.Build) !void {
386384 }
387385 const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
388386
389 // run stage1 `zig fmt` on this build.zig file just to make sure it works
390 test_step.dependOn(&fmt_build_zig.step);
391 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
392 fmt_step.dependOn(&fmt_build_zig.step);
387 const fmt_include_paths = &.{ "doc", "lib", "src", "test", "tools", "build.zig" };
388 const fmt_exclude_paths = &.{ "test/cases" };
389 const check_fmt = b.addFmt(.{
390 .paths = fmt_include_paths,
391 .exclude_paths = fmt_exclude_paths,
392 .check = true,
393 });
394 const do_fmt = b.addFmt(.{
395 .paths = fmt_include_paths,
396 .exclude_paths = fmt_exclude_paths,
397 });
398
399 const test_fmt_step = b.step("test-fmt", "Check whether source files have conforming formatting");
400 test_fmt_step.dependOn(&check_fmt.step);
401
402 const do_fmt_step = b.step("fmt", "Modify source files in place to have conforming formatting");
403 do_fmt_step.dependOn(&do_fmt.step);
404
393405
394406 test_step.dependOn(tests.addPkgTests(
395407 b,
lib/build_runner.zig+46-25
......@@ -93,6 +93,7 @@ pub fn main() !void {
9393
9494 var install_prefix: ?[]const u8 = null;
9595 var dir_list = std.Build.DirList{};
96 var enable_summary: ?bool = null;
9697
9798 const Color = enum { auto, off, on };
9899 var color: Color = .auto;
......@@ -217,6 +218,10 @@ pub fn main() !void {
217218 builder.enable_darling = true;
218219 } else if (mem.eql(u8, arg, "-fno-darling")) {
219220 builder.enable_darling = false;
221 } else if (mem.eql(u8, arg, "-fsummary")) {
222 enable_summary = true;
223 } else if (mem.eql(u8, arg, "-fno-summary")) {
224 enable_summary = false;
220225 } else if (mem.eql(u8, arg, "-freference-trace")) {
221226 builder.reference_trace = 256;
222227 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
......@@ -252,8 +257,9 @@ pub fn main() !void {
252257 }
253258 }
254259
260 const stderr = std.io.getStdErr();
255261 const ttyconf: std.debug.TTY.Config = switch (color) {
256 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
262 .auto => std.debug.detectTTYConfig(stderr),
257263 .on => .escape_codes,
258264 .off => .no_color,
259265 };
......@@ -279,6 +285,8 @@ pub fn main() !void {
279285 main_progress_node,
280286 thread_pool_options,
281287 ttyconf,
288 stderr,
289 enable_summary,
282290 ) catch |err| switch (err) {
283291 error.UncleanExit => process.exit(1),
284292 else => return err,
......@@ -292,6 +300,8 @@ fn runStepNames(
292300 parent_prog_node: *std.Progress.Node,
293301 thread_pool_options: std.Thread.Pool.Options,
294302 ttyconf: std.debug.TTY.Config,
303 stderr: std.fs.File,
304 enable_summary: ?bool,
295305) !void {
296306 const gpa = b.allocator;
297307 var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{};
......@@ -382,28 +392,35 @@ fn runStepNames(
382392
383393 // A proper command line application defaults to silently succeeding.
384394 // The user may request verbose mode if they have a different preference.
385 if (failure_count == 0 and !b.verbose) return cleanExit();
386
387 const stderr = std.io.getStdErr();
388
389 const total_count = success_count + failure_count + pending_count;
390 ttyconf.setColor(stderr, .Cyan) catch {};
391 stderr.writeAll("Build Summary: ") catch {};
392 ttyconf.setColor(stderr, .Reset) catch {};
393 stderr.writer().print("{d}/{d} steps succeeded; {d} failed; {d} total compile errors\n", .{
394 success_count, total_count, failure_count, total_compile_errors,
395 }) catch {};
395 if (failure_count == 0 and enable_summary != true) return cleanExit();
396
397 if (enable_summary != false) {
398 const total_count = success_count + failure_count + pending_count;
399 ttyconf.setColor(stderr, .Cyan) catch {};
400 stderr.writeAll("Build Summary:") catch {};
401 ttyconf.setColor(stderr, .Reset) catch {};
402 stderr.writer().print(" {d}/{d} steps succeeded; {d} failed", .{
403 success_count, total_count, failure_count,
404 }) catch {};
405
406 if (enable_summary == null) {
407 ttyconf.setColor(stderr, .Dim) catch {};
408 stderr.writeAll(" (disable with -fno-summary)") catch {};
409 ttyconf.setColor(stderr, .Reset) catch {};
410 }
411 stderr.writeAll("\n") catch {};
396412
397 // Print a fancy tree with build results.
398 var print_node: PrintNode = .{ .parent = null };
399 if (step_names.len == 0) {
400 print_node.last = true;
401 printTreeStep(b, b.default_step, stderr, ttyconf, &print_node, &step_stack) catch {};
402 } else {
403 for (step_names, 0..) |step_name, i| {
404 const tls = b.top_level_steps.get(step_name).?;
405 print_node.last = i + 1 == b.top_level_steps.count();
406 printTreeStep(b, &tls.step, stderr, ttyconf, &print_node, &step_stack) catch {};
413 // Print a fancy tree with build results.
414 var print_node: PrintNode = .{ .parent = null };
415 if (step_names.len == 0) {
416 print_node.last = true;
417 printTreeStep(b, b.default_step, stderr, ttyconf, &print_node, &step_stack) catch {};
418 } else {
419 for (step_names, 0..) |step_name, i| {
420 const tls = b.top_level_steps.get(step_name).?;
421 print_node.last = i + 1 == b.top_level_steps.count();
422 printTreeStep(b, &tls.step, stderr, ttyconf, &print_node, &step_stack) catch {};
423 }
407424 }
408425 }
409426
......@@ -453,9 +470,9 @@ fn printTreeStep(
453470 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
454471) !void {
455472 const first = step_stack.swapRemove(s);
456 if (!first) try ttyconf.setColor(stderr, .Dim);
457473 try printPrefix(parent_node, stderr);
458474
475 if (!first) try ttyconf.setColor(stderr, .Dim);
459476 if (parent_node.parent != null) {
460477 if (parent_node.last) {
461478 try stderr.writeAll("└─ ");
......@@ -464,7 +481,7 @@ fn printTreeStep(
464481 }
465482 }
466483
467 // TODO print the dep prefix too?
484 // dep_prefix omitted here because it is redundant with the tree.
468485 try stderr.writeAll(s.name);
469486
470487 if (first) {
......@@ -608,8 +625,10 @@ fn workerMakeOneStep(
608625 const stderr = std.io.getStdErr();
609626
610627 for (s.result_error_msgs.items) |msg| {
611 // TODO print the dep prefix too
628 // Sometimes it feels like you just can't catch a break. Finally,
629 // with Zig, you can.
612630 ttyconf.setColor(stderr, .Bold) catch break;
631 stderr.writeAll(s.owner.dep_prefix) catch break;
613632 stderr.writeAll(s.name) catch break;
614633 stderr.writeAll(": ") catch break;
615634 ttyconf.setColor(stderr, .Red) catch break;
......@@ -735,6 +754,8 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
735754 \\Advanced Options:
736755 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
737756 \\ -fno-reference-trace Disable reference trace
757 \\ -fsummary Print the build summary, even on success
758 \\ -fno-summary Omit the build summary, even on failure
738759 \\ --build-file [file] Override path to build.zig
739760 \\ --cache-dir [path] Override path to local Zig cache directory
740761 \\ --global-cache-dir [path] Override path to global Zig cache directory
lib/std/Build.zig+14-212
......@@ -32,14 +32,12 @@ pub const Step = @import("Build/Step.zig");
3232pub const CheckFileStep = @import("Build/CheckFileStep.zig");
3333pub const CheckObjectStep = @import("Build/CheckObjectStep.zig");
3434pub const ConfigHeaderStep = @import("Build/ConfigHeaderStep.zig");
35pub const EmulatableRunStep = @import("Build/EmulatableRunStep.zig");
3635pub const FmtStep = @import("Build/FmtStep.zig");
3736pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
3837pub const InstallDirStep = @import("Build/InstallDirStep.zig");
3938pub const InstallFileStep = @import("Build/InstallFileStep.zig");
4039pub const ObjCopyStep = @import("Build/ObjCopyStep.zig");
4140pub const CompileStep = @import("Build/CompileStep.zig");
42pub const LogStep = @import("Build/LogStep.zig");
4341pub const OptionsStep = @import("Build/OptionsStep.zig");
4442pub const RemoveDirStep = @import("Build/RemoveDirStep.zig");
4543pub const RunStep = @import("Build/RunStep.zig");
......@@ -195,7 +193,7 @@ pub fn create(
195193 env_map.* = try process.getEnvMap(allocator);
196194
197195 const self = try allocator.create(Build);
198 self.* = Build{
196 self.* = .{
199197 .zig_exe = zig_exe,
200198 .build_root = build_root,
201199 .cache_root = cache_root,
......@@ -224,16 +222,18 @@ pub fn create(
224222 .dest_dir = env_map.get("DESTDIR"),
225223 .installed_files = ArrayList(InstalledFile).init(allocator),
226224 .install_tls = .{
227 .step = Step.init(allocator, .{
225 .step = Step.init(.{
228226 .id = .top_level,
229227 .name = "install",
228 .owner = self,
230229 }),
231230 .description = "Copy build artifacts to prefix path",
232231 },
233232 .uninstall_tls = .{
234 .step = Step.init(allocator, .{
233 .step = Step.init(.{
235234 .id = .top_level,
236235 .name = "uninstall",
236 .owner = self,
237237 .makeFn = makeUninstall,
238238 }),
239239 .description = "Remove build artifacts from prefix path",
......@@ -267,16 +267,18 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
267267 child.* = .{
268268 .allocator = allocator,
269269 .install_tls = .{
270 .step = Step.init(allocator, .{
270 .step = Step.init(.{
271271 .id = .top_level,
272272 .name = "install",
273 .owner = child,
273274 }),
274275 .description = "Copy build artifacts to prefix path",
275276 },
276277 .uninstall_tls = .{
277 .step = Step.init(allocator, .{
278 .step = Step.init(.{
278279 .id = .top_level,
279280 .name = "uninstall",
281 .owner = child,
280282 .makeFn = makeUninstall,
281283 }),
282284 .description = "Remove build artifacts from prefix path",
......@@ -689,21 +691,14 @@ pub fn addWriteFiles(self: *Build) *WriteFileStep {
689691 return write_file_step;
690692}
691693
692pub fn addLog(self: *Build, comptime format: []const u8, args: anytype) *LogStep {
693 const data = self.fmt(format, args);
694 const log_step = self.allocator.create(LogStep) catch @panic("OOM");
695 log_step.* = LogStep.init(self, data);
696 return log_step;
697}
698
699694pub fn addRemoveDirTree(self: *Build, dir_path: []const u8) *RemoveDirStep {
700695 const remove_dir_step = self.allocator.create(RemoveDirStep) catch @panic("OOM");
701696 remove_dir_step.* = RemoveDirStep.init(self, dir_path);
702697 return remove_dir_step;
703698}
704699
705pub fn addFmt(self: *Build, paths: []const []const u8) *FmtStep {
706 return FmtStep.create(self, paths);
700pub fn addFmt(b: *Build, options: FmtStep.Options) *FmtStep {
701 return FmtStep.create(b, options);
707702}
708703
709704pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCStep {
......@@ -870,10 +865,11 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
870865
871866pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {
872867 const step_info = self.allocator.create(TopLevelStep) catch @panic("OOM");
873 step_info.* = TopLevelStep{
874 .step = Step.init(self.allocator, .{
868 step_info.* = .{
869 .step = Step.init(.{
875870 .id = .top_level,
876871 .name = name,
872 .owner = self,
877873 }),
878874 .description = self.dupe(description),
879875 };
......@@ -1145,10 +1141,6 @@ pub fn validateUserInputDidItFail(self: *Build) bool {
11451141 return self.invalid_user_input;
11461142}
11471143
1148pub fn spawnChild(self: *Build, argv: []const []const u8) !void {
1149 return self.spawnChildEnvMap(null, self.env_map, argv);
1150}
1151
11521144fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
11531145 var buf = ArrayList(u8).init(ally);
11541146 if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd});
......@@ -1163,40 +1155,6 @@ fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
11631155 std.debug.print("{s}\n", .{text});
11641156}
11651157
1166pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void {
1167 if (self.verbose) {
1168 printCmd(self.allocator, cwd, argv);
1169 }
1170
1171 if (!process.can_spawn)
1172 return error.ExecNotSupported;
1173
1174 var child = std.ChildProcess.init(argv, self.allocator);
1175 child.cwd = cwd;
1176 child.env_map = env_map;
1177
1178 const term = child.spawnAndWait() catch |err| {
1179 log.err("Unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
1180 return err;
1181 };
1182
1183 switch (term) {
1184 .Exited => |code| {
1185 if (code != 0) {
1186 log.err("The following command exited with error code {}:", .{code});
1187 printCmd(self.allocator, cwd, argv);
1188 return error.UncleanExit;
1189 }
1190 },
1191 else => {
1192 log.err("The following command terminated unexpectedly:", .{});
1193 printCmd(self.allocator, cwd, argv);
1194
1195 return error.UncleanExit;
1196 },
1197 }
1198}
1199
12001158pub fn installArtifact(self: *Build, artifact: *CompileStep) void {
12011159 self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
12021160}
......@@ -1403,160 +1361,6 @@ pub fn execAllowFail(
14031361 }
14041362}
14051363
1406/// This function is used exclusively for spawning and communicating with the zig compiler.
1407/// TODO: move to build_runner.zig
1408pub fn execFromStep(b: *Build, argv: []const []const u8, s: *Step, prog_node: *std.Progress.Node) ![]const u8 {
1409 assert(argv.len != 0);
1410
1411 if (b.verbose) {
1412 const text = try allocPrintCmd(b.allocator, null, argv);
1413 try s.result_error_msgs.append(b.allocator, text);
1414 }
1415
1416 if (!process.can_spawn) {
1417 try s.result_error_msgs.append(b.allocator, b.fmt("Unable to spawn the following command: cannot spawn child processes\n{s}", .{
1418 try allocPrintCmd(b.allocator, null, argv),
1419 }));
1420 return error.MakeFailed;
1421 }
1422
1423 var child = std.ChildProcess.init(argv, b.allocator);
1424 child.env_map = b.env_map;
1425 child.stdin_behavior = .Pipe;
1426 child.stdout_behavior = .Pipe;
1427 child.stderr_behavior = .Pipe;
1428
1429 try child.spawn();
1430
1431 var poller = std.io.poll(b.allocator, enum { stdout, stderr }, .{
1432 .stdout = child.stdout.?,
1433 .stderr = child.stderr.?,
1434 });
1435 defer poller.deinit();
1436
1437 try sendMessage(child.stdin.?, .update);
1438 try sendMessage(child.stdin.?, .exit);
1439
1440 const Header = std.zig.Server.Message.Header;
1441 var result: ?[]const u8 = null;
1442
1443 var node_name: std.ArrayListUnmanaged(u8) = .{};
1444 defer node_name.deinit(b.allocator);
1445 var sub_prog_node: ?std.Progress.Node = null;
1446 defer if (sub_prog_node) |*n| n.end();
1447
1448 while (try poller.poll()) {
1449 const stdout = poller.fifo(.stdout);
1450 const buf = stdout.readableSlice(0);
1451 assert(stdout.readableLength() == buf.len);
1452 if (buf.len >= @sizeOf(Header)) {
1453 const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]);
1454 const header_and_msg_len = header.bytes_len + @sizeOf(Header);
1455 if (buf.len >= header_and_msg_len) {
1456 const body = buf[@sizeOf(Header)..][0..header.bytes_len];
1457 switch (header.tag) {
1458 .zig_version => {
1459 if (!mem.eql(u8, builtin.zig_version_string, body)) {
1460 try s.result_error_msgs.append(
1461 b.allocator,
1462 b.fmt("zig version mismatch build runner vs compiler: '{s}' vs '{s}'", .{
1463 builtin.zig_version_string, body,
1464 }),
1465 );
1466 return error.MakeFailed;
1467 }
1468 },
1469 .error_bundle => {
1470 const EbHdr = std.zig.Server.Message.ErrorBundle;
1471 const eb_hdr = @ptrCast(*align(1) const EbHdr, body);
1472 const extra_bytes =
1473 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
1474 const string_bytes =
1475 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
1476 // TODO: use @ptrCast when the compiler supports it
1477 const unaligned_extra = mem.bytesAsSlice(u32, extra_bytes);
1478 const extra_array = try b.allocator.alloc(u32, unaligned_extra.len);
1479 // TODO: use @memcpy when it supports slices
1480 for (extra_array, unaligned_extra) |*dst, src| dst.* = src;
1481 s.result_error_bundle = .{
1482 .string_bytes = try b.allocator.dupe(u8, string_bytes),
1483 .extra = extra_array,
1484 };
1485 },
1486 .progress => {
1487 if (sub_prog_node) |*n| n.end();
1488 node_name.clearRetainingCapacity();
1489 try node_name.appendSlice(b.allocator, body);
1490 sub_prog_node = prog_node.start(node_name.items, 0);
1491 sub_prog_node.?.activate();
1492 },
1493 .emit_bin_path => {
1494 result = try b.allocator.dupe(u8, body);
1495 },
1496 _ => {
1497 // Unrecognized message.
1498 },
1499 }
1500 stdout.discard(header_and_msg_len);
1501 }
1502 }
1503 }
1504
1505 const stderr = poller.fifo(.stderr);
1506 if (stderr.readableLength() > 0) {
1507 try s.result_error_msgs.append(b.allocator, try stderr.toOwnedSlice());
1508 }
1509
1510 // Send EOF to stdin.
1511 child.stdin.?.close();
1512 child.stdin = null;
1513
1514 const term = try child.wait();
1515 switch (term) {
1516 .Exited => |code| {
1517 if (code != 0) {
1518 try s.result_error_msgs.append(b.allocator, b.fmt("the following command exited with error code {d}:\n{s}", .{
1519 code, try allocPrintCmd(b.allocator, null, argv),
1520 }));
1521 return error.MakeFailed;
1522 }
1523 },
1524 .Signal, .Stopped, .Unknown => |code| {
1525 _ = code;
1526 try s.result_error_msgs.append(b.allocator, b.fmt("the following command terminated unexpectedly:\n{s}", .{
1527 try allocPrintCmd(b.allocator, null, argv),
1528 }));
1529 return error.MakeFailed;
1530 },
1531 }
1532
1533 if (s.result_error_bundle.errorMessageCount() > 0) {
1534 try s.result_error_msgs.append(
1535 b.allocator,
1536 b.fmt("the following command failed with {d} compilation errors:\n{s}", .{
1537 s.result_error_bundle.errorMessageCount(),
1538 try allocPrintCmd(b.allocator, null, argv),
1539 }),
1540 );
1541 return error.MakeFailed;
1542 }
1543
1544 return result orelse {
1545 try s.result_error_msgs.append(b.allocator, b.fmt("the following command failed to communicate the compilation result:\n{s}", .{
1546 try allocPrintCmd(b.allocator, null, argv),
1547 }));
1548 return error.MakeFailed;
1549 };
1550}
1551
1552fn sendMessage(file: fs.File, tag: std.zig.Client.Message.Tag) !void {
1553 const header: std.zig.Client.Message.Header = .{
1554 .tag = tag,
1555 .bytes_len = 0,
1556 };
1557 try file.writeAll(std.mem.asBytes(&header));
1558}
1559
15601364/// This is a helper function to be called from build.zig scripts, *not* from
15611365/// inside step make() functions. If any errors occur, it fails the build with
15621366/// a helpful message.
......@@ -1910,14 +1714,12 @@ pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 {
19101714test {
19111715 _ = CheckFileStep;
19121716 _ = CheckObjectStep;
1913 _ = EmulatableRunStep;
19141717 _ = FmtStep;
19151718 _ = InstallArtifactStep;
19161719 _ = InstallDirStep;
19171720 _ = InstallFileStep;
19181721 _ = ObjCopyStep;
19191722 _ = CompileStep;
1920 _ = LogStep;
19211723 _ = OptionsStep;
19221724 _ = RemoveDirStep;
19231725 _ = RunStep;
lib/std/Build/CheckFileStep.zig+9-9
......@@ -8,26 +8,25 @@ const CheckFileStep = @This();
88pub const base_id = .check_file;
99
1010step: Step,
11builder: *std.Build,
1211expected_matches: []const []const u8,
1312source: std.Build.FileSource,
1413max_bytes: usize = 20 * 1024 * 1024,
1514
1615pub fn create(
17 builder: *std.Build,
16 owner: *std.Build,
1817 source: std.Build.FileSource,
1918 expected_matches: []const []const u8,
2019) *CheckFileStep {
21 const self = builder.allocator.create(CheckFileStep) catch @panic("OOM");
20 const self = owner.allocator.create(CheckFileStep) catch @panic("OOM");
2221 self.* = CheckFileStep{
23 .builder = builder,
24 .step = Step.init(builder.allocator, .{
22 .step = Step.init(.{
2523 .id = .check_file,
2624 .name = "CheckFile",
25 .owner = owner,
2726 .makeFn = make,
2827 }),
29 .source = source.dupe(builder),
30 .expected_matches = builder.dupeStrings(expected_matches),
28 .source = source.dupe(owner),
29 .expected_matches = owner.dupeStrings(expected_matches),
3130 };
3231 self.source.addStepDependencies(&self.step);
3332 return self;
......@@ -35,10 +34,11 @@ pub fn create(
3534
3635fn make(step: *Step, prog_node: *std.Progress.Node) !void {
3736 _ = prog_node;
37 const b = step.owner;
3838 const self = @fieldParentPtr(CheckFileStep, "step", step);
3939
40 const src_path = self.source.getPath(self.builder);
41 const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes);
40 const src_path = self.source.getPath(b);
41 const contents = try fs.cwd().readFileAlloc(b.allocator, src_path, self.max_bytes);
4242
4343 for (self.expected_matches) |expected_match| {
4444 if (mem.indexOf(u8, contents, expected_match) == null) {
lib/std/Build/CheckObjectStep.zig+22-15
......@@ -10,29 +10,31 @@ const CheckObjectStep = @This();
1010
1111const Allocator = mem.Allocator;
1212const Step = std.Build.Step;
13const EmulatableRunStep = std.Build.EmulatableRunStep;
1413
1514pub const base_id = .check_object;
1615
1716step: Step,
18builder: *std.Build,
1917source: std.Build.FileSource,
2018max_bytes: usize = 20 * 1024 * 1024,
2119checks: std.ArrayList(Check),
2220dump_symtab: bool = false,
2321obj_format: std.Target.ObjectFormat,
2422
25pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
26 const gpa = builder.allocator;
23pub fn create(
24 owner: *std.Build,
25 source: std.Build.FileSource,
26 obj_format: std.Target.ObjectFormat,
27) *CheckObjectStep {
28 const gpa = owner.allocator;
2729 const self = gpa.create(CheckObjectStep) catch @panic("OOM");
2830 self.* = .{
29 .builder = builder,
30 .step = Step.init(gpa, .{
31 .step = Step.init(.{
3132 .id = .check_file,
3233 .name = "CheckObject",
34 .owner = owner,
3335 .makeFn = make,
3436 }),
35 .source = source.dupe(builder),
37 .source = source.dupe(owner),
3638 .checks = std.ArrayList(Check).init(gpa),
3739 .obj_format = obj_format,
3840 };
......@@ -42,14 +44,18 @@ pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std
4244
4345/// Runs and (optionally) compares the output of a binary.
4446/// Asserts `self` was generated from an executable step.
45pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep {
47/// TODO this doesn't actually compare, and there's no apparent reason for it
48/// to depend on the check object step. I don't see why this function should exist,
49/// the caller could just add the run step directly.
50pub fn runAndCompare(self: *CheckObjectStep) *std.Build.RunStep {
4651 const dependencies_len = self.step.dependencies.items.len;
4752 assert(dependencies_len > 0);
4853 const exe_step = self.step.dependencies.items[dependencies_len - 1];
4954 const exe = exe_step.cast(std.Build.CompileStep).?;
50 const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe);
51 emulatable_step.step.dependOn(&self.step);
52 return emulatable_step;
55 const run = self.step.owner.addRunArtifact(exe);
56 run.skip_foreign_checks = true;
57 run.step.dependOn(&self.step);
58 return run;
5359}
5460
5561/// There two types of actions currently suported:
......@@ -253,7 +259,7 @@ const Check = struct {
253259
254260/// Creates a new sequence of actions with `phrase` as the first anchor searched phrase.
255261pub fn checkStart(self: *CheckObjectStep, phrase: []const u8) void {
256 var new_check = Check.create(self.builder);
262 var new_check = Check.create(self.step.owner);
257263 new_check.match(phrase);
258264 self.checks.append(new_check) catch @panic("OOM");
259265}
......@@ -295,17 +301,18 @@ pub fn checkComputeCompare(
295301 program: []const u8,
296302 expected: ComputeCompareExpected,
297303) void {
298 var new_check = Check.create(self.builder);
304 var new_check = Check.create(self.step.owner);
299305 new_check.computeCmp(program, expected);
300306 self.checks.append(new_check) catch @panic("OOM");
301307}
302308
303309fn make(step: *Step, prog_node: *std.Progress.Node) !void {
304310 _ = prog_node;
311 const b = step.owner;
312 const gpa = b.allocator;
305313 const self = @fieldParentPtr(CheckObjectStep, "step", step);
306314
307 const gpa = self.builder.allocator;
308 const src_path = self.source.getPath(self.builder);
315 const src_path = self.source.getPath(b);
309316 const contents = try fs.cwd().readFileAllocOptions(
310317 gpa,
311318 src_path,
lib/std/Build/CompileStep.zig+241-215
......@@ -22,7 +22,6 @@ const InstallDir = std.Build.InstallDir;
2222const InstallArtifactStep = std.Build.InstallArtifactStep;
2323const GeneratedFile = std.Build.GeneratedFile;
2424const ObjCopyStep = std.Build.ObjCopyStep;
25const EmulatableRunStep = std.Build.EmulatableRunStep;
2625const CheckObjectStep = std.Build.CheckObjectStep;
2726const RunStep = std.Build.RunStep;
2827const OptionsStep = std.Build.OptionsStep;
......@@ -32,7 +31,6 @@ const CompileStep = @This();
3231pub const base_id: Step.Id = .compile;
3332
3433step: Step,
35builder: *std.Build,
3634name: []const u8,
3735target: CrossTarget,
3836target_info: NativeTargetInfo,
......@@ -305,24 +303,23 @@ pub const EmitOption = union(enum) {
305303 }
306304};
307305
308pub fn create(builder: *std.Build, options: Options) *CompileStep {
309 const name = builder.dupe(options.name);
310 const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null;
306pub fn create(owner: *std.Build, options: Options) *CompileStep {
307 const name = owner.dupe(options.name);
308 const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(owner) else null;
311309 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
312310 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
313311 }
314312
315 const step_name = builder.fmt("compile {s} {s} {s}", .{
313 const step_name = owner.fmt("compile {s} {s} {s}", .{
316314 name,
317315 @tagName(options.optimize),
318 options.target.zigTriple(builder.allocator) catch @panic("OOM"),
316 options.target.zigTriple(owner.allocator) catch @panic("OOM"),
319317 });
320318
321 const self = builder.allocator.create(CompileStep) catch @panic("OOM");
319 const self = owner.allocator.create(CompileStep) catch @panic("OOM");
322320 self.* = CompileStep{
323321 .strip = null,
324322 .unwind_tables = null,
325 .builder = builder,
326323 .verbose_link = false,
327324 .verbose_cc = false,
328325 .optimize = options.optimize,
......@@ -331,27 +328,28 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
331328 .kind = options.kind,
332329 .root_src = root_src,
333330 .name = name,
334 .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator),
335 .step = Step.init(builder.allocator, .{
331 .frameworks = StringHashMap(FrameworkLinkInfo).init(owner.allocator),
332 .step = Step.init(.{
336333 .id = base_id,
337334 .name = step_name,
335 .owner = owner,
338336 .makeFn = make,
339337 }),
340338 .version = options.version,
341339 .out_filename = undefined,
342 .out_h_filename = builder.fmt("{s}.h", .{name}),
340 .out_h_filename = owner.fmt("{s}.h", .{name}),
343341 .out_lib_filename = undefined,
344 .out_pdb_filename = builder.fmt("{s}.pdb", .{name}),
342 .out_pdb_filename = owner.fmt("{s}.pdb", .{name}),
345343 .major_only_filename = null,
346344 .name_only_filename = null,
347 .modules = std.StringArrayHashMap(*Module).init(builder.allocator),
348 .include_dirs = ArrayList(IncludeDir).init(builder.allocator),
349 .link_objects = ArrayList(LinkObject).init(builder.allocator),
350 .c_macros = ArrayList([]const u8).init(builder.allocator),
351 .lib_paths = ArrayList([]const u8).init(builder.allocator),
352 .rpaths = ArrayList([]const u8).init(builder.allocator),
353 .framework_dirs = ArrayList([]const u8).init(builder.allocator),
354 .installed_headers = ArrayList(*Step).init(builder.allocator),
345 .modules = std.StringArrayHashMap(*Module).init(owner.allocator),
346 .include_dirs = ArrayList(IncludeDir).init(owner.allocator),
347 .link_objects = ArrayList(LinkObject).init(owner.allocator),
348 .c_macros = ArrayList([]const u8).init(owner.allocator),
349 .lib_paths = ArrayList([]const u8).init(owner.allocator),
350 .rpaths = ArrayList([]const u8).init(owner.allocator),
351 .framework_dirs = ArrayList([]const u8).init(owner.allocator),
352 .installed_headers = ArrayList(*Step).init(owner.allocator),
355353 .object_src = undefined,
356354 .c_std = std.Build.CStd.C99,
357355 .zig_lib_dir = null,
......@@ -382,9 +380,10 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
382380}
383381
384382fn computeOutFileNames(self: *CompileStep) void {
383 const b = self.step.owner;
385384 const target = self.target_info.target;
386385
387 self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{
386 self.out_filename = std.zig.binNameAlloc(b.allocator, .{
388387 .root_name = self.name,
389388 .target = target,
390389 .output_mode = switch (self.kind) {
......@@ -404,30 +403,30 @@ fn computeOutFileNames(self: *CompileStep) void {
404403 self.out_lib_filename = self.out_filename;
405404 } else if (self.version) |version| {
406405 if (target.isDarwin()) {
407 self.major_only_filename = self.builder.fmt("lib{s}.{d}.dylib", .{
406 self.major_only_filename = b.fmt("lib{s}.{d}.dylib", .{
408407 self.name,
409408 version.major,
410409 });
411 self.name_only_filename = self.builder.fmt("lib{s}.dylib", .{self.name});
410 self.name_only_filename = b.fmt("lib{s}.dylib", .{self.name});
412411 self.out_lib_filename = self.out_filename;
413412 } else if (target.os.tag == .windows) {
414 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
413 self.out_lib_filename = b.fmt("{s}.lib", .{self.name});
415414 } else {
416 self.major_only_filename = self.builder.fmt("lib{s}.so.{d}", .{ self.name, version.major });
417 self.name_only_filename = self.builder.fmt("lib{s}.so", .{self.name});
415 self.major_only_filename = b.fmt("lib{s}.so.{d}", .{ self.name, version.major });
416 self.name_only_filename = b.fmt("lib{s}.so", .{self.name});
418417 self.out_lib_filename = self.out_filename;
419418 }
420419 } else {
421420 if (target.isDarwin()) {
422421 self.out_lib_filename = self.out_filename;
423422 } else if (target.os.tag == .windows) {
424 self.out_lib_filename = self.builder.fmt("{s}.lib", .{self.name});
423 self.out_lib_filename = b.fmt("{s}.lib", .{self.name});
425424 } else {
426425 self.out_lib_filename = self.out_filename;
427426 }
428427 }
429428 if (self.output_dir != null) {
430 self.output_lib_path_source.path = self.builder.pathJoin(
429 self.output_lib_path_source.path = b.pathJoin(
431430 &.{ self.output_dir.?, self.out_lib_filename },
432431 );
433432 }
......@@ -435,17 +434,20 @@ fn computeOutFileNames(self: *CompileStep) void {
435434}
436435
437436pub fn setOutputDir(self: *CompileStep, dir: []const u8) void {
438 self.output_dir = self.builder.dupePath(dir);
437 const b = self.step.owner;
438 self.output_dir = b.dupePath(dir);
439439}
440440
441441pub fn install(self: *CompileStep) void {
442 self.builder.installArtifact(self);
442 const b = self.step.owner;
443 b.installArtifact(self);
443444}
444445
445pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
446 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
447 a.builder.getInstallStep().dependOn(&install_file.step);
448 a.installed_headers.append(&install_file.step) catch @panic("OOM");
446pub fn installHeader(cs: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
447 const b = cs.step.owner;
448 const install_file = b.addInstallHeaderFile(src_path, dest_rel_path);
449 b.getInstallStep().dependOn(&install_file.step);
450 cs.installed_headers.append(&install_file.step) catch @panic("OOM");
449451}
450452
451453pub const InstallConfigHeaderOptions = struct {
......@@ -459,13 +461,14 @@ pub fn installConfigHeader(
459461 options: InstallConfigHeaderOptions,
460462) void {
461463 const dest_rel_path = options.dest_rel_path orelse config_header.include_path;
462 const install_file = cs.builder.addInstallFileWithDir(
464 const b = cs.step.owner;
465 const install_file = b.addInstallFileWithDir(
463466 .{ .generated = &config_header.output_file },
464467 options.install_dir,
465468 dest_rel_path,
466469 );
467470 install_file.step.dependOn(&config_header.step);
468 cs.builder.getInstallStep().dependOn(&install_file.step);
471 b.getInstallStep().dependOn(&install_file.step);
469472 cs.installed_headers.append(&install_file.step) catch @panic("OOM");
470473}
471474
......@@ -482,91 +485,84 @@ pub fn installHeadersDirectory(
482485}
483486
484487pub fn installHeadersDirectoryOptions(
485 a: *CompileStep,
488 cs: *CompileStep,
486489 options: std.Build.InstallDirStep.Options,
487490) void {
488 const install_dir = a.builder.addInstallDirectory(options);
489 a.builder.getInstallStep().dependOn(&install_dir.step);
490 a.installed_headers.append(&install_dir.step) catch @panic("OOM");
491 const b = cs.step.owner;
492 const install_dir = b.addInstallDirectory(options);
493 b.getInstallStep().dependOn(&install_dir.step);
494 cs.installed_headers.append(&install_dir.step) catch @panic("OOM");
491495}
492496
493pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
497pub fn installLibraryHeaders(cs: *CompileStep, l: *CompileStep) void {
494498 assert(l.kind == .lib);
495 const install_step = a.builder.getInstallStep();
499 const b = cs.step.owner;
500 const install_step = b.getInstallStep();
496501 // Copy each element from installed_headers, modifying the builder
497502 // to be the new parent's builder.
498503 for (l.installed_headers.items) |step| {
499504 const step_copy = switch (step.id) {
500505 inline .install_file, .install_dir => |id| blk: {
501506 const T = id.Type();
502 const ptr = a.builder.allocator.create(T) catch @panic("OOM");
507 const ptr = b.allocator.create(T) catch @panic("OOM");
503508 ptr.* = step.cast(T).?.*;
504 ptr.override_source_builder = ptr.builder;
505 ptr.builder = a.builder;
509 ptr.dest_builder = b;
506510 break :blk &ptr.step;
507511 },
508512 else => unreachable,
509513 };
510 a.installed_headers.append(step_copy) catch @panic("OOM");
514 cs.installed_headers.append(step_copy) catch @panic("OOM");
511515 install_step.dependOn(step_copy);
512516 }
513 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
517 cs.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
514518}
515519
516520pub fn addObjCopy(cs: *CompileStep, options: ObjCopyStep.Options) *ObjCopyStep {
521 const b = cs.step.owner;
517522 var copy = options;
518523 if (copy.basename == null) {
519524 if (options.format) |f| {
520 copy.basename = cs.builder.fmt("{s}.{s}", .{ cs.name, @tagName(f) });
525 copy.basename = b.fmt("{s}.{s}", .{ cs.name, @tagName(f) });
521526 } else {
522527 copy.basename = cs.name;
523528 }
524529 }
525 return cs.builder.addObjCopy(cs.getOutputSource(), copy);
530 return b.addObjCopy(cs.getOutputSource(), copy);
526531}
527532
528533/// Deprecated: use `std.Build.addRunArtifact`
529534/// This function will run in the context of the package that created the executable,
530535/// which is undesirable when running an executable provided by a dependency package.
531pub fn run(exe: *CompileStep) *RunStep {
532 return exe.builder.addRunArtifact(exe);
533}
534
535/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
536/// Allows running foreign binaries through emulation platforms such as Qemu or Rosetta.
537/// When a binary cannot be ran through emulation or the option is disabled, a warning
538/// will be printed and the binary will *NOT* be ran.
539pub fn runEmulatable(exe: *CompileStep) *EmulatableRunStep {
540 assert(exe.kind == .exe or exe.kind == .test_exe);
541
542 const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe);
543 if (exe.vcpkg_bin_path) |path| {
544 RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
545 }
546 return run_step;
536pub fn run(cs: *CompileStep) *RunStep {
537 return cs.step.owner.addRunArtifact(cs);
547538}
548539
549540pub fn checkObject(self: *CompileStep, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
550 return CheckObjectStep.create(self.builder, self.getOutputSource(), obj_format);
541 const b = self.step.owner;
542 return CheckObjectStep.create(b, self.getOutputSource(), obj_format);
551543}
552544
553545pub fn setLinkerScriptPath(self: *CompileStep, source: FileSource) void {
554 self.linker_script = source.dupe(self.builder);
546 const b = self.step.owner;
547 self.linker_script = source.dupe(b);
555548 source.addStepDependencies(&self.step);
556549}
557550
558551pub fn linkFramework(self: *CompileStep, framework_name: []const u8) void {
559 self.frameworks.put(self.builder.dupe(framework_name), .{}) catch @panic("OOM");
552 const b = self.step.owner;
553 self.frameworks.put(b.dupe(framework_name), .{}) catch @panic("OOM");
560554}
561555
562556pub fn linkFrameworkNeeded(self: *CompileStep, framework_name: []const u8) void {
563 self.frameworks.put(self.builder.dupe(framework_name), .{
557 const b = self.step.owner;
558 self.frameworks.put(b.dupe(framework_name), .{
564559 .needed = true,
565560 }) catch @panic("OOM");
566561}
567562
568563pub fn linkFrameworkWeak(self: *CompileStep, framework_name: []const u8) void {
569 self.frameworks.put(self.builder.dupe(framework_name), .{
564 const b = self.step.owner;
565 self.frameworks.put(b.dupe(framework_name), .{
570566 .weak = true,
571567 }) catch @panic("OOM");
572568}
......@@ -619,21 +615,24 @@ pub fn linkLibCpp(self: *CompileStep) void {
619615/// If the value is omitted, it is set to 1.
620616/// `name` and `value` need not live longer than the function call.
621617pub fn defineCMacro(self: *CompileStep, name: []const u8, value: ?[]const u8) void {
622 const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
618 const b = self.step.owner;
619 const macro = std.Build.constructCMacro(b.allocator, name, value);
623620 self.c_macros.append(macro) catch @panic("OOM");
624621}
625622
626623/// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1.
627624pub fn defineCMacroRaw(self: *CompileStep, name_and_value: []const u8) void {
628 self.c_macros.append(self.builder.dupe(name_and_value)) catch @panic("OOM");
625 const b = self.step.owner;
626 self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");
629627}
630628
631629/// This one has no integration with anything, it just puts -lname on the command line.
632630/// Prefer to use `linkSystemLibrary` instead.
633631pub fn linkSystemLibraryName(self: *CompileStep, name: []const u8) void {
632 const b = self.step.owner;
634633 self.link_objects.append(.{
635634 .system_lib = .{
636 .name = self.builder.dupe(name),
635 .name = b.dupe(name),
637636 .needed = false,
638637 .weak = false,
639638 .use_pkg_config = .no,
......@@ -644,9 +643,10 @@ pub fn linkSystemLibraryName(self: *CompileStep, name: []const u8) void {
644643/// This one has no integration with anything, it just puts -needed-lname on the command line.
645644/// Prefer to use `linkSystemLibraryNeeded` instead.
646645pub fn linkSystemLibraryNeededName(self: *CompileStep, name: []const u8) void {
646 const b = self.step.owner;
647647 self.link_objects.append(.{
648648 .system_lib = .{
649 .name = self.builder.dupe(name),
649 .name = b.dupe(name),
650650 .needed = true,
651651 .weak = false,
652652 .use_pkg_config = .no,
......@@ -657,9 +657,10 @@ pub fn linkSystemLibraryNeededName(self: *CompileStep, name: []const u8) void {
657657/// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the
658658/// command line. Prefer to use `linkSystemLibraryWeak` instead.
659659pub fn linkSystemLibraryWeakName(self: *CompileStep, name: []const u8) void {
660 const b = self.step.owner;
660661 self.link_objects.append(.{
661662 .system_lib = .{
662 .name = self.builder.dupe(name),
663 .name = b.dupe(name),
663664 .needed = false,
664665 .weak = true,
665666 .use_pkg_config = .no,
......@@ -670,9 +671,10 @@ pub fn linkSystemLibraryWeakName(self: *CompileStep, name: []const u8) void {
670671/// This links against a system library, exclusively using pkg-config to find the library.
671672/// Prefer to use `linkSystemLibrary` instead.
672673pub fn linkSystemLibraryPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void {
674 const b = self.step.owner;
673675 self.link_objects.append(.{
674676 .system_lib = .{
675 .name = self.builder.dupe(lib_name),
677 .name = b.dupe(lib_name),
676678 .needed = false,
677679 .weak = false,
678680 .use_pkg_config = .force,
......@@ -683,9 +685,10 @@ pub fn linkSystemLibraryPkgConfigOnly(self: *CompileStep, lib_name: []const u8)
683685/// This links against a system library, exclusively using pkg-config to find the library.
684686/// Prefer to use `linkSystemLibraryNeeded` instead.
685687pub fn linkSystemLibraryNeededPkgConfigOnly(self: *CompileStep, lib_name: []const u8) void {
688 const b = self.step.owner;
686689 self.link_objects.append(.{
687690 .system_lib = .{
688 .name = self.builder.dupe(lib_name),
691 .name = b.dupe(lib_name),
689692 .needed = true,
690693 .weak = false,
691694 .use_pkg_config = .force,
......@@ -696,13 +699,14 @@ pub fn linkSystemLibraryNeededPkgConfigOnly(self: *CompileStep, lib_name: []cons
696699/// Run pkg-config for the given library name and parse the output, returning the arguments
697700/// that should be passed to zig to link the given library.
698701pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u8 {
702 const b = self.step.owner;
699703 const pkg_name = match: {
700704 // First we have to map the library name to pkg config name. Unfortunately,
701705 // there are several examples where this is not straightforward:
702706 // -lSDL2 -> pkg-config sdl2
703707 // -lgdk-3 -> pkg-config gdk-3.0
704708 // -latk-1.0 -> pkg-config atk
705 const pkgs = try getPkgConfigList(self.builder);
709 const pkgs = try getPkgConfigList(b);
706710
707711 // Exact match means instant winner.
708712 for (pkgs) |pkg| {
......@@ -742,7 +746,7 @@ pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u
742746 };
743747
744748 var code: u8 = undefined;
745 const stdout = if (self.builder.execAllowFail(&[_][]const u8{
749 const stdout = if (b.execAllowFail(&[_][]const u8{
746750 "pkg-config",
747751 pkg_name,
748752 "--cflags",
......@@ -755,7 +759,7 @@ pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u
755759 else => return err,
756760 };
757761
758 var zig_args = ArrayList([]const u8).init(self.builder.allocator);
762 var zig_args = ArrayList([]const u8).init(b.allocator);
759763 defer zig_args.deinit();
760764
761765 var it = mem.tokenize(u8, stdout, " \r\n\t");
......@@ -780,7 +784,7 @@ pub fn runPkgConfig(self: *CompileStep, lib_name: []const u8) ![]const []const u
780784 try zig_args.appendSlice(&[_][]const u8{ "-D", macro });
781785 } else if (mem.startsWith(u8, tok, "-D")) {
782786 try zig_args.append(tok);
783 } else if (self.builder.verbose) {
787 } else if (b.verbose) {
784788 log.warn("Ignoring pkg-config flag '{s}'", .{tok});
785789 }
786790 }
......@@ -804,6 +808,7 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct {
804808 needed: bool = false,
805809 weak: bool = false,
806810}) void {
811 const b = self.step.owner;
807812 if (isLibCLibrary(name)) {
808813 self.linkLibC();
809814 return;
......@@ -815,7 +820,7 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct {
815820
816821 self.link_objects.append(.{
817822 .system_lib = .{
818 .name = self.builder.dupe(name),
823 .name = b.dupe(name),
819824 .needed = opts.needed,
820825 .weak = opts.weak,
821826 .use_pkg_config = .yes,
......@@ -824,26 +829,30 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct {
824829}
825830
826831pub fn setNamePrefix(self: *CompileStep, text: []const u8) void {
832 const b = self.step.owner;
827833 assert(self.kind == .@"test" or self.kind == .test_exe);
828 self.name_prefix = self.builder.dupe(text);
834 self.name_prefix = b.dupe(text);
829835}
830836
831837pub fn setFilter(self: *CompileStep, text: ?[]const u8) void {
838 const b = self.step.owner;
832839 assert(self.kind == .@"test" or self.kind == .test_exe);
833 self.filter = if (text) |t| self.builder.dupe(t) else null;
840 self.filter = if (text) |t| b.dupe(t) else null;
834841}
835842
836843pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void {
844 const b = self.step.owner;
837845 assert(self.kind == .@"test" or self.kind == .test_exe);
838 self.test_runner = if (path) |p| self.builder.dupePath(p) else null;
846 self.test_runner = if (path) |p| b.dupePath(p) else null;
839847}
840848
841849/// Handy when you have many C/C++ source files and want them all to have the same flags.
842850pub fn addCSourceFiles(self: *CompileStep, files: []const []const u8, flags: []const []const u8) void {
843 const c_source_files = self.builder.allocator.create(CSourceFiles) catch @panic("OOM");
851 const b = self.step.owner;
852 const c_source_files = b.allocator.create(CSourceFiles) catch @panic("OOM");
844853
845 const files_copy = self.builder.dupeStrings(files);
846 const flags_copy = self.builder.dupeStrings(flags);
854 const files_copy = b.dupeStrings(files);
855 const flags_copy = b.dupeStrings(flags);
847856
848857 c_source_files.* = .{
849858 .files = files_copy,
......@@ -860,8 +869,9 @@ pub fn addCSourceFile(self: *CompileStep, file: []const u8, flags: []const []con
860869}
861870
862871pub fn addCSourceFileSource(self: *CompileStep, source: CSourceFile) void {
863 const c_source_file = self.builder.allocator.create(CSourceFile) catch @panic("OOM");
864 c_source_file.* = source.dupe(self.builder);
872 const b = self.step.owner;
873 const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM");
874 c_source_file.* = source.dupe(b);
865875 self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM");
866876 source.source.addStepDependencies(&self.step);
867877}
......@@ -875,15 +885,18 @@ pub fn setVerboseCC(self: *CompileStep, value: bool) void {
875885}
876886
877887pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void {
878 self.zig_lib_dir = self.builder.dupePath(dir_path);
888 const b = self.step.owner;
889 self.zig_lib_dir = b.dupePath(dir_path);
879890}
880891
881892pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void {
882 self.main_pkg_path = self.builder.dupePath(dir_path);
893 const b = self.step.owner;
894 self.main_pkg_path = b.dupePath(dir_path);
883895}
884896
885897pub fn setLibCFile(self: *CompileStep, libc_file: ?FileSource) void {
886 self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null;
898 const b = self.step.owner;
899 self.libc_file = if (libc_file) |f| f.dupe(b) else null;
887900}
888901
889902/// Returns the generated executable, library or object file.
......@@ -914,13 +927,15 @@ pub fn getOutputPdbSource(self: *CompileStep) FileSource {
914927}
915928
916929pub fn addAssemblyFile(self: *CompileStep, path: []const u8) void {
930 const b = self.step.owner;
917931 self.link_objects.append(.{
918 .assembly_file = .{ .path = self.builder.dupe(path) },
932 .assembly_file = .{ .path = b.dupe(path) },
919933 }) catch @panic("OOM");
920934}
921935
922936pub fn addAssemblyFileSource(self: *CompileStep, source: FileSource) void {
923 const source_duped = source.dupe(self.builder);
937 const b = self.step.owner;
938 const source_duped = source.dupe(b);
924939 self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM");
925940 source_duped.addStepDependencies(&self.step);
926941}
......@@ -930,7 +945,8 @@ pub fn addObjectFile(self: *CompileStep, source_file: []const u8) void {
930945}
931946
932947pub fn addObjectFileSource(self: *CompileStep, source: FileSource) void {
933 self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch @panic("OOM");
948 const b = self.step.owner;
949 self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM");
934950 source.addStepDependencies(&self.step);
935951}
936952
......@@ -945,11 +961,13 @@ pub const addLibPath = @compileError("deprecated, use addLibraryPath");
945961pub const addFrameworkDir = @compileError("deprecated, use addFrameworkPath");
946962
947963pub fn addSystemIncludePath(self: *CompileStep, path: []const u8) void {
948 self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch @panic("OOM");
964 const b = self.step.owner;
965 self.include_dirs.append(IncludeDir{ .raw_path_system = b.dupe(path) }) catch @panic("OOM");
949966}
950967
951968pub fn addIncludePath(self: *CompileStep, path: []const u8) void {
952 self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch @panic("OOM");
969 const b = self.step.owner;
970 self.include_dirs.append(IncludeDir{ .raw_path = b.dupe(path) }) catch @panic("OOM");
953971}
954972
955973pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) void {
......@@ -958,23 +976,27 @@ pub fn addConfigHeader(self: *CompileStep, config_header: *ConfigHeaderStep) voi
958976}
959977
960978pub fn addLibraryPath(self: *CompileStep, path: []const u8) void {
961 self.lib_paths.append(self.builder.dupe(path)) catch @panic("OOM");
979 const b = self.step.owner;
980 self.lib_paths.append(b.dupe(path)) catch @panic("OOM");
962981}
963982
964983pub fn addRPath(self: *CompileStep, path: []const u8) void {
965 self.rpaths.append(self.builder.dupe(path)) catch @panic("OOM");
984 const b = self.step.owner;
985 self.rpaths.append(b.dupe(path)) catch @panic("OOM");
966986}
967987
968988pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void {
969 self.framework_dirs.append(self.builder.dupe(dir_path)) catch @panic("OOM");
989 const b = self.step.owner;
990 self.framework_dirs.append(b.dupe(dir_path)) catch @panic("OOM");
970991}
971992
972993/// Adds a module to be used with `@import` and exposing it in the current
973994/// package's module table using `name`.
974995pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void {
975 cs.modules.put(cs.builder.dupe(name), module) catch @panic("OOM");
996 const b = cs.step.owner;
997 cs.modules.put(b.dupe(name), module) catch @panic("OOM");
976998
977 var done = std.AutoHashMap(*Module, void).init(cs.builder.allocator);
999 var done = std.AutoHashMap(*Module, void).init(b.allocator);
9781000 defer done.deinit();
9791001 cs.addRecursiveBuildDeps(module, &done) catch @panic("OOM");
9801002}
......@@ -982,7 +1004,8 @@ pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void {
9821004/// Adds a module to be used with `@import` without exposing it in the current
9831005/// package's module table.
9841006pub fn addAnonymousModule(cs: *CompileStep, name: []const u8, options: std.Build.CreateModuleOptions) void {
985 const module = cs.builder.createModule(options);
1007 const b = cs.step.owner;
1008 const module = b.createModule(options);
9861009 return addModule(cs, name, module);
9871010}
9881011
......@@ -1002,12 +1025,13 @@ fn addRecursiveBuildDeps(cs: *CompileStep, module: *Module, done: *std.AutoHashM
10021025/// If Vcpkg was found on the system, it will be added to include and lib
10031026/// paths for the specified target.
10041027pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void {
1028 const b = self.step.owner;
10051029 // Ideally in the Unattempted case we would call the function recursively
10061030 // after findVcpkgRoot and have only one switch statement, but the compiler
10071031 // cannot resolve the error set.
1008 switch (self.builder.vcpkg_root) {
1032 switch (b.vcpkg_root) {
10091033 .unattempted => {
1010 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|
1034 b.vcpkg_root = if (try findVcpkgRoot(b.allocator)) |root|
10111035 VcpkgRoot{ .found = root }
10121036 else
10131037 .not_found;
......@@ -1016,31 +1040,32 @@ pub fn addVcpkgPaths(self: *CompileStep, linkage: CompileStep.Linkage) !void {
10161040 .found => {},
10171041 }
10181042
1019 switch (self.builder.vcpkg_root) {
1043 switch (b.vcpkg_root) {
10201044 .unattempted => unreachable,
10211045 .not_found => return error.VcpkgNotFound,
10221046 .found => |root| {
1023 const allocator = self.builder.allocator;
1047 const allocator = b.allocator;
10241048 const triplet = try self.target.vcpkgTriplet(allocator, if (linkage == .static) .Static else .Dynamic);
1025 defer self.builder.allocator.free(triplet);
1049 defer b.allocator.free(triplet);
10261050
1027 const include_path = self.builder.pathJoin(&.{ root, "installed", triplet, "include" });
1051 const include_path = b.pathJoin(&.{ root, "installed", triplet, "include" });
10281052 errdefer allocator.free(include_path);
10291053 try self.include_dirs.append(IncludeDir{ .raw_path = include_path });
10301054
1031 const lib_path = self.builder.pathJoin(&.{ root, "installed", triplet, "lib" });
1055 const lib_path = b.pathJoin(&.{ root, "installed", triplet, "lib" });
10321056 try self.lib_paths.append(lib_path);
10331057
1034 self.vcpkg_bin_path = self.builder.pathJoin(&.{ root, "installed", triplet, "bin" });
1058 self.vcpkg_bin_path = b.pathJoin(&.{ root, "installed", triplet, "bin" });
10351059 },
10361060 }
10371061}
10381062
10391063pub fn setExecCmd(self: *CompileStep, args: []const ?[]const u8) void {
1064 const b = self.step.owner;
10401065 assert(self.kind == .@"test");
1041 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch @panic("OOM");
1066 const duped_args = b.allocator.alloc(?[]u8, args.len) catch @panic("OOM");
10421067 for (args, 0..) |arg, i| {
1043 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
1068 duped_args[i] = if (arg) |a| b.dupe(a) else null;
10441069 }
10451070 self.exec_cmd_args = duped_args;
10461071}
......@@ -1055,16 +1080,17 @@ fn appendModuleArgs(
10551080 cs: *CompileStep,
10561081 zig_args: *ArrayList([]const u8),
10571082) error{OutOfMemory}!void {
1083 const b = cs.step.owner;
10581084 // First, traverse the whole dependency graph and give every module a unique name, ideally one
10591085 // named after what it's called somewhere in the graph. It will help here to have both a mapping
10601086 // from module to name and a set of all the currently-used names.
1061 var mod_names = std.AutoHashMap(*Module, []const u8).init(cs.builder.allocator);
1062 var names = std.StringHashMap(void).init(cs.builder.allocator);
1087 var mod_names = std.AutoHashMap(*Module, []const u8).init(b.allocator);
1088 var names = std.StringHashMap(void).init(b.allocator);
10631089
10641090 var to_name = std.ArrayList(struct {
10651091 name: []const u8,
10661092 mod: *Module,
1067 }).init(cs.builder.allocator);
1093 }).init(b.allocator);
10681094 {
10691095 var it = cs.modules.iterator();
10701096 while (it.next()) |kv| {
......@@ -1085,7 +1111,7 @@ fn appendModuleArgs(
10851111 if (mod_names.contains(dep.mod)) continue;
10861112
10871113 // We'll use this buffer to store the name we decide on
1088 var buf = try cs.builder.allocator.alloc(u8, dep.name.len + 32);
1114 var buf = try b.allocator.alloc(u8, dep.name.len + 32);
10891115 // First, try just the exposed dependency name
10901116 std.mem.copy(u8, buf, dep.name);
10911117 var name = buf[0..dep.name.len];
......@@ -1122,15 +1148,15 @@ fn appendModuleArgs(
11221148 const mod = kv.key_ptr.*;
11231149 const name = kv.value_ptr.*;
11241150
1125 const deps_str = try constructDepString(cs.builder.allocator, mod_names, mod.dependencies);
1151 const deps_str = try constructDepString(b.allocator, mod_names, mod.dependencies);
11261152 const src = mod.builder.pathFromRoot(mod.source_file.getPath(mod.builder));
11271153 try zig_args.append("--mod");
1128 try zig_args.append(try std.fmt.allocPrint(cs.builder.allocator, "{s}:{s}:{s}", .{ name, deps_str, src }));
1154 try zig_args.append(try std.fmt.allocPrint(b.allocator, "{s}:{s}:{s}", .{ name, deps_str, src }));
11291155 }
11301156 }
11311157
11321158 // Lastly, output the root dependencies
1133 const deps_str = try constructDepString(cs.builder.allocator, mod_names, cs.modules);
1159 const deps_str = try constructDepString(b.allocator, mod_names, cs.modules);
11341160 if (deps_str.len > 0) {
11351161 try zig_args.append("--deps");
11361162 try zig_args.append(deps_str);
......@@ -1161,18 +1187,18 @@ fn constructDepString(
11611187}
11621188
11631189fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1190 const b = step.owner;
11641191 const self = @fieldParentPtr(CompileStep, "step", step);
1165 const builder = self.builder;
11661192
11671193 if (self.root_src == null and self.link_objects.items.len == 0) {
11681194 log.err("{s}: linker needs 1 or more objects to link", .{self.step.name});
11691195 return error.NeedAnObject;
11701196 }
11711197
1172 var zig_args = ArrayList([]const u8).init(builder.allocator);
1198 var zig_args = ArrayList([]const u8).init(b.allocator);
11731199 defer zig_args.deinit();
11741200
1175 try zig_args.append(builder.zig_exe);
1201 try zig_args.append(b.zig_exe);
11761202
11771203 const cmd = switch (self.kind) {
11781204 .lib => "build-lib",
......@@ -1183,15 +1209,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11831209 };
11841210 try zig_args.append(cmd);
11851211
1186 if (builder.reference_trace) |some| {
1187 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some}));
1212 if (b.reference_trace) |some| {
1213 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-freference-trace={d}", .{some}));
11881214 }
11891215
11901216 try addFlag(&zig_args, "LLVM", self.use_llvm);
11911217 try addFlag(&zig_args, "LLD", self.use_lld);
11921218
11931219 if (self.target.ofmt) |ofmt| {
1194 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
1220 try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
11951221 }
11961222
11971223 if (self.entry_symbol_name) |entry| {
......@@ -1201,18 +1227,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12011227
12021228 if (self.stack_size) |stack_size| {
12031229 try zig_args.append("--stack");
1204 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "{}", .{stack_size}));
1230 try zig_args.append(try std.fmt.allocPrint(b.allocator, "{}", .{stack_size}));
12051231 }
12061232
1207 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
1233 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(b));
12081234
12091235 // We will add link objects from transitive dependencies, but we want to keep
12101236 // all link objects in the same order provided.
12111237 // This array is used to keep self.link_objects immutable.
12121238 var transitive_deps: TransitiveDeps = .{
1213 .link_objects = ArrayList(LinkObject).init(builder.allocator),
1214 .seen_system_libs = StringHashMap(void).init(builder.allocator),
1215 .seen_steps = std.AutoHashMap(*const Step, void).init(builder.allocator),
1239 .link_objects = ArrayList(LinkObject).init(b.allocator),
1240 .seen_system_libs = StringHashMap(void).init(b.allocator),
1241 .seen_steps = std.AutoHashMap(*const Step, void).init(b.allocator),
12161242 .is_linking_libcpp = self.is_linking_libcpp,
12171243 .is_linking_libc = self.is_linking_libc,
12181244 .frameworks = &self.frameworks,
......@@ -1225,14 +1251,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12251251
12261252 for (transitive_deps.link_objects.items) |link_object| {
12271253 switch (link_object) {
1228 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
1254 .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
12291255
12301256 .other_step => |other| switch (other.kind) {
12311257 .exe => @panic("Cannot link with an executable build artifact"),
12321258 .test_exe => @panic("Cannot link with an executable build artifact"),
12331259 .@"test" => @panic("Cannot link with a test"),
12341260 .obj => {
1235 try zig_args.append(other.getOutputSource().getPath(builder));
1261 try zig_args.append(other.getOutputSource().getPath(b));
12361262 },
12371263 .lib => l: {
12381264 if (self.isStaticLibrary() and other.isStaticLibrary()) {
......@@ -1240,7 +1266,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12401266 break :l;
12411267 }
12421268
1243 const full_path_lib = other.getOutputLibSource().getPath(builder);
1269 const full_path_lib = other.getOutputLibSource().getPath(b);
12441270 try zig_args.append(full_path_lib);
12451271
12461272 if (other.linkage == Linkage.dynamic and !self.target.isWindows()) {
......@@ -1262,7 +1288,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12621288 break :prefix "-l";
12631289 };
12641290 switch (system_lib.use_pkg_config) {
1265 .no => try zig_args.append(builder.fmt("{s}{s}", .{ prefix, system_lib.name })),
1291 .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),
12661292 .yes, .force => {
12671293 if (self.runPkgConfig(system_lib.name)) |args| {
12681294 try zig_args.appendSlice(args);
......@@ -1276,7 +1302,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12761302 .yes => {
12771303 // pkg-config failed, so fall back to linking the library
12781304 // by name directly.
1279 try zig_args.append(builder.fmt("{s}{s}", .{
1305 try zig_args.append(b.fmt("{s}{s}", .{
12801306 prefix,
12811307 system_lib.name,
12821308 }));
......@@ -1299,7 +1325,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12991325 try zig_args.append("--");
13001326 prev_has_extra_flags = false;
13011327 }
1302 try zig_args.append(asm_file.getPath(builder));
1328 try zig_args.append(asm_file.getPath(b));
13031329 },
13041330
13051331 .c_source_file => |c_source_file| {
......@@ -1316,7 +1342,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
13161342 }
13171343 try zig_args.append("--");
13181344 }
1319 try zig_args.append(c_source_file.source.getPath(builder));
1345 try zig_args.append(c_source_file.source.getPath(b));
13201346 },
13211347
13221348 .c_source_files => |c_source_files| {
......@@ -1334,7 +1360,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
13341360 try zig_args.append("--");
13351361 }
13361362 for (c_source_files.files) |file| {
1337 try zig_args.append(builder.pathFromRoot(file));
1363 try zig_args.append(b.pathFromRoot(file));
13381364 }
13391365 },
13401366 }
......@@ -1350,7 +1376,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
13501376
13511377 if (self.image_base) |image_base| {
13521378 try zig_args.append("--image-base");
1353 try zig_args.append(builder.fmt("0x{x}", .{image_base}));
1379 try zig_args.append(b.fmt("0x{x}", .{image_base}));
13541380 }
13551381
13561382 if (self.filter) |filter| {
......@@ -1369,32 +1395,32 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
13691395
13701396 if (self.test_runner) |test_runner| {
13711397 try zig_args.append("--test-runner");
1372 try zig_args.append(builder.pathFromRoot(test_runner));
1398 try zig_args.append(b.pathFromRoot(test_runner));
13731399 }
13741400
1375 for (builder.debug_log_scopes) |log_scope| {
1401 for (b.debug_log_scopes) |log_scope| {
13761402 try zig_args.append("--debug-log");
13771403 try zig_args.append(log_scope);
13781404 }
13791405
1380 if (builder.debug_compile_errors) {
1406 if (b.debug_compile_errors) {
13811407 try zig_args.append("--debug-compile-errors");
13821408 }
13831409
1384 if (builder.verbose_cimport) try zig_args.append("--verbose-cimport");
1385 if (builder.verbose_air) try zig_args.append("--verbose-air");
1386 if (builder.verbose_llvm_ir) try zig_args.append("--verbose-llvm-ir");
1387 if (builder.verbose_link or self.verbose_link) try zig_args.append("--verbose-link");
1388 if (builder.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc");
1389 if (builder.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features");
1410 if (b.verbose_cimport) try zig_args.append("--verbose-cimport");
1411 if (b.verbose_air) try zig_args.append("--verbose-air");
1412 if (b.verbose_llvm_ir) try zig_args.append("--verbose-llvm-ir");
1413 if (b.verbose_link or self.verbose_link) try zig_args.append("--verbose-link");
1414 if (b.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc");
1415 if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features");
13901416
1391 if (self.emit_analysis.getArg(builder, "emit-analysis")) |arg| try zig_args.append(arg);
1392 if (self.emit_asm.getArg(builder, "emit-asm")) |arg| try zig_args.append(arg);
1393 if (self.emit_bin.getArg(builder, "emit-bin")) |arg| try zig_args.append(arg);
1394 if (self.emit_docs.getArg(builder, "emit-docs")) |arg| try zig_args.append(arg);
1395 if (self.emit_implib.getArg(builder, "emit-implib")) |arg| try zig_args.append(arg);
1396 if (self.emit_llvm_bc.getArg(builder, "emit-llvm-bc")) |arg| try zig_args.append(arg);
1397 if (self.emit_llvm_ir.getArg(builder, "emit-llvm-ir")) |arg| try zig_args.append(arg);
1417 if (self.emit_analysis.getArg(b, "emit-analysis")) |arg| try zig_args.append(arg);
1418 if (self.emit_asm.getArg(b, "emit-asm")) |arg| try zig_args.append(arg);
1419 if (self.emit_bin.getArg(b, "emit-bin")) |arg| try zig_args.append(arg);
1420 if (self.emit_docs.getArg(b, "emit-docs")) |arg| try zig_args.append(arg);
1421 if (self.emit_implib.getArg(b, "emit-implib")) |arg| try zig_args.append(arg);
1422 if (self.emit_llvm_bc.getArg(b, "emit-llvm-bc")) |arg| try zig_args.append(arg);
1423 if (self.emit_llvm_ir.getArg(b, "emit-llvm-ir")) |arg| try zig_args.append(arg);
13981424
13991425 if (self.emit_h) try zig_args.append("-femit-h");
14001426
......@@ -1435,31 +1461,31 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14351461 }
14361462 if (self.link_z_common_page_size) |size| {
14371463 try zig_args.append("-z");
1438 try zig_args.append(builder.fmt("common-page-size={d}", .{size}));
1464 try zig_args.append(b.fmt("common-page-size={d}", .{size}));
14391465 }
14401466 if (self.link_z_max_page_size) |size| {
14411467 try zig_args.append("-z");
1442 try zig_args.append(builder.fmt("max-page-size={d}", .{size}));
1468 try zig_args.append(b.fmt("max-page-size={d}", .{size}));
14431469 }
14441470
14451471 if (self.libc_file) |libc_file| {
14461472 try zig_args.append("--libc");
1447 try zig_args.append(libc_file.getPath(builder));
1448 } else if (builder.libc_file) |libc_file| {
1473 try zig_args.append(libc_file.getPath(b));
1474 } else if (b.libc_file) |libc_file| {
14491475 try zig_args.append("--libc");
14501476 try zig_args.append(libc_file);
14511477 }
14521478
14531479 switch (self.optimize) {
14541480 .Debug => {}, // Skip since it's the default.
1455 else => try zig_args.append(builder.fmt("-O{s}", .{@tagName(self.optimize)})),
1481 else => try zig_args.append(b.fmt("-O{s}", .{@tagName(self.optimize)})),
14561482 }
14571483
14581484 try zig_args.append("--cache-dir");
1459 try zig_args.append(builder.cache_root.path orelse ".");
1485 try zig_args.append(b.cache_root.path orelse ".");
14601486
14611487 try zig_args.append("--global-cache-dir");
1462 try zig_args.append(builder.global_cache_root.path orelse ".");
1488 try zig_args.append(b.global_cache_root.path orelse ".");
14631489
14641490 try zig_args.append("--name");
14651491 try zig_args.append(self.name);
......@@ -1471,11 +1497,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14711497 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic) {
14721498 if (self.version) |version| {
14731499 try zig_args.append("--version");
1474 try zig_args.append(builder.fmt("{}", .{version}));
1500 try zig_args.append(b.fmt("{}", .{version}));
14751501 }
14761502
14771503 if (self.target.isDarwin()) {
1478 const install_name = self.install_name orelse builder.fmt("@rpath/{s}{s}{s}", .{
1504 const install_name = self.install_name orelse b.fmt("@rpath/{s}{s}{s}", .{
14791505 self.target.libPrefix(),
14801506 self.name,
14811507 self.target.dynamicLibSuffix(),
......@@ -1489,7 +1515,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14891515 try zig_args.appendSlice(&[_][]const u8{ "--entitlements", entitlements });
14901516 }
14911517 if (self.pagezero_size) |pagezero_size| {
1492 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{pagezero_size});
1518 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{pagezero_size});
14931519 try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
14941520 }
14951521 if (self.search_strategy) |strat| switch (strat) {
......@@ -1497,7 +1523,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14971523 .dylibs_first => try zig_args.append("-search_dylibs_first"),
14981524 };
14991525 if (self.headerpad_size) |headerpad_size| {
1500 const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{headerpad_size});
1526 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{headerpad_size});
15011527 try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
15021528 }
15031529 if (self.headerpad_max_install_names) {
......@@ -1545,16 +1571,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
15451571 try zig_args.append("--export-table");
15461572 }
15471573 if (self.initial_memory) |initial_memory| {
1548 try zig_args.append(builder.fmt("--initial-memory={d}", .{initial_memory}));
1574 try zig_args.append(b.fmt("--initial-memory={d}", .{initial_memory}));
15491575 }
15501576 if (self.max_memory) |max_memory| {
1551 try zig_args.append(builder.fmt("--max-memory={d}", .{max_memory}));
1577 try zig_args.append(b.fmt("--max-memory={d}", .{max_memory}));
15521578 }
15531579 if (self.shared_memory) {
15541580 try zig_args.append("--shared-memory");
15551581 }
15561582 if (self.global_base) |global_base| {
1557 try zig_args.append(builder.fmt("--global-base={d}", .{global_base}));
1583 try zig_args.append(b.fmt("--global-base={d}", .{global_base}));
15581584 }
15591585
15601586 if (self.code_model != .default) {
......@@ -1562,16 +1588,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
15621588 try zig_args.append(@tagName(self.code_model));
15631589 }
15641590 if (self.wasi_exec_model) |model| {
1565 try zig_args.append(builder.fmt("-mexec-model={s}", .{@tagName(model)}));
1591 try zig_args.append(b.fmt("-mexec-model={s}", .{@tagName(model)}));
15661592 }
15671593 for (self.export_symbol_names) |symbol_name| {
1568 try zig_args.append(builder.fmt("--export={s}", .{symbol_name}));
1594 try zig_args.append(b.fmt("--export={s}", .{symbol_name}));
15691595 }
15701596
15711597 if (!self.target.isNative()) {
15721598 try zig_args.appendSlice(&.{
1573 "-target", try self.target.zigTriple(builder.allocator),
1574 "-mcpu", try std.Build.serializeCpu(builder.allocator, self.target.getCpu()),
1599 "-target", try self.target.zigTriple(b.allocator),
1600 "-mcpu", try std.Build.serializeCpu(b.allocator, self.target.getCpu()),
15751601 });
15761602
15771603 if (self.target.dynamic_linker.get()) |dynamic_linker| {
......@@ -1582,12 +1608,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
15821608
15831609 if (self.linker_script) |linker_script| {
15841610 try zig_args.append("--script");
1585 try zig_args.append(linker_script.getPath(builder));
1611 try zig_args.append(linker_script.getPath(b));
15861612 }
15871613
15881614 if (self.version_script) |version_script| {
15891615 try zig_args.append("--version-script");
1590 try zig_args.append(builder.pathFromRoot(version_script));
1616 try zig_args.append(b.pathFromRoot(version_script));
15911617 }
15921618
15931619 if (self.kind == .@"test") {
......@@ -1603,23 +1629,23 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16031629 } else {
16041630 const need_cross_glibc = self.target.isGnuLibC() and transitive_deps.is_linking_libc;
16051631
1606 switch (builder.host.getExternalExecutor(self.target_info, .{
1607 .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null,
1632 switch (b.host.getExternalExecutor(self.target_info, .{
1633 .qemu_fixes_dl = need_cross_glibc and b.glibc_runtimes_dir != null,
16081634 .link_libc = transitive_deps.is_linking_libc,
16091635 })) {
16101636 .native => {},
16111637 .bad_dl, .bad_os_or_cpu => {
16121638 try zig_args.append("--test-no-exec");
16131639 },
1614 .rosetta => if (builder.enable_rosetta) {
1640 .rosetta => if (b.enable_rosetta) {
16151641 try zig_args.append("--test-cmd-bin");
16161642 } else {
16171643 try zig_args.append("--test-no-exec");
16181644 },
16191645 .qemu => |bin_name| ok: {
1620 if (builder.enable_qemu) qemu: {
1646 if (b.enable_qemu) qemu: {
16211647 const glibc_dir_arg = if (need_cross_glibc)
1622 builder.glibc_runtimes_dir orelse break :qemu
1648 b.glibc_runtimes_dir orelse break :qemu
16231649 else
16241650 null;
16251651 try zig_args.append("--test-cmd");
......@@ -1636,7 +1662,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16361662 "i686"
16371663 else
16381664 @tagName(cpu_arch);
1639 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
1665 const full_dir = try std.fmt.allocPrint(b.allocator, fmt_str, .{
16401666 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
16411667 });
16421668
......@@ -1650,14 +1676,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16501676 }
16511677 try zig_args.append("--test-no-exec");
16521678 },
1653 .wine => |bin_name| if (builder.enable_wine) {
1679 .wine => |bin_name| if (b.enable_wine) {
16541680 try zig_args.append("--test-cmd");
16551681 try zig_args.append(bin_name);
16561682 try zig_args.append("--test-cmd-bin");
16571683 } else {
16581684 try zig_args.append("--test-no-exec");
16591685 },
1660 .wasmtime => |bin_name| if (builder.enable_wasmtime) {
1686 .wasmtime => |bin_name| if (b.enable_wasmtime) {
16611687 try zig_args.append("--test-cmd");
16621688 try zig_args.append(bin_name);
16631689 try zig_args.append("--test-cmd");
......@@ -1666,7 +1692,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16661692 } else {
16671693 try zig_args.append("--test-no-exec");
16681694 },
1669 .darling => |bin_name| if (builder.enable_darling) {
1695 .darling => |bin_name| if (b.enable_darling) {
16701696 try zig_args.append("--test-cmd");
16711697 try zig_args.append(bin_name);
16721698 try zig_args.append("--test-cmd-bin");
......@@ -1685,18 +1711,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
16851711 switch (include_dir) {
16861712 .raw_path => |include_path| {
16871713 try zig_args.append("-I");
1688 try zig_args.append(builder.pathFromRoot(include_path));
1714 try zig_args.append(b.pathFromRoot(include_path));
16891715 },
16901716 .raw_path_system => |include_path| {
1691 if (builder.sysroot != null) {
1717 if (b.sysroot != null) {
16921718 try zig_args.append("-iwithsysroot");
16931719 } else {
16941720 try zig_args.append("-isystem");
16951721 }
16961722
1697 const resolved_include_path = builder.pathFromRoot(include_path);
1723 const resolved_include_path = b.pathFromRoot(include_path);
16981724
1699 const common_include_path = if (builtin.os.tag == .windows and builder.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: {
1725 const common_include_path = if (builtin.os.tag == .windows and b.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: {
17001726 // We need to check for disk designator and strip it out from dir path so
17011727 // that zig/clang can concat resolved_include_path with sysroot.
17021728 const disk_designator = fs.path.diskDesignatorWindows(resolved_include_path);
......@@ -1712,7 +1738,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17121738 },
17131739 .other_step => |other| {
17141740 if (other.emit_h) {
1715 const h_path = other.getOutputHSource().getPath(builder);
1741 const h_path = other.getOutputHSource().getPath(b);
17161742 try zig_args.append("-isystem");
17171743 try zig_args.append(fs.path.dirname(h_path).?);
17181744 }
......@@ -1721,8 +1747,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17211747 try install_step.make(prog_node);
17221748 }
17231749 try zig_args.append("-I");
1724 try zig_args.append(builder.pathJoin(&.{
1725 other.builder.install_prefix, "include",
1750 try zig_args.append(b.pathJoin(&.{
1751 other.step.owner.install_prefix, "include",
17261752 }));
17271753 }
17281754 },
......@@ -1751,7 +1777,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17511777
17521778 if (self.target.isDarwin()) {
17531779 for (self.framework_dirs.items) |dir| {
1754 if (builder.sysroot != null) {
1780 if (b.sysroot != null) {
17551781 try zig_args.append("-iframeworkwithsysroot");
17561782 } else {
17571783 try zig_args.append("-iframework");
......@@ -1784,17 +1810,17 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
17841810 }
17851811 }
17861812
1787 if (builder.sysroot) |sysroot| {
1813 if (b.sysroot) |sysroot| {
17881814 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
17891815 }
17901816
1791 for (builder.search_prefixes.items) |search_prefix| {
1817 for (b.search_prefixes.items) |search_prefix| {
17921818 try zig_args.append("-L");
1793 try zig_args.append(builder.pathJoin(&.{
1819 try zig_args.append(b.pathJoin(&.{
17941820 search_prefix, "lib",
17951821 }));
17961822 try zig_args.append("-I");
1797 try zig_args.append(builder.pathJoin(&.{
1823 try zig_args.append(b.pathJoin(&.{
17981824 search_prefix, "include",
17991825 }));
18001826 }
......@@ -1805,15 +1831,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18051831
18061832 if (self.zig_lib_dir) |dir| {
18071833 try zig_args.append("--zig-lib-dir");
1808 try zig_args.append(builder.pathFromRoot(dir));
1809 } else if (builder.zig_lib_dir) |dir| {
1834 try zig_args.append(b.pathFromRoot(dir));
1835 } else if (b.zig_lib_dir) |dir| {
18101836 try zig_args.append("--zig-lib-dir");
18111837 try zig_args.append(dir);
18121838 }
18131839
18141840 if (self.main_pkg_path) |dir| {
18151841 try zig_args.append("--main-pkg-path");
1816 try zig_args.append(builder.pathFromRoot(dir));
1842 try zig_args.append(b.pathFromRoot(dir));
18171843 }
18181844
18191845 try addFlag(&zig_args, "PIC", self.force_pic);
......@@ -1846,15 +1872,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18461872 args_length += arg.len + 1; // +1 to account for null terminator
18471873 }
18481874 if (args_length >= 30 * 1024) {
1849 try builder.cache_root.handle.makePath("args");
1875 try b.cache_root.handle.makePath("args");
18501876
18511877 const args_to_escape = zig_args.items[2..];
1852 var escaped_args = try ArrayList([]const u8).initCapacity(builder.allocator, args_to_escape.len);
1878 var escaped_args = try ArrayList([]const u8).initCapacity(b.allocator, args_to_escape.len);
18531879 arg_blk: for (args_to_escape) |arg| {
18541880 for (arg, 0..) |c, arg_idx| {
18551881 if (c == '\\' or c == '"') {
18561882 // Slow path for arguments that need to be escaped. We'll need to allocate and copy
1857 var escaped = try ArrayList(u8).initCapacity(builder.allocator, arg.len + 1);
1883 var escaped = try ArrayList(u8).initCapacity(b.allocator, arg.len + 1);
18581884 const writer = escaped.writer();
18591885 try writer.writeAll(arg[0..arg_idx]);
18601886 for (arg[arg_idx..]) |to_escape| {
......@@ -1870,8 +1896,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18701896
18711897 // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with
18721898 // other zig build commands running in parallel.
1873 const partially_quoted = try std.mem.join(builder.allocator, "\" \"", escaped_args.items);
1874 const args = try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" });
1899 const partially_quoted = try std.mem.join(b.allocator, "\" \"", escaped_args.items);
1900 const args = try std.mem.concat(b.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" });
18751901
18761902 var args_hash: [Sha256.digest_length]u8 = undefined;
18771903 Sha256.hash(args, &args_hash, .{});
......@@ -1883,18 +1909,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
18831909 );
18841910
18851911 const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
1886 try builder.cache_root.handle.writeFile(args_file, args);
1912 try b.cache_root.handle.writeFile(args_file, args);
18871913
1888 const resolved_args_file = try mem.concat(builder.allocator, u8, &.{
1914 const resolved_args_file = try mem.concat(b.allocator, u8, &.{
18891915 "@",
1890 try builder.cache_root.join(builder.allocator, &.{args_file}),
1916 try b.cache_root.join(b.allocator, &.{args_file}),
18911917 });
18921918
18931919 zig_args.shrinkRetainingCapacity(2);
18941920 try zig_args.append(resolved_args_file);
18951921 }
18961922
1897 const output_bin_path = try builder.execFromStep(zig_args.items, &self.step, prog_node);
1923 const output_bin_path = try step.evalZigProcess(zig_args.items, prog_node);
18981924 const build_output_dir = fs.path.dirname(output_bin_path).?;
18991925
19001926 if (self.output_dir) |output_dir| {
......@@ -1928,25 +1954,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
19281954
19291955 // Update generated files
19301956 if (self.output_dir != null) {
1931 self.output_path_source.path = builder.pathJoin(
1957 self.output_path_source.path = b.pathJoin(
19321958 &.{ self.output_dir.?, self.out_filename },
19331959 );
19341960
19351961 if (self.emit_h) {
1936 self.output_h_path_source.path = builder.pathJoin(
1962 self.output_h_path_source.path = b.pathJoin(
19371963 &.{ self.output_dir.?, self.out_h_filename },
19381964 );
19391965 }
19401966
19411967 if (self.target.isWindows() or self.target.isUefi()) {
1942 self.output_pdb_path_source.path = builder.pathJoin(
1968 self.output_pdb_path_source.path = b.pathJoin(
19431969 &.{ self.output_dir.?, self.out_pdb_filename },
19441970 );
19451971 }
19461972 }
19471973
19481974 if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
1949 try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?);
1975 try doAtomicSymLinks(b.allocator, self.getOutputSource().getPath(b), self.major_only_filename.?, self.name_only_filename.?);
19501976 }
19511977}
19521978
lib/std/Build/ConfigHeaderStep.zig+13-14
......@@ -34,7 +34,6 @@ pub const Value = union(enum) {
3434};
3535
3636step: Step,
37builder: *std.Build,
3837values: std.StringArrayHashMap(Value),
3938output_file: std.Build.GeneratedFile,
4039
......@@ -49,8 +48,8 @@ pub const Options = struct {
4948 first_ret_addr: ?usize = null,
5049};
5150
52pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
53 const self = builder.allocator.create(ConfigHeaderStep) catch @panic("OOM");
51pub fn create(owner: *std.Build, options: Options) *ConfigHeaderStep {
52 const self = owner.allocator.create(ConfigHeaderStep) catch @panic("OOM");
5453
5554 var include_path: []const u8 = "config.h";
5655
......@@ -69,29 +68,28 @@ pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
6968 }
7069
7170 const name = if (options.style.getFileSource()) |s|
72 builder.fmt("configure {s} header {s} to {s}", .{
71 owner.fmt("configure {s} header {s} to {s}", .{
7372 @tagName(options.style), s.getDisplayName(), include_path,
7473 })
7574 else
76 builder.fmt("configure {s} header to {s}", .{@tagName(options.style), include_path});
75 owner.fmt("configure {s} header to {s}", .{ @tagName(options.style), include_path });
7776
7877 self.* = .{
79 .builder = builder,
80 .step = Step.init(builder.allocator, .{
78 .step = Step.init(.{
8179 .id = base_id,
8280 .name = name,
81 .owner = owner,
8382 .makeFn = make,
8483 .first_ret_addr = options.first_ret_addr orelse @returnAddress(),
8584 }),
8685 .style = options.style,
87 .values = std.StringArrayHashMap(Value).init(builder.allocator),
86 .values = std.StringArrayHashMap(Value).init(owner.allocator),
8887
8988 .max_bytes = options.max_bytes,
9089 .include_path = include_path,
9190 .output_file = .{ .step = &self.step },
9291 };
9392
94
9593 return self;
9694}
9795
......@@ -161,8 +159,9 @@ fn putValue(self: *ConfigHeaderStep, field_name: []const u8, comptime T: type, v
161159
162160fn make(step: *Step, prog_node: *std.Progress.Node) !void {
163161 _ = prog_node;
162 const b = step.owner;
164163 const self = @fieldParentPtr(ConfigHeaderStep, "step", step);
165 const gpa = self.builder.allocator;
164 const gpa = b.allocator;
166165
167166 // The cache is used here not really as a way to speed things up - because writing
168167 // the data to a file would probably be very fast - but as a way to find a canonical
......@@ -191,13 +190,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
191190 switch (self.style) {
192191 .autoconf => |file_source| {
193192 try output.appendSlice(c_generated_line);
194 const src_path = file_source.getPath(self.builder);
193 const src_path = file_source.getPath(b);
195194 const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
196195 try render_autoconf(contents, &output, self.values, src_path);
197196 },
198197 .cmake => |file_source| {
199198 try output.appendSlice(c_generated_line);
200 const src_path = file_source.getPath(self.builder);
199 const src_path = file_source.getPath(b);
201200 const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
202201 try render_cmake(contents, &output, self.values, src_path);
203202 },
......@@ -222,7 +221,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
222221 .{std.fmt.fmtSliceHexLower(&digest)},
223222 ) catch unreachable;
224223
225 const output_dir = try self.builder.cache_root.join(gpa, &.{ "o", &hash_basename });
224 const output_dir = try b.cache_root.join(gpa, &.{ "o", &hash_basename });
226225
227226 // If output_path has directory parts, deal with them. Example:
228227 // output_dir is zig-cache/o/HASH
......@@ -242,7 +241,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
242241
243242 try dir.writeFile(std.fs.path.basename(self.include_path), output.items);
244243
245 self.output_file.path = try std.fs.path.join(self.builder.allocator, &.{
244 self.output_file.path = try std.fs.path.join(b.allocator, &.{
246245 output_dir, self.include_path,
247246 });
248247}
lib/std/Build/EmulatableRunStep.zig deleted-218
......@@ -1,218 +0,0 @@
1//! Unlike `RunStep` this step will provide emulation, when enabled, to run foreign binaries.
2//! When a binary is foreign, but emulation for the target is disabled, the specified binary
3//! will not be run and therefore also not validated against its output.
4//! This step can be useful when wishing to run a built binary on multiple platforms,
5//! without having to verify if it's possible to be ran against.
6
7const std = @import("../std.zig");
8const Step = std.Build.Step;
9const CompileStep = std.Build.CompileStep;
10const RunStep = std.Build.RunStep;
11
12const fs = std.fs;
13const process = std.process;
14const EnvMap = process.EnvMap;
15
16const EmulatableRunStep = @This();
17
18pub const base_id = .emulatable_run;
19
20const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
21
22step: Step,
23builder: *std.Build,
24
25/// The artifact (executable) to be run by this step
26exe: *CompileStep,
27
28/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution
29expected_term: ?std.ChildProcess.Term = .{ .Exited = 0 },
30
31/// Override this field to modify the environment
32env_map: ?*EnvMap,
33
34/// Set this to modify the current working directory
35cwd: ?[]const u8,
36
37stdout_action: RunStep.StdIoAction = .inherit,
38stderr_action: RunStep.StdIoAction = .inherit,
39
40/// When set to true, hides the warning of skipping a foreign binary which cannot be run on the host
41/// or through emulation.
42hide_foreign_binaries_warning: bool,
43
44/// Creates a step that will execute the given artifact. This step will allow running the
45/// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true.
46/// When set to false, and the binary is foreign, running the executable is skipped.
47/// Asserts given artifact is an executable.
48pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *EmulatableRunStep {
49 std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe);
50 const self = builder.allocator.create(EmulatableRunStep) catch @panic("OOM");
51
52 const option_name = "hide-foreign-warnings";
53 const hide_warnings = if (builder.available_options_map.get(option_name) == null) warn: {
54 break :warn builder.option(bool, option_name, "Hide the warning when a foreign binary which is incompatible is skipped") orelse false;
55 } else false;
56
57 self.* = .{
58 .builder = builder,
59 .step = Step.init(builder.allocator, .{
60 .id = .emulatable_run,
61 .name = name,
62 .makeFn = make,
63 }),
64 .exe = artifact,
65 .env_map = null,
66 .cwd = null,
67 .hide_foreign_binaries_warning = hide_warnings,
68 };
69 self.step.dependOn(&artifact.step);
70
71 return self;
72}
73
74fn make(step: *Step, prog_node: *std.Progress.Node) !void {
75 _ = prog_node;
76 const self = @fieldParentPtr(EmulatableRunStep, "step", step);
77 const host_info = self.builder.host;
78
79 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
80 defer argv_list.deinit();
81
82 const need_cross_glibc = self.exe.target.isGnuLibC() and self.exe.is_linking_libc;
83 switch (host_info.getExternalExecutor(self.exe.target_info, .{
84 .qemu_fixes_dl = need_cross_glibc and self.builder.glibc_runtimes_dir != null,
85 .link_libc = self.exe.is_linking_libc,
86 })) {
87 .native => {},
88 .rosetta => if (!self.builder.enable_rosetta) return warnAboutForeignBinaries(self),
89 .wine => |bin_name| if (self.builder.enable_wine) {
90 try argv_list.append(bin_name);
91 } else return,
92 .qemu => |bin_name| if (self.builder.enable_qemu) {
93 const glibc_dir_arg = if (need_cross_glibc)
94 self.builder.glibc_runtimes_dir orelse return
95 else
96 null;
97 try argv_list.append(bin_name);
98 if (glibc_dir_arg) |dir| {
99 // TODO look into making this a call to `linuxTriple`. This
100 // needs the directory to be called "i686" rather than
101 // "x86" which is why we do it manually here.
102 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
103 const cpu_arch = self.exe.target.getCpuArch();
104 const os_tag = self.exe.target.getOsTag();
105 const abi = self.exe.target.getAbi();
106 const cpu_arch_name: []const u8 = if (cpu_arch == .x86)
107 "i686"
108 else
109 @tagName(cpu_arch);
110 const full_dir = try std.fmt.allocPrint(self.builder.allocator, fmt_str, .{
111 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
112 });
113
114 try argv_list.append("-L");
115 try argv_list.append(full_dir);
116 }
117 } else return warnAboutForeignBinaries(self),
118 .darling => |bin_name| if (self.builder.enable_darling) {
119 try argv_list.append(bin_name);
120 } else return warnAboutForeignBinaries(self),
121 .wasmtime => |bin_name| if (self.builder.enable_wasmtime) {
122 try argv_list.append(bin_name);
123 try argv_list.append("--dir=.");
124 } else return warnAboutForeignBinaries(self),
125 else => return warnAboutForeignBinaries(self),
126 }
127
128 if (self.exe.target.isWindows()) {
129 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
130 RunStep.addPathForDynLibsInternal(&self.step, self.builder, self.exe);
131 }
132
133 const executable_path = self.exe.installed_path orelse self.exe.getOutputSource().getPath(self.builder);
134 try argv_list.append(executable_path);
135
136 try RunStep.runCommand(
137 argv_list.items,
138 self.builder,
139 self.expected_term,
140 self.stdout_action,
141 self.stderr_action,
142 .Inherit,
143 self.env_map,
144 self.cwd,
145 false,
146 );
147}
148
149pub fn expectStdErrEqual(self: *EmulatableRunStep, bytes: []const u8) void {
150 self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
151}
152
153pub fn expectStdOutEqual(self: *EmulatableRunStep, bytes: []const u8) void {
154 self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
155}
156
157fn warnAboutForeignBinaries(step: *EmulatableRunStep) void {
158 if (step.hide_foreign_binaries_warning) return;
159 const builder = step.builder;
160 const artifact = step.exe;
161
162 const host_name = builder.host.target.zigTriple(builder.allocator) catch @panic("unhandled error");
163 const foreign_name = artifact.target.zigTriple(builder.allocator) catch @panic("unhandled error");
164 const target_info = std.zig.system.NativeTargetInfo.detect(artifact.target) catch @panic("unhandled error");
165 const need_cross_glibc = artifact.target.isGnuLibC() and artifact.is_linking_libc;
166 switch (builder.host.getExternalExecutor(target_info, .{
167 .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null,
168 .link_libc = artifact.is_linking_libc,
169 })) {
170 .native => unreachable,
171 .bad_dl => |foreign_dl| {
172 const host_dl = builder.host.dynamic_linker.get() orelse "(none)";
173 std.debug.print("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is '{s}', while the target dynamic linker is '{s}'. Consider setting the dynamic linker as '{s}'.\n", .{
174 host_dl, foreign_dl, host_dl,
175 });
176 },
177 .bad_os_or_cpu => {
178 std.debug.print("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}).\n", .{
179 host_name, foreign_name,
180 });
181 },
182 .darling => if (!builder.enable_darling) {
183 std.debug.print(
184 "the host system ({s}) does not appear to be capable of executing binaries " ++
185 "from the target ({s}). Consider enabling darling.\n",
186 .{ host_name, foreign_name },
187 );
188 },
189 .rosetta => if (!builder.enable_rosetta) {
190 std.debug.print(
191 "the host system ({s}) does not appear to be capable of executing binaries " ++
192 "from the target ({s}). Consider enabling rosetta.\n",
193 .{ host_name, foreign_name },
194 );
195 },
196 .wine => if (!builder.enable_wine) {
197 std.debug.print(
198 "the host system ({s}) does not appear to be capable of executing binaries " ++
199 "from the target ({s}). Consider enabling wine.\n",
200 .{ host_name, foreign_name },
201 );
202 },
203 .qemu => if (!builder.enable_qemu) {
204 std.debug.print(
205 "the host system ({s}) does not appear to be capable of executing binaries " ++
206 "from the target ({s}). Consider enabling qemu.\n",
207 .{ host_name, foreign_name },
208 );
209 },
210 .wasmtime => {
211 std.debug.print(
212 "the host system ({s}) does not appear to be capable of executing binaries " ++
213 "from the target ({s}). Consider enabling wasmtime.\n",
214 .{ host_name, foreign_name },
215 );
216 },
217 }
218}
lib/std/Build/FmtStep.zig+58-22
......@@ -1,37 +1,73 @@
1const std = @import("../std.zig");
2const Step = std.Build.Step;
3const FmtStep = @This();
1//! This step has two modes:
2//! * Modify mode: directly modify source files, formatting them in place.
3//! * Check mode: fail the step if a non-conforming file is found.
4
5step: Step,
6paths: []const []const u8,
7exclude_paths: []const []const u8,
8check: bool,
49
510pub const base_id = .fmt;
611
7step: Step,
8builder: *std.Build,
9argv: [][]const u8,
10
11pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {
12 const self = builder.allocator.create(FmtStep) catch @panic("OOM");
13 const name = "zig fmt";
14 self.* = FmtStep{
15 .step = Step.init(builder.allocator, .{
16 .id = .fmt,
12pub const Options = struct {
13 paths: []const []const u8 = &.{},
14 exclude_paths: []const []const u8 = &.{},
15 /// If true, fails the build step when any non-conforming files are encountered.
16 check: bool = false,
17};
18
19pub fn create(owner: *std.Build, options: Options) *FmtStep {
20 const self = owner.allocator.create(FmtStep) catch @panic("OOM");
21 const name = if (options.check) "zig fmt --check" else "zig fmt";
22 self.* = .{
23 .step = Step.init(.{
24 .id = base_id,
1725 .name = name,
26 .owner = owner,
1827 .makeFn = make,
1928 }),
20 .builder = builder,
21 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch @panic("OOM"),
29 .paths = options.paths,
30 .exclude_paths = options.exclude_paths,
31 .check = options.check,
2232 };
23
24 self.argv[0] = builder.zig_exe;
25 self.argv[1] = "fmt";
26 for (paths, 0..) |path, i| {
27 self.argv[2 + i] = builder.pathFromRoot(path);
28 }
2933 return self;
3034}
3135
3236fn make(step: *Step, prog_node: *std.Progress.Node) !void {
37 // zig fmt is fast enough that no progress is needed.
3338 _ = prog_node;
39
40 // TODO: if check=false, this means we are modifying source files in place, which
41 // is an operation that could race against other operations also modifying source files
42 // in place. In this case, this step should obtain a write lock while making those
43 // modifications.
44
45 const b = step.owner;
46 const arena = b.allocator;
3447 const self = @fieldParentPtr(FmtStep, "step", step);
3548
36 return self.builder.spawnChild(self.argv);
49 var argv: std.ArrayListUnmanaged([]const u8) = .{};
50 try argv.ensureUnusedCapacity(arena, 2 + 1 + self.paths.len + 2 * self.exclude_paths.len);
51
52 argv.appendAssumeCapacity(b.zig_exe);
53 argv.appendAssumeCapacity("fmt");
54
55 if (self.check) {
56 argv.appendAssumeCapacity("--check");
57 }
58
59 for (self.paths) |p| {
60 argv.appendAssumeCapacity(b.pathFromRoot(p));
61 }
62
63 for (self.exclude_paths) |p| {
64 argv.appendAssumeCapacity("--exclude");
65 argv.appendAssumeCapacity(b.pathFromRoot(p));
66 }
67
68 return step.evalChildProcess(argv.items);
3769}
70
71const std = @import("../std.zig");
72const Step = std.Build.Step;
73const FmtStep = @This();
lib/std/Build/InstallArtifactStep.zig+27-22
......@@ -7,23 +7,24 @@ const InstallArtifactStep = @This();
77pub const base_id = .install_artifact;
88
99step: Step,
10builder: *std.Build,
10dest_builder: *std.Build,
1111artifact: *CompileStep,
1212dest_dir: InstallDir,
1313pdb_dir: ?InstallDir,
1414h_dir: ?InstallDir,
1515
16pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep {
16pub fn create(owner: *std.Build, artifact: *CompileStep) *InstallArtifactStep {
1717 if (artifact.install_step) |s| return s;
1818
19 const self = builder.allocator.create(InstallArtifactStep) catch @panic("OOM");
19 const self = owner.allocator.create(InstallArtifactStep) catch @panic("OOM");
2020 self.* = InstallArtifactStep{
21 .builder = builder,
22 .step = Step.init(builder.allocator, .{
21 .step = Step.init(.{
2322 .id = base_id,
24 .name = builder.fmt("install {s}", .{artifact.name}),
23 .name = owner.fmt("install {s}", .{artifact.name}),
24 .owner = owner,
2525 .makeFn = make,
2626 }),
27 .dest_builder = owner,
2728 .artifact = artifact,
2829 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
2930 .obj => @panic("Cannot install a .obj build artifact."),
......@@ -43,48 +44,52 @@ pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep
4344 self.step.dependOn(&artifact.step);
4445 artifact.install_step = self;
4546
46 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);
47 owner.pushInstalledFile(self.dest_dir, artifact.out_filename);
4748 if (self.artifact.isDynamicLibrary()) {
4849 if (artifact.major_only_filename) |name| {
49 builder.pushInstalledFile(.lib, name);
50 owner.pushInstalledFile(.lib, name);
5051 }
5152 if (artifact.name_only_filename) |name| {
52 builder.pushInstalledFile(.lib, name);
53 owner.pushInstalledFile(.lib, name);
5354 }
5455 if (self.artifact.target.isWindows()) {
55 builder.pushInstalledFile(.lib, artifact.out_lib_filename);
56 owner.pushInstalledFile(.lib, artifact.out_lib_filename);
5657 }
5758 }
5859 if (self.pdb_dir) |pdb_dir| {
59 builder.pushInstalledFile(pdb_dir, artifact.out_pdb_filename);
60 owner.pushInstalledFile(pdb_dir, artifact.out_pdb_filename);
6061 }
6162 if (self.h_dir) |h_dir| {
62 builder.pushInstalledFile(h_dir, artifact.out_h_filename);
63 owner.pushInstalledFile(h_dir, artifact.out_h_filename);
6364 }
6465 return self;
6566}
6667
6768fn make(step: *Step, prog_node: *std.Progress.Node) !void {
6869 _ = prog_node;
70 const src_builder = step.owner;
6971 const self = @fieldParentPtr(InstallArtifactStep, "step", step);
70 const builder = self.builder;
72 const dest_builder = self.dest_builder;
7173
72 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
73 try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path);
74 const full_dest_path = dest_builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
75 try src_builder.updateFile(
76 self.artifact.getOutputSource().getPath(src_builder),
77 full_dest_path,
78 );
7479 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {
75 try CompileStep.doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
80 try CompileStep.doAtomicSymLinks(src_builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
7681 }
7782 if (self.artifact.isDynamicLibrary() and self.artifact.target.isWindows() and self.artifact.emit_implib != .no_emit) {
78 const full_implib_path = builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename);
79 try builder.updateFile(self.artifact.getOutputLibSource().getPath(builder), full_implib_path);
83 const full_implib_path = dest_builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename);
84 try src_builder.updateFile(self.artifact.getOutputLibSource().getPath(src_builder), full_implib_path);
8085 }
8186 if (self.pdb_dir) |pdb_dir| {
82 const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename);
83 try builder.updateFile(self.artifact.getOutputPdbSource().getPath(builder), full_pdb_path);
87 const full_pdb_path = dest_builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename);
88 try src_builder.updateFile(self.artifact.getOutputPdbSource().getPath(src_builder), full_pdb_path);
8489 }
8590 if (self.h_dir) |h_dir| {
86 const full_h_path = builder.getInstallPath(h_dir, self.artifact.out_h_filename);
87 try builder.updateFile(self.artifact.getOutputHSource().getPath(builder), full_h_path);
91 const full_h_path = dest_builder.getInstallPath(h_dir, self.artifact.out_h_filename);
92 try src_builder.updateFile(self.artifact.getOutputHSource().getPath(src_builder), full_h_path);
8893 }
8994 self.artifact.installed_path = full_dest_path;
9095}
lib/std/Build/InstallDirStep.zig+16-18
......@@ -7,11 +7,10 @@ const InstallDirStep = @This();
77const log = std.log;
88
99step: Step,
10builder: *std.Build,
1110options: Options,
1211/// This is used by the build system when a file being installed comes from one
1312/// package but is being installed by another.
14override_source_builder: ?*std.Build = null,
13dest_builder: *std.Build,
1514
1615pub const base_id = .install_dir;
1716
......@@ -40,27 +39,26 @@ pub const Options = struct {
4039 }
4140};
4241
43pub fn init(
44 builder: *std.Build,
45 options: Options,
46) InstallDirStep {
47 builder.pushInstalledFile(options.install_dir, options.install_subdir);
42pub fn init(owner: *std.Build, options: Options) InstallDirStep {
43 owner.pushInstalledFile(options.install_dir, options.install_subdir);
4844 return .{
49 .builder = builder,
50 .step = Step.init(builder.allocator, .{
45 .step = Step.init(.{
5146 .id = .install_dir,
52 .name = builder.fmt("install {s}/", .{options.source_dir}),
47 .name = owner.fmt("install {s}/", .{options.source_dir}),
48 .owner = owner,
5349 .makeFn = make,
5450 }),
55 .options = options.dupe(builder),
51 .options = options.dupe(owner),
52 .dest_builder = owner,
5653 };
5754}
5855
5956fn make(step: *Step, prog_node: *std.Progress.Node) !void {
6057 _ = prog_node;
6158 const self = @fieldParentPtr(InstallDirStep, "step", step);
62 const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
63 const src_builder = self.override_source_builder orelse self.builder;
59 const dest_builder = self.dest_builder;
60 const dest_prefix = dest_builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
61 const src_builder = self.step.owner;
6462 const full_src_dir = src_builder.pathFromRoot(self.options.source_dir);
6563 var src_dir = std.fs.cwd().openIterableDir(full_src_dir, .{}) catch |err| {
6664 log.err("InstallDirStep: unable to open source directory '{s}': {s}", .{
......@@ -69,7 +67,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
6967 return error.StepFailed;
7068 };
7169 defer src_dir.close();
72 var it = try src_dir.walk(self.builder.allocator);
70 var it = try src_dir.walk(dest_builder.allocator);
7371 next_entry: while (try it.next()) |entry| {
7472 for (self.options.exclude_extensions) |ext| {
7573 if (mem.endsWith(u8, entry.path, ext)) {
......@@ -77,20 +75,20 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
7775 }
7876 }
7977
80 const full_path = self.builder.pathJoin(&.{ full_src_dir, entry.path });
81 const dest_path = self.builder.pathJoin(&.{ dest_prefix, entry.path });
78 const full_path = dest_builder.pathJoin(&.{ full_src_dir, entry.path });
79 const dest_path = dest_builder.pathJoin(&.{ dest_prefix, entry.path });
8280
8381 switch (entry.kind) {
8482 .Directory => try fs.cwd().makePath(dest_path),
8583 .File => {
8684 for (self.options.blank_extensions) |ext| {
8785 if (mem.endsWith(u8, entry.path, ext)) {
88 try self.builder.truncateFile(dest_path);
86 try dest_builder.truncateFile(dest_path);
8987 continue :next_entry;
9088 }
9189 }
9290
93 try self.builder.updateFile(full_path, dest_path);
91 try dest_builder.updateFile(full_path, dest_path);
9492 },
9593 else => continue,
9694 }
lib/std/Build/InstallFileStep.zig+15-14
......@@ -7,39 +7,40 @@ const InstallFileStep = @This();
77pub const base_id = .install_file;
88
99step: Step,
10builder: *std.Build,
1110source: FileSource,
1211dir: InstallDir,
1312dest_rel_path: []const u8,
1413/// This is used by the build system when a file being installed comes from one
1514/// package but is being installed by another.
16override_source_builder: ?*std.Build = null,
15dest_builder: *std.Build,
1716
1817pub fn init(
19 builder: *std.Build,
18 owner: *std.Build,
2019 source: FileSource,
2120 dir: InstallDir,
2221 dest_rel_path: []const u8,
2322) InstallFileStep {
24 builder.pushInstalledFile(dir, dest_rel_path);
23 owner.pushInstalledFile(dir, dest_rel_path);
2524 return InstallFileStep{
26 .builder = builder,
27 .step = Step.init(builder.allocator, .{
28 .id = .install_file,
29 .name = builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }),
25 .step = Step.init(.{
26 .id = base_id,
27 .name = owner.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }),
28 .owner = owner,
3029 .makeFn = make,
3130 }),
32 .source = source.dupe(builder),
33 .dir = dir.dupe(builder),
34 .dest_rel_path = builder.dupePath(dest_rel_path),
31 .source = source.dupe(owner),
32 .dir = dir.dupe(owner),
33 .dest_rel_path = owner.dupePath(dest_rel_path),
34 .dest_builder = owner,
3535 };
3636}
3737
3838fn make(step: *Step, prog_node: *std.Progress.Node) !void {
3939 _ = prog_node;
40 const src_builder = step.owner;
4041 const self = @fieldParentPtr(InstallFileStep, "step", step);
41 const src_builder = self.override_source_builder orelse self.builder;
42 const dest_builder = self.dest_builder;
4243 const full_src_path = self.source.getPath2(src_builder, step);
43 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);
44 try self.builder.updateFile(full_src_path, full_dest_path);
44 const full_dest_path = dest_builder.getInstallPath(self.dir, self.dest_rel_path);
45 try dest_builder.updateFile(full_src_path, full_dest_path);
4546}
lib/std/Build/LogStep.zig deleted-28
......@@ -1,28 +0,0 @@
1const std = @import("../std.zig");
2const log = std.log;
3const Step = std.Build.Step;
4const LogStep = @This();
5
6pub const base_id = .log;
7
8step: Step,
9builder: *std.Build,
10data: []const u8,
11
12pub fn init(builder: *std.Build, data: []const u8) LogStep {
13 return LogStep{
14 .builder = builder,
15 .step = Step.init(builder.allocator, .{
16 .id = .log,
17 .name = builder.fmt("log {s}", .{data}),
18 .makeFn = make,
19 }),
20 .data = builder.dupe(data),
21 };
22}
23
24fn make(step: *Step, prog_node: *std.Progress.Node) anyerror!void {
25 _ = prog_node;
26 const self = @fieldParentPtr(LogStep, "step", step);
27 log.info("{s}", .{self.data});
28}
lib/std/Build/ObjCopyStep.zig+8-25
......@@ -21,7 +21,6 @@ pub const RawFormat = enum {
2121};
2222
2323step: Step,
24builder: *std.Build,
2524file_source: std.Build.FileSource,
2625basename: []const u8,
2726output_file: std.Build.GeneratedFile,
......@@ -38,18 +37,18 @@ pub const Options = struct {
3837};
3938
4039pub fn create(
41 builder: *std.Build,
40 owner: *std.Build,
4241 file_source: std.Build.FileSource,
4342 options: Options,
4443) *ObjCopyStep {
45 const self = builder.allocator.create(ObjCopyStep) catch @panic("OOM");
44 const self = owner.allocator.create(ObjCopyStep) catch @panic("OOM");
4645 self.* = ObjCopyStep{
47 .step = Step.init(builder.allocator, .{
46 .step = Step.init(.{
4847 .id = base_id,
49 .name = builder.fmt("objcopy {s}", .{file_source.getDisplayName()}),
48 .name = owner.fmt("objcopy {s}", .{file_source.getDisplayName()}),
49 .owner = owner,
5050 .makeFn = make,
5151 }),
52 .builder = builder,
5352 .file_source = file_source,
5453 .basename = options.basename orelse file_source.getDisplayName(),
5554 .output_file = std.Build.GeneratedFile{ .step = &self.step },
......@@ -67,9 +66,8 @@ pub fn getOutputSource(self: *const ObjCopyStep) std.Build.FileSource {
6766}
6867
6968fn make(step: *Step, prog_node: *std.Progress.Node) !void {
70 _ = prog_node;
69 const b = step.owner;
7170 const self = @fieldParentPtr(ObjCopyStep, "step", step);
72 const b = self.builder;
7371
7472 var man = b.cache.obtain();
7573 defer man.deinit();
......@@ -84,7 +82,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
8482 man.hash.addOptional(self.pad_to);
8583 man.hash.addOptional(self.format);
8684
87 if (man.hit() catch |err| failWithCacheError(man, err)) {
85 if (try step.cacheHit(&man)) {
8886 // Cache hit, skip subprocess execution.
8987 const digest = man.final();
9088 self.output_file.path = try b.cache_root.join(b.allocator, &.{
......@@ -116,23 +114,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
116114 };
117115
118116 try argv.appendSlice(&.{ full_src_path, full_dest_path });
119 _ = try self.builder.execFromStep(argv.items, &self.step);
117 _ = try step.spawnZigProcess(argv.items, prog_node);
120118
121119 self.output_file.path = full_dest_path;
122120 try man.writeManifest();
123121}
124
125/// TODO consolidate this with the same function in RunStep?
126/// Also properly deal with concurrency (see open PR)
127fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
128 const i = man.failed_file_index orelse failWithSimpleError(err);
129 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
130 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
131 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
132 std.process.exit(1);
133}
134
135fn failWithSimpleError(err: anyerror) noreturn {
136 std.debug.print("{s}\n", .{@errorName(err)});
137 std.process.exit(1);
138}
lib/std/Build/OptionsStep.zig+17-17
......@@ -12,25 +12,24 @@ pub const base_id = .options;
1212
1313step: Step,
1414generated_file: GeneratedFile,
15builder: *std.Build,
1615
1716contents: std.ArrayList(u8),
1817artifact_args: std.ArrayList(OptionArtifactArg),
1918file_source_args: std.ArrayList(OptionFileSourceArg),
2019
21pub fn create(builder: *std.Build) *OptionsStep {
22 const self = builder.allocator.create(OptionsStep) catch @panic("OOM");
20pub fn create(owner: *std.Build) *OptionsStep {
21 const self = owner.allocator.create(OptionsStep) catch @panic("OOM");
2322 self.* = .{
24 .builder = builder,
25 .step = Step.init(builder.allocator, .{
23 .step = Step.init(.{
2624 .id = base_id,
2725 .name = "options",
26 .owner = owner,
2827 .makeFn = make,
2928 }),
3029 .generated_file = undefined,
31 .contents = std.ArrayList(u8).init(builder.allocator),
32 .artifact_args = std.ArrayList(OptionArtifactArg).init(builder.allocator),
33 .file_source_args = std.ArrayList(OptionFileSourceArg).init(builder.allocator),
30 .contents = std.ArrayList(u8).init(owner.allocator),
31 .artifact_args = std.ArrayList(OptionArtifactArg).init(owner.allocator),
32 .file_source_args = std.ArrayList(OptionFileSourceArg).init(owner.allocator),
3433 };
3534 self.generated_file = .{ .step = &self.step };
3635
......@@ -196,7 +195,7 @@ pub fn addOptionFileSource(
196195) void {
197196 self.file_source_args.append(.{
198197 .name = name,
199 .source = source.dupe(self.builder),
198 .source = source.dupe(self.step.owner),
200199 }) catch @panic("OOM");
201200 source.addStepDependencies(&self.step);
202201}
......@@ -204,12 +203,12 @@ pub fn addOptionFileSource(
204203/// The value is the path in the cache dir.
205204/// Adds a dependency automatically.
206205pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *CompileStep) void {
207 self.artifact_args.append(.{ .name = self.builder.dupe(name), .artifact = artifact }) catch @panic("OOM");
206 self.artifact_args.append(.{ .name = self.step.owner.dupe(name), .artifact = artifact }) catch @panic("OOM");
208207 self.step.dependOn(&artifact.step);
209208}
210209
211210pub fn createModule(self: *OptionsStep) *std.Build.Module {
212 return self.builder.createModule(.{
211 return self.step.owner.createModule(.{
213212 .source_file = self.getSource(),
214213 .dependencies = &.{},
215214 });
......@@ -220,14 +219,17 @@ pub fn getSource(self: *OptionsStep) FileSource {
220219}
221220
222221fn make(step: *Step, prog_node: *std.Progress.Node) !void {
222 // This step completes so quickly that no progress is necessary.
223223 _ = prog_node;
224
225 const b = step.owner;
224226 const self = @fieldParentPtr(OptionsStep, "step", step);
225227
226228 for (self.artifact_args.items) |item| {
227229 self.addOption(
228230 []const u8,
229231 item.name,
230 self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)),
232 b.pathFromRoot(item.artifact.getOutputSource().getPath(b)),
231233 );
232234 }
233235
......@@ -235,20 +237,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
235237 self.addOption(
236238 []const u8,
237239 item.name,
238 item.source.getPath(self.builder),
240 item.source.getPath(b),
239241 );
240242 }
241243
242 var options_dir = try self.builder.cache_root.handle.makeOpenPath("options", .{});
244 var options_dir = try b.cache_root.handle.makeOpenPath("options", .{});
243245 defer options_dir.close();
244246
245247 const basename = self.hashContentsToFileName();
246248
247249 try options_dir.writeFile(&basename, self.contents.items);
248250
249 self.generated_file.path = try self.builder.cache_root.join(self.builder.allocator, &.{
250 "options", &basename,
251 });
251 self.generated_file.path = try b.cache_root.join(b.allocator, &.{ "options", &basename });
252252}
253253
254254fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
lib/std/Build/RemoveDirStep.zig+19-10
......@@ -7,28 +7,37 @@ const RemoveDirStep = @This();
77pub const base_id = .remove_dir;
88
99step: Step,
10builder: *std.Build,
1110dir_path: []const u8,
1211
13pub fn init(builder: *std.Build, dir_path: []const u8) RemoveDirStep {
12pub fn init(owner: *std.Build, dir_path: []const u8) RemoveDirStep {
1413 return RemoveDirStep{
15 .builder = builder,
16 .step = Step.init(builder.allocator, .{
14 .step = Step.init(.{
1715 .id = .remove_dir,
18 .name = builder.fmt("RemoveDir {s}", .{dir_path}),
16 .name = owner.fmt("RemoveDir {s}", .{dir_path}),
17 .owner = owner,
1918 .makeFn = make,
2019 }),
21 .dir_path = builder.dupePath(dir_path),
20 .dir_path = owner.dupePath(dir_path),
2221 };
2322}
2423
2524fn make(step: *Step, prog_node: *std.Progress.Node) !void {
25 // TODO update progress node while walking file system.
26 // Should the standard library support this use case??
2627 _ = prog_node;
28
29 const b = step.owner;
2730 const self = @fieldParentPtr(RemoveDirStep, "step", step);
2831
29 const full_path = self.builder.pathFromRoot(self.dir_path);
30 fs.cwd().deleteTree(full_path) catch |err| {
31 log.err("Unable to remove {s}: {s}", .{ full_path, @errorName(err) });
32 return err;
32 b.build_root.handle.deleteTree(self.dir_path) catch |err| {
33 if (b.build_root.path) |base| {
34 return step.fail("unable to recursively delete path '{s}/{s}': {s}", .{
35 base, self.dir_path, @errorName(err),
36 });
37 } else {
38 return step.fail("unable to recursively delete path '{s}': {s}", .{
39 self.dir_path, @errorName(err),
40 });
41 }
3342 };
3443}
lib/std/Build/RunStep.zig+295-216
......@@ -11,14 +11,11 @@ const EnvMap = process.EnvMap;
1111const Allocator = mem.Allocator;
1212const ExecError = std.Build.ExecError;
1313
14const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
15
1614const RunStep = @This();
1715
1816pub const base_id: Step.Id = .run;
1917
2018step: Step,
21builder: *std.Build,
2219
2320/// See also addArg and addArgs to modifying this directly
2421argv: ArrayList(Arg),
......@@ -29,35 +26,68 @@ cwd: ?[]const u8,
2926/// Override this field to modify the environment, or use setEnvironmentVariable
3027env_map: ?*EnvMap,
3128
32stdout_action: StdIoAction = .inherit,
33stderr_action: StdIoAction = .inherit,
34
35stdin_behavior: std.ChildProcess.StdIo = .Inherit,
36
37/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution
38expected_term: ?std.ChildProcess.Term = .{ .Exited = 0 },
39
40/// Print the command before running it
41print: bool,
42/// Controls whether execution is skipped if the output file is up-to-date.
43/// The default is to always run if there is no output file, and to skip
44/// running if all output files are up-to-date.
45condition: enum { output_outdated, always } = .output_outdated,
29/// Configures whether the RunStep is considered to have side-effects, and also
30/// whether the RunStep will inherit stdio streams, forwarding them to the
31/// parent process, in which case will require a global lock to prevent other
32/// steps from interfering with stdio while the subprocess associated with this
33/// RunStep is running.
34/// If the RunStep is determined to not have side-effects, then execution will
35/// be skipped if all output files are up-to-date and input files are
36/// unchanged.
37stdio: StdIo = .infer_from_args,
4638
4739/// Additional file paths relative to build.zig that, when modified, indicate
4840/// that the RunStep should be re-executed.
41/// If the RunStep is determined to have side-effects, this field is ignored
42/// and the RunStep is always executed when it appears in the build graph.
4943extra_file_dependencies: []const []const u8 = &.{},
5044
5145/// After adding an output argument, this step will by default rename itself
5246/// for a better display name in the build summary.
5347/// This can be disabled by setting this to false.
54rename_step_with_output_arg: bool,
55
56pub const StdIoAction = union(enum) {
48rename_step_with_output_arg: bool = true,
49
50/// If this is true, a RunStep which is configured to check the output of the
51/// executed binary will not fail the build if the binary cannot be executed
52/// due to being for a foreign binary to the host system which is running the
53/// build graph.
54/// Command-line arguments such as -fqemu and -fwasmtime may affect whether a
55/// binary is detected as foreign, as well as system configuration such as
56/// Rosetta (macOS) and binfmt_misc (Linux).
57skip_foreign_checks: bool = false,
58
59/// If stderr or stdout exceeds this amount, the child process is killed and
60/// the step fails.
61max_stdio_size: usize = 10 * 1024 * 1024,
62
63pub const StdIo = union(enum) {
64 /// Whether the RunStep has side-effects will be determined by whether or not one
65 /// of the args is an output file (added with `addOutputFileArg`).
66 /// If the RunStep is determined to have side-effects, this is the same as `inherit`.
67 /// The step will fail if the subprocess crashes or returns a non-zero exit code.
68 infer_from_args,
69 /// Causes the RunStep to be considered to have side-effects, and therefore
70 /// always execute when it appears in the build graph.
71 /// It also means that this step will obtain a global lock to prevent other
72 /// steps from running in the meantime.
73 /// The step will fail if the subprocess crashes or returns a non-zero exit code.
5774 inherit,
58 ignore,
59 expect_exact: []const u8,
60 expect_matches: []const []const u8,
75 /// Causes the RunStep to be considered to *not* have side-effects. The
76 /// process will be re-executed if any of the input dependencies are
77 /// modified. The exit code and standard I/O streams will be checked for
78 /// certain conditions, and the step will succeed or fail based on these
79 /// conditions.
80 /// Note that an explicit check for exit code 0 needs to be added to this
81 /// list if such a check is desireable.
82 check: []const Check,
83
84 pub const Check = union(enum) {
85 expect_stderr_exact: []const u8,
86 expect_stderr_match: []const u8,
87 expect_stdout_exact: []const u8,
88 expect_stdout_match: []const u8,
89 expect_term: std.ChildProcess.Term,
90 };
6191};
6292
6393pub const Arg = union(enum) {
......@@ -72,20 +102,20 @@ pub const Arg = union(enum) {
72102 };
73103};
74104
75pub fn create(builder: *std.Build, name: []const u8) *RunStep {
76 const self = builder.allocator.create(RunStep) catch @panic("OOM");
105pub fn create(owner: *std.Build, name: []const u8) *RunStep {
106 const self = owner.allocator.create(RunStep) catch @panic("OOM");
77107 self.* = .{
78 .builder = builder,
79 .step = Step.init(builder.allocator, .{
108 .step = Step.init(.{
80109 .id = base_id,
81110 .name = name,
111 .owner = owner,
82112 .makeFn = make,
83113 }),
84 .argv = ArrayList(Arg).init(builder.allocator),
114 .argv = ArrayList(Arg).init(owner.allocator),
85115 .cwd = null,
86116 .env_map = null,
87 .print = builder.verbose,
88117 .rename_step_with_output_arg = true,
118 .max_stdio_size = 10 * 1024 * 1024,
89119 };
90120 return self;
91121}
......@@ -99,16 +129,17 @@ pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void {
99129/// run, and returns a FileSource which can be used as inputs to other APIs
100130/// throughout the build system.
101131pub fn addOutputFileArg(rs: *RunStep, basename: []const u8) std.Build.FileSource {
102 const generated_file = rs.builder.allocator.create(std.Build.GeneratedFile) catch @panic("OOM");
132 const b = rs.step.owner;
133 const generated_file = b.allocator.create(std.Build.GeneratedFile) catch @panic("OOM");
103134 generated_file.* = .{ .step = &rs.step };
104135 rs.argv.append(.{ .output = .{
105136 .generated_file = generated_file,
106 .basename = rs.builder.dupe(basename),
137 .basename = b.dupe(basename),
107138 } }) catch @panic("OOM");
108139
109140 if (rs.rename_step_with_output_arg) {
110141 rs.rename_step_with_output_arg = false;
111 rs.step.name = rs.builder.fmt("{s} ({s})", .{ rs.step.name, basename });
142 rs.step.name = b.fmt("{s} ({s})", .{ rs.step.name, basename });
112143 }
113144
114145 return .{ .generated = generated_file };
......@@ -116,13 +147,13 @@ pub fn addOutputFileArg(rs: *RunStep, basename: []const u8) std.Build.FileSource
116147
117148pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void {
118149 self.argv.append(Arg{
119 .file_source = file_source.dupe(self.builder),
150 .file_source = file_source.dupe(self.step.owner),
120151 }) catch @panic("OOM");
121152 file_source.addStepDependencies(&self.step);
122153}
123154
124155pub fn addArg(self: *RunStep, arg: []const u8) void {
125 self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch @panic("OOM");
156 self.argv.append(Arg{ .bytes = self.step.owner.dupe(arg) }) catch @panic("OOM");
126157}
127158
128159pub fn addArgs(self: *RunStep, args: []const []const u8) void {
......@@ -132,13 +163,14 @@ pub fn addArgs(self: *RunStep, args: []const []const u8) void {
132163}
133164
134165pub fn clearEnvironment(self: *RunStep) void {
135 const new_env_map = self.builder.allocator.create(EnvMap) catch @panic("OOM");
136 new_env_map.* = EnvMap.init(self.builder.allocator);
166 const b = self.step.owner;
167 const new_env_map = b.allocator.create(EnvMap) catch @panic("OOM");
168 new_env_map.* = EnvMap.init(b.allocator);
137169 self.env_map = new_env_map;
138170}
139171
140172pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
141 addPathDirInternal(&self.step, self.builder, search_path);
173 addPathDirInternal(&self.step, self.step.owner, search_path);
142174}
143175
144176/// For internal use only, users of `RunStep` should use `addPathDir` directly.
......@@ -157,13 +189,12 @@ pub fn addPathDirInternal(step: *Step, builder: *std.Build, search_path: []const
157189}
158190
159191pub fn getEnvMap(self: *RunStep) *EnvMap {
160 return getEnvMapInternal(&self.step, self.builder.allocator);
192 return getEnvMapInternal(&self.step, self.step.owner.allocator);
161193}
162194
163195fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap {
164196 const maybe_env_map = switch (step.id) {
165197 .run => step.cast(RunStep).?.env_map,
166 .emulatable_run => step.cast(std.Build.EmulatableRunStep).?.env_map,
167198 else => unreachable,
168199 };
169200 return maybe_env_map orelse {
......@@ -171,7 +202,6 @@ fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap {
171202 env_map.* = process.getEnvMap(allocator) catch @panic("unhandled error");
172203 switch (step.id) {
173204 .run => step.cast(RunStep).?.env_map = env_map,
174 .emulatable_run => step.cast(RunStep).?.env_map = env_map,
175205 else => unreachable,
176206 }
177207 return env_map;
......@@ -179,41 +209,85 @@ fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap {
179209}
180210
181211pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void {
212 const b = self.step.owner;
182213 const env_map = self.getEnvMap();
183 env_map.put(
184 self.builder.dupe(key),
185 self.builder.dupe(value),
186 ) catch @panic("unhandled error");
214 env_map.put(b.dupe(key), b.dupe(value)) catch @panic("unhandled error");
187215}
188216
189217pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void {
190 self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
218 const new_check: StdIo.Check = .{ .expect_stderr_exact = self.step.owner.dupe(bytes) };
219 self.addCheck(new_check);
191220}
192221
193222pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void {
194 self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
223 const new_check: StdIo.Check = .{ .expect_stdout_exact = self.step.owner.dupe(bytes) };
224 self.addCheck(new_check);
195225}
196226
197fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
198 return switch (action) {
199 .ignore => .Ignore,
200 .inherit => .Inherit,
201 .expect_exact, .expect_matches => .Pipe,
202 };
227pub fn expectExitCode(self: *RunStep, code: u8) void {
228 const new_check: StdIo.Check = .{ .expect_term = .{ .Exited = code } };
229 self.addCheck(new_check);
203230}
204231
205fn needOutputCheck(self: RunStep) bool {
206 switch (self.condition) {
207 .always => return false,
208 .output_outdated => {},
232pub fn addCheck(self: *RunStep, new_check: StdIo.Check) void {
233 const arena = self.step.owner.allocator;
234 switch (self.stdio) {
235 .infer_from_args => {
236 const list = arena.create([1]StdIo.Check) catch @panic("OOM");
237 list.* = .{new_check};
238 self.stdio = .{ .check = list };
239 },
240 .check => |checks| {
241 const new_list = arena.alloc(StdIo.Check, checks.len + 1) catch @panic("OOM");
242 std.mem.copy(StdIo.Check, new_list, checks);
243 new_list[checks.len] = new_check;
244 },
245 else => @panic("illegal call to addCheck: conflicting helper method calls. Suggest to directly set stdio field of RunStep instead"),
209246 }
210 if (self.extra_file_dependencies.len > 0) return true;
247}
248
249/// Returns whether the RunStep has side effects *other than* updating the output arguments.
250fn hasSideEffects(self: RunStep) bool {
251 return switch (self.stdio) {
252 .infer_from_args => !self.hasAnyOutputArgs(),
253 .inherit => true,
254 .check => false,
255 };
256}
211257
258fn hasAnyOutputArgs(self: RunStep) bool {
212259 for (self.argv.items) |arg| switch (arg) {
213260 .output => return true,
214261 else => continue,
215262 };
263 return false;
264}
216265
266fn checksContainStdout(checks: []const StdIo.Check) bool {
267 for (checks) |check| switch (check) {
268 .expect_stderr_exact,
269 .expect_stderr_match,
270 .expect_term,
271 => continue,
272
273 .expect_stdout_exact,
274 .expect_stdout_match,
275 => return true,
276 };
277 return false;
278}
279
280fn checksContainStderr(checks: []const StdIo.Check) bool {
281 for (checks) |check| switch (check) {
282 .expect_stdout_exact,
283 .expect_stdout_match,
284 .expect_term,
285 => continue,
286
287 .expect_stderr_exact,
288 .expect_stderr_match,
289 => return true,
290 };
217291 return false;
218292}
219293
......@@ -223,16 +297,17 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
223297 // processes could use to supply progress updates.
224298 _ = prog_node;
225299
300 const b = step.owner;
226301 const self = @fieldParentPtr(RunStep, "step", step);
227 const need_output_check = self.needOutputCheck();
302 const has_side_effects = self.hasSideEffects();
228303
229 var argv_list = ArrayList([]const u8).init(self.builder.allocator);
304 var argv_list = ArrayList([]const u8).init(b.allocator);
230305 var output_placeholders = ArrayList(struct {
231306 index: usize,
232307 output: Arg.Output,
233 }).init(self.builder.allocator);
308 }).init(b.allocator);
234309
235 var man = self.builder.cache.obtain();
310 var man = b.cache.obtain();
236311 defer man.deinit();
237312
238313 for (self.argv.items) |arg| {
......@@ -242,7 +317,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
242317 man.hash.addBytes(bytes);
243318 },
244319 .file_source => |file| {
245 const file_path = file.getPath(self.builder);
320 const file_path = file.getPath(b);
246321 try argv_list.append(file_path);
247322 _ = try man.addFile(file_path, null);
248323 },
......@@ -252,7 +327,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
252327 self.addPathForDynLibs(artifact);
253328 }
254329 const file_path = artifact.installed_path orelse
255 artifact.getOutputSource().getPath(self.builder);
330 artifact.getOutputSource().getPath(b);
256331
257332 try argv_list.append(file_path);
258333
......@@ -272,17 +347,17 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
272347 }
273348 }
274349
275 if (need_output_check) {
350 if (!has_side_effects) {
276351 for (self.extra_file_dependencies) |file_path| {
277 _ = try man.addFile(self.builder.pathFromRoot(file_path), null);
352 _ = try man.addFile(b.pathFromRoot(file_path), null);
278353 }
279354
280 if (man.hit() catch |err| failWithCacheError(man, err)) {
355 if (try step.cacheHit(&man)) {
281356 // cache hit, skip running command
282357 const digest = man.final();
283358 for (output_placeholders.items) |placeholder| {
284 placeholder.output.generated_file.path = try self.builder.cache_root.join(
285 self.builder.allocator,
359 placeholder.output.generated_file.path = try b.cache_root.join(
360 b.allocator,
286361 &.{ "o", &digest, placeholder.output.basename },
287362 );
288363 }
......@@ -292,8 +367,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
292367 const digest = man.final();
293368
294369 for (output_placeholders.items) |placeholder| {
295 const output_path = try self.builder.cache_root.join(
296 self.builder.allocator,
370 const output_path = try b.cache_root.join(
371 b.allocator,
297372 &.{ "o", &digest, placeholder.output.basename },
298373 );
299374 const output_dir = fs.path.dirname(output_path).?;
......@@ -308,18 +383,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
308383 }
309384
310385 try runCommand(
386 step,
387 self.cwd,
311388 argv_list.items,
312 self.builder,
313 self.expected_term,
314 self.stdout_action,
315 self.stderr_action,
316 self.stdin_behavior,
317389 self.env_map,
318 self.cwd,
319 self.print,
390 self.stdio,
391 has_side_effects,
392 self.max_stdio_size,
320393 );
321394
322 if (need_output_check) {
395 if (!has_side_effects) {
323396 try man.writeManifest();
324397 }
325398}
......@@ -369,165 +442,171 @@ fn termMatches(expected: ?std.ChildProcess.Term, actual: std.ChildProcess.Term)
369442 };
370443}
371444
372pub fn runCommand(
445fn runCommand(
446 step: *Step,
447 opt_cwd: ?[]const u8,
373448 argv: []const []const u8,
374 builder: *std.Build,
375 expected_term: ?std.ChildProcess.Term,
376 stdout_action: StdIoAction,
377 stderr_action: StdIoAction,
378 stdin_behavior: std.ChildProcess.StdIo,
379449 env_map: ?*EnvMap,
380 maybe_cwd: ?[]const u8,
381 print: bool,
450 stdio: StdIo,
451 has_side_effects: bool,
452 max_stdio_size: usize,
382453) !void {
383 const cwd = if (maybe_cwd) |cwd| builder.pathFromRoot(cwd) else builder.build_root.path;
384
385 if (!std.process.can_spawn) {
386 const cmd = try std.mem.join(builder.allocator, " ", argv);
387 std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
388 @tagName(builtin.os.tag), cmd,
389 });
390 builder.allocator.free(cmd);
391 return ExecError.ExecNotSupported;
392 }
454 const b = step.owner;
455 const arena = b.allocator;
456 const cwd = if (opt_cwd) |cwd| b.pathFromRoot(cwd) else b.build_root.path;
393457
394 var child = std.ChildProcess.init(argv, builder.allocator);
395 child.cwd = cwd;
396 child.env_map = env_map orelse builder.env_map;
458 try step.handleChildProcUnsupported(opt_cwd, argv);
459 try Step.handleVerbose(step.owner, opt_cwd, argv);
397460
398 child.stdin_behavior = stdin_behavior;
399 child.stdout_behavior = stdIoActionToBehavior(stdout_action);
400 child.stderr_behavior = stdIoActionToBehavior(stderr_action);
401
402 if (print)
403 printCmd(cwd, argv);
461 var child = std.ChildProcess.init(argv, arena);
462 child.cwd = cwd;
463 child.env_map = env_map orelse b.env_map;
404464
405 child.spawn() catch |err| {
406 std.debug.print("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
407 return err;
465 child.stdin_behavior = switch (stdio) {
466 .infer_from_args => if (has_side_effects) .Inherit else .Ignore,
467 .inherit => .Inherit,
468 .check => .Close,
469 };
470 child.stdout_behavior = switch (stdio) {
471 .infer_from_args => if (has_side_effects) .Inherit else .Ignore,
472 .inherit => .Inherit,
473 .check => |checks| if (checksContainStdout(checks)) .Pipe else .Ignore,
474 };
475 child.stderr_behavior = switch (stdio) {
476 .infer_from_args => if (has_side_effects) .Inherit else .Pipe,
477 .inherit => .Inherit,
478 .check => .Pipe,
408479 };
409480
410 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
411
412 var stdout: ?[]const u8 = null;
413 defer if (stdout) |s| builder.allocator.free(s);
481 child.spawn() catch |err| return step.fail("unable to spawn {s}: {s}", .{
482 argv[0], @errorName(err),
483 });
484
485 var stdout_bytes: ?[]const u8 = null;
486 var stderr_bytes: ?[]const u8 = null;
487
488 if (child.stdout) |stdout| {
489 if (child.stderr) |stderr| {
490 var poller = std.io.poll(arena, enum { stdout, stderr }, .{
491 .stdout = stdout,
492 .stderr = stderr,
493 });
494 defer poller.deinit();
495
496 while (try poller.poll()) {
497 if (poller.fifo(.stdout).count > max_stdio_size)
498 return error.StdoutStreamTooLong;
499 if (poller.fifo(.stderr).count > max_stdio_size)
500 return error.StderrStreamTooLong;
501 }
414502
415 switch (stdout_action) {
416 .expect_exact, .expect_matches => {
417 stdout = try child.stdout.?.reader().readAllAlloc(builder.allocator, max_stdout_size);
418 },
419 .inherit, .ignore => {},
503 stdout_bytes = try poller.fifo(.stdout).toOwnedSlice();
504 stderr_bytes = try poller.fifo(.stderr).toOwnedSlice();
505 } else {
506 stdout_bytes = try stdout.reader().readAllAlloc(arena, max_stdio_size);
507 }
508 } else if (child.stderr) |stderr| {
509 stderr_bytes = try stderr.reader().readAllAlloc(arena, max_stdio_size);
420510 }
421511
422 var stderr: ?[]const u8 = null;
423 defer if (stderr) |s| builder.allocator.free(s);
424
425 switch (stderr_action) {
426 .expect_exact, .expect_matches => {
427 stderr = try child.stderr.?.reader().readAllAlloc(builder.allocator, max_stdout_size);
428 },
429 .inherit, .ignore => {},
430 }
512 if (stderr_bytes) |stderr| if (stderr.len > 0) {
513 const stderr_is_diagnostic = switch (stdio) {
514 .check => |checks| !checksContainStderr(checks),
515 else => true,
516 };
517 if (stderr_is_diagnostic) {
518 try step.result_error_msgs.append(arena, stderr);
519 }
520 };
431521
432522 const term = child.wait() catch |err| {
433 std.debug.print("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
434 return err;
523 return step.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(err) });
435524 };
436525
437 if (!termMatches(expected_term, term)) {
438 std.debug.print("The following command {} (expected {}):\n", .{ fmtTerm(term), fmtTerm(expected_term) });
439 printCmd(cwd, argv);
440 return error.UnexpectedExit;
441 }
442
443 switch (stderr_action) {
444 .inherit, .ignore => {},
445 .expect_exact => |expected_bytes| {
446 if (!mem.eql(u8, expected_bytes, stderr.?)) {
447 std.debug.print(
448 \\
449 \\========= Expected this stderr: =========
450 \\{s}
451 \\========= But found: ====================
452 \\{s}
453 \\
454 , .{ expected_bytes, stderr.? });
455 printCmd(cwd, argv);
456 return error.TestFailed;
457 }
458 },
459 .expect_matches => |matches| for (matches) |match| {
460 if (mem.indexOf(u8, stderr.?, match) == null) {
461 std.debug.print(
462 \\
463 \\========= Expected to find in stderr: =========
464 \\{s}
465 \\========= But stderr does not contain it: =====
466 \\{s}
467 \\
468 , .{ match, stderr.? });
469 printCmd(cwd, argv);
470 return error.TestFailed;
471 }
472 },
473 }
474
475 switch (stdout_action) {
476 .inherit, .ignore => {},
477 .expect_exact => |expected_bytes| {
478 if (!mem.eql(u8, expected_bytes, stdout.?)) {
479 std.debug.print(
480 \\
481 \\========= Expected this stdout: =========
482 \\{s}
483 \\========= But found: ====================
484 \\{s}
485 \\
486 , .{ expected_bytes, stdout.? });
487 printCmd(cwd, argv);
488 return error.TestFailed;
489 }
526 switch (stdio) {
527 .check => |checks| for (checks) |check| switch (check) {
528 .expect_stderr_exact => |expected_bytes| {
529 if (!mem.eql(u8, expected_bytes, stderr_bytes.?)) {
530 return step.fail(
531 \\========= expected this stderr: =========
532 \\{s}
533 \\========= but found: ====================
534 \\{s}
535 \\========= from the following command: ===
536 \\{s}
537 , .{
538 expected_bytes,
539 stderr_bytes.?,
540 try Step.allocPrintCmd(arena, opt_cwd, argv),
541 });
542 }
543 },
544 .expect_stderr_match => |match| {
545 if (mem.indexOf(u8, stderr_bytes.?, match) == null) {
546 return step.fail(
547 \\========= expected to find in stderr: =========
548 \\{s}
549 \\========= but stderr does not contain it: =====
550 \\{s}
551 \\========= from the following command: =========
552 \\{s}
553 , .{
554 match,
555 stderr_bytes.?,
556 try Step.allocPrintCmd(arena, opt_cwd, argv),
557 });
558 }
559 },
560 .expect_stdout_exact => |expected_bytes| {
561 if (!mem.eql(u8, expected_bytes, stdout_bytes.?)) {
562 return step.fail(
563 \\========= expected this stdout: =========
564 \\{s}
565 \\========= but found: ====================
566 \\{s}
567 \\========= from the following command: ===
568 \\{s}
569 , .{
570 expected_bytes,
571 stdout_bytes.?,
572 try Step.allocPrintCmd(arena, opt_cwd, argv),
573 });
574 }
575 },
576 .expect_stdout_match => |match| {
577 if (mem.indexOf(u8, stdout_bytes.?, match) == null) {
578 return step.fail(
579 \\========= expected to find in stdout: =========
580 \\{s}
581 \\========= but stdout does not contain it: =====
582 \\{s}
583 \\========= from the following command: =========
584 \\{s}
585 , .{
586 match,
587 stdout_bytes.?,
588 try Step.allocPrintCmd(arena, opt_cwd, argv),
589 });
590 }
591 },
592 .expect_term => |expected_term| {
593 if (!termMatches(expected_term, term)) {
594 return step.fail("the following command {} (expected {}):\n{s}", .{
595 fmtTerm(term),
596 fmtTerm(expected_term),
597 try Step.allocPrintCmd(arena, opt_cwd, argv),
598 });
599 }
600 },
490601 },
491 .expect_matches => |matches| for (matches) |match| {
492 if (mem.indexOf(u8, stdout.?, match) == null) {
493 std.debug.print(
494 \\
495 \\========= Expected to find in stdout: =========
496 \\{s}
497 \\========= But stdout does not contain it: =====
498 \\{s}
499 \\
500 , .{ match, stdout.? });
501 printCmd(cwd, argv);
502 return error.TestFailed;
503 }
602 else => {
603 try step.handleChildProcessTerm(term, opt_cwd, argv);
504604 },
505605 }
506606}
507607
508fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
509 const i = man.failed_file_index orelse failWithSimpleError(err);
510 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
511 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
512 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
513 std.process.exit(1);
514}
515
516fn failWithSimpleError(err: anyerror) noreturn {
517 std.debug.print("{s}\n", .{@errorName(err)});
518 std.process.exit(1);
519}
520
521fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
522 if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
523 for (argv) |arg| {
524 std.debug.print("{s} ", .{arg});
525 }
526 std.debug.print("\n", .{});
527}
528
529608fn addPathForDynLibs(self: *RunStep, artifact: *CompileStep) void {
530 addPathForDynLibsInternal(&self.step, self.builder, artifact);
609 addPathForDynLibsInternal(&self.step, self.step.owner, artifact);
531610}
532611
533612/// This should only be used for internal usage, this is called automatically
lib/std/Build/Step.zig+236-5
......@@ -1,5 +1,6 @@
11id: Id,
22name: []const u8,
3owner: *Build,
34makeFn: MakeFn,
45dependencies: std.ArrayList(*Step),
56/// This field is empty during execution of the user's build script, and
......@@ -39,7 +40,6 @@ pub const Id = enum {
3940 translate_c,
4041 write_file,
4142 run,
42 emulatable_run,
4343 check_file,
4444 check_object,
4545 config_header,
......@@ -60,7 +60,6 @@ pub const Id = enum {
6060 .translate_c => Build.TranslateCStep,
6161 .write_file => Build.WriteFileStep,
6262 .run => Build.RunStep,
63 .emulatable_run => Build.EmulatableRunStep,
6463 .check_file => Build.CheckFileStep,
6564 .check_object => Build.CheckObjectStep,
6665 .config_header => Build.ConfigHeaderStep,
......@@ -74,11 +73,14 @@ pub const Id = enum {
7473pub const Options = struct {
7574 id: Id,
7675 name: []const u8,
76 owner: *Build,
7777 makeFn: MakeFn = makeNoOp,
7878 first_ret_addr: ?usize = null,
7979};
8080
81pub fn init(allocator: Allocator, options: Options) Step {
81pub fn init(options: Options) Step {
82 const arena = options.owner.allocator;
83
8284 var addresses = [1]usize{0} ** n_debug_stack_frames;
8385 const first_ret_addr = options.first_ret_addr orelse @returnAddress();
8486 var stack_trace = std.builtin.StackTrace{
......@@ -89,9 +91,10 @@ pub fn init(allocator: Allocator, options: Options) Step {
8991
9092 return .{
9193 .id = options.id,
92 .name = allocator.dupe(u8, options.name) catch @panic("OOM"),
94 .name = arena.dupe(u8, options.name) catch @panic("OOM"),
95 .owner = options.owner,
9396 .makeFn = options.makeFn,
94 .dependencies = std.ArrayList(*Step).init(allocator),
97 .dependencies = std.ArrayList(*Step).init(arena),
9598 .dependants = .{},
9699 .state = .precheck_unstarted,
97100 .debug_stack_trace = addresses,
......@@ -168,3 +171,231 @@ const std = @import("../std.zig");
168171const Build = std.Build;
169172const Allocator = std.mem.Allocator;
170173const assert = std.debug.assert;
174const builtin = @import("builtin");
175
176pub fn evalChildProcess(s: *Step, argv: []const []const u8) !void {
177 const arena = s.owner.allocator;
178
179 try handleChildProcUnsupported(s, null, argv);
180 try handleVerbose(s.owner, null, argv);
181
182 const result = std.ChildProcess.exec(.{
183 .allocator = arena,
184 .argv = argv,
185 }) catch |err| return s.fail("unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
186
187 if (result.stderr.len > 0) {
188 try s.result_error_msgs.append(arena, result.stderr);
189 }
190
191 try handleChildProcessTerm(s, result.term, null, argv);
192}
193
194pub fn fail(step: *Step, comptime fmt: []const u8, args: anytype) error{ OutOfMemory, MakeFailed } {
195 const arena = step.owner.allocator;
196 const msg = try std.fmt.allocPrint(arena, fmt, args);
197 try step.result_error_msgs.append(arena, msg);
198 return error.MakeFailed;
199}
200
201/// Assumes that argv contains `--listen=-` and that the process being spawned
202/// is the zig compiler - the same version that compiled the build runner.
203pub fn evalZigProcess(
204 s: *Step,
205 argv: []const []const u8,
206 prog_node: *std.Progress.Node,
207) ![]const u8 {
208 assert(argv.len != 0);
209 const b = s.owner;
210 const arena = b.allocator;
211 const gpa = arena;
212
213 try handleChildProcUnsupported(s, null, argv);
214 try handleVerbose(s.owner, null, argv);
215
216 var child = std.ChildProcess.init(argv, arena);
217 child.env_map = b.env_map;
218 child.stdin_behavior = .Pipe;
219 child.stdout_behavior = .Pipe;
220 child.stderr_behavior = .Pipe;
221
222 child.spawn() catch |err| return s.fail("unable to spawn {s}: {s}", .{
223 argv[0], @errorName(err),
224 });
225
226 var poller = std.io.poll(gpa, enum { stdout, stderr }, .{
227 .stdout = child.stdout.?,
228 .stderr = child.stderr.?,
229 });
230 defer poller.deinit();
231
232 try sendMessage(child.stdin.?, .update);
233 try sendMessage(child.stdin.?, .exit);
234
235 const Header = std.zig.Server.Message.Header;
236 var result: ?[]const u8 = null;
237
238 var node_name: std.ArrayListUnmanaged(u8) = .{};
239 defer node_name.deinit(gpa);
240 var sub_prog_node: ?std.Progress.Node = null;
241 defer if (sub_prog_node) |*n| n.end();
242
243 while (try poller.poll()) {
244 const stdout = poller.fifo(.stdout);
245 const buf = stdout.readableSlice(0);
246 assert(stdout.readableLength() == buf.len);
247 if (buf.len >= @sizeOf(Header)) {
248 const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]);
249 const header_and_msg_len = header.bytes_len + @sizeOf(Header);
250 if (buf.len >= header_and_msg_len) {
251 const body = buf[@sizeOf(Header)..][0..header.bytes_len];
252 switch (header.tag) {
253 .zig_version => {
254 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
255 return s.fail(
256 "zig version mismatch build runner vs compiler: '{s}' vs '{s}'",
257 .{ builtin.zig_version_string, body },
258 );
259 }
260 },
261 .error_bundle => {
262 const EbHdr = std.zig.Server.Message.ErrorBundle;
263 const eb_hdr = @ptrCast(*align(1) const EbHdr, body);
264 const extra_bytes =
265 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
266 const string_bytes =
267 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
268 // TODO: use @ptrCast when the compiler supports it
269 const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
270 const extra_array = try arena.alloc(u32, unaligned_extra.len);
271 // TODO: use @memcpy when it supports slices
272 for (extra_array, unaligned_extra) |*dst, src| dst.* = src;
273 s.result_error_bundle = .{
274 .string_bytes = try arena.dupe(u8, string_bytes),
275 .extra = extra_array,
276 };
277 },
278 .progress => {
279 if (sub_prog_node) |*n| n.end();
280 node_name.clearRetainingCapacity();
281 try node_name.appendSlice(gpa, body);
282 sub_prog_node = prog_node.start(node_name.items, 0);
283 sub_prog_node.?.activate();
284 },
285 .emit_bin_path => {
286 result = try arena.dupe(u8, body);
287 },
288 _ => {
289 // Unrecognized message.
290 },
291 }
292 stdout.discard(header_and_msg_len);
293 }
294 }
295 }
296
297 const stderr = poller.fifo(.stderr);
298 if (stderr.readableLength() > 0) {
299 try s.result_error_msgs.append(arena, try stderr.toOwnedSlice());
300 }
301
302 // Send EOF to stdin.
303 child.stdin.?.close();
304 child.stdin = null;
305
306 const term = child.wait() catch |err| {
307 return s.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(err) });
308 };
309 try handleChildProcessTerm(s, term, null, argv);
310
311 if (s.result_error_bundle.errorMessageCount() > 0) {
312 return s.fail("the following command failed with {d} compilation errors:\n{s}", .{
313 s.result_error_bundle.errorMessageCount(),
314 try allocPrintCmd(arena, null, argv),
315 });
316 }
317
318 return result orelse return s.fail(
319 "the following command failed to communicate the compilation result:\n{s}",
320 .{try allocPrintCmd(arena, null, argv)},
321 );
322}
323
324fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
325 const header: std.zig.Client.Message.Header = .{
326 .tag = tag,
327 .bytes_len = 0,
328 };
329 try file.writeAll(std.mem.asBytes(&header));
330}
331
332pub fn handleVerbose(
333 b: *Build,
334 opt_cwd: ?[]const u8,
335 argv: []const []const u8,
336) error{OutOfMemory}!void {
337 if (b.verbose) {
338 // Intention of verbose is to print all sub-process command lines to
339 // stderr before spawning them.
340 const text = try allocPrintCmd(b.allocator, opt_cwd, argv);
341 std.debug.print("{s}\n", .{text});
342 }
343}
344
345pub inline fn handleChildProcUnsupported(
346 s: *Step,
347 opt_cwd: ?[]const u8,
348 argv: []const []const u8,
349) error{ OutOfMemory, MakeFailed }!void {
350 if (!std.process.can_spawn) {
351 return s.fail(
352 "unable to execute the following command: host cannot spawn child processes\n{s}",
353 .{try allocPrintCmd(s.owner.allocator, opt_cwd, argv)},
354 );
355 }
356}
357
358pub fn handleChildProcessTerm(
359 s: *Step,
360 term: std.ChildProcess.Term,
361 opt_cwd: ?[]const u8,
362 argv: []const []const u8,
363) error{ MakeFailed, OutOfMemory }!void {
364 const arena = s.owner.allocator;
365 switch (term) {
366 .Exited => |code| {
367 if (code != 0) {
368 return s.fail(
369 "the following command exited with error code {d}:\n{s}",
370 .{ code, try allocPrintCmd(arena, opt_cwd, argv) },
371 );
372 }
373 },
374 .Signal, .Stopped, .Unknown => {
375 return s.fail(
376 "the following command terminated unexpectedly:\n{s}",
377 .{try allocPrintCmd(arena, opt_cwd, argv)},
378 );
379 },
380 }
381}
382
383pub fn allocPrintCmd(arena: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) ![]u8 {
384 var buf: std.ArrayListUnmanaged(u8) = .{};
385 if (opt_cwd) |cwd| try buf.writer(arena).print("cd {s} && ", .{cwd});
386 for (argv) |arg| {
387 try buf.writer(arena).print("{s} ", .{arg});
388 }
389 return buf.toOwnedSlice(arena);
390}
391
392pub fn cacheHit(s: *Step, man: *std.Build.Cache.Manifest) !bool {
393 return man.hit() catch |err| return failWithCacheError(s, man, err);
394}
395
396fn failWithCacheError(s: *Step, man: *const std.Build.Cache.Manifest, err: anyerror) anyerror {
397 const i = man.failed_file_index orelse return err;
398 const pp = man.files.items[i].prefixed_path orelse return err;
399 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
400 return s.fail("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
401}
lib/std/Build/TranslateCStep.zig+20-20
......@@ -11,7 +11,6 @@ const TranslateCStep = @This();
1111pub const base_id = .translate_c;
1212
1313step: Step,
14builder: *std.Build,
1514source: std.Build.FileSource,
1615include_dirs: std.ArrayList([]const u8),
1716c_macros: std.ArrayList([]const u8),
......@@ -26,19 +25,19 @@ pub const Options = struct {
2625 optimize: std.builtin.OptimizeMode,
2726};
2827
29pub fn create(builder: *std.Build, options: Options) *TranslateCStep {
30 const self = builder.allocator.create(TranslateCStep) catch @panic("OOM");
31 const source = options.source_file.dupe(builder);
28pub fn create(owner: *std.Build, options: Options) *TranslateCStep {
29 const self = owner.allocator.create(TranslateCStep) catch @panic("OOM");
30 const source = options.source_file.dupe(owner);
3231 self.* = TranslateCStep{
33 .step = Step.init(builder.allocator, .{
32 .step = Step.init(.{
3433 .id = .translate_c,
3534 .name = "translate-c",
35 .owner = owner,
3636 .makeFn = make,
3737 }),
38 .builder = builder,
3938 .source = source,
40 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
41 .c_macros = std.ArrayList([]const u8).init(builder.allocator),
39 .include_dirs = std.ArrayList([]const u8).init(owner.allocator),
40 .c_macros = std.ArrayList([]const u8).init(owner.allocator),
4241 .out_basename = undefined,
4342 .target = options.target,
4443 .optimize = options.optimize,
......@@ -58,7 +57,7 @@ pub const AddExecutableOptions = struct {
5857
5958/// Creates a step to build an executable from the translated source.
6059pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *CompileStep {
61 return self.builder.addExecutable(.{
60 return self.step.owner.addExecutable(.{
6261 .root_source_file = .{ .generated = &self.output_file },
6362 .name = options.name orelse "translated_c",
6463 .version = options.version,
......@@ -69,30 +68,31 @@ pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *Comp
6968}
7069
7170pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
72 self.include_dirs.append(self.builder.dupePath(include_dir)) catch @panic("OOM");
71 self.include_dirs.append(self.step.owner.dupePath(include_dir)) catch @panic("OOM");
7372}
7473
7574pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
76 return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches));
75 return CheckFileStep.create(self.step.owner, .{ .generated = &self.output_file }, self.step.owner.dupeStrings(expected_matches));
7776}
7877
7978/// If the value is omitted, it is set to 1.
8079/// `name` and `value` need not live longer than the function call.
8180pub fn defineCMacro(self: *TranslateCStep, name: []const u8, value: ?[]const u8) void {
82 const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
81 const macro = std.Build.constructCMacro(self.step.owner.allocator, name, value);
8382 self.c_macros.append(macro) catch @panic("OOM");
8483}
8584
8685/// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1.
8786pub fn defineCMacroRaw(self: *TranslateCStep, name_and_value: []const u8) void {
88 self.c_macros.append(self.builder.dupe(name_and_value)) catch @panic("OOM");
87 self.c_macros.append(self.step.owner.dupe(name_and_value)) catch @panic("OOM");
8988}
9089
9190fn make(step: *Step, prog_node: *std.Progress.Node) !void {
91 const b = step.owner;
9292 const self = @fieldParentPtr(TranslateCStep, "step", step);
9393
94 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
95 try argv_list.append(self.builder.zig_exe);
94 var argv_list = std.ArrayList([]const u8).init(b.allocator);
95 try argv_list.append(b.zig_exe);
9696 try argv_list.append("translate-c");
9797 try argv_list.append("-lc");
9898
......@@ -101,12 +101,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
101101
102102 if (!self.target.isNative()) {
103103 try argv_list.append("-target");
104 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
104 try argv_list.append(try self.target.zigTriple(b.allocator));
105105 }
106106
107107 switch (self.optimize) {
108108 .Debug => {}, // Skip since it's the default.
109 else => try argv_list.append(self.builder.fmt("-O{s}", .{@tagName(self.optimize)})),
109 else => try argv_list.append(b.fmt("-O{s}", .{@tagName(self.optimize)})),
110110 }
111111
112112 for (self.include_dirs.items) |include_dir| {
......@@ -119,15 +119,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
119119 try argv_list.append(c_macro);
120120 }
121121
122 try argv_list.append(self.source.getPath(self.builder));
122 try argv_list.append(self.source.getPath(b));
123123
124 const output_path = try self.builder.execFromStep(argv_list.items, &self.step, prog_node);
124 const output_path = try step.evalZigProcess(argv_list.items, prog_node);
125125
126126 self.out_basename = fs.path.basename(output_path);
127127 const output_dir = fs.path.dirname(output_path).?;
128128
129129 self.output_file.path = try fs.path.join(
130 self.builder.allocator,
130 b.allocator,
131131 &[_][]const u8{ output_dir, self.out_basename },
132132 );
133133}
lib/std/Build/WriteFileStep.zig+26-37
......@@ -10,7 +10,6 @@
1010//! control.
1111
1212step: Step,
13builder: *std.Build,
1413/// The elements here are pointers because we need stable pointers for the
1514/// GeneratedFile field.
1615files: std.ArrayListUnmanaged(*File),
......@@ -34,12 +33,12 @@ pub const Contents = union(enum) {
3433 copy: std.Build.FileSource,
3534};
3635
37pub fn init(builder: *std.Build) WriteFileStep {
36pub fn init(owner: *std.Build) WriteFileStep {
3837 return .{
39 .builder = builder,
40 .step = Step.init(builder.allocator, .{
38 .step = Step.init(.{
4139 .id = .write_file,
4240 .name = "writefile",
41 .owner = owner,
4342 .makeFn = make,
4443 }),
4544 .files = .{},
......@@ -48,12 +47,13 @@ pub fn init(builder: *std.Build) WriteFileStep {
4847}
4948
5049pub fn add(wf: *WriteFileStep, sub_path: []const u8, bytes: []const u8) void {
51 const gpa = wf.builder.allocator;
50 const b = wf.step.owner;
51 const gpa = b.allocator;
5252 const file = gpa.create(File) catch @panic("OOM");
5353 file.* = .{
5454 .generated_file = .{ .step = &wf.step },
55 .sub_path = wf.builder.dupePath(sub_path),
56 .contents = .{ .bytes = wf.builder.dupe(bytes) },
55 .sub_path = b.dupePath(sub_path),
56 .contents = .{ .bytes = b.dupe(bytes) },
5757 };
5858 wf.files.append(gpa, file) catch @panic("OOM");
5959}
......@@ -66,11 +66,12 @@ pub fn add(wf: *WriteFileStep, sub_path: []const u8, bytes: []const u8) void {
6666/// required sub-path exists.
6767/// This is the option expected to be used most commonly with `addCopyFile`.
6868pub fn addCopyFile(wf: *WriteFileStep, source: std.Build.FileSource, sub_path: []const u8) void {
69 const gpa = wf.builder.allocator;
69 const b = wf.step.owner;
70 const gpa = b.allocator;
7071 const file = gpa.create(File) catch @panic("OOM");
7172 file.* = .{
7273 .generated_file = .{ .step = &wf.step },
73 .sub_path = wf.builder.dupePath(sub_path),
74 .sub_path = b.dupePath(sub_path),
7475 .contents = .{ .copy = source },
7576 };
7677 wf.files.append(gpa, file) catch @panic("OOM");
......@@ -83,7 +84,8 @@ pub fn addCopyFile(wf: *WriteFileStep, source: std.Build.FileSource, sub_path: [
8384/// those changes to version control.
8485/// A file added this way is not available with `getFileSource`.
8586pub fn addCopyFileToSource(wf: *WriteFileStep, source: std.Build.FileSource, sub_path: []const u8) void {
86 wf.output_source_files.append(wf.builder.allocator, .{
87 const b = wf.step.owner;
88 wf.output_source_files.append(b.allocator, .{
8789 .contents = .{ .copy = source },
8890 .sub_path = sub_path,
8991 }) catch @panic("OOM");
......@@ -101,6 +103,7 @@ pub fn getFileSource(wf: *WriteFileStep, sub_path: []const u8) ?std.Build.FileSo
101103
102104fn make(step: *Step, prog_node: *std.Progress.Node) !void {
103105 _ = prog_node;
106 const b = step.owner;
104107 const wf = @fieldParentPtr(WriteFileStep, "step", step);
105108
106109 // Writing to source files is kind of an extra capability of this
......@@ -110,11 +113,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
110113 for (wf.output_source_files.items) |output_source_file| {
111114 const basename = fs.path.basename(output_source_file.sub_path);
112115 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
113 var dir = try wf.builder.build_root.handle.makeOpenPath(dirname, .{});
116 var dir = try b.build_root.handle.makeOpenPath(dirname, .{});
114117 defer dir.close();
115118 try writeFile(wf, dir, output_source_file.contents, basename);
116119 } else {
117 try writeFile(wf, wf.builder.build_root.handle, output_source_file.contents, basename);
120 try writeFile(wf, b.build_root.handle, output_source_file.contents, basename);
118121 }
119122 }
120123
......@@ -125,7 +128,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
125128 // If, for example, a hard-coded path was used as the location to put WriteFileStep
126129 // files, then two WriteFileSteps executing in parallel might clobber each other.
127130
128 var man = wf.builder.cache.obtain();
131 var man = b.cache.obtain();
129132 defer man.deinit();
130133
131134 // Random bytes to make WriteFileStep unique. Refresh this with
......@@ -140,17 +143,17 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
140143 man.hash.addBytes(bytes);
141144 },
142145 .copy => |file_source| {
143 _ = try man.addFile(file_source.getPath(wf.builder), null);
146 _ = try man.addFile(file_source.getPath(b), null);
144147 },
145148 }
146149 }
147150
148 if (man.hit() catch |err| failWithCacheError(man, err)) {
151 if (try step.cacheHit(&man)) {
149152 // Cache hit, skip writing file data.
150153 const digest = man.final();
151154 for (wf.files.items) |file| {
152 file.generated_file.path = try wf.builder.cache_root.join(
153 wf.builder.allocator,
155 file.generated_file.path = try b.cache_root.join(
156 b.allocator,
154157 &.{ "o", &digest, file.sub_path },
155158 );
156159 }
......@@ -160,7 +163,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
160163 const digest = man.final();
161164 const cache_path = "o" ++ fs.path.sep_str ++ digest;
162165
163 var cache_dir = wf.builder.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
166 var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
164167 std.debug.print("unable to make path {s}: {s}\n", .{ cache_path, @errorName(err) });
165168 return err;
166169 };
......@@ -169,15 +172,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
169172 for (wf.files.items) |file| {
170173 const basename = fs.path.basename(file.sub_path);
171174 if (fs.path.dirname(file.sub_path)) |dirname| {
172 var dir = try wf.builder.cache_root.handle.makeOpenPath(dirname, .{});
175 var dir = try b.cache_root.handle.makeOpenPath(dirname, .{});
173176 defer dir.close();
174177 try writeFile(wf, dir, file.contents, basename);
175178 } else {
176179 try writeFile(wf, cache_dir, file.contents, basename);
177180 }
178181
179 file.generated_file.path = try wf.builder.cache_root.join(
180 wf.builder.allocator,
182 file.generated_file.path = try b.cache_root.join(
183 b.allocator,
181184 &.{ cache_path, file.sub_path },
182185 );
183186 }
......@@ -186,32 +189,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
186189}
187190
188191fn writeFile(wf: *WriteFileStep, dir: fs.Dir, contents: Contents, basename: []const u8) !void {
192 const b = wf.step.owner;
189193 // TODO after landing concurrency PR, improve error reporting here
190194 switch (contents) {
191195 .bytes => |bytes| return dir.writeFile(basename, bytes),
192196 .copy => |file_source| {
193 const source_path = file_source.getPath(wf.builder);
197 const source_path = file_source.getPath(b);
194198 const prev_status = try fs.Dir.updateFile(fs.cwd(), source_path, dir, basename, .{});
195199 _ = prev_status; // TODO logging (affected by open PR regarding concurrency)
196200 },
197201 }
198202}
199203
200/// TODO consolidate this with the same function in RunStep?
201/// Also properly deal with concurrency (see open PR)
202fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
203 const i = man.failed_file_index orelse failWithSimpleError(err);
204 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
205 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
206 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
207 std.process.exit(1);
208}
209
210fn failWithSimpleError(err: anyerror) noreturn {
211 std.debug.print("{s}\n", .{@errorName(err)});
212 std.process.exit(1);
213}
214
215204const std = @import("../std.zig");
216205const Step = std.Build.Step;
217206const fs = std.fs;
src/main.zig+6-6
......@@ -4419,6 +4419,8 @@ pub const usage_build =
44194419 \\Options:
44204420 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
44214421 \\ -fno-reference-trace Disable reference trace
4422 \\ -fsummary Print the build summary, even on success
4423 \\ -fno-summary Omit the build summary, even on failure
44224424 \\ --build-file [file] Override path to build.zig
44234425 \\ --cache-dir [path] Override path to local Zig cache directory
44244426 \\ --global-cache-dir [path] Override path to global Zig cache directory
......@@ -4920,8 +4922,6 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
49204922 };
49214923 defer tree.deinit(gpa);
49224924
4923 try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
4924 var has_ast_error = false;
49254925 if (check_ast_flag) {
49264926 var file: Module.File = .{
49274927 .status = .never_loaded,
......@@ -4957,11 +4957,11 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
49574957 var error_bundle = try wip_errors.toOwnedBundle();
49584958 defer error_bundle.deinit(gpa);
49594959 error_bundle.renderToStdErr(ttyconf);
4960 has_ast_error = true;
4960 process.exit(2);
49614961 }
4962 }
4963 if (tree.errors.len != 0 or has_ast_error) {
4964 process.exit(1);
4962 } else if (tree.errors.len != 0) {
4963 try printAstErrorsToStderr(gpa, tree, "<stdin>", color);
4964 process.exit(2);
49654965 }
49664966 const formatted = try tree.render(gpa);
49674967 defer gpa.free(formatted);
test/src/compare_output.zig+1-3
......@@ -166,9 +166,7 @@ pub const CompareOutputContext = struct {
166166
167167 const run = exe.run();
168168 run.addArgs(case.cli_args);
169 run.stderr_action = .ignore;
170 run.stdout_action = .ignore;
171 run.expected_term = .{ .Exited = 126 };
169 run.expectExitCode(126);
172170
173171 self.step.dependOn(&run.step);
174172 },
test/tests.zig+6-10
......@@ -858,10 +858,11 @@ pub const StackTracesContext = struct {
858858 const allocator = context.b.allocator;
859859 const ptr = allocator.create(RunAndCompareStep) catch unreachable;
860860 ptr.* = RunAndCompareStep{
861 .step = Step.init(allocator, .{
861 .step = Step.init(.{
862862 .id = .custom,
863863 .name = "StackTraceCompareOutputStep",
864864 .makeFn = make,
865 .owner = context.b,
865866 }),
866867 .context = context,
867868 .exe = exe,
......@@ -1121,10 +1122,7 @@ pub const StandaloneContext = struct {
11211122 defer zig_args.resize(zig_args_base_len) catch unreachable;
11221123
11231124 const run_cmd = b.addSystemCommand(zig_args.items);
1124 const log_step = b.addLog("PASS {s} ({s})", .{ annotated_case_name, @tagName(optimize_mode) });
1125 log_step.step.dependOn(&run_cmd.step);
1126
1127 self.step.dependOn(&log_step.step);
1125 self.step.dependOn(&run_cmd.step);
11281126 }
11291127 }
11301128
......@@ -1150,10 +1148,7 @@ pub const StandaloneContext = struct {
11501148 exe.linkSystemLibrary("c");
11511149 }
11521150
1153 const log_step = b.addLog("PASS {s}", .{annotated_case_name});
1154 log_step.step.dependOn(&exe.step);
1155
1156 self.step.dependOn(&log_step.step);
1151 self.step.dependOn(&exe.step);
11571152 }
11581153 }
11591154};
......@@ -1203,9 +1198,10 @@ pub const GenHContext = struct {
12031198 const allocator = context.b.allocator;
12041199 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
12051200 ptr.* = GenHCmpOutputStep{
1206 .step = Step.init(allocator, .{
1201 .step = Step.init(.{
12071202 .id = .custom,
12081203 .name = "ParseCCmpOutput",
1204 .owner = context.b,
12091205 .makeFn = make,
12101206 }),
12111207 .context = context,