authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-14 12:47:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:12-07:00
log02381c037221937e941e03c5e7439383dde8a2a1
treed51532b9fa4773c498723e581e069b7ddb086e81
parent9580fbcf3596a39ba4c7d7af2f3a1df0e0abb746

std.Build: improve debugging of misconfigured steps

* Step.init() now takes an options struct * Step.init() now captures a small stack trace and stores it in the Step so that it can be accessed when printing user-friendly debugging information, including the lines of code that created the step in question.

20 files changed, 209 insertions(+), 68 deletions(-)

lib/std/Build.zig+67-21
...@@ -227,12 +227,19 @@ pub fn create(...@@ -227,12 +227,19 @@ pub fn create(
227 .h_dir = undefined,227 .h_dir = undefined,
228 .dest_dir = env_map.get("DESTDIR"),228 .dest_dir = env_map.get("DESTDIR"),
229 .installed_files = ArrayList(InstalledFile).init(allocator),229 .installed_files = ArrayList(InstalledFile).init(allocator),
230 .install_tls = TopLevelStep{230 .install_tls = .{
231 .step = Step.initNoOp(.top_level, "install", allocator),231 .step = Step.init(allocator, .{
232 .id = .top_level,
233 .name = "install",
234 }),
232 .description = "Copy build artifacts to prefix path",235 .description = "Copy build artifacts to prefix path",
233 },236 },
234 .uninstall_tls = TopLevelStep{237 .uninstall_tls = .{
235 .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),238 .step = Step.init(allocator, .{
239 .id = .top_level,
240 .name = "uninstall",
241 .makeFn = makeUninstall,
242 }),
236 .description = "Remove build artifacts from prefix path",243 .description = "Remove build artifacts from prefix path",
237 },244 },
238 .zig_lib_dir = null,245 .zig_lib_dir = null,
...@@ -264,11 +271,18 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc...@@ -264,11 +271,18 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
264 child.* = .{271 child.* = .{
265 .allocator = allocator,272 .allocator = allocator,
266 .install_tls = .{273 .install_tls = .{
267 .step = Step.initNoOp(.top_level, "install", allocator),274 .step = Step.init(allocator, .{
275 .id = .top_level,
276 .name = "install",
277 }),
268 .description = "Copy build artifacts to prefix path",278 .description = "Copy build artifacts to prefix path",
269 },279 },
270 .uninstall_tls = .{280 .uninstall_tls = .{
271 .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),281 .step = Step.init(allocator, .{
282 .id = .top_level,
283 .name = "uninstall",
284 .makeFn = makeUninstall,
285 }),
272 .description = "Remove build artifacts from prefix path",286 .description = "Remove build artifacts from prefix path",
273 },287 },
274 .user_input_options = UserInputOptionsMap.init(allocator),288 .user_input_options = UserInputOptionsMap.init(allocator),
...@@ -634,7 +648,11 @@ pub fn addConfigHeader(...@@ -634,7 +648,11 @@ pub fn addConfigHeader(
634 options: ConfigHeaderStep.Options,648 options: ConfigHeaderStep.Options,
635 values: anytype,649 values: anytype,
636) *ConfigHeaderStep {650) *ConfigHeaderStep {
637 const config_header_step = ConfigHeaderStep.create(b, options);651 var options_copy = options;
652 if (options_copy.first_ret_addr == null)
653 options_copy.first_ret_addr = @returnAddress();
654
655 const config_header_step = ConfigHeaderStep.create(b, options_copy);
638 config_header_step.addValues(values);656 config_header_step.addValues(values);
639 return config_header_step;657 return config_header_step;
640}658}
...@@ -858,7 +876,10 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_...@@ -858,7 +876,10 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
858pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {876pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {
859 const step_info = self.allocator.create(TopLevelStep) catch @panic("OOM");877 const step_info = self.allocator.create(TopLevelStep) catch @panic("OOM");
860 step_info.* = TopLevelStep{878 step_info.* = TopLevelStep{
861 .step = Step.initNoOp(.top_level, name, self.allocator),879 .step = Step.init(self.allocator, .{
880 .id = .top_level,
881 .name = name,
882 }),
862 .description = self.dupe(description),883 .description = self.dupe(description),
863 };884 };
864 self.top_level_steps.put(self.allocator, step_info.step.name, step_info) catch @panic("OOM");885 self.top_level_steps.put(self.allocator, step_info.step.name, step_info) catch @panic("OOM");
...@@ -1153,7 +1174,7 @@ pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap,...@@ -1153,7 +1174,7 @@ pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap,
1153 printCmd(self.allocator, cwd, argv);1174 printCmd(self.allocator, cwd, argv);
1154 }1175 }
11551176
1156 if (!std.process.can_spawn)1177 if (!process.can_spawn)
1157 return error.ExecNotSupported;1178 return error.ExecNotSupported;
11581179
1159 var child = std.ChildProcess.init(argv, self.allocator);1180 var child = std.ChildProcess.init(argv, self.allocator);
...@@ -1355,7 +1376,7 @@ pub fn execAllowFail(...@@ -1355,7 +1376,7 @@ pub fn execAllowFail(
1355) ExecError![]u8 {1376) ExecError![]u8 {
1356 assert(argv.len != 0);1377 assert(argv.len != 0);
13571378
1358 if (!std.process.can_spawn)1379 if (!process.can_spawn)
1359 return error.ExecNotSupported;1380 return error.ExecNotSupported;
13601381
1361 const max_output_size = 400 * 1024;1382 const max_output_size = 400 * 1024;
...@@ -1395,7 +1416,7 @@ pub fn execFromStep(b: *Build, argv: []const []const u8, s: *Step) ![]u8 {...@@ -1395,7 +1416,7 @@ pub fn execFromStep(b: *Build, argv: []const []const u8, s: *Step) ![]u8 {
1395 printCmd(b.allocator, null, argv);1416 printCmd(b.allocator, null, argv);
1396 }1417 }
13971418
1398 if (!std.process.can_spawn) {1419 if (!process.can_spawn) {
1399 s.result.stderr = b.fmt("Unable to spawn the following command: cannot spawn child processes\n{s}", .{1420 s.result.stderr = b.fmt("Unable to spawn the following command: cannot spawn child processes\n{s}", .{
1400 try allocPrintCmd(b.allocator, null, argv),1421 try allocPrintCmd(b.allocator, null, argv),
1401 });1422 });
...@@ -1458,7 +1479,7 @@ fn unwrapExecResult(...@@ -1458,7 +1479,7 @@ fn unwrapExecResult(
1458/// inside step make() functions. If any errors occur, it fails the build with1479/// inside step make() functions. If any errors occur, it fails the build with
1459/// a helpful message.1480/// a helpful message.
1460pub fn exec(b: *Build, argv: []const []const u8) []u8 {1481pub fn exec(b: *Build, argv: []const []const u8) []u8 {
1461 if (!std.process.can_spawn) {1482 if (!process.can_spawn) {
1462 std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}", .{1483 std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}", .{
1463 try allocPrintCmd(b.allocator, null, argv),1484 try allocPrintCmd(b.allocator, null, argv),
1464 });1485 });
...@@ -1539,7 +1560,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {...@@ -1539,7 +1560,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
15391560
1540 const full_path = b.pathFromRoot("build.zig.zon");1561 const full_path = b.pathFromRoot("build.zig.zon");
1541 std.debug.print("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file.\n", .{ name, full_path });1562 std.debug.print("no dependency named '{s}' in '{s}'. All packages used in build.zig must be declared in this file.\n", .{ name, full_path });
1542 std.process.exit(1);1563 process.exit(1);
1543}1564}
15441565
1545fn dependencyInner(1566fn dependencyInner(
...@@ -1555,7 +1576,7 @@ fn dependencyInner(...@@ -1555,7 +1576,7 @@ fn dependencyInner(
1555 std.debug.print("unable to open '{s}': {s}\n", .{1576 std.debug.print("unable to open '{s}': {s}\n", .{
1556 build_root_string, @errorName(err),1577 build_root_string, @errorName(err),
1557 });1578 });
1558 std.process.exit(1);1579 process.exit(1);
1559 },1580 },
1560 };1581 };
1561 const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");1582 const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");
...@@ -1599,7 +1620,7 @@ pub const GeneratedFile = struct {...@@ -1599,7 +1620,7 @@ pub const GeneratedFile = struct {
15991620
1600 pub fn getPath(self: GeneratedFile) []const u8 {1621 pub fn getPath(self: GeneratedFile) []const u8 {
1601 return self.path orelse std.debug.panic(1622 return self.path orelse std.debug.panic(
1602 "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?",1623 "getPath() was called on a GeneratedFile that wasn't built yet. Is there a missing Step dependency on step '{s}'?",
1603 .{self.step.name},1624 .{self.step.name},
1604 );1625 );
1605 }1626 }
...@@ -1639,12 +1660,16 @@ pub const FileSource = union(enum) {...@@ -1639,12 +1660,16 @@ pub const FileSource = union(enum) {
1639 }1660 }
16401661
1641 /// Should only be called during make(), returns a path relative to the build root or absolute.1662 /// Should only be called during make(), returns a path relative to the build root or absolute.
1642 pub fn getPath(self: FileSource, builder: *Build) []const u8 {1663 pub fn getPath(self: FileSource, src_builder: *Build) []const u8 {
1643 const path = switch (self) {1664 switch (self) {
1644 .path => |p| builder.pathFromRoot(p),1665 .path => |p| return src_builder.pathFromRoot(p),
1645 .generated => |gen| gen.getPath(),1666 .generated => |gen| return gen.path orelse {
1646 };1667 std.debug.getStderrMutex().lock();
1647 return path;1668 const stderr = std.io.getStdErr();
1669 dumpBadGetPathHelp(gen.step, stderr, src_builder) catch {};
1670 @panic("unable to get path");
1671 },
1672 }
1648 }1673 }
16491674
1650 /// Duplicates the file source for a given builder.1675 /// Duplicates the file source for a given builder.
...@@ -1656,6 +1681,27 @@ pub const FileSource = union(enum) {...@@ -1656,6 +1681,27 @@ pub const FileSource = union(enum) {
1656 }1681 }
1657};1682};
16581683
1684fn dumpBadGetPathHelp(s: *Step, stderr: fs.File, src_builder: *Build) anyerror!void {
1685 try stderr.writer().print(
1686 \\getPath() was called on a GeneratedFile that wasn't built yet.
1687 \\ source package path: {s}
1688 \\ Is there a missing Step dependency on step '{s}'?
1689 \\ The step was created by this stack trace:
1690 \\
1691 , .{
1692 src_builder.build_root.path orelse ".",
1693 s.name,
1694 });
1695 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
1696 try stderr.writer().print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
1697 return;
1698 };
1699 std.debug.writeStackTrace(s.getStackTrace(), stderr.writer(), debug_info.allocator, debug_info, std.debug.detectTTYConfig(stderr)) catch |err| {
1700 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
1701 return;
1702 };
1703}
1704
1659/// Allocates a new string for assigning a value to a named macro.1705/// Allocates a new string for assigning a value to a named macro.
1660/// If the value is omitted, it is set to 1.1706/// If the value is omitted, it is set to 1.
1661/// `name` and `value` need not live longer than the function call.1707/// `name` and `value` need not live longer than the function call.
lib/std/Build/CheckFileStep.zig+5-1
...@@ -21,7 +21,11 @@ pub fn create(...@@ -21,7 +21,11 @@ pub fn create(
21 const self = builder.allocator.create(CheckFileStep) catch @panic("OOM");21 const self = builder.allocator.create(CheckFileStep) catch @panic("OOM");
22 self.* = CheckFileStep{22 self.* = CheckFileStep{
23 .builder = builder,23 .builder = builder,
24 .step = Step.init(.check_file, "CheckFile", builder.allocator, make),24 .step = Step.init(builder.allocator, .{
25 .id = .check_file,
26 .name = "CheckFile",
27 .makeFn = make,
28 }),
25 .source = source.dupe(builder),29 .source = source.dupe(builder),
26 .expected_matches = builder.dupeStrings(expected_matches),30 .expected_matches = builder.dupeStrings(expected_matches),
27 };31 };
lib/std/Build/CheckObjectStep.zig+5-1
...@@ -27,7 +27,11 @@ pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std...@@ -27,7 +27,11 @@ pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std
27 const self = gpa.create(CheckObjectStep) catch @panic("OOM");27 const self = gpa.create(CheckObjectStep) catch @panic("OOM");
28 self.* = .{28 self.* = .{
29 .builder = builder,29 .builder = builder,
30 .step = Step.init(.check_file, "CheckObject", gpa, make),30 .step = Step.init(gpa, .{
31 .id = .check_file,
32 .name = "CheckObject",
33 .makeFn = make,
34 }),
31 .source = source.dupe(builder),35 .source = source.dupe(builder),
32 .checks = std.ArrayList(Check).init(gpa),36 .checks = std.ArrayList(Check).init(gpa),
33 .obj_format = obj_format,37 .obj_format = obj_format,
lib/std/Build/CompileStep.zig+5-1
...@@ -326,7 +326,11 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {...@@ -326,7 +326,11 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
326 .root_src = root_src,326 .root_src = root_src,
327 .name = name,327 .name = name,
328 .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator),328 .frameworks = StringHashMap(FrameworkLinkInfo).init(builder.allocator),
329 .step = Step.init(base_id, name, builder.allocator, make),329 .step = Step.init(builder.allocator, .{
330 .id = base_id,
331 .name = name,
332 .makeFn = make,
333 }),
330 .version = options.version,334 .version = options.version,
331 .out_filename = undefined,335 .out_filename = undefined,
332 .out_h_filename = builder.fmt("{s}.h", .{name}),336 .out_h_filename = builder.fmt("{s}.h", .{name}),
lib/std/Build/ConfigHeaderStep.zig+7-1
...@@ -46,6 +46,7 @@ pub const Options = struct {...@@ -46,6 +46,7 @@ pub const Options = struct {
46 style: Style = .blank,46 style: Style = .blank,
47 max_bytes: usize = 2 * 1024 * 1024,47 max_bytes: usize = 2 * 1024 * 1024,
48 include_path: ?[]const u8 = null,48 include_path: ?[]const u8 = null,
49 first_ret_addr: ?usize = null,
49};50};
5051
51pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {52pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
...@@ -56,7 +57,12 @@ pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {...@@ -56,7 +57,12 @@ pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
56 builder.fmt("configure {s} header", .{@tagName(options.style)});57 builder.fmt("configure {s} header", .{@tagName(options.style)});
57 self.* = .{58 self.* = .{
58 .builder = builder,59 .builder = builder,
59 .step = Step.init(base_id, name, builder.allocator, make),60 .step = Step.init(builder.allocator, .{
61 .id = base_id,
62 .name = name,
63 .makeFn = make,
64 .first_ret_addr = options.first_ret_addr orelse @returnAddress(),
65 }),
60 .style = options.style,66 .style = options.style,
61 .values = std.StringArrayHashMap(Value).init(builder.allocator),67 .values = std.StringArrayHashMap(Value).init(builder.allocator),
6268
lib/std/Build/EmulatableRunStep.zig+5-1
...@@ -56,7 +56,11 @@ pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *Em...@@ -56,7 +56,11 @@ pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *Em
5656
57 self.* = .{57 self.* = .{
58 .builder = builder,58 .builder = builder,
59 .step = Step.init(.emulatable_run, name, builder.allocator, make),59 .step = Step.init(builder.allocator, .{
60 .id = .emulatable_run,
61 .name = name,
62 .makeFn = make,
63 }),
60 .exe = artifact,64 .exe = artifact,
61 .env_map = null,65 .env_map = null,
62 .cwd = null,66 .cwd = null,
lib/std/Build/FmtStep.zig+5-1
...@@ -12,7 +12,11 @@ pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {...@@ -12,7 +12,11 @@ pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {
12 const self = builder.allocator.create(FmtStep) catch @panic("OOM");12 const self = builder.allocator.create(FmtStep) catch @panic("OOM");
13 const name = "zig fmt";13 const name = "zig fmt";
14 self.* = FmtStep{14 self.* = FmtStep{
15 .step = Step.init(.fmt, name, builder.allocator, make),15 .step = Step.init(builder.allocator, .{
16 .id = .fmt,
17 .name = name,
18 .makeFn = make,
19 }),
16 .builder = builder,20 .builder = builder,
17 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch @panic("OOM"),21 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch @panic("OOM"),
18 };22 };
lib/std/Build/InstallArtifactStep.zig+5-1
...@@ -19,7 +19,11 @@ pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep...@@ -19,7 +19,11 @@ pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep
19 const self = builder.allocator.create(InstallArtifactStep) catch @panic("OOM");19 const self = builder.allocator.create(InstallArtifactStep) catch @panic("OOM");
20 self.* = InstallArtifactStep{20 self.* = InstallArtifactStep{
21 .builder = builder,21 .builder = builder,
22 .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make),22 .step = Step.init(builder.allocator, .{
23 .id = base_id,
24 .name = builder.fmt("install {s}", .{artifact.step.name}),
25 .makeFn = make,
26 }),
23 .artifact = artifact,27 .artifact = artifact,
24 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {28 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
25 .obj => @panic("Cannot install a .obj build artifact."),29 .obj => @panic("Cannot install a .obj build artifact."),
lib/std/Build/InstallDirStep.zig+6-2
...@@ -45,9 +45,13 @@ pub fn init(...@@ -45,9 +45,13 @@ pub fn init(
45 options: Options,45 options: Options,
46) InstallDirStep {46) InstallDirStep {
47 builder.pushInstalledFile(options.install_dir, options.install_subdir);47 builder.pushInstalledFile(options.install_dir, options.install_subdir);
48 return InstallDirStep{48 return .{
49 .builder = builder,49 .builder = builder,
50 .step = Step.init(.install_dir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make),50 .step = Step.init(builder.allocator, .{
51 .id = .install_dir,
52 .name = builder.fmt("install {s}/", .{options.source_dir}),
53 .makeFn = make,
54 }),
51 .options = options.dupe(builder),55 .options = options.dupe(builder),
52 };56 };
53}57}
lib/std/Build/InstallFileStep.zig+5-1
...@@ -24,7 +24,11 @@ pub fn init(...@@ -24,7 +24,11 @@ pub fn init(
24 builder.pushInstalledFile(dir, dest_rel_path);24 builder.pushInstalledFile(dir, dest_rel_path);
25 return InstallFileStep{25 return InstallFileStep{
26 .builder = builder,26 .builder = builder,
27 .step = Step.init(.install_file, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make),27 .step = Step.init(builder.allocator, .{
28 .id = .install_file,
29 .name = builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }),
30 .makeFn = make,
31 }),
28 .source = source.dupe(builder),32 .source = source.dupe(builder),
29 .dir = dir.dupe(builder),33 .dir = dir.dupe(builder),
30 .dest_rel_path = builder.dupePath(dest_rel_path),34 .dest_rel_path = builder.dupePath(dest_rel_path),
lib/std/Build/LogStep.zig+5-1
...@@ -12,7 +12,11 @@ data: []const u8,...@@ -12,7 +12,11 @@ data: []const u8,
12pub fn init(builder: *std.Build, data: []const u8) LogStep {12pub fn init(builder: *std.Build, data: []const u8) LogStep {
13 return LogStep{13 return LogStep{
14 .builder = builder,14 .builder = builder,
15 .step = Step.init(.log, builder.fmt("log {s}", .{data}), builder.allocator, make),15 .step = Step.init(builder.allocator, .{
16 .id = .log,
17 .name = builder.fmt("log {s}", .{data}),
18 .makeFn = make,
19 }),
16 .data = builder.dupe(data),20 .data = builder.dupe(data),
17 };21 };
18}22}
lib/std/Build/ObjCopyStep.zig+5-6
...@@ -44,12 +44,11 @@ pub fn create(...@@ -44,12 +44,11 @@ pub fn create(
44) *ObjCopyStep {44) *ObjCopyStep {
45 const self = builder.allocator.create(ObjCopyStep) catch @panic("OOM");45 const self = builder.allocator.create(ObjCopyStep) catch @panic("OOM");
46 self.* = ObjCopyStep{46 self.* = ObjCopyStep{
47 .step = Step.init(47 .step = Step.init(builder.allocator, .{
48 base_id,48 .id = base_id,
49 builder.fmt("objcopy {s}", .{file_source.getDisplayName()}),49 .name = builder.fmt("objcopy {s}", .{file_source.getDisplayName()}),
50 builder.allocator,50 .makeFn = make,
51 make,51 }),
52 ),
53 .builder = builder,52 .builder = builder,
54 .file_source = file_source,53 .file_source = file_source,
55 .basename = options.basename orelse file_source.getDisplayName(),54 .basename = options.basename orelse file_source.getDisplayName(),
lib/std/Build/OptionsStep.zig+5-1
...@@ -22,7 +22,11 @@ pub fn create(builder: *std.Build) *OptionsStep {...@@ -22,7 +22,11 @@ pub fn create(builder: *std.Build) *OptionsStep {
22 const self = builder.allocator.create(OptionsStep) catch @panic("OOM");22 const self = builder.allocator.create(OptionsStep) catch @panic("OOM");
23 self.* = .{23 self.* = .{
24 .builder = builder,24 .builder = builder,
25 .step = Step.init(.options, "options", builder.allocator, make),25 .step = Step.init(builder.allocator, .{
26 .id = base_id,
27 .name = "options",
28 .makeFn = make,
29 }),
26 .generated_file = undefined,30 .generated_file = undefined,
27 .contents = std.ArrayList(u8).init(builder.allocator),31 .contents = std.ArrayList(u8).init(builder.allocator),
28 .artifact_args = std.ArrayList(OptionArtifactArg).init(builder.allocator),32 .artifact_args = std.ArrayList(OptionArtifactArg).init(builder.allocator),
lib/std/Build/RemoveDirStep.zig+5-1
...@@ -13,7 +13,11 @@ dir_path: []const u8,...@@ -13,7 +13,11 @@ dir_path: []const u8,
13pub fn init(builder: *std.Build, dir_path: []const u8) RemoveDirStep {13pub fn init(builder: *std.Build, dir_path: []const u8) RemoveDirStep {
14 return RemoveDirStep{14 return RemoveDirStep{
15 .builder = builder,15 .builder = builder,
16 .step = Step.init(.remove_dir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make),16 .step = Step.init(builder.allocator, .{
17 .id = .remove_dir,
18 .name = builder.fmt("RemoveDir {s}", .{dir_path}),
19 .makeFn = make,
20 }),
17 .dir_path = builder.dupePath(dir_path),21 .dir_path = builder.dupePath(dir_path),
18 };22 };
19}23}
lib/std/Build/RunStep.zig+6-2
...@@ -69,9 +69,13 @@ pub const Arg = union(enum) {...@@ -69,9 +69,13 @@ pub const Arg = union(enum) {
6969
70pub fn create(builder: *std.Build, name: []const u8) *RunStep {70pub fn create(builder: *std.Build, name: []const u8) *RunStep {
71 const self = builder.allocator.create(RunStep) catch @panic("OOM");71 const self = builder.allocator.create(RunStep) catch @panic("OOM");
72 self.* = RunStep{72 self.* = .{
73 .builder = builder,73 .builder = builder,
74 .step = Step.init(base_id, name, builder.allocator, make),74 .step = Step.init(builder.allocator, .{
75 .id = base_id,
76 .name = name,
77 .makeFn = make,
78 }),
75 .argv = ArrayList(Arg).init(builder.allocator),79 .argv = ArrayList(Arg).init(builder.allocator),
76 .cwd = null,80 .cwd = null,
77 .env_map = null,81 .env_map = null,
lib/std/Build/Step.zig+36-12
...@@ -11,6 +11,11 @@ result: struct {...@@ -11,6 +11,11 @@ result: struct {
11 err_code: anyerror,11 err_code: anyerror,
12 stderr: []u8,12 stderr: []u8,
13},13},
14/// The return addresss associated with creation of this step that can be useful
15/// to print along with debugging messages.
16debug_stack_trace: [n_debug_stack_frames]usize,
17
18const n_debug_stack_frames = 4;
1419
15pub const State = enum {20pub const State = enum {
16 precheck_unstarted,21 precheck_unstarted,
...@@ -66,16 +71,26 @@ pub const Id = enum {...@@ -66,16 +71,26 @@ pub const Id = enum {
66 }71 }
67};72};
6873
69pub fn init(74pub const Options = struct {
70 id: Id,75 id: Id,
71 name: []const u8,76 name: []const u8,
72 allocator: Allocator,77 makeFn: *const fn (self: *Step) anyerror!void = makeNoOp,
73 makeFn: *const fn (self: *Step) anyerror!void,78 first_ret_addr: ?usize = null,
74) Step {79};
75 return Step{80
76 .id = id,81pub fn init(allocator: Allocator, options: Options) Step {
77 .name = allocator.dupe(u8, name) catch @panic("OOM"),82 var addresses = [1]usize{0} ** n_debug_stack_frames;
78 .makeFn = makeFn,83 const first_ret_addr = options.first_ret_addr orelse @returnAddress();
84 var stack_trace = std.builtin.StackTrace{
85 .instruction_addresses = &addresses,
86 .index = 0,
87 };
88 std.debug.captureStackTrace(first_ret_addr, &stack_trace);
89
90 return .{
91 .id = options.id,
92 .name = allocator.dupe(u8, options.name) catch @panic("OOM"),
93 .makeFn = options.makeFn,
79 .dependencies = std.ArrayList(*Step).init(allocator),94 .dependencies = std.ArrayList(*Step).init(allocator),
80 .dependants = .{},95 .dependants = .{},
81 .state = .precheck_unstarted,96 .state = .precheck_unstarted,
...@@ -83,13 +98,10 @@ pub fn init(...@@ -83,13 +98,10 @@ pub fn init(
83 .err_code = undefined,98 .err_code = undefined,
84 .stderr = &.{},99 .stderr = &.{},
85 },100 },
101 .debug_stack_trace = addresses,
86 };102 };
87}103}
88104
89pub fn initNoOp(id: Id, name: []const u8, allocator: Allocator) Step {
90 return init(id, name, allocator, makeNoOp);
91}
92
93pub fn make(self: *Step) !void {105pub fn make(self: *Step) !void {
94 try self.makeFn(self);106 try self.makeFn(self);
95}107}
...@@ -98,6 +110,18 @@ pub fn dependOn(self: *Step, other: *Step) void {...@@ -98,6 +110,18 @@ pub fn dependOn(self: *Step, other: *Step) void {
98 self.dependencies.append(other) catch @panic("OOM");110 self.dependencies.append(other) catch @panic("OOM");
99}111}
100112
113pub fn getStackTrace(s: *Step) std.builtin.StackTrace {
114 const stack_addresses = &s.debug_stack_trace;
115 var len: usize = 0;
116 while (len < n_debug_stack_frames and stack_addresses[len] != 0) {
117 len += 1;
118 }
119 return .{
120 .instruction_addresses = stack_addresses,
121 .index = len,
122 };
123}
124
101fn makeNoOp(self: *Step) anyerror!void {125fn makeNoOp(self: *Step) anyerror!void {
102 _ = self;126 _ = self;
103}127}
lib/std/Build/TranslateCStep.zig+5-1
...@@ -30,7 +30,11 @@ pub fn create(builder: *std.Build, options: Options) *TranslateCStep {...@@ -30,7 +30,11 @@ pub fn create(builder: *std.Build, options: Options) *TranslateCStep {
30 const self = builder.allocator.create(TranslateCStep) catch @panic("OOM");30 const self = builder.allocator.create(TranslateCStep) catch @panic("OOM");
31 const source = options.source_file.dupe(builder);31 const source = options.source_file.dupe(builder);
32 self.* = TranslateCStep{32 self.* = TranslateCStep{
33 .step = Step.init(.translate_c, "translate-c", builder.allocator, make),33 .step = Step.init(builder.allocator, .{
34 .id = .translate_c,
35 .name = "translate-c",
36 .makeFn = make,
37 }),
34 .builder = builder,38 .builder = builder,
35 .source = source,39 .source = source,
36 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),40 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
lib/std/Build/WriteFileStep.zig+5-1
...@@ -37,7 +37,11 @@ pub const Contents = union(enum) {...@@ -37,7 +37,11 @@ pub const Contents = union(enum) {
37pub fn init(builder: *std.Build) WriteFileStep {37pub fn init(builder: *std.Build) WriteFileStep {
38 return .{38 return .{
39 .builder = builder,39 .builder = builder,
40 .step = Step.init(.write_file, "writefile", builder.allocator, make),40 .step = Step.init(builder.allocator, .{
41 .id = .write_file,
42 .name = "writefile",
43 .makeFn = make,
44 }),
41 .files = .{},45 .files = .{},
42 .output_source_files = .{},46 .output_source_files = .{},
43 };47 };
test/link/macho/uuid/build.zig+12-10
...@@ -90,10 +90,13 @@ const InstallWithRename = struct {...@@ -90,10 +90,13 @@ const InstallWithRename = struct {
90 const self = builder.allocator.create(InstallWithRename) catch @panic("OOM");90 const self = builder.allocator.create(InstallWithRename) catch @panic("OOM");
91 self.* = InstallWithRename{91 self.* = InstallWithRename{
92 .builder = builder,92 .builder = builder,
93 .step = Step.init(.custom, builder.fmt("install and rename: {s} -> {s}", .{93 .step = Step.init(builder.allocator, .{
94 source.getDisplayName(),94 .id = .custom,
95 name,95 .name = builder.fmt("install and rename: {s} -> {s}", .{
96 }), builder.allocator, make),96 source.getDisplayName(), name,
97 }),
98 .makeFn = make,
99 }),
97 .source = source,100 .source = source,
98 .name = builder.dupe(name),101 .name = builder.dupe(name),
99 };102 };
...@@ -123,15 +126,14 @@ const CompareUuid = struct {...@@ -123,15 +126,14 @@ const CompareUuid = struct {
123 const self = builder.allocator.create(CompareUuid) catch @panic("OOM");126 const self = builder.allocator.create(CompareUuid) catch @panic("OOM");
124 self.* = CompareUuid{127 self.* = CompareUuid{
125 .builder = builder,128 .builder = builder,
126 .step = Step.init(129 .step = Step.init(builder.allocator, .{
127 .custom,130 .id = .custom,
128 builder.fmt("compare uuid: {s} and {s}", .{131 .name = builder.fmt("compare uuid: {s} and {s}", .{
129 lhs,132 lhs,
130 rhs,133 rhs,
131 }),134 }),
132 builder.allocator,135 .makeFn = make,
133 make,136 }),
134 ),
135 .lhs = lhs,137 .lhs = lhs,
136 .rhs = rhs,138 .rhs = rhs,
137 };139 };
test/tests.zig+10-2
...@@ -858,7 +858,11 @@ pub const StackTracesContext = struct {...@@ -858,7 +858,11 @@ pub const StackTracesContext = struct {
858 const allocator = context.b.allocator;858 const allocator = context.b.allocator;
859 const ptr = allocator.create(RunAndCompareStep) catch unreachable;859 const ptr = allocator.create(RunAndCompareStep) catch unreachable;
860 ptr.* = RunAndCompareStep{860 ptr.* = RunAndCompareStep{
861 .step = Step.init(.custom, "StackTraceCompareOutputStep", allocator, make),861 .step = Step.init(allocator, .{
862 .id = .custom,
863 .name = "StackTraceCompareOutputStep",
864 .makeFn = make,
865 }),
862 .context = context,866 .context = context,
863 .exe = exe,867 .exe = exe,
864 .name = name,868 .name = name,
...@@ -1194,7 +1198,11 @@ pub const GenHContext = struct {...@@ -1194,7 +1198,11 @@ pub const GenHContext = struct {
1194 const allocator = context.b.allocator;1198 const allocator = context.b.allocator;
1195 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;1199 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
1196 ptr.* = GenHCmpOutputStep{1200 ptr.* = GenHCmpOutputStep{
1197 .step = Step.init(.Custom, "ParseCCmpOutput", allocator, make),1201 .step = Step.init(allocator, .{
1202 .id = .custom,
1203 .name = "ParseCCmpOutput",
1204 .makeFn = make,
1205 }),
1198 .context = context,1206 .context = context,
1199 .obj = obj,1207 .obj = obj,
1200 .name = name,1208 .name = name,