Skip to content

Commit 1d0af1f

Browse files
committed
std.Build: Add a finalize function to Build.Steps
It is called after the user has fully configured the steps in the build() function.
1 parent 2b3395b commit 1d0af1f

File tree

3 files changed

+77
-21
lines changed

3 files changed

+77
-21
lines changed

lib/compiler/build_runner.zig

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ pub fn main() !void {
339339
try builder.runBuild(root);
340340
}
341341

342+
for (builder.top_level_steps.values()) |s| {
343+
try finalizeSteps(&s.step);
344+
}
345+
342346
if (graph.needed_lazy_dependencies.entries.len != 0) {
343347
var buffer: std.ArrayListUnmanaged(u8) = .empty;
344348
for (graph.needed_lazy_dependencies.keys()) |k| {
@@ -636,6 +640,7 @@ fn runStepNames(
636640
test_count += s.test_results.test_count;
637641

638642
switch (s.state) {
643+
.unfinalized => unreachable,
639644
.precheck_unstarted => unreachable,
640645
.precheck_started => unreachable,
641646
.running => unreachable,
@@ -781,6 +786,7 @@ fn printStepStatus(
781786
run: *const Run,
782787
) !void {
783788
switch (s.state) {
789+
.unfinalized => unreachable,
784790
.precheck_unstarted => unreachable,
785791
.precheck_started => unreachable,
786792
.precheck_done => unreachable,
@@ -978,6 +984,34 @@ fn printTreeStep(
978984
}
979985
}
980986

987+
/// Traverse the dependency graph after the user build() call,
988+
/// this allows for checks and postprocessing after the steps are fully configured by the user.
989+
fn finalizeSteps(
990+
s: *Step,
991+
) !void {
992+
switch (s.state) {
993+
.unfinalized => {
994+
try s.finalize();
995+
s.state = .precheck_unstarted;
996+
997+
for (s.dependencies.items) |dep| {
998+
try finalizeSteps(dep);
999+
}
1000+
},
1001+
1002+
.precheck_unstarted => {},
1003+
1004+
.precheck_started => unreachable,
1005+
.precheck_done => unreachable,
1006+
.dependency_failure => unreachable,
1007+
.running => unreachable,
1008+
.success => unreachable,
1009+
.failure => unreachable,
1010+
.skipped => unreachable,
1011+
.skipped_oom => unreachable,
1012+
}
1013+
}
1014+
9811015
/// Traverse the dependency graph depth-first and make it undirected by having
9821016
/// steps know their dependants (they only know dependencies at start).
9831017
/// Along the way, check that there is no dependency loop, and record the steps
@@ -996,6 +1030,7 @@ fn constructGraphAndCheckForDependencyLoop(
9961030
rand: std.Random,
9971031
) !void {
9981032
switch (s.state) {
1033+
.unfinalized => unreachable,
9991034
.precheck_started => {
10001035
std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
10011036
return error.DependencyLoopDetected;
@@ -1058,6 +1093,7 @@ fn workerMakeOneStep(
10581093
// dependency is not finished yet.
10591094
return;
10601095
},
1096+
.unfinalized => unreachable,
10611097
.precheck_unstarted => unreachable,
10621098
.precheck_started => unreachable,
10631099
}

lib/std/Build/Step.zig

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
id: Id,
22
name: []const u8,
33
owner: *Build,
4+
finalizeFn: FinalizeFn,
45
makeFn: MakeFn,
56

67
dependencies: std.ArrayList(*Step),
@@ -68,6 +69,8 @@ pub const TestResults = struct {
6869
}
6970
};
7071

72+
pub const FinalizeFn = *const fn (step: *Step) anyerror!void;
73+
7174
pub const MakeOptions = struct {
7275
progress_node: std.Progress.Node,
7376
thread_pool: *std.Thread.Pool,
@@ -77,6 +80,7 @@ pub const MakeOptions = struct {
7780
pub const MakeFn = *const fn (step: *Step, options: MakeOptions) anyerror!void;
7881

7982
pub const State = enum {
83+
unfinalized,
8084
precheck_unstarted,
8185
precheck_started,
8286
/// This is also used to indicate "dirty" steps that have been modified
@@ -183,6 +187,7 @@ pub const StepOptions = struct {
183187
id: Id,
184188
name: []const u8,
185189
owner: *Build,
190+
finalizeFn: FinalizeFn = finalizeNoOp,
186191
makeFn: MakeFn = makeNoOp,
187192
first_ret_addr: ?usize = null,
188193
max_rss: usize = 0,
@@ -195,11 +200,12 @@ pub fn init(options: StepOptions) Step {
195200
.id = options.id,
196201
.name = arena.dupe(u8, options.name) catch @panic("OOM"),
197202
.owner = options.owner,
203+
.finalizeFn = options.finalizeFn,
198204
.makeFn = options.makeFn,
199205
.dependencies = std.ArrayList(*Step).init(arena),
200206
.dependants = .{},
201207
.inputs = Inputs.init,
202-
.state = .precheck_unstarted,
208+
.state = .unfinalized,
203209
.max_rss = options.max_rss,
204210
.debug_stack_trace = blk: {
205211
const addresses = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
@@ -222,6 +228,11 @@ pub fn init(options: StepOptions) Step {
222228
};
223229
}
224230

231+
pub fn finalize(s: *Step) !void {
232+
assert(s.state == .unfinalized);
233+
try s.finalizeFn(s);
234+
}
235+
225236
/// If the Step's `make` function reports `error.MakeFailed`, it indicates they
226237
/// have already reported the error. Otherwise, we add a simple error report
227238
/// here.
@@ -266,6 +277,10 @@ pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace {
266277
};
267278
}
268279

280+
fn finalizeNoOp(step: *Step) anyerror!void {
281+
_ = step;
282+
}
283+
269284
fn makeNoOp(step: *Step, options: MakeOptions) anyerror!void {
270285
_ = options;
271286

lib/std/Build/Step/Compile.zig

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@ generated_h: ?*GeneratedFile,
216216
/// Defaults to `std.math.maxInt(u16)`
217217
error_limit: ?u32 = null,
218218

219-
/// Computed during make().
219+
/// Computed during finalize().
220220
is_linking_libc: bool = false,
221-
/// Computed during make().
221+
/// Computed during finalize().
222222
is_linking_libcpp: bool = false,
223223

224224
no_builtin: bool = false,
@@ -404,6 +404,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
404404
.id = base_id,
405405
.name = step_name,
406406
.owner = owner,
407+
.finalizeFn = finalize,
407408
.makeFn = make,
408409
.max_rss = options.max_rss,
409410
}),
@@ -1111,24 +1112,6 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
11111112
// emitted if there is nothing to link.
11121113
var total_linker_objects: usize = @intFromBool(compile.root_module.root_source_file != null);
11131114

1114-
{
1115-
// Fully recursive iteration including dynamic libraries to detect
1116-
// libc and libc++ linkage.
1117-
var dep_it = compile.root_module.iterateDependencies(compile, true);
1118-
while (dep_it.next()) |key| {
1119-
if (key.module.link_libc == true) compile.is_linking_libc = true;
1120-
if (key.module.link_libcpp == true) compile.is_linking_libcpp = true;
1121-
}
1122-
}
1123-
1124-
if (compile.kind == .pch) {
1125-
// precompiled headers must have a single input header file.
1126-
var it = compile.root_module.iterateDependencies(compile, false);
1127-
const link_objects = it.next().?.module.link_objects;
1128-
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1129-
assert(it.next() == null);
1130-
}
1131-
11321115
var cli_named_modules = try CliNamedModules.init(arena, &compile.root_module);
11331116

11341117
// For this loop, don't chase dynamic libraries because their link
@@ -1807,6 +1790,28 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
18071790
return try zig_args.toOwnedSlice();
18081791
}
18091792

1793+
fn finalize(step: *Step) !void {
1794+
const compile: *Compile = @fieldParentPtr("step", step);
1795+
1796+
{
1797+
// Fully recursive iteration including dynamic libraries to detect
1798+
// libc and libc++ linkage.
1799+
var dep_it = compile.root_module.iterateDependencies(compile, true);
1800+
while (dep_it.next()) |key| {
1801+
if (key.module.link_libc == true) compile.is_linking_libc = true;
1802+
if (key.module.link_libcpp == true) compile.is_linking_libcpp = true;
1803+
}
1804+
}
1805+
1806+
if (compile.kind == .pch) {
1807+
// precompiled headers must have a single input header file.
1808+
var it = compile.root_module.iterateDependencies(compile, false);
1809+
const link_objects = it.next().?.module.link_objects;
1810+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1811+
assert(it.next() == null);
1812+
}
1813+
}
1814+
18101815
fn make(step: *Step, options: Step.MakeOptions) !void {
18111816
const b = step.owner;
18121817
const compile: *Compile = @fieldParentPtr("step", step);

0 commit comments

Comments
 (0)