authorgravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-06-03 02:24:08-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-06-24 02:41:05+02:00
logb40b1178ef29ea9b013f73cc3cd4f9b976d0e120
tree66b4f4416ff944f95e72dedae4c52f4ebb356612
parentc5d6277ace183cf4261c13cc9b44a53ec1622199

Adds support for making run step argument paths absolute

* Adds a new API that takes an options struct instead of having a function for each combination of options * Adds support for prefix and suffix to every argument type * Adds support for making paths absolute when passed as arguments * Deprecates the old API * Fixes mismatch between documentation and behavior of `process.currentPath` on WASI

7 files changed, 384 insertions(+), 132 deletions(-)

lib/compiler/Maker/Step/Run.zig+31-13
...@@ -87,8 +87,9 @@ pub fn make(...@@ -87,8 +87,9 @@ pub fn make(
87 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";87 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
88 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);88 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
89 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{89 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
90 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,90 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
91 }));91 }));
92 man.hash.add(arg.flags.make_absolute);
92 man.hash.addBytesZ(prefix);93 man.hash.addBytesZ(prefix);
93 man.hash.addBytesZ(suffix);94 man.hash.addBytesZ(suffix);
94 _ = try man.addFilePath(file_path, null);95 _ = try man.addFilePath(file_path, null);
...@@ -98,9 +99,10 @@ pub fn make(...@@ -98,9 +99,10 @@ pub fn make(
98 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";99 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
99 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);100 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
100 const resolved_arg = try mem.concat(arena, u8, &.{101 const resolved_arg = try mem.concat(arena, u8, &.{
101 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,102 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
102 });103 });
103 argv_list.appendAssumeCapacity(resolved_arg);104 argv_list.appendAssumeCapacity(resolved_arg);
105 man.hash.add(arg.flags.make_absolute);
104 man.hash.addBytes(resolved_arg);106 man.hash.addBytes(resolved_arg);
105 },107 },
106 .file_content => {108 .file_content => {
...@@ -142,9 +144,12 @@ pub fn make(...@@ -142,9 +144,12 @@ pub fn make(
142 const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*;144 const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*;
143145
144 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{146 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
145 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,147 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
146 }));148 }));
147149
150 man.hash.add(arg.flags.make_absolute);
151 man.hash.addBytesZ(prefix);
152 man.hash.addBytesZ(suffix);
148 _ = try man.addFilePath(file_path, null);153 _ = try man.addFilePath(file_path, null);
149 },154 },
150 .output_file, .output_directory => {155 .output_file, .output_directory => {
...@@ -152,6 +157,7 @@ pub fn make(...@@ -152,6 +157,7 @@ pub fn make(
152 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";157 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
153 const basename = arg.basename.value.?.slice(conf);158 const basename = arg.basename.value.?.slice(conf);
154159
160 man.hash.add(arg.flags.make_absolute);
155 man.hash.addBytesZ(prefix);161 man.hash.addBytesZ(prefix);
156 man.hash.addBytesZ(basename);162 man.hash.addBytesZ(basename);
157 man.hash.addBytesZ(suffix);163 man.hash.addBytesZ(suffix);
...@@ -181,7 +187,7 @@ pub fn make(...@@ -181,7 +187,7 @@ pub fn make(
181187
182 man.hash.add(conf_run.flags.test_runner_mode);188 man.hash.add(conf_run.flags.test_runner_mode);
183 if (conf_run.flags.test_runner_mode) {189 if (conf_run.flags.test_runner_mode) {
184 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root });190 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false);
185191
186 try argv_list.ensureUnusedCapacity(gpa, 3);192 try argv_list.ensureUnusedCapacity(gpa, 3);
187 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));193 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));
...@@ -1552,7 +1558,7 @@ pub fn rerunInFuzzMode(...@@ -1552,7 +1558,7 @@ pub fn rerunInFuzzMode(
1552 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1558 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
1553 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);1559 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
1554 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{1560 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
1555 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,1561 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
1556 }));1562 }));
1557 },1563 },
1558 .path_directory => {1564 .path_directory => {
...@@ -1560,7 +1566,7 @@ pub fn rerunInFuzzMode(...@@ -1560,7 +1566,7 @@ pub fn rerunInFuzzMode(
1560 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1566 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
1561 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);1567 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);
1562 const resolved_arg = try mem.concat(arena, u8, &.{1568 const resolved_arg = try mem.concat(arena, u8, &.{
1563 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,1569 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
1564 });1570 });
1565 argv_list.appendAssumeCapacity(resolved_arg);1571 argv_list.appendAssumeCapacity(resolved_arg);
1566 },1572 },
...@@ -1602,7 +1608,7 @@ pub fn rerunInFuzzMode(...@@ -1602,7 +1608,7 @@ pub fn rerunInFuzzMode(
1602 producer_make_comp.installed_path orelse1608 producer_make_comp.installed_path orelse
1603 maker.generatedPath(producer.generated_bin.value.?).*;1609 maker.generatedPath(producer.generated_bin.value.?).*;
1604 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{1610 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
1605 prefix, try convertPathArg(arena, run_index, maker, file_path), suffix,1611 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
1606 }));1612 }));
1607 },1613 },
1608 .output_file => unreachable,1614 .output_file => unreachable,
...@@ -1612,7 +1618,7 @@ pub fn rerunInFuzzMode(...@@ -1612,7 +1618,7 @@ pub fn rerunInFuzzMode(
1612 }1618 }
16131619
1614 if (conf_run.flags.test_runner_mode) {1620 if (conf_run.flags.test_runner_mode) {
1615 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root });1621 const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false);
16161622
1617 try argv_list.ensureUnusedCapacity(gpa, 3);1623 try argv_list.ensureUnusedCapacity(gpa, 3);
1618 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));1624 argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string}));
...@@ -1688,7 +1694,7 @@ fn populateGeneratedPathsCreateDirs(...@@ -1688,7 +1694,7 @@ fn populateGeneratedPathsCreateDirs(
16881694
1689 maker.generatedPath(arg.generated.value.?).* = generated_path;1695 maker.generatedPath(arg.generated.value.?).* = generated_path;
16901696
1691 const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path);1697 const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute);
1692 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });1698 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });
1693 }1699 }
1694}1700}
...@@ -2290,11 +2296,18 @@ fn checksContainStderr(conf_run: *const Configuration.Step.Run) bool {...@@ -2290,11 +2296,18 @@ fn checksContainStderr(conf_run: *const Configuration.Step.Run) bool {
2290 return conf_run.expect_stderr_exact.value != null or conf_run.expect_stderr_match.slice.len != 0;2296 return conf_run.expect_stderr_exact.value != null or conf_run.expect_stderr_match.slice.len != 0;
2291}2297}
22922298
2293/// If `path` is cwd-relative, make it relative to the cwd of the child instead.2299/// If `path` is absolute, return it unchanged. If `make_absolute` is true, make it absolute.
2300/// Otherwise, make it relative to the cwd of the child.
2294///2301///
2295/// Whenever a path is included in the argv of a child, it should be put through this function first2302/// Whenever a path is included in the argv of a child, it should be put through this function
2296/// to make sure the child doesn't see paths relative to a cwd other than its own.2303/// first.
2297fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker: *Maker, path: Path) ![]const u8 {2304fn convertPathArg(
2305 arena: Allocator,
2306 run_index: Configuration.Step.Index,
2307 maker: *Maker,
2308 path: Path,
2309 make_absolute: bool,
2310) ![]const u8 {
2298 const conf = &maker.scanned_config.configuration;2311 const conf = &maker.scanned_config.configuration;
2299 const conf_step = run_index.ptr(conf);2312 const conf_step = run_index.ptr(conf);
2300 const conf_run = conf_step.extended.get(conf.extra).run;2313 const conf_run = conf_step.extended.get(conf.extra).run;
...@@ -2305,6 +2318,11 @@ fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker:...@@ -2305,6 +2318,11 @@ fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker:
2305 // Absolute paths don't need changing.2318 // Absolute paths don't need changing.
2306 return path_str;2319 return path_str;
2307 }2320 }
2321
2322 if (make_absolute) {
2323 return Dir.path.join(arena, &.{ graph.cache.cwd, path_str });
2324 }
2325
2308 const child_cwd_rel: []const u8 = rel: {2326 const child_cwd_rel: []const u8 = rel: {
2309 const child_lazy_cwd = conf_run.cwd.value orelse break :rel path_str;2327 const child_lazy_cwd = conf_run.cwd.value orelse break :rel path_str;
2310 const child_cwd = try maker.resolveLazyPathIndexAbs(arena, child_lazy_cwd, run_index);2328 const child_cwd = try maker.resolveLazyPathIndexAbs(arena, child_lazy_cwd, run_index);
lib/compiler/configurer.zig+22-14
...@@ -312,15 +312,16 @@ const Serialize = struct {...@@ -312,15 +312,16 @@ const Serialize = struct {
312 .flags = .{312 .flags = .{
313 .tag = .artifact,313 .tag = .artifact,
314 .prefix = a.prefix.len != 0,314 .prefix = a.prefix.len != 0,
315 .suffix = false,315 .suffix = a.suffix.len != 0,
316 .basename = false,316 .basename = false,
317 .path = false,317 .path = false,
318 .producer = true,318 .producer = true,
319 .generated = false,319 .generated = false,
320 .dep_file = false,320 .dep_file = false,
321 .make_absolute = a.make_absolute,
321 },322 },
322 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },323 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
323 .suffix = .{ .value = null },324 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
324 .basename = .{ .value = null },325 .basename = .{ .value = null },
325 .path = .{ .value = null },326 .path = .{ .value = null },
326 .producer = .{ .value = stepIndex(s, &a.artifact.step) },327 .producer = .{ .value = stepIndex(s, &a.artifact.step) },
...@@ -330,15 +331,16 @@ const Serialize = struct {...@@ -330,15 +331,16 @@ const Serialize = struct {
330 .flags = .{331 .flags = .{
331 .tag = .path_file,332 .tag = .path_file,
332 .prefix = a.prefix.len != 0,333 .prefix = a.prefix.len != 0,
333 .suffix = false,334 .suffix = a.suffix.len != 0,
334 .basename = false,335 .basename = false,
335 .path = true,336 .path = true,
336 .producer = false,337 .producer = false,
337 .generated = false,338 .generated = false,
338 .dep_file = false,339 .dep_file = false,
340 .make_absolute = a.make_absolute,
339 },341 },
340 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },342 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
341 .suffix = .{ .value = null },343 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
342 .basename = .{ .value = null },344 .basename = .{ .value = null },
343 .path = .{ .value = try addLazyPath(s, a.lazy_path) },345 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
344 .producer = .{ .value = null },346 .producer = .{ .value = null },
...@@ -354,6 +356,7 @@ const Serialize = struct {...@@ -354,6 +356,7 @@ const Serialize = struct {
354 .producer = false,356 .producer = false,
355 .generated = false,357 .generated = false,
356 .dep_file = false,358 .dep_file = false,
359 .make_absolute = a.make_absolute,
357 },360 },
358 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },361 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
359 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },362 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
...@@ -366,15 +369,16 @@ const Serialize = struct {...@@ -366,15 +369,16 @@ const Serialize = struct {
366 .flags = .{369 .flags = .{
367 .tag = .file_content,370 .tag = .file_content,
368 .prefix = a.prefix.len != 0,371 .prefix = a.prefix.len != 0,
369 .suffix = false,372 .suffix = a.suffix.len != 0,
370 .basename = false,373 .basename = false,
371 .path = true,374 .path = true,
372 .producer = false,375 .producer = false,
373 .generated = false,376 .generated = false,
374 .dep_file = false,377 .dep_file = false,
378 .make_absolute = false,
375 },379 },
376 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },380 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
377 .suffix = .{ .value = null },381 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
378 .basename = .{ .value = null },382 .basename = .{ .value = null },
379 .path = .{ .value = try addLazyPath(s, a.lazy_path) },383 .path = .{ .value = try addLazyPath(s, a.lazy_path) },
380 .producer = .{ .value = null },384 .producer = .{ .value = null },
...@@ -390,6 +394,7 @@ const Serialize = struct {...@@ -390,6 +394,7 @@ const Serialize = struct {
390 .producer = false,394 .producer = false,
391 .generated = false,395 .generated = false,
392 .dep_file = false,396 .dep_file = false,
397 .make_absolute = false,
393 },398 },
394 .prefix = .{ .value = try wc.addString(a) },399 .prefix = .{ .value = try wc.addString(a) },
395 .suffix = .{ .value = null },400 .suffix = .{ .value = null },
...@@ -402,15 +407,16 @@ const Serialize = struct {...@@ -402,15 +407,16 @@ const Serialize = struct {
402 .flags = .{407 .flags = .{
403 .tag = .output_file,408 .tag = .output_file,
404 .prefix = a.prefix.len != 0,409 .prefix = a.prefix.len != 0,
405 .suffix = false,410 .suffix = a.suffix.len != 0,
406 .basename = a.basename.len != 0,411 .basename = a.basename.len != 0,
407 .path = false,412 .path = false,
408 .producer = false,413 .producer = false,
409 .generated = true,414 .generated = true,
410 .dep_file = tag == .output_file_dep,415 .dep_file = tag == .output_file_dep,
416 .make_absolute = a.make_absolute,
411 },417 },
412 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },418 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
413 .suffix = .{ .value = null },419 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
414 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },420 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
415 .path = .{ .value = null },421 .path = .{ .value = null },
416 .producer = .{ .value = null },422 .producer = .{ .value = null },
...@@ -420,15 +426,16 @@ const Serialize = struct {...@@ -420,15 +426,16 @@ const Serialize = struct {
420 .flags = .{426 .flags = .{
421 .tag = .output_directory,427 .tag = .output_directory,
422 .prefix = a.prefix.len != 0,428 .prefix = a.prefix.len != 0,
423 .suffix = false,429 .suffix = a.suffix.len != 0,
424 .basename = a.basename.len != 0,430 .basename = a.basename.len != 0,
425 .path = false,431 .path = false,
426 .producer = false,432 .producer = false,
427 .generated = true,433 .generated = true,
428 .dep_file = false,434 .dep_file = false,
435 .make_absolute = a.make_absolute,
429 },436 },
430 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },437 .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null },
431 .suffix = .{ .value = null },438 .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null },
432 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },439 .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null },
433 .path = .{ .value = null },440 .path = .{ .value = null },
434 .producer = .{ .value = null },441 .producer = .{ .value = null },
...@@ -444,6 +451,7 @@ const Serialize = struct {...@@ -444,6 +451,7 @@ const Serialize = struct {
444 .producer = false,451 .producer = false,
445 .generated = false,452 .generated = false,
446 .dep_file = false,453 .dep_file = false,
454 .make_absolute = false,
447 },455 },
448 .prefix = .{ .value = null },456 .prefix = .{ .value = null },
449 .suffix = .{ .value = null },457 .suffix = .{ .value = null },
...@@ -1066,12 +1074,12 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -1066,12 +1074,12 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
1066 .args = .{ .slice = try s.initArgsList(run.argv.items) },1074 .args = .{ .slice = try s.initArgsList(run.argv.items) },
1067 .cwd = .{ .value = try s.addOptionalLazyPath(run.cwd) },1075 .cwd = .{ .value = try s.addOptionalLazyPath(run.cwd) },
1068 .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{1076 .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{
1069 .basename = try wc.addString(cs.output.basename),1077 .basename = try wc.addString(cs.basename),
1070 .generated_file = cs.output.generated_file,1078 .generated_file = cs.generated_file,
1071 } else null },1079 } else null },
1072 .captured_stderr = .{ .value = if (run.captured_stderr) |cs| .{1080 .captured_stderr = .{ .value = if (run.captured_stderr) |cs| .{
1073 .basename = try wc.addString(cs.output.basename),1081 .basename = try wc.addString(cs.basename),
1074 .generated_file = cs.output.generated_file,1082 .generated_file = cs.generated_file,
1075 } else null },1083 } else null },
1076 .environ_map = .{ .value = try s.addEnvironMap(run.environ_map) },1084 .environ_map = .{ .value = try s.addEnvironMap(run.environ_map) },
1077 .expect_term_value = .{ .value = if (expect_term) |t| t.value else null },1085 .expect_term_value = .{ .value = if (expect_term) |t| t.value else null },
lib/std/Build/Configuration.zig+2-1
...@@ -610,7 +610,8 @@ pub const Step = extern struct {...@@ -610,7 +610,8 @@ pub const Step = extern struct {
610 producer: bool,610 producer: bool,
611 generated: bool,611 generated: bool,
612 dep_file: bool,612 dep_file: bool,
613 _: u21 = 0,613 make_absolute: bool,
614 _: u20 = 0,
614 };615 };
615616
616 pub const Tag = enum(u4) {617 pub const Tag = enum(u4) {
lib/std/Build/Step/Run.zig+134-104
...@@ -133,10 +133,10 @@ pub const StdIo = union(enum) {...@@ -133,10 +133,10 @@ pub const StdIo = union(enum) {
133};133};
134134
135pub const Arg = union(enum) {135pub const Arg = union(enum) {
136 artifact: PrefixedArtifact,136 artifact: DecoratedArtifact,
137 lazy_path: PrefixedLazyPath,137 lazy_path: DecoratedLazyPath,
138 decorated_directory: DecoratedLazyPath,138 decorated_directory: DecoratedLazyPath,
139 file_content: PrefixedLazyPath,139 file_content: DecoratedFileContent,
140 bytes: []const u8,140 bytes: []const u8,
141 output_file: *Output,141 output_file: *Output,
142 output_file_dep: *Output,142 output_file_dep: *Output,
...@@ -145,17 +145,21 @@ pub const Arg = union(enum) {...@@ -145,17 +145,21 @@ pub const Arg = union(enum) {
145 passthru,145 passthru,
146};146};
147147
148pub const PrefixedArtifact = struct {148pub const DecoratedArtifact = struct {
149 prefix: []const u8,149 prefix: []const u8,
150 suffix: []const u8,
150 artifact: *Step.Compile,151 artifact: *Step.Compile,
152 make_absolute: bool,
151};153};
152154
153pub const PrefixedLazyPath = struct {155pub const DecoratedLazyPath = struct {
154 prefix: []const u8,156 prefix: []const u8,
155 lazy_path: std.Build.LazyPath,157 lazy_path: std.Build.LazyPath,
158 suffix: []const u8,
159 make_absolute: bool,
156};160};
157161
158pub const DecoratedLazyPath = struct {162pub const DecoratedFileContent = struct {
159 prefix: []const u8,163 prefix: []const u8,
160 lazy_path: std.Build.LazyPath,164 lazy_path: std.Build.LazyPath,
161 suffix: []const u8,165 suffix: []const u8,
...@@ -165,10 +169,14 @@ pub const Output = struct {...@@ -165,10 +169,14 @@ pub const Output = struct {
165 generated_file: Configuration.GeneratedFileIndex,169 generated_file: Configuration.GeneratedFileIndex,
166 prefix: []const u8,170 prefix: []const u8,
167 basename: []const u8,171 basename: []const u8,
172 suffix: []const u8,
173 make_absolute: bool,
168};174};
169175
170pub const CapturedStdIo = struct {176pub const CapturedStdIo = struct {
171 output: Output,177 generated_file: Configuration.GeneratedFileIndex,
178 prefix: []const u8,
179 basename: []const u8,
172 trim_whitespace: TrimWhitespace,180 trim_whitespace: TrimWhitespace,
173181
174 pub const Options = struct {182 pub const Options = struct {
...@@ -219,17 +227,38 @@ pub fn enableTestRunnerMode(run: *Run) void {...@@ -219,17 +227,38 @@ pub fn enableTestRunnerMode(run: *Run) void {
219 run.test_runner_mode = true;227 run.test_runner_mode = true;
220}228}
221229
230pub const ArgOptions = struct {
231 prefix: []const u8 = "",
232 suffix: []const u8 = "",
233};
234
235pub const PathArgOptions = struct {
236 prefix: []const u8 = "",
237 suffix: []const u8 = "",
238 /// Makes the path absolute before passing it to the child process. Not supported by all hosts,
239 /// prefer accepting relative paths when possible.
240 make_absolute: bool = false,
241};
242
243/// Deprecated, use `addArtifactArg2`.
222pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void {244pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void {
223 run.addPrefixedArtifactArg("", artifact);245 run.addArtifactArg2(artifact, .{});
224}246}
225247
248/// Deprecated, use `addArtifactArg2`.
226pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void {249pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void {
250 run.addArtifactArg2(artifact, .{ .prefix = prefix });
251}
252
253pub fn addArtifactArg2(run: *Run, artifact: *Step.Compile, options: PathArgOptions) void {
227 const graph = run.step.owner.graph;254 const graph = run.step.owner.graph;
228 const arena = graph.arena;255 const arena = graph.arena;
229256
230 const prefixed_artifact: PrefixedArtifact = .{257 const prefixed_artifact: DecoratedArtifact = .{
231 .prefix = graph.dupeString(prefix),258 .prefix = graph.dupeString(options.prefix),
232 .artifact = artifact,259 .artifact = artifact,
260 .suffix = graph.dupeString(options.suffix),
261 .make_absolute = options.make_absolute,
233 };262 };
234 run.argv.append(arena, .{ .artifact = prefixed_artifact }) catch @panic("OOM");263 run.argv.append(arena, .{ .artifact = prefixed_artifact }) catch @panic("OOM");
235264
...@@ -237,19 +266,18 @@ pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Com...@@ -237,19 +266,18 @@ pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Com
237 bin_file.addStepDependencies(&run.step);266 bin_file.addStepDependencies(&run.step);
238}267}
239268
240/// Provides a file path as a command line argument to the command being run.269/// Deprecated, use `addOutputFileArg2`.
241///
242/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs
243/// throughout the build system.
244///
245/// `sub_path` is the name of the generated output file which may have zero or
246/// more path components.
247///
248/// Related:
249/// * `addPrefixedOutputFileArg` - same thing but prepends a string to the argument
250/// * `addFileArg` - for input files given to the child process
251pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath {270pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath {
252 return run.addPrefixedOutputFileArg("", sub_path);271 return run.addOutputFileArg2(sub_path, .{});
272}
273
274/// Deprecated, use `addOutputFileArg2`.
275pub fn addPrefixedOutputFileArg(
276 run: *Run,
277 prefix: []const u8,
278 sub_path: []const u8,
279) std.Build.LazyPath {
280 return run.addOutputFileArg2(sub_path, .{ .prefix = prefix });
253}281}
254282
255/// Provides a file path as a command line argument to the command being run.283/// Provides a file path as a command line argument to the command being run.
...@@ -264,16 +292,15 @@ pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath {...@@ -264,16 +292,15 @@ pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath {
264/// throughout the build system.292/// throughout the build system.
265///293///
266/// Related:294/// Related:
267/// * `addOutputFileArg` - same thing but without the prefix
268/// * `addFileArg` - for input files given to the child process295/// * `addFileArg` - for input files given to the child process
269pub fn addPrefixedOutputFileArg(296pub fn addOutputFileArg2(
270 run: *Run,297 run: *Run,
271 prefix: []const u8,
272 /// The name of the generated output file which may have zero or more path298 /// The name of the generated output file which may have zero or more path
273 /// components.299 /// components.
274 ///300 ///
275 /// Asserted to be non-empty.301 /// Asserted to be non-empty.
276 sub_path: []const u8,302 sub_path: []const u8,
303 options: PathArgOptions,
277) std.Build.LazyPath {304) std.Build.LazyPath {
278 const b = run.step.owner;305 const b = run.step.owner;
279 const graph = b.graph;306 const graph = b.graph;
...@@ -282,9 +309,11 @@ pub fn addPrefixedOutputFileArg(...@@ -282,9 +309,11 @@ pub fn addPrefixedOutputFileArg(
282309
283 const output = graph.create(Output);310 const output = graph.create(Output);
284 output.* = .{311 output.* = .{
285 .prefix = graph.dupeString(prefix),312 .prefix = graph.dupeString(options.prefix),
286 .basename = graph.dupeString(sub_path),313 .basename = graph.dupeString(sub_path),
314 .suffix = graph.dupeString(options.suffix),
287 .generated_file = graph.addGeneratedFile(&run.step),315 .generated_file = graph.addGeneratedFile(&run.step),
316 .make_absolute = options.make_absolute,
288 };317 };
289 run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM");318 run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM");
290319
...@@ -295,17 +324,14 @@ pub fn addPrefixedOutputFileArg(...@@ -295,17 +324,14 @@ pub fn addPrefixedOutputFileArg(
295 return .{ .generated = .{ .index = output.generated_file } };324 return .{ .generated = .{ .index = output.generated_file } };
296}325}
297326
298/// Appends an input file to the command line arguments.327/// See `addFileArg2`.
299///
300/// The child process will see a file path. Modifications to this file will be
301/// detected as a cache miss in subsequent builds, causing the child process to
302/// be re-executed.
303///
304/// Related:
305/// * `addPrefixedFileArg` - same thing but prepends a string to the argument
306/// * `addOutputFileArg` - for files generated by the child process
307pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {328pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {
308 run.addPrefixedFileArg("", lp);329 run.addFileArg2(lp, .{});
330}
331
332/// See `addFileArg2`.
333pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {
334 run.addFileArg2(lp, .{ .prefix = prefix });
309}335}
310336
311/// Appends an input file to the command line arguments prepended with a string.337/// Appends an input file to the command line arguments prepended with a string.
...@@ -318,36 +344,29 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {...@@ -318,36 +344,29 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void {
318/// subsequent builds, causing the child process to be re-executed.344/// subsequent builds, causing the child process to be re-executed.
319///345///
320/// Related:346/// Related:
321/// * `addFileArg` - same thing but without the prefix
322/// * `addOutputFileArg` - for files generated by the child process347/// * `addOutputFileArg` - for files generated by the child process
323pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {348pub fn addFileArg2(run: *Run, lp: std.Build.LazyPath, options: PathArgOptions) void {
324 const graph = run.step.owner.graph;349 const graph = run.step.owner.graph;
325 const arena = graph.arena;350 const arena = graph.arena;
326351
327 const prefixed_file_source: PrefixedLazyPath = .{352 const prefixed_file_source: DecoratedLazyPath = .{
328 .prefix = graph.dupeString(prefix),353 .prefix = graph.dupeString(options.prefix),
329 .lazy_path = lp.dupe(graph),354 .lazy_path = lp.dupe(graph),
355 .suffix = graph.dupeString(options.suffix),
356 .make_absolute = options.make_absolute,
330 };357 };
331 run.argv.append(arena, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM");358 run.argv.append(arena, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM");
332 lp.addStepDependencies(&run.step);359 lp.addStepDependencies(&run.step);
333}360}
334361
335/// Appends the content of an input file to the command line arguments.362/// Deprecated, use `addFileContentArg2`.
336///
337/// The child process will see a single argument, even if the file contains whitespace.
338/// This means that the entire file content up to EOF is rendered as one contiguous
339/// string, including escape sequences. Notably, any (trailing) newlines will show up
340/// like this: "hello,\nfile world!\n"
341///
342/// Modifications to the source file will be detected as a cache miss in subsequent
343/// builds, causing the child process to be re-executed.
344///
345/// This function may not be used to supply the first argument of a `Run` step.
346///
347/// Related:
348/// * `addPrefixedFileContentArg` - same thing but prepends a string to the argument
349pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {363pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {
350 run.addPrefixedFileContentArg("", lp);364 return run.addFileContentArg2(lp, .{});
365}
366
367/// Deprecated, use `addFileContentArg2`.
368pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {
369 return run.addFileContentArg2(lp, .{ .prefix = prefix });
351}370}
352371
353/// Appends the content of an input file to the command line arguments prepended with a string.372/// Appends the content of an input file to the command line arguments prepended with a string.
...@@ -368,7 +387,7 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {...@@ -368,7 +387,7 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void {
368///387///
369/// Related:388/// Related:
370/// * `addFileContentArg` - same thing but without the prefix389/// * `addFileContentArg` - same thing but without the prefix
371pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void {390pub fn addFileContentArg2(run: *Run, lp: std.Build.LazyPath, options: ArgOptions) void {
372 const graph = run.step.owner.graph;391 const graph = run.step.owner.graph;
373 const arena = graph.arena;392 const arena = graph.arena;
374393
...@@ -379,24 +398,27 @@ pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.La...@@ -379,24 +398,27 @@ pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.La
379 @panic("'addFileContentArg'/'addPrefixedFileContentArg' cannot be first argument");398 @panic("'addFileContentArg'/'addPrefixedFileContentArg' cannot be first argument");
380 }399 }
381400
382 const prefixed_file_source: PrefixedLazyPath = .{401 const file_content: DecoratedFileContent = .{
383 .prefix = graph.dupeString(prefix),402 .prefix = graph.dupeString(options.prefix),
384 .lazy_path = lp.dupe(graph),403 .lazy_path = lp.dupe(graph),
404 .suffix = graph.dupeString(options.suffix),
385 };405 };
386 run.argv.append(arena, .{ .file_content = prefixed_file_source }) catch @panic("OOM");406 run.argv.append(arena, .{ .file_content = file_content }) catch @panic("OOM");
387 lp.addStepDependencies(&run.step);407 lp.addStepDependencies(&run.step);
388}408}
389409
390/// Provides a directory path as a command line argument to the command being run.410/// Deprecated, use `addOutputDirectoryArg2`.
391///
392/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs
393/// throughout the build system.
394///
395/// Related:
396/// * `addPrefixedOutputDirectoryArg` - same thing but prepends a string to the argument
397/// * `addDirectoryArg` - for input directories given to the child process
398pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath {411pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath {
399 return run.addPrefixedOutputDirectoryArg("", basename);412 return run.addOutputDirectoryArg2(basename, .{});
413}
414
415/// Deprecated, use `addOutputDirectoryArg2`.
416pub fn addPrefixedOutputDirectoryArg(
417 run: *Run,
418 prefix: []const u8,
419 basename: []const u8,
420) std.Build.LazyPath {
421 return run.addOutputDirectoryArg2(basename, .{ .prefix = prefix });
400}422}
401423
402/// Provides a directory path as a command line argument to the command being run.424/// Provides a directory path as a command line argument to the command being run.
...@@ -412,12 +434,11 @@ pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath...@@ -412,12 +434,11 @@ pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath
412/// throughout the build system.434/// throughout the build system.
413///435///
414/// Related:436/// Related:
415/// * `addOutputDirectoryArg` - same thing but without the prefix
416/// * `addDirectoryArg` - for input directories given to the child process437/// * `addDirectoryArg` - for input directories given to the child process
417pub fn addPrefixedOutputDirectoryArg(438pub fn addOutputDirectoryArg2(
418 run: *Run,439 run: *Run,
419 prefix: []const u8,
420 basename: []const u8,440 basename: []const u8,
441 options: PathArgOptions,
421) std.Build.LazyPath {442) std.Build.LazyPath {
422 if (basename.len == 0) @panic("basename must not be empty");443 if (basename.len == 0) @panic("basename must not be empty");
423 const graph = run.step.owner.graph;444 const graph = run.step.owner.graph;
...@@ -425,9 +446,11 @@ pub fn addPrefixedOutputDirectoryArg(...@@ -425,9 +446,11 @@ pub fn addPrefixedOutputDirectoryArg(
425446
426 const output = arena.create(Output) catch @panic("OOM");447 const output = arena.create(Output) catch @panic("OOM");
427 output.* = .{448 output.* = .{
428 .prefix = graph.dupeString(prefix),449 .prefix = graph.dupeString(options.prefix),
429 .basename = graph.dupeString(basename),450 .basename = graph.dupeString(basename),
451 .suffix = graph.dupeString(options.suffix),
430 .generated_file = graph.addGeneratedFile(&run.step),452 .generated_file = graph.addGeneratedFile(&run.step),
453 .make_absolute = options.make_absolute,
431 };454 };
432 run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM");455 run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM");
433456
...@@ -438,56 +461,67 @@ pub fn addPrefixedOutputDirectoryArg(...@@ -438,56 +461,67 @@ pub fn addPrefixedOutputDirectoryArg(
438 return .{ .generated = .{ .index = output.generated_file } };461 return .{ .generated = .{ .index = output.generated_file } };
439}462}
440463
464/// Deprecated, use `addDirectoryArg2`.
441pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {465pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {
442 run.addDecoratedDirectoryArg("", lazy_directory, "");466 run.addDirectoryArg2(lazy_directory, .{});
443}467}
444468
469/// Deprecated, use `addDirectoryArg2`.
445pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void {470pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void {
446 const graph = run.step.owner.graph;471 run.addDirectoryArg2(lazy_directory, .{ .prefix = prefix });
447 const arena = graph.arena;
448 run.argv.append(arena, .{ .decorated_directory = .{
449 .prefix = graph.dupeString(prefix),
450 .lazy_path = lazy_directory.dupe(graph),
451 .suffix = "",
452 } }) catch @panic("OOM");
453 lazy_directory.addStepDependencies(&run.step);
454}472}
455473
474/// Deprecated, use `addDirectoryArg2`.
456pub fn addDecoratedDirectoryArg(475pub fn addDecoratedDirectoryArg(
457 run: *Run,476 run: *Run,
458 prefix: []const u8,477 prefix: []const u8,
459 lazy_directory: std.Build.LazyPath,478 lazy_directory: std.Build.LazyPath,
460 suffix: []const u8,479 suffix: []const u8,
480) void {
481 run.addDirectoryArg2(lazy_directory, .{ .prefix = prefix, .suffix = suffix });
482}
483
484pub fn addDirectoryArg2(
485 run: *Run,
486 lazy_directory: std.Build.LazyPath,
487 options: PathArgOptions,
461) void {488) void {
462 const graph = run.step.owner.graph;489 const graph = run.step.owner.graph;
463 const arena = graph.arena;490 const arena = graph.arena;
464 run.argv.append(arena, .{ .decorated_directory = .{491 run.argv.append(arena, .{ .decorated_directory = .{
465 .prefix = graph.dupeString(prefix),492 .prefix = graph.dupeString(options.prefix),
466 .lazy_path = lazy_directory.dupe(graph),493 .lazy_path = lazy_directory.dupe(graph),
467 .suffix = graph.dupeString(suffix),494 .suffix = graph.dupeString(options.suffix),
495 .make_absolute = options.make_absolute,
468 } }) catch @panic("OOM");496 } }) catch @panic("OOM");
469 lazy_directory.addStepDependencies(&run.step);497 lazy_directory.addStepDependencies(&run.step);
470}498}
471499
472/// Add a path argument to a dep file (.d) for the child process to write its500/// Deprecated, use `addDepFileOutputArg2`.
473/// discovered additional dependencies.
474/// Only one dep file argument is allowed by instance.
475pub fn addDepFileOutputArg(run: *Run, basename: []const u8) std.Build.LazyPath {501pub fn addDepFileOutputArg(run: *Run, basename: []const u8) std.Build.LazyPath {
476 return run.addPrefixedDepFileOutputArg("", basename);502 return run.addDepFileOutputArg2(basename, .{});
477}503}
478504
479/// Add a prefixed path argument to a dep file (.d) for the child process to505/// Deprecated, use `addDepFileOutputArg2`.
480/// write its discovered additional dependencies.
481pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath {506pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath {
507 return run.addDepFileOutputArg2(basename, .{ .prefix = prefix });
508}
509
510/// Add a path argument to a dep file (.d) for the child process to write its
511/// discovered additional dependencies.
512/// Only one dep file argument is allowed by instance.
513pub fn addDepFileOutputArg2(run: *Run, basename: []const u8, options: PathArgOptions) std.Build.LazyPath {
482 const b = run.step.owner;514 const b = run.step.owner;
483 const graph = b.graph;515 const graph = b.graph;
484 const arena = graph.arena;516 const arena = graph.arena;
485517
486 const dep_file = arena.create(Output) catch @panic("OOM");518 const dep_file = arena.create(Output) catch @panic("OOM");
487 dep_file.* = .{519 dep_file.* = .{
488 .prefix = graph.dupeString(prefix),520 .prefix = graph.dupeString(options.prefix),
489 .basename = graph.dupeString(basename),521 .basename = graph.dupeString(basename),
522 .suffix = graph.dupeString(options.suffix),
490 .generated_file = graph.addGeneratedFile(&run.step),523 .generated_file = graph.addGeneratedFile(&run.step),
524 .make_absolute = options.make_absolute,
491 };525 };
492526
493 run.argv.append(arena, .{ .output_file_dep = dep_file }) catch @panic("OOM");527 run.argv.append(arena, .{ .output_file_dep = dep_file }) catch @panic("OOM");
...@@ -642,19 +676,17 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa...@@ -642,19 +676,17 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa
642 const graph = b.graph;676 const graph = b.graph;
643 const arena = graph.arena;677 const arena = graph.arena;
644678
645 if (run.captured_stderr) |captured| return .{ .generated = .{ .index = captured.output.generated_file } };679 if (run.captured_stderr) |captured| return .{ .generated = .{ .index = captured.generated_file } };
646680
647 const captured = arena.create(CapturedStdIo) catch @panic("OOM");681 const captured = arena.create(CapturedStdIo) catch @panic("OOM");
648 captured.* = .{682 captured.* = .{
649 .output = .{683 .prefix = "",
650 .prefix = "",684 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr",
651 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr",685 .generated_file = graph.addGeneratedFile(&run.step),
652 .generated_file = graph.addGeneratedFile(&run.step),
653 },
654 .trim_whitespace = options.trim_whitespace,686 .trim_whitespace = options.trim_whitespace,
655 };687 };
656 run.captured_stderr = captured;688 run.captured_stderr = captured;
657 return .{ .generated = .{ .index = captured.output.generated_file } };689 return .{ .generated = .{ .index = captured.generated_file } };
658}690}
659691
660pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath {692pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath {
...@@ -665,19 +697,17 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa...@@ -665,19 +697,17 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa
665 const graph = b.graph;697 const graph = b.graph;
666 const arena = graph.arena;698 const arena = graph.arena;
667699
668 if (run.captured_stdout) |captured| return .{ .generated = .{ .index = captured.output.generated_file } };700 if (run.captured_stdout) |captured| return .{ .generated = .{ .index = captured.generated_file } };
669701
670 const captured = arena.create(CapturedStdIo) catch @panic("OOM");702 const captured = arena.create(CapturedStdIo) catch @panic("OOM");
671 captured.* = .{703 captured.* = .{
672 .output = .{704 .prefix = "",
673 .prefix = "",705 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout",
674 .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout",706 .generated_file = graph.addGeneratedFile(&run.step),
675 .generated_file = graph.addGeneratedFile(&run.step),
676 },
677 .trim_whitespace = options.trim_whitespace,707 .trim_whitespace = options.trim_whitespace,
678 };708 };
679 run.captured_stdout = captured;709 run.captured_stdout = captured;
680 return .{ .generated = .{ .index = captured.output.generated_file } };710 return .{ .generated = .{ .index = captured.generated_file } };
681}711}
682712
683/// Adds an additional input files that, when modified, indicates that this Run713/// Adds an additional input files that, when modified, indicates that this Run
test/standalone/build.zig.zon+3
...@@ -196,6 +196,9 @@...@@ -196,6 +196,9 @@
196 .elf2 = .{196 .elf2 = .{
197 .path = "elf2",197 .path = "elf2",
198 },198 },
199 .run_args = .{
200 .path = "run_args",
201 },
199 },202 },
200 .paths = .{203 .paths = .{
201 "build.zig",204 "build.zig",
test/standalone/run_args/build.zig created+160
...@@ -0,0 +1,160 @@
1const std = @import("std");
2
3/// Tests that args are passed to run steps correctly.
4///
5/// Note that when `make_absolute` is true we make sure the resulting path argument is absolute, but
6/// when it is false we allow either absolute or relative paths. This is because the maker receives
7/// absolute paths when build is run from anywhere other than the build root.
8pub fn build(b: *std.Build) !void {
9 const step = b.step("test", "Run artifact args standalone test cases");
10 b.default_step = step;
11
12 const exe = b.addExecutable(.{
13 .name = "exe",
14 .root_module = b.createModule(.{
15 .root_source_file = b.path("main.zig"),
16 .target = b.graph.host,
17 }),
18 });
19
20 // Arg
21 {
22 const run = b.addRunArtifact(exe);
23 step.dependOn(&run.step);
24 run.addArg("arg1");
25 run.expectStdErrEqual("arg1\n");
26 }
27
28 // Args
29 {
30 const run = b.addRunArtifact(exe);
31 step.dependOn(&run.step);
32 run.addArgs(&.{ "arg1", "arg2" });
33 run.expectStdErrEqual("arg1\narg2\n");
34 }
35
36 // Artifact Args
37 {
38 // Absolute
39 {
40 const run = b.addRunArtifact(exe);
41 step.dependOn(&run.step);
42 _ = run.addArtifactArg2(exe, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
43 run.expectStdErrMatch("abs exe");
44 }
45 // Relative
46 {
47 const run = b.addRunArtifact(exe);
48 step.dependOn(&run.step);
49 _ = run.addArtifactArg2(exe, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
50 run.expectStdErrMatch("exe\n");
51 }
52 }
53
54 // File Args
55 {
56 const write_files = b.addWriteFiles();
57 const file = write_files.add("file", "");
58
59 // Absolute
60 {
61 const run = b.addRunArtifact(exe);
62 step.dependOn(&run.step);
63 _ = run.addFileArg2(file, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
64 run.expectStdErrEqual("abs file\n");
65 }
66 // Relative
67 {
68 const run = b.addRunArtifact(exe);
69 step.dependOn(&run.step);
70 _ = run.addFileArg2(file, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
71 run.expectStdErrMatch("file\n");
72 }
73 }
74
75 // File Content
76 {
77 const write_files = b.addWriteFiles();
78 const file = write_files.add("file", "foo bar baz");
79
80 const run = b.addRunArtifact(exe);
81 step.dependOn(&run.step);
82 _ = run.addFileContentArg2(file, .{ .prefix = "content-prefix ", .suffix = " content-suffix" });
83 run.expectStdErrEqual("content-prefix foo bar baz content-suffix\n");
84 }
85
86 // Output File Args
87 {
88 // Absolute
89 {
90 const run = b.addRunArtifact(exe);
91 step.dependOn(&run.step);
92 _ = run.addOutputFileArg2("output-file", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
93 run.expectStdErrEqual("abs output-file\n");
94 }
95 // Relative
96 {
97 const run = b.addRunArtifact(exe);
98 step.dependOn(&run.step);
99 _ = run.addOutputFileArg2("output-file", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
100 run.expectStdErrMatch("output-file\n");
101 }
102 }
103
104 // Output Directory Args
105 {
106 // Absolute
107 {
108 const run = b.addRunArtifact(exe);
109 step.dependOn(&run.step);
110 _ = run.addOutputDirectoryArg2("output-dir", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
111 run.expectStdErrEqual("abs output-dir\n");
112 }
113 // Relative
114 {
115 const run = b.addRunArtifact(exe);
116 step.dependOn(&run.step);
117 _ = run.addOutputDirectoryArg2("output-dir", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
118 run.expectStdErrMatch("output-dir\n");
119 }
120 }
121
122 // Directory Args
123 {
124 const write_files = b.addWriteFiles();
125 const directory = try write_files.getDirectory().join(b.graph.arena, "dir");
126
127 // Absolute
128 {
129 const run = b.addRunArtifact(exe);
130 step.dependOn(&run.step);
131 _ = run.addDirectoryArg2(directory, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
132 run.expectStdErrEqual("abs dir\n");
133 }
134 // Relative
135 {
136 const run = b.addRunArtifact(exe);
137 step.dependOn(&run.step);
138 _ = run.addDirectoryArg2(directory, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
139 run.expectStdErrMatch("dir\n");
140 }
141 }
142
143 // Dep File Args
144 {
145 // Absolute
146 {
147 const run = b.addRunArtifact(exe);
148 step.dependOn(&run.step);
149 _ = run.addDepFileOutputArg2("deps.d", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" });
150 run.expectStdErrEqual("abs deps.d\n");
151 }
152 // Relative
153 {
154 const run = b.addRunArtifact(exe);
155 step.dependOn(&run.step);
156 _ = run.addDepFileOutputArg2("deps.d", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" });
157 run.expectStdErrMatch("deps.d\n");
158 }
159 }
160}
test/standalone/run_args/main.zig created+32
...@@ -0,0 +1,32 @@
1const std = @import("std");
2
3pub fn main(init: std.process.Init) !void {
4 const io = init.io;
5 const arena = init.arena.allocator();
6
7 var iter = try init.minimal.args.iterateAllocator(arena);
8 std.debug.assert(iter.skip());
9 while (iter.next()) |arg| {
10 const path_prefix = "path^";
11 const path_suffix = "$";
12 if (std.mem.startsWith(u8, arg, path_prefix) and std.mem.endsWith(u8, arg, path_suffix)) {
13 // If we're a path, log whether we're absolute or relative, and log the basename
14 const path = arg[path_prefix.len..][0 .. arg.len - path_prefix.len - path_suffix.len];
15 if (std.fs.path.isAbsolute(path)) {
16 std.debug.print("abs ", .{});
17 } else {
18 std.debug.print("rel ", .{});
19 }
20 std.debug.print("{s}\n", .{std.fs.path.basename(path)});
21
22 // Create an empty dep file if necessary
23 if (std.mem.endsWith(u8, path, ".d")) {
24 const file = try std.Io.Dir.cwd().createFile(io, path, .{});
25 defer file.close(io);
26 }
27 } else {
28 // If it's not a path, log the arg as is
29 std.debug.print("{s}\n", .{arg});
30 }
31 }
32}