Commit 36499c251c
Changed files (5)
lib
std
Build
Step
test
standalone
run_cwd
lib/std/Build/Step/Run.zig
@@ -629,9 +629,22 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
const b = run.step.owner;
const path_str = path.toString(b.graph.arena) catch @panic("OOM");
- const child_lazy_cwd = run.cwd orelse return path_str;
- const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
- return std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
+ if (std.fs.path.isAbsolute(path_str)) {
+ // Absolute paths don't need changing.
+ return path_str;
+ }
+ const child_cwd_rel: []const u8 = rel: {
+ const child_lazy_cwd = run.cwd orelse break :rel path_str;
+ const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
+ // Convert it from relative to *our* cwd, to relative to the *child's* cwd.
+ break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
+ };
+ assert(!std.fs.path.isAbsolute(child_cwd_rel));
+ // We're not done yet. In some cases this path must be prefixed with './':
+ // * On POSIX, the executable name cannot be a single component like 'foo'
+ // * Some executables might treat a leading '-' like a flag, which we must avoid
+ // There's no harm in it, so just *always* apply this prefix.
+ return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
}
const IndexedOutput = struct {
@@ -756,6 +769,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
_ = try man.addFile(lazy_path.getPath2(b, step), null);
}
+ if (run.cwd) |cwd| {
+ const cwd_path = cwd.getPath3(b, step);
+ _ = man.hash.addBytes(try cwd_path.toString(arena));
+ }
+
if (!has_side_effects and try step.cacheHitAndWatch(&man)) {
// cache hit, skip running command
const digest = man.final();
test/standalone/run_cwd/empty_dir/make_git_happy
test/standalone/run_cwd/build.zig
@@ -0,0 +1,30 @@
+pub fn build(b: *Build) void {
+ const exe = b.addExecutable(.{
+ .name = "check_file_exists",
+ .root_module = b.createModule(.{
+ .target = b.graph.host,
+ .optimize = .Debug,
+ .root_source_file = b.path("check_file_exists.zig"),
+ }),
+ });
+
+ const test_step = b.step("test", "Test it");
+ b.default_step = test_step;
+
+ test_step.dependOn(addCheck(b, exe, ".", null));
+ test_step.dependOn(addCheck(b, exe, "..", b.path("..")));
+ test_step.dependOn(addCheck(b, exe, "exe dir", exe.getEmittedBin().dirname()));
+ test_step.dependOn(addCheck(b, exe, "exe dir/..", exe.getEmittedBin().dirname().dirname()));
+ test_step.dependOn(addCheck(b, exe, "./empty_dir", b.path("empty_dir")));
+}
+
+fn addCheck(b: *Build, exe: *Build.Step.Compile, cwd_name: []const u8, opt_cwd: ?Build.LazyPath) *Build.Step {
+ const run = b.addRunArtifact(exe);
+ if (opt_cwd) |cwd| run.setCwd(cwd);
+ run.addFileArg(b.path("file_that_exists.txt"));
+ run.setName(b.fmt("check in '{s}'", .{cwd_name}));
+ run.expectExitCode(0);
+ return &run.step;
+}
+
+const Build = @import("std").Build;
test/standalone/run_cwd/check_file_exists.zig
@@ -0,0 +1,14 @@
+pub fn main() !void {
+ var arena_state: std.heap.ArenaAllocator = .init(std.heap.page_allocator);
+ defer arena_state.deinit();
+ const arena = arena_state.allocator();
+
+ const args = try std.process.argsAlloc(arena);
+
+ if (args.len != 2) return error.BadUsage;
+ const path = args[1];
+
+ std.fs.cwd().access(path, .{}) catch return error.AccessFailed;
+}
+
+const std = @import("std");
test/standalone/run_cwd/file_that_exists.txt