Commit 2ceeade99a

Sahnvour <sahnvour@pm.me>
2023-08-12 13:15:05
std.Build: add support for deps .d file in Step.Run
1 parent 1c5c3f4
Changed files (2)
lib
std
Build
lib/std/Build/Step/Run.zig
@@ -77,6 +77,8 @@ max_stdio_size: usize = 10 * 1024 * 1024,
 captured_stdout: ?*Output = null,
 captured_stderr: ?*Output = null,
 
+dep_output_file: ?*Output = null,
+
 has_side_effects: bool = false,
 
 pub const StdIn = union(enum) {
@@ -240,6 +242,33 @@ pub fn addPrefixedDirectoryArg(self: *Run, prefix: []const u8, directory_source:
     directory_source.addStepDependencies(&self.step);
 }
 
+/// Add a path argument to a dep file (.d) for the child process to write its
+/// discovered additional dependencies.
+/// Only one dep file argument is allowed by instance.
+pub fn addDepFileOutputArg(self: *Run, basename: []const u8) std.Build.LazyPath {
+    return self.addPrefixedDepFileOutputArg("", basename);
+}
+
+/// Add a prefixed path argument to a dep file (.d) for the child process to
+/// write its discovered additional dependencies.
+/// Only one dep file argument is allowed by instance.
+pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) void {
+    assert(self.dep_output_file == null);
+
+    const b = self.step.owner;
+
+    const dep_file = b.allocator.create(Output) catch @panic("OOM");
+    dep_file.* = .{
+        .prefix = b.dupe(prefix),
+        .basename = b.dupe(basename),
+        .generated_file = .{ .step = &self.step },
+    };
+
+    self.dep_output_file = dep_file;
+
+    self.argv.append(.{ .output = dep_file }) catch @panic("OOM");
+}
+
 pub fn addArg(self: *Run, arg: []const u8) void {
     self.argv.append(.{ .bytes = self.step.owner.dupe(arg) }) catch @panic("OOM");
 }
@@ -559,6 +588,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
 
     try runCommand(self, argv_list.items, has_side_effects, &digest, prog_node);
 
+    if (self.dep_output_file) |dep_output_file|
+        try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
+
     try step.writeManifest(&man);
 }
 
lib/std/Build/Cache.zig
@@ -778,20 +778,11 @@ pub const Manifest = struct {
 
         var it: DepTokenizer = .{ .bytes = dep_file_contents };
 
-        // Skip first token: target.
-        switch (it.next() orelse return) { // Empty dep file OK.
-            .target, .target_must_resolve, .prereq => {},
-            else => |err| {
-                try err.printError(error_buf.writer());
-                log.err("failed parsing {s}: {s}", .{ dep_file_basename, error_buf.items });
-                return error.InvalidDepFile;
-            },
-        }
-        // Process 0+ preqreqs.
-        // Clang is invoked in single-source mode so we never get more targets.
         while (true) {
             switch (it.next() orelse return) {
-                .target, .target_must_resolve => return,
+                // We don't care about targets, we only want the prereqs
+                // Clang is invoked in single-source mode but other programs may not
+                .target, .target_must_resolve => {},
                 .prereq => |file_path| try self.addFilePost(file_path),
                 else => |err| {
                     try err.printError(error_buf.writer());