authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-05-04 15:12:24-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-05-05 15:58:08-04:00
logdee9f82f69db0d034251b844e0bc4083a1b25fdd
tree14adb7ca55844ef04872501174cd006812edbf43
parente3424332d3fa1264e1f6861b76bb0d1b2996728d

Run: add output directory arguments

This allows running commands that take an output directory argument. The main thing that was needed for this feature was generated file subpaths, to allow access to the files in a generated directory. Additionally, a minor change was required to so that the correct directory is created for output directory args.

12 files changed, 274 insertions(+), 121 deletions(-)

lib/std/Build.zig+87-80
......@@ -2131,28 +2131,23 @@ test dirnameAllowEmpty {
21312131
21322132/// A reference to an existing or future path.
21332133pub const LazyPath = union(enum) {
2134 /// Deprecated; use the `path` function instead.
2135 path: []const u8,
2136
21372134 /// A source file path relative to build root.
21382135 src_path: struct {
21392136 owner: *std.Build,
21402137 sub_path: []const u8,
21412138 },
21422139
2143 /// A file that is generated by an interface. Those files usually are
2144 /// not available until built by a build step.
2145 generated: *const GeneratedFile,
2146
2147 /// One of the parent directories of a file generated by an interface.
2148 /// The path is not available until built by a build step.
2149 generated_dirname: struct {
2150 generated: *const GeneratedFile,
2140 generated: struct {
2141 file: *const GeneratedFile,
21512142
21522143 /// The number of parent directories to go up.
2153 /// 0 means the directory of the generated file,
2154 /// 1 means the parent of that directory, and so on.
2155 up: usize,
2144 /// 0 means the generated file itself.
2145 /// 1 means the directory of the generated file.
2146 /// 2 means the parent of that directory, and so on.
2147 up: usize = 0,
2148
2149 /// Applied after `up`.
2150 sub_path: []const u8 = "",
21562151 },
21572152
21582153 /// An absolute path or a path relative to the current working directory of
......@@ -2168,12 +2163,6 @@ pub const LazyPath = union(enum) {
21682163 sub_path: []const u8,
21692164 },
21702165
2171 /// Deprecated. Call `path` instead.
2172 pub fn relative(sub_path: []const u8) LazyPath {
2173 std.log.warn("deprecated. call std.Build.path instead", .{});
2174 return .{ .path = sub_path };
2175 }
2176
21772166 /// Returns a lazy path referring to the directory containing this path.
21782167 ///
21792168 /// The dirname is not allowed to escape the logical root for underlying path.
......@@ -2183,8 +2172,6 @@ pub const LazyPath = union(enum) {
21832172 /// the dirname is not allowed to traverse outside of zig-cache.
21842173 pub fn dirname(lazy_path: LazyPath) LazyPath {
21852174 return switch (lazy_path) {
2186 .generated => |gen| .{ .generated_dirname = .{ .generated = gen, .up = 0 } },
2187 .generated_dirname => |gen| .{ .generated_dirname = .{ .generated = gen.generated, .up = gen.up + 1 } },
21882175 .src_path => |sp| .{ .src_path = .{
21892176 .owner = sp.owner,
21902177 .sub_path = dirnameAllowEmpty(sp.sub_path) orelse {
......@@ -2192,12 +2179,15 @@ pub const LazyPath = union(enum) {
21922179 @panic("misconfigured build script");
21932180 },
21942181 } },
2195 .path => |sub_path| .{
2196 .path = dirnameAllowEmpty(sub_path) orelse {
2197 dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the build root\n", .{}) catch {};
2198 @panic("misconfigured build script");
2199 },
2200 },
2182 .generated => |generated| .{ .generated = if (dirnameAllowEmpty(generated.sub_path)) |sub_dirname| .{
2183 .file = generated.file,
2184 .up = generated.up,
2185 .sub_path = sub_dirname,
2186 } else .{
2187 .file = generated.file,
2188 .up = generated.up + 1,
2189 .sub_path = "",
2190 } },
22012191 .cwd_relative => |rel_path| .{
22022192 .cwd_relative = dirnameAllowEmpty(rel_path) orelse {
22032193 // If we get null, it means one of two things:
......@@ -2234,14 +2224,34 @@ pub const LazyPath = union(enum) {
22342224 };
22352225 }
22362226
2227 pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath {
2228 return switch (lazy_path) {
2229 .src_path => |src| .{ .src_path = .{
2230 .owner = src.owner,
2231 .sub_path = b.pathResolve(&.{ src.sub_path, sub_path }),
2232 } },
2233 .generated => |gen| .{ .generated = .{
2234 .file = gen.file,
2235 .up = gen.up,
2236 .sub_path = b.pathResolve(&.{ gen.sub_path, sub_path }),
2237 } },
2238 .cwd_relative => |cwd_relative| .{
2239 .cwd_relative = b.pathResolve(&.{ cwd_relative, sub_path }),
2240 },
2241 .dependency => |dep| .{ .dependency = .{
2242 .dependency = dep.dependency,
2243 .sub_path = b.pathResolve(&.{ dep.sub_path, sub_path }),
2244 } },
2245 };
2246 }
2247
22372248 /// Returns a string that can be shown to represent the file source.
2238 /// Either returns the path or `"generated"`.
2249 /// Either returns the path, `"generated"`, or `"dependency"`.
22392250 pub fn getDisplayName(lazy_path: LazyPath) []const u8 {
22402251 return switch (lazy_path) {
2241 .src_path => |src_path| src_path.sub_path,
2242 .path, .cwd_relative => |sub_path| sub_path,
2252 .src_path => |sp| sp.sub_path,
2253 .cwd_relative => |p| p,
22432254 .generated => "generated",
2244 .generated_dirname => "generated",
22452255 .dependency => "dependency",
22462256 };
22472257 }
......@@ -2249,9 +2259,8 @@ pub const LazyPath = union(enum) {
22492259 /// Adds dependencies this file source implies to the given step.
22502260 pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void {
22512261 switch (lazy_path) {
2252 .src_path, .path, .cwd_relative, .dependency => {},
2253 .generated => |gen| other_step.dependOn(gen.step),
2254 .generated_dirname => |gen| other_step.dependOn(gen.generated.step),
2262 .src_path, .cwd_relative, .dependency => {},
2263 .generated => |gen| other_step.dependOn(gen.file.step),
22552264 }
22562265 }
22572266
......@@ -2268,47 +2277,48 @@ pub const LazyPath = union(enum) {
22682277 /// run that is asking for the path.
22692278 pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 {
22702279 switch (lazy_path) {
2271 .path => |p| return src_builder.pathFromRoot(p),
22722280 .src_path => |sp| return sp.owner.pathFromRoot(sp.sub_path),
22732281 .cwd_relative => |p| return src_builder.pathFromCwd(p),
2274 .generated => |gen| return gen.step.owner.pathFromRoot(gen.path orelse {
2275 std.debug.getStderrMutex().lock();
2276 const stderr = std.io.getStdErr();
2277 dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {};
2278 @panic("misconfigured build script");
2279 }),
2280 .generated_dirname => |gen| {
2281 const cache_root_path = src_builder.cache_root.path orelse
2282 (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));
2283
2284 const gen_step = gen.generated.step;
2285 var p = getPath2(LazyPath{ .generated = gen.generated }, src_builder, asking_step);
2286 var i: usize = 0;
2287 while (i <= gen.up) : (i += 1) {
2288 // path is absolute.
2289 // dirname will return null only if we're at root.
2290 // Typically, we'll stop well before that at the cache root.
2291 p = fs.path.dirname(p) orelse {
2292 dumpBadDirnameHelp(gen_step, asking_step,
2293 \\dirname() reached root.
2294 \\No more directories left to go up.
2295 \\
2296 , .{}) catch {};
2297 @panic("misconfigured build script");
2298 };
2299
2300 if (mem.eql(u8, p, cache_root_path) and i < gen.up) {
2301 // If we hit the cache root and there's still more to go,
2302 // the script attempted to go too far.
2303 dumpBadDirnameHelp(gen_step, asking_step,
2304 \\dirname() attempted to traverse outside the cache root.
2305 \\This is not allowed.
2306 \\
2307 , .{}) catch {};
2308 @panic("misconfigured build script");
2282 .generated => |gen| {
2283 var file_path: []const u8 = gen.file.step.owner.pathFromRoot(gen.file.path orelse {
2284 std.debug.getStderrMutex().lock();
2285 const stderr = std.io.getStdErr();
2286 dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
2287 std.debug.getStderrMutex().unlock();
2288 @panic("misconfigured build script");
2289 });
2290
2291 if (gen.up > 0) {
2292 const cache_root_path = src_builder.cache_root.path orelse
2293 (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM"));
2294
2295 for (0..gen.up) |_| {
2296 if (mem.eql(u8, file_path, cache_root_path)) {
2297 // If we hit the cache root and there's still more to go,
2298 // the script attempted to go too far.
2299 dumpBadDirnameHelp(gen.file.step, asking_step,
2300 \\dirname() attempted to traverse outside the cache root.
2301 \\This is not allowed.
2302 \\
2303 , .{}) catch {};
2304 @panic("misconfigured build script");
2305 }
2306
2307 // path is absolute.
2308 // dirname will return null only if we're at root.
2309 // Typically, we'll stop well before that at the cache root.
2310 file_path = fs.path.dirname(file_path) orelse {
2311 dumpBadDirnameHelp(gen.file.step, asking_step,
2312 \\dirname() reached root.
2313 \\No more directories left to go up.
2314 \\
2315 , .{}) catch {};
2316 @panic("misconfigured build script");
2317 };
23092318 }
23102319 }
2311 return p;
2320
2321 return src_builder.pathResolve(&.{ file_path, gen.sub_path });
23122322 },
23132323 .dependency => |dep| return dep.dependency.builder.pathFromRoot(dep.sub_path),
23142324 }
......@@ -2324,15 +2334,12 @@ pub const LazyPath = union(enum) {
23242334 .owner = sp.owner,
23252335 .sub_path = sp.owner.dupePath(sp.sub_path),
23262336 } },
2327 .path => |p| .{ .path = b.dupePath(p) },
23282337 .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) },
2329 .generated => |gen| .{ .generated = gen },
2330 .generated_dirname => |gen| .{
2331 .generated_dirname = .{
2332 .generated = gen.generated,
2333 .up = gen.up,
2334 },
2335 },
2338 .generated => |gen| .{ .generated = .{
2339 .file = gen.file,
2340 .up = gen.up,
2341 .sub_path = b.dupePath(gen.sub_path),
2342 } },
23362343 .dependency => |dep| .{ .dependency = dep },
23372344 };
23382345 }
lib/std/Build/Step/Compile.zig+2-4
......@@ -806,14 +806,12 @@ pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void {
806806}
807807
808808fn getEmittedFileGeneric(compile: *Compile, output_file: *?*GeneratedFile) LazyPath {
809 if (output_file.*) |g| {
810 return .{ .generated = g };
811 }
809 if (output_file.*) |file| return .{ .generated = .{ .file = file } };
812810 const arena = compile.step.owner.allocator;
813811 const generated_file = arena.create(GeneratedFile) catch @panic("OOM");
814812 generated_file.* = .{ .step = &compile.step };
815813 output_file.* = generated_file;
816 return .{ .generated = generated_file };
814 return .{ .generated = .{ .file = generated_file } };
817815}
818816
819817/// Returns the path to the directory that contains the emitted binary file.
lib/std/Build/Step/ConfigHeader.zig+2-3
......@@ -59,8 +59,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
5959 if (options.style.getPath()) |s| default_include_path: {
6060 const sub_path = switch (s) {
6161 .src_path => |sp| sp.sub_path,
62 .path => |path| path,
63 .generated, .generated_dirname => break :default_include_path,
62 .generated => break :default_include_path,
6463 .cwd_relative => |sub_path| sub_path,
6564 .dependency => |dependency| dependency.sub_path,
6665 };
......@@ -106,7 +105,7 @@ pub fn addValues(config_header: *ConfigHeader, values: anytype) void {
106105}
107106
108107pub fn getOutput(config_header: *ConfigHeader) std.Build.LazyPath {
109 return .{ .generated = &config_header.output_file };
108 return .{ .generated = .{ .file = &config_header.output_file } };
110109}
111110
112111fn addValuesInner(config_header: *ConfigHeader, values: anytype) !void {
lib/std/Build/Step/ObjCopy.zig+2-2
......@@ -84,10 +84,10 @@ pub fn create(
8484pub const getOutputSource = getOutput;
8585
8686pub fn getOutput(objcopy: *const ObjCopy) std.Build.LazyPath {
87 return .{ .generated = &objcopy.output_file };
87 return .{ .generated = .{ .file = &objcopy.output_file } };
8888}
8989pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {
90 return if (objcopy.output_file_debug) |*file| .{ .generated = file } else null;
90 return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null;
9191}
9292
9393fn make(step: *Step, prog_node: *std.Progress.Node) !void {
lib/std/Build/Step/Options.zig+1-1
......@@ -407,7 +407,7 @@ pub const getSource = getOutput;
407407/// Returns the main artifact of this Build Step which is a Zig source file
408408/// generated from the key-value pairs of the Options.
409409pub fn getOutput(options: *Options) LazyPath {
410 return .{ .generated = &options.generated_file };
410 return .{ .generated = .{ .file = &options.generated_file } };
411411}
412412
413413fn make(step: *Step, prog_node: *std.Progress.Node) !void {
lib/std/Build/Step/Run.zig+113-26
......@@ -125,7 +125,8 @@ pub const Arg = union(enum) {
125125 lazy_path: PrefixedLazyPath,
126126 directory_source: PrefixedLazyPath,
127127 bytes: []u8,
128 output: *Output,
128 output_file: *Output,
129 output_directory: *Output,
129130};
130131
131132pub const PrefixedLazyPath = struct {
......@@ -225,13 +226,13 @@ pub fn addPrefixedOutputFileArg(
225226 .basename = b.dupe(basename),
226227 .generated_file = .{ .step = &run.step },
227228 };
228 run.argv.append(b.allocator, .{ .output = output }) catch @panic("OOM");
229 run.argv.append(b.allocator, .{ .output_file = output }) catch @panic("OOM");
229230
230231 if (run.rename_step_with_output_arg) {
231232 run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename }));
232233 }
233234
234 return .{ .generated = &output.generated_file };
235 return .{ .generated = .{ .file = &output.generated_file } };
235236}
236237
237238/// Appends an input file to the command line arguments.
......@@ -270,6 +271,56 @@ pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath)
270271 lp.addStepDependencies(&run.step);
271272}
272273
274/// Provides a directory path as a command line argument to the command being run.
275///
276/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs
277/// throughout the build system.
278///
279/// Related:
280/// * `addPrefixedOutputDirectoryArg` - same thing but prepends a string to the argument
281/// * `addDirectoryArg` - for input directories given to the child process
282pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath {
283 return run.addPrefixedOutputDirectoryArg("", basename);
284}
285
286/// Provides a directory path as a command line argument to the command being run.
287/// Asserts `basename` is not empty.
288///
289/// For example, a prefix of "-o" and basename of "output_dir" will result in
290/// the child process seeing something like this: "-ozig-cache/.../output_dir"
291///
292/// The child process will see a single argument, regardless of whether the
293/// prefix or basename have spaces.
294///
295/// The returned `std.Build.LazyPath` can be used as inputs to other APIs
296/// throughout the build system.
297///
298/// Related:
299/// * `addOutputDirectoryArg` - same thing but without the prefix
300/// * `addDirectoryArg` - for input directories given to the child process
301pub fn addPrefixedOutputDirectoryArg(
302 run: *Run,
303 prefix: []const u8,
304 basename: []const u8,
305) std.Build.LazyPath {
306 if (basename.len == 0) @panic("basename must not be empty");
307 const b = run.step.owner;
308
309 const output = b.allocator.create(Output) catch @panic("OOM");
310 output.* = .{
311 .prefix = b.dupe(prefix),
312 .basename = b.dupe(basename),
313 .generated_file = .{ .step = &run.step },
314 };
315 run.argv.append(b.allocator, .{ .output_directory = output }) catch @panic("OOM");
316
317 if (run.rename_step_with_output_arg) {
318 run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename }));
319 }
320
321 return .{ .generated = .{ .file = &output.generated_file } };
322}
323
273324/// deprecated: use `addDirectoryArg`
274325pub const addDirectorySourceArg = addDirectoryArg;
275326
......@@ -314,9 +365,9 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co
314365
315366 run.dep_output_file = dep_file;
316367
317 run.argv.append(b.allocator, .{ .output = dep_file }) catch @panic("OOM");
368 run.argv.append(b.allocator, .{ .output_file = dep_file }) catch @panic("OOM");
318369
319 return .{ .generated = &dep_file.generated_file };
370 return .{ .generated = .{ .file = &dep_file.generated_file } };
320371}
321372
322373pub fn addArg(run: *Run, arg: []const u8) void {
......@@ -432,7 +483,7 @@ pub fn addCheck(run: *Run, new_check: StdIo.Check) void {
432483pub fn captureStdErr(run: *Run) std.Build.LazyPath {
433484 assert(run.stdio != .inherit);
434485
435 if (run.captured_stderr) |output| return .{ .generated = &output.generated_file };
486 if (run.captured_stderr) |output| return .{ .generated = .{ .file = &output.generated_file } };
436487
437488 const output = run.step.owner.allocator.create(Output) catch @panic("OOM");
438489 output.* = .{
......@@ -441,13 +492,13 @@ pub fn captureStdErr(run: *Run) std.Build.LazyPath {
441492 .generated_file = .{ .step = &run.step },
442493 };
443494 run.captured_stderr = output;
444 return .{ .generated = &output.generated_file };
495 return .{ .generated = .{ .file = &output.generated_file } };
445496}
446497
447498pub fn captureStdOut(run: *Run) std.Build.LazyPath {
448499 assert(run.stdio != .inherit);
449500
450 if (run.captured_stdout) |output| return .{ .generated = &output.generated_file };
501 if (run.captured_stdout) |output| return .{ .generated = .{ .file = &output.generated_file } };
451502
452503 const output = run.step.owner.allocator.create(Output) catch @panic("OOM");
453504 output.* = .{
......@@ -456,7 +507,7 @@ pub fn captureStdOut(run: *Run) std.Build.LazyPath {
456507 .generated_file = .{ .step = &run.step },
457508 };
458509 run.captured_stdout = output;
459 return .{ .generated = &output.generated_file };
510 return .{ .generated = .{ .file = &output.generated_file } };
460511}
461512
462513/// Adds an additional input files that, when modified, indicates that this Run
......@@ -484,7 +535,7 @@ fn hasAnyOutputArgs(run: Run) bool {
484535 if (run.captured_stdout != null) return true;
485536 if (run.captured_stderr != null) return true;
486537 for (run.argv.items) |arg| switch (arg) {
487 .output => return true,
538 .output_file, .output_directory => return true,
488539 else => continue,
489540 };
490541 return false;
......@@ -520,6 +571,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
520571
521572const IndexedOutput = struct {
522573 index: usize,
574 tag: @typeInfo(Arg).Union.tag_type.?,
523575 output: *Output,
524576};
525577fn make(step: *Step, prog_node: *std.Progress.Node) !void {
......@@ -563,17 +615,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
563615
564616 _ = try man.addFile(file_path, null);
565617 },
566 .output => |output| {
618 .output_file, .output_directory => |output| {
567619 man.hash.addBytes(output.prefix);
568620 man.hash.addBytes(output.basename);
569621 // Add a placeholder into the argument list because we need the
570622 // manifest hash to be updated with all arguments before the
571623 // object directory is computed.
572 try argv_list.append("");
573624 try output_placeholders.append(.{
574 .index = argv_list.items.len - 1,
625 .index = argv_list.items.len,
626 .tag = arg,
575627 .output = output,
576628 });
629 _ = try argv_list.addOne();
577630 },
578631 }
579632 }
......@@ -599,11 +652,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
599652
600653 hashStdIo(&man.hash, run.stdio);
601654
602 if (has_side_effects) {
603 try runCommand(run, argv_list.items, has_side_effects, null, prog_node);
604 return;
605 }
606
607655 for (run.extra_file_dependencies) |file_path| {
608656 _ = try man.addFile(b.pathFromRoot(file_path), null);
609657 }
......@@ -611,7 +659,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
611659 _ = try man.addFile(lazy_path.getPath2(b, step), null);
612660 }
613661
614 if (try step.cacheHit(&man)) {
662 if (try step.cacheHit(&man) and !has_side_effects) {
615663 // cache hit, skip running command
616664 const digest = man.final();
617665
......@@ -628,13 +676,54 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
628676 return;
629677 }
630678
679 const dep_output_file = run.dep_output_file orelse {
680 // We already know the final output paths, use them directly.
681 const digest = man.final();
682
683 try populateGeneratedPaths(
684 arena,
685 output_placeholders.items,
686 run.captured_stdout,
687 run.captured_stderr,
688 b.cache_root,
689 &digest,
690 );
691
692 const output_dir_path = "o" ++ fs.path.sep_str ++ &digest;
693 for (output_placeholders.items) |placeholder| {
694 const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });
695 const output_sub_dir_path = switch (placeholder.tag) {
696 .output_file => fs.path.dirname(output_sub_path).?,
697 .output_directory => output_sub_path,
698 else => unreachable,
699 };
700 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
701 return step.fail("unable to make path '{}{s}': {s}", .{
702 b.cache_root, output_sub_dir_path, @errorName(err),
703 });
704 };
705 const output_path = placeholder.output.generated_file.path.?;
706 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)
707 output_path
708 else
709 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });
710 }
711
712 return runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node);
713 };
714
715 // We do not know the final output paths yet, use temp paths to run the command.
631716 const rand_int = std.crypto.random.int(u64);
632717 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int);
633718
634719 for (output_placeholders.items) |placeholder| {
635720 const output_components = .{ tmp_dir_path, placeholder.output.basename };
636721 const output_sub_path = b.pathJoin(&output_components);
637 const output_sub_dir_path = fs.path.dirname(output_sub_path).?;
722 const output_sub_dir_path = switch (placeholder.tag) {
723 .output_file => fs.path.dirname(output_sub_path).?,
724 .output_directory => output_sub_path,
725 else => unreachable,
726 };
638727 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
639728 return step.fail("unable to make path '{}{s}': {s}", .{
640729 b.cache_root, output_sub_dir_path, @errorName(err),
......@@ -642,17 +731,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
642731 };
643732 const output_path = try b.cache_root.join(arena, &output_components);
644733 placeholder.output.generated_file.path = output_path;
645 const cli_arg = if (placeholder.output.prefix.len == 0)
734 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)
646735 output_path
647736 else
648737 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });
649 argv_list.items[placeholder.index] = cli_arg;
650738 }
651739
652740 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, prog_node);
653741
654 if (run.dep_output_file) |dep_output_file|
655 try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
742 try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
656743
657744 const digest = man.final();
658745
......@@ -777,7 +864,7 @@ fn runCommand(
777864 run: *Run,
778865 argv: []const []const u8,
779866 has_side_effects: bool,
780 tmp_dir_path: ?[]const u8,
867 output_dir_path: []const u8,
781868 prog_node: *std.Progress.Node,
782869) !void {
783870 const step = &run.step;
......@@ -950,7 +1037,7 @@ fn runCommand(
9501037 },
9511038 }) |stream| {
9521039 if (stream.captured) |output| {
953 const output_components = .{ tmp_dir_path.?, output.basename };
1040 const output_components = .{ output_dir_path, output.basename };
9541041 const output_path = try b.cache_root.join(arena, &output_components);
9551042 output.generated_file.path = output_path;
9561043
lib/std/Build/Step/TranslateC.zig+1-1
......@@ -59,7 +59,7 @@ pub const AddExecutableOptions = struct {
5959};
6060
6161pub fn getOutput(translate_c: *TranslateC) std.Build.LazyPath {
62 return .{ .generated = &translate_c.output_file };
62 return .{ .generated = .{ .file = &translate_c.output_file } };
6363}
6464
6565/// Creates a step to build an executable from the translated source.
lib/std/Build/Step/WriteFile.zig+3-3
......@@ -31,7 +31,7 @@ pub const File = struct {
3131 contents: Contents,
3232
3333 pub fn getPath(file: *File) std.Build.LazyPath {
34 return .{ .generated = &file.generated_file };
34 return .{ .generated = .{ .file = &file.generated_file } };
3535 }
3636};
3737
......@@ -58,7 +58,7 @@ pub const Directory = struct {
5858 };
5959
6060 pub fn getPath(dir: *Directory) std.Build.LazyPath {
61 return .{ .generated = &dir.generated_dir };
61 return .{ .generated = .{ .file = &dir.generated_dir } };
6262 }
6363};
6464
......@@ -181,7 +181,7 @@ pub fn addBytesToSource(write_file: *WriteFile, bytes: []const u8, sub_path: []c
181181/// Returns a `LazyPath` representing the base directory that contains all the
182182/// files from this `WriteFile`.
183183pub fn getDirectory(write_file: *WriteFile) std.Build.LazyPath {
184 return .{ .generated = &write_file.generated_directory };
184 return .{ .generated = .{ .file = &write_file.generated_directory } };
185185}
186186
187187fn maybeUpdateName(write_file: *WriteFile) void {
test/standalone/build.zig.zon+3
......@@ -164,6 +164,9 @@
164164 .dependencyFromBuildZig = .{
165165 .path = "dependencyFromBuildZig",
166166 },
167 .run_output_paths = .{
168 .path = "run_output_paths",
169 },
167170 },
168171 .paths = .{
169172 "build.zig",
test/standalone/run_output_paths/build.zig created+40
......@@ -0,0 +1,40 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const target = b.standardTargetOptions(.{});
8 const optimize = b.standardOptimizeOption(.{});
9
10 const create_file_exe = b.addExecutable(.{
11 .name = "create_file",
12 .root_source_file = b.path("create_file.zig"),
13 .target = target,
14 .optimize = optimize,
15 });
16
17 const create_first = b.addRunArtifact(create_file_exe);
18 const first_dir = create_first.addOutputDirectoryArg("first");
19 create_first.addArg("hello1.txt");
20 test_step.dependOn(&b.addCheckFile(first_dir.path(b, "hello1.txt"), .{ .expected_matches = &.{
21 std.fs.path.sep_str ++
22 \\first
23 \\hello1.txt
24 \\Hello, world!
25 \\
26 ,
27 } }).step);
28
29 const create_second = b.addRunArtifact(create_file_exe);
30 const second_dir = create_second.addPrefixedOutputDirectoryArg("--dir=", "second");
31 create_second.addArg("hello2.txt");
32 test_step.dependOn(&b.addCheckFile(second_dir.path(b, "hello2.txt"), .{ .expected_matches = &.{
33 std.fs.path.sep_str ++
34 \\second
35 \\hello2.txt
36 \\Hello, world!
37 \\
38 ,
39 } }).step);
40}
test/standalone/run_output_paths/create_file.zig created+19
......@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn main() !void {
4 var args = try std.process.argsWithAllocator(std.heap.page_allocator);
5 _ = args.skip();
6 const dir_name = args.next().?;
7 const dir = try std.fs.cwd().openDir(if (std.mem.startsWith(u8, dir_name, "--dir="))
8 dir_name["--dir=".len..]
9 else
10 dir_name, .{});
11 const file_name = args.next().?;
12 const file = try dir.createFile(file_name, .{});
13 try file.writer().print(
14 \\{s}
15 \\{s}
16 \\Hello, world!
17 \\
18 , .{ dir_name, file_name });
19}
test/standalone/windows_resources/build.zig+1-1
......@@ -36,7 +36,7 @@ fn add(
3636 .file = b.path("res/zig.rc"),
3737 .flags = &.{"/c65001"}, // UTF-8 code page
3838 .include_paths = &.{
39 .{ .generated = &generated_h_step.generated_directory },
39 .{ .generated = .{ .file = &generated_h_step.generated_directory } },
4040 },
4141 });
4242 exe.rc_includes = switch (rc_includes) {