authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-06-15 15:01:06+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-06-15 15:01:06+02:00
log1ca213dab02db42c63a6b7e191044c0124f9bfb2
tree0d7c42e0ab9f64927c62648a5162847762a201ea
parent878b7b80c15d4b9a894f6ab1d4e8753de77568ad
parent14e033ed95a43a5ff994df9dc524e5bc4f34452a
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24168 from mlugg/relative-paths

std.Build: fix relative path bugs

6 files changed, 53 insertions(+), 41 deletions(-)

lib/std/Build/Step/Run.zig+46-22
......@@ -622,6 +622,18 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
622622 return false;
623623}
624624
625/// If `path` is cwd-relative, make it relative to the cwd of the child instead.
626///
627/// Whenever a path is included in the argv of a child, it should be put through this function first
628/// to make sure the child doesn't see paths relative to a cwd other than its own.
629fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
630 const b = run.step.owner;
631 const path_str = path.toString(b.graph.arena) catch @panic("OOM");
632 const child_lazy_cwd = run.cwd orelse return path_str;
633 const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
634 return std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
635}
636
625637const IndexedOutput = struct {
626638 index: usize,
627639 tag: @typeInfo(Arg).@"union".tag_type.?,
......@@ -676,14 +688,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
676688 man.hash.addBytes(bytes);
677689 },
678690 .lazy_path => |file| {
679 const file_path = file.lazy_path.getPath2(b, step);
680 try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path }));
691 const file_path = file.lazy_path.getPath3(b, step);
692 try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) }));
681693 man.hash.addBytes(file.prefix);
682 _ = try man.addFile(file_path, null);
694 _ = try man.addFilePath(file_path, null);
683695 },
684696 .decorated_directory => |dd| {
685697 const file_path = dd.lazy_path.getPath3(b, step);
686 const resolved_arg = b.fmt("{s}{}{s}", .{ dd.prefix, file_path, dd.suffix });
698 const resolved_arg = b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix });
687699 try argv_list.append(resolved_arg);
688700 man.hash.addBytes(resolved_arg);
689701 },
......@@ -696,7 +708,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
696708 }
697709 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;
698710
699 try argv_list.append(b.fmt("{s}{s}", .{ pa.prefix, file_path }));
711 try argv_list.append(b.fmt("{s}{s}", .{
712 pa.prefix,
713 run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }),
714 }));
700715
701716 _ = try man.addFile(file_path, null);
702717 },
......@@ -787,11 +802,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
787802 b.cache_root, output_sub_dir_path, @errorName(err),
788803 });
789804 };
790 const output_path = placeholder.output.generated_file.path.?;
805 const arg_output_path = run.convertPathArg(.{
806 .root_dir = .cwd(),
807 .sub_path = placeholder.output.generated_file.getPath(),
808 });
791809 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)
792 output_path
810 arg_output_path
793811 else
794 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });
812 b.fmt("{s}{s}", .{ placeholder.output.prefix, arg_output_path });
795813 }
796814
797815 try runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node, null);
......@@ -816,12 +834,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
816834 b.cache_root, output_sub_dir_path, @errorName(err),
817835 });
818836 };
819 const output_path = try b.cache_root.join(arena, &output_components);
820 placeholder.output.generated_file.path = output_path;
821 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)
822 output_path
823 else
824 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });
837 const raw_output_path: Build.Cache.Path = .{
838 .root_dir = b.cache_root,
839 .sub_path = b.pathJoin(&output_components),
840 };
841 placeholder.output.generated_file.path = raw_output_path.toString(b.graph.arena) catch @panic("OOM");
842 argv_list.items[placeholder.index] = b.fmt("{s}{s}", .{
843 placeholder.output.prefix,
844 run.convertPathArg(raw_output_path),
845 });
825846 }
826847
827848 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, prog_node, null);
......@@ -899,20 +920,23 @@ pub fn rerunInFuzzMode(
899920 try argv_list.append(arena, bytes);
900921 },
901922 .lazy_path => |file| {
902 const file_path = file.lazy_path.getPath2(b, step);
903 try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, file_path }));
923 const file_path = file.lazy_path.getPath3(b, step);
924 try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) }));
904925 },
905926 .decorated_directory => |dd| {
906927 const file_path = dd.lazy_path.getPath3(b, step);
907 try argv_list.append(arena, b.fmt("{s}{}{s}", .{ dd.prefix, file_path, dd.suffix }));
928 try argv_list.append(arena, b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix }));
908929 },
909930 .artifact => |pa| {
910931 const artifact = pa.artifact;
911 const file_path = if (artifact == run.producer.?)
912 b.fmt("{}", .{run.rebuilt_executable.?})
913 else
914 (artifact.installed_path orelse artifact.generated_bin.?.path.?);
915 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));
932 const file_path: []const u8 = p: {
933 if (artifact == run.producer.?) break :p b.fmt("{}", .{run.rebuilt_executable.?});
934 break :p artifact.installed_path orelse artifact.generated_bin.?.path.?;
935 };
936 try argv_list.append(arena, b.fmt("{s}{s}", .{
937 pa.prefix,
938 run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }),
939 }));
916940 },
917941 .output_file, .output_directory => unreachable,
918942 }
test/standalone/dirname/exists_in.zig+1-6
......@@ -29,17 +29,12 @@ fn run(allocator: std.mem.Allocator) !void {
2929 return error.BadUsage;
3030 };
3131
32 if (!std.fs.path.isAbsolute(dir_path)) {
33 std.log.err("expected <dir> to be an absolute path", .{});
34 return error.BadUsage;
35 }
36
3732 const relpath = args.next() orelse {
3833 std.log.err("missing <path> argument", .{});
3934 return error.BadUsage;
4035 };
4136
42 var dir = try std.fs.openDirAbsolute(dir_path, .{});
37 var dir = try std.fs.cwd().openDir(dir_path, .{});
4338 defer dir.close();
4439
4540 _ = try dir.statFile(relpath);
test/standalone/dirname/has_basename.zig-5
......@@ -31,11 +31,6 @@ fn run(allocator: std.mem.Allocator) !void {
3131 return error.BadUsage;
3232 };
3333
34 if (!std.fs.path.isAbsolute(path)) {
35 std.log.err("path must be absolute", .{});
36 return error.BadUsage;
37 }
38
3934 const basename = args.next() orelse {
4035 std.log.err("missing <basename> argument", .{});
4136 return error.BadUsage;
test/standalone/dirname/touch.zig+1-6
......@@ -26,15 +26,10 @@ fn run(allocator: std.mem.Allocator) !void {
2626 return error.BadUsage;
2727 };
2828
29 if (!std.fs.path.isAbsolute(path)) {
30 std.log.err("path must be absolute: {s}", .{path});
31 return error.BadUsage;
32 }
33
3429 const dir_path = std.fs.path.dirname(path) orelse unreachable;
3530 const basename = std.fs.path.basename(path);
3631
37 var dir = try std.fs.openDirAbsolute(dir_path, .{});
32 var dir = try std.fs.cwd().openDir(dir_path, .{});
3833 defer dir.close();
3934
4035 _ = dir.statFile(basename) catch {
test/standalone/run_output_caching/main.zig+1-1
......@@ -4,7 +4,7 @@ pub fn main() !void {
44 var args = try std.process.argsWithAllocator(std.heap.page_allocator);
55 _ = args.skip();
66 const filename = args.next().?;
7 const file = try std.fs.createFileAbsolute(filename, .{});
7 const file = try std.fs.cwd().createFile(filename, .{});
88 defer file.close();
99 try file.writeAll(filename);
1010}
test/standalone/self_exe_symlink/create-symlink.zig+4-1
......@@ -11,5 +11,8 @@ pub fn main() anyerror!void {
1111 const exe_path = it.next() orelse unreachable;
1212 const symlink_path = it.next() orelse unreachable;
1313
14 try std.fs.cwd().symLink(exe_path, symlink_path, .{});
14 // If `exe_path` is relative to our cwd, we need to convert it to be relative to the dirname of `symlink_path`.
15 const exe_rel_path = try std.fs.path.relative(allocator, std.fs.path.dirname(symlink_path) orelse ".", exe_path);
16 defer allocator.free(exe_rel_path);
17 try std.fs.cwd().symLink(exe_rel_path, symlink_path, .{});
1518}