Skip to content

Commit 02381c0

Browse files
committed
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.
1 parent 9580fbc commit 02381c0

20 files changed

+209
-68
lines changed

lib/std/Build.zig

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,19 @@ pub fn create(
227227
.h_dir = undefined,
228228
.dest_dir = env_map.get("DESTDIR"),
229229
.installed_files = ArrayList(InstalledFile).init(allocator),
230-
.install_tls = TopLevelStep{
231-
.step = Step.initNoOp(.top_level, "install", allocator),
230+
.install_tls = .{
231+
.step = Step.init(allocator, .{
232+
.id = .top_level,
233+
.name = "install",
234+
}),
232235
.description = "Copy build artifacts to prefix path",
233236
},
234-
.uninstall_tls = TopLevelStep{
235-
.step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
237+
.uninstall_tls = .{
238+
.step = Step.init(allocator, .{
239+
.id = .top_level,
240+
.name = "uninstall",
241+
.makeFn = makeUninstall,
242+
}),
236243
.description = "Remove build artifacts from prefix path",
237244
},
238245
.zig_lib_dir = null,
@@ -264,11 +271,18 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc
264271
child.* = .{
265272
.allocator = allocator,
266273
.install_tls = .{
267-
.step = Step.initNoOp(.top_level, "install", allocator),
274+
.step = Step.init(allocator, .{
275+
.id = .top_level,
276+
.name = "install",
277+
}),
268278
.description = "Copy build artifacts to prefix path",
269279
},
270280
.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+
}),
272286
.description = "Remove build artifacts from prefix path",
273287
},
274288
.user_input_options = UserInputOptionsMap.init(allocator),
@@ -634,7 +648,11 @@ pub fn addConfigHeader(
634648
options: ConfigHeaderStep.Options,
635649
values: anytype,
636650
) *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);
638656
config_header_step.addValues(values);
639657
return config_header_step;
640658
}
@@ -858,7 +876,10 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_
858876
pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {
859877
const step_info = self.allocator.create(TopLevelStep) catch @panic("OOM");
860878
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+
}),
862883
.description = self.dupe(description),
863884
};
864885
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,
11531174
printCmd(self.allocator, cwd, argv);
11541175
}
11551176

1156-
if (!std.process.can_spawn)
1177+
if (!process.can_spawn)
11571178
return error.ExecNotSupported;
11581179

11591180
var child = std.ChildProcess.init(argv, self.allocator);
@@ -1355,7 +1376,7 @@ pub fn execAllowFail(
13551376
) ExecError![]u8 {
13561377
assert(argv.len != 0);
13571378

1358-
if (!std.process.can_spawn)
1379+
if (!process.can_spawn)
13591380
return error.ExecNotSupported;
13601381

13611382
const max_output_size = 400 * 1024;
@@ -1395,7 +1416,7 @@ pub fn execFromStep(b: *Build, argv: []const []const u8, s: *Step) ![]u8 {
13951416
printCmd(b.allocator, null, argv);
13961417
}
13971418

1398-
if (!std.process.can_spawn) {
1419+
if (!process.can_spawn) {
13991420
s.result.stderr = b.fmt("Unable to spawn the following command: cannot spawn child processes\n{s}", .{
14001421
try allocPrintCmd(b.allocator, null, argv),
14011422
});
@@ -1458,7 +1479,7 @@ fn unwrapExecResult(
14581479
/// inside step make() functions. If any errors occur, it fails the build with
14591480
/// a helpful message.
14601481
pub fn exec(b: *Build, argv: []const []const u8) []u8 {
1461-
if (!std.process.can_spawn) {
1482+
if (!process.can_spawn) {
14621483
std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}", .{
14631484
try allocPrintCmd(b.allocator, null, argv),
14641485
});
@@ -1539,7 +1560,7 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
15391560

15401561
const full_path = b.pathFromRoot("build.zig.zon");
15411562
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);
15431564
}
15441565

15451566
fn dependencyInner(
@@ -1555,7 +1576,7 @@ fn dependencyInner(
15551576
std.debug.print("unable to open '{s}': {s}\n", .{
15561577
build_root_string, @errorName(err),
15571578
});
1558-
std.process.exit(1);
1579+
process.exit(1);
15591580
},
15601581
};
15611582
const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");
@@ -1599,7 +1620,7 @@ pub const GeneratedFile = struct {
15991620

16001621
pub fn getPath(self: GeneratedFile) []const u8 {
16011622
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}'?",
16031624
.{self.step.name},
16041625
);
16051626
}
@@ -1639,12 +1660,16 @@ pub const FileSource = union(enum) {
16391660
}
16401661

16411662
/// 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 {
1643-
const path = switch (self) {
1644-
.path => |p| builder.pathFromRoot(p),
1645-
.generated => |gen| gen.getPath(),
1646-
};
1647-
return path;
1663+
pub fn getPath(self: FileSource, src_builder: *Build) []const u8 {
1664+
switch (self) {
1665+
.path => |p| return src_builder.pathFromRoot(p),
1666+
.generated => |gen| return gen.path orelse {
1667+
std.debug.getStderrMutex().lock();
1668+
const stderr = std.io.getStdErr();
1669+
dumpBadGetPathHelp(gen.step, stderr, src_builder) catch {};
1670+
@panic("unable to get path");
1671+
},
1672+
}
16481673
}
16491674

16501675
/// Duplicates the file source for a given builder.
@@ -1656,6 +1681,27 @@ pub const FileSource = union(enum) {
16561681
}
16571682
};
16581683

