diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index ca5525eff4..eb5ea1c607 100644 --- a/lib/std/Build/Step/Run.zig +++ b/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(); diff --git a/test/standalone/run_cwd/build.zig b/test/standalone/run_cwd/build.zig new file mode 100644 index 0000000000..d66393a602 --- /dev/null +++ b/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; diff --git a/test/standalone/run_cwd/check_file_exists.zig b/test/standalone/run_cwd/check_file_exists.zig new file mode 100644 index 0000000000..640fc99a7a --- /dev/null +++ b/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"); diff --git a/test/standalone/run_cwd/empty_dir/make_git_happy b/test/standalone/run_cwd/empty_dir/make_git_happy new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/standalone/run_cwd/file_that_exists.txt b/test/standalone/run_cwd/file_that_exists.txt new file mode 100644 index 0000000000..e69de29bb2