Files
zig/lib/compiler/Maker/Step/Options.zig
T
Andrew Kelley 43209551b7 maker: implement Step.Options
also revert #35224
2026-05-25 18:54:35 -07:00

105 lines
3.8 KiB
Zig

const Options = @This();
const std = @import("std");
const Io = std.Io;
const Configuration = std.Build.Configuration;
const Cache = std.Build.Cache;
const Step = @import("../Step.zig");
const Maker = @import("../../Maker.zig");
pub fn make(
options: *Options,
step_index: Configuration.Step.Index,
maker: *Maker,
progress_node: std.Progress.Node,
) Step.ExtendedMakeError!void {
_ = options;
// This step completes so quickly that no progress reporting is necessary.
_ = progress_node;
const graph = maker.graph;
const step = maker.stepByIndex(step_index);
const io = graph.io;
const cache_root = graph.local_cache_root;
const arena = graph.arena; // TODO don't leak into the process arena
const conf = &maker.scanned_config.configuration;
const conf_step = step_index.ptr(conf);
const conf_options = conf_step.extended.get(conf.extra).options;
const contents = conf_options.contents.slice(conf);
// This step operates under the assumption that all contents of the
// generated zig file are observable by dependant steps, as well as the
// contents of files added via Options.Arg.
step.clearWatchInputs(maker);
var man = graph.cache.obtain();
defer man.deinit();
var args_bytes: std.ArrayList(u8) = .empty;
for (conf_options.args.slice) |arg| {
const name = arg.name.slice(conf);
const lazy_path = arg.path.get(conf);
try step.addWatchInput(maker, arena, lazy_path);
const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
_ = try man.addFilePath(arg_path, null);
try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{
std.zig.fmtId(name), arg_path.fmtEscapeString(),
});
}
man.hash.addBytes(contents);
man.hash.addBytes(args_bytes.items);
const basename = "options.zig";
if (try step.cacheHitAndWatch(maker, &man)) {
const digest = man.final();
maker.generatedPath(conf_options.generated_file).* = .{
.root_dir = cache_root,
.sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),
};
step.result_cached = true;
return;
}
const digest = man.final();
const out_path: Cache.Path = .{
.root_dir = cache_root,
.sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),
};
var file: Io.File = out_path.root_dir.handle.createFile(io, out_path.sub_path, .{}) catch |err| switch (err) {
error.Canceled => |e| return e,
error.FileNotFound => f: {
out_path.root_dir.handle.createDirPath(io, Io.Dir.path.dirname(out_path.sub_path).?) catch |inner| switch (inner) {
error.Canceled => |e| return e,
else => |e| return step.fail(maker, "failed to create {f}: {t}", .{ out_path, e }),
};
break :f out_path.root_dir.handle.createFile(io, out_path.sub_path, .{}) catch |inner| switch (inner) {
error.Canceled => |e| return e,
else => |e| return step.fail(maker, "failed to create {f}: {t}", .{ out_path, e }),
};
},
else => |e| return step.fail(maker, "failed to create {f}: {t}", .{ out_path, e }),
};
defer file.close(io);
// No buffer because we already have all contents buffered.
var file_writer = file.writer(io, &.{});
var data: [2][]const u8 = .{ contents, args_bytes.items };
file_writer.interface.writeVecAll(&data) catch |write_err| switch (write_err) {
error.WriteFailed => switch (file_writer.err.?) {
error.Canceled => |e| return e,
else => |e| return step.fail(maker, "failed to write to {f}: {t}", .{ out_path, e }),
},
};
try step.writeManifestAndWatch(maker, &man);
maker.generatedPath(conf_options.generated_file).* = out_path;
}