Skip to content

Commit 1ca213d

Browse files
authored
Merge pull request #24168 from mlugg/relative-paths
std.Build: fix relative path bugs
2 parents 878b7b8 + 14e033e commit 1ca213d

File tree

6 files changed

+53
-41
lines changed

6 files changed

+53
-41
lines changed

lib/std/Build/Step/Run.zig

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
629+
fn 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+
625637
const 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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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
}

0 commit comments

Comments
 (0)