1684+
fn 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+
16591705
/// Allocates a new string for assigning a value to a named macro.
16601706
/// If the value is omitted, it is set to 1.
16611707
/// `name` and `value` need not live longer than the function call.

lib/std/Build/CheckFileStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ pub fn create(
2121
const self = builder.allocator.create(CheckFileStep) catch @panic("OOM");
2222
self.* = CheckFileStep{
2323
.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+
}),
2529
.source = source.dupe(builder),
2630
.expected_matches = builder.dupeStrings(expected_matches),
2731
};

lib/std/Build/CheckObjectStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std
2727
const self = gpa.create(CheckObjectStep) catch @panic("OOM");
2828
self.* = .{
2929
.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+
}),
3135
.source = source.dupe(builder),
3236
.checks = std.ArrayList(Check).init(gpa),
3337
.obj_format = obj_format,

lib/std/Build/CompileStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,11 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
326326
.root_src = root_src,
327327
.name = name,
328328
.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+
}),
330334
.version = options.version,
331335
.out_filename = undefined,
332336
.out_h_filename = builder.fmt("{s}.h", .{name}),

lib/std/Build/ConfigHeaderStep.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub const Options = struct {
4646
style: Style = .blank,
4747
max_bytes: usize = 2 * 1024 * 1024,
4848
include_path: ?[]const u8 = null,
49+
first_ret_addr: ?usize = null,
4950
};
5051

5152
pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
@@ -56,7 +57,12 @@ pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
5657
builder.fmt("configure {s} header", .{@tagName(options.style)});
5758
self.* = .{
5859
.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+
}),
6066
.style = options.style,
6167
.values = std.StringArrayHashMap(Value).init(builder.allocator),
6268

lib/std/Build/EmulatableRunStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ pub fn create(builder: *std.Build, name: []const u8, artifact: *CompileStep) *Em
5656

5757
self.* = .{
5858
.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+
}),
6064
.exe = artifact,
6165
.env_map = null,
6266
.cwd = null,

lib/std/Build/FmtStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {
1212
const self = builder.allocator.create(FmtStep) catch @panic("OOM");
1313
const name = "zig fmt";
1414
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+
}),
1620
.builder = builder,
1721
.argv = builder.allocator.alloc([]u8, paths.len + 2) catch @panic("OOM"),
1822
};

lib/std/Build/InstallArtifactStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ pub fn create(builder: *std.Build, artifact: *CompileStep) *InstallArtifactStep
1919
const self = builder.allocator.create(InstallArtifactStep) catch @panic("OOM");
2020
self.* = InstallArtifactStep{
2121
.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+
}),
2327
.artifact = artifact,
2428
.dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
2529
.obj => @panic("Cannot install a .obj build artifact."),

lib/std/Build/InstallDirStep.zig

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@ pub fn init(
4545
options: Options,
4646
) InstallDirStep {
4747
builder.pushInstalledFile(options.install_dir, options.install_subdir);
48-
return InstallDirStep{
48+
return .{
4949
.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+
}),
5155
.options = options.dupe(builder),
5256
};
5357
}

lib/std/Build/InstallFileStep.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ pub fn init(
2424
builder.pushInstalledFile(dir, dest_rel_path);
2525
return InstallFileStep{
2626
.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+
}),
2832
.source = source.dupe(builder),
2933
.dir = dir.dupe(builder),
3034
.dest_rel_path = builder.dupePath(dest_rel_path),

0 commit comments

Comments
 (0)