| author | |
| committer | |
| log | 36499c251c592d10a8258b1562bee22e5fb7899a |
| tree | fa03fda7f222e30607b62a6e2c25d193f6e96c43 |
| parent | f3940ad858937cc4bb2e1b99828183e070f40bf9 |
This is necessary in two cases:
* On POSIX, the exe path (`argv[0]`) must contain a path separator
* Some programs might treat a file named e.g. `-foo` as a flag, which
can be avoided by passing `./-foo`
Rather than detecting these two cases, just always include the prefix;
there's no harm in it.
Also, if the cwd is specified, include it in the manifest. If the user
has set the cwd of a Run step, it is clearly because this affects the
behavior of the executable somehow, so that cwd path should be a part of
the step's manifest.
Resolves: #242165 files changed, 65 insertions(+), 3 deletions(-)
lib/std/Build/Step/Run.zig+21-3| ... | @@ -629,9 +629,22 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { | ... | @@ -629,9 +629,22 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { |
| 629 | fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 { | 629 | fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 { |
| 630 | const b = run.step.owner; | 630 | const b = run.step.owner; |
| 631 | const path_str = path.toString(b.graph.arena) catch @panic("OOM"); | 631 | const path_str = path.toString(b.graph.arena) catch @panic("OOM"); |
| 632 | const child_lazy_cwd = run.cwd orelse return path_str; | 632 | if (std.fs.path.isAbsolute(path_str)) { |
| 633 | const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM"); | 633 | // Absolute paths don't need changing. |
| 634 | return std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM"); | 634 | return path_str; |
| 635 | } | ||
| 636 | const child_cwd_rel: []const u8 = rel: { | ||
| 637 | const child_lazy_cwd = run.cwd orelse break :rel path_str; | ||
| 638 | const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM"); | ||
| 639 | // Convert it from relative to *our* cwd, to relative to the *child's* cwd. | ||
| 640 | break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM"); | ||
| 641 | }; | ||
| 642 | assert(!std.fs.path.isAbsolute(child_cwd_rel)); | ||
| 643 | // We're not done yet. In some cases this path must be prefixed with './': | ||
| 644 | // * On POSIX, the executable name cannot be a single component like 'foo' | ||
| 645 | // * Some executables might treat a leading '-' like a flag, which we must avoid | ||
| 646 | // There's no harm in it, so just *always* apply this prefix. | ||
| 647 | return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM"); | ||
| 635 | } | 648 | } |
| 636 | 649 | ||
| 637 | const IndexedOutput = struct { | 650 | const IndexedOutput = struct { |
| ... | @@ -756,6 +769,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void { | ... | @@ -756,6 +769,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 756 | _ = try man.addFile(lazy_path.getPath2(b, step), null); | 769 | _ = try man.addFile(lazy_path.getPath2(b, step), null); |
| 757 | } | 770 | } |
| 758 | 771 | ||
| 772 | if (run.cwd) |cwd| { | ||
| 773 | const cwd_path = cwd.getPath3(b, step); | ||
| 774 | _ = man.hash.addBytes(try cwd_path.toString(arena)); | ||
| 775 | } | ||
| 776 | |||
| 759 | if (!has_side_effects and try step.cacheHitAndWatch(&man)) { | 777 | if (!has_side_effects and try step.cacheHitAndWatch(&man)) { |
| 760 | // cache hit, skip running command | 778 | // cache hit, skip running command |
| 761 | const digest = man.final(); | 779 | const digest = man.final(); |
test/standalone/run_cwd/build.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | pub fn build(b: *Build) void { | ||
| 2 | const exe = b.addExecutable(.{ | ||
| 3 | .name = "check_file_exists", | ||
| 4 | .root_module = b.createModule(.{ | ||
| 5 | .target = b.graph.host, | ||
| 6 | .optimize = .Debug, | ||
| 7 | .root_source_file = b.path("check_file_exists.zig"), | ||
| 8 | }), | ||
| 9 | }); | ||
| 10 | |||
| 11 | const test_step = b.step("test", "Test it"); | ||
| 12 | b.default_step = test_step; | ||
| 13 | |||
| 14 | test_step.dependOn(addCheck(b, exe, ".", null)); | ||
| 15 | test_step.dependOn(addCheck(b, exe, "..", b.path(".."))); | ||
| 16 | test_step.dependOn(addCheck(b, exe, "exe dir", exe.getEmittedBin().dirname())); | ||
| 17 | test_step.dependOn(addCheck(b, exe, "exe dir/..", exe.getEmittedBin().dirname().dirname())); | ||
| 18 | test_step.dependOn(addCheck(b, exe, "./empty_dir", b.path("empty_dir"))); | ||
| 19 | } | ||
| 20 | |||
| 21 | fn addCheck(b: *Build, exe: *Build.Step.Compile, cwd_name: []const u8, opt_cwd: ?Build.LazyPath) *Build.Step { | ||
| 22 | const run = b.addRunArtifact(exe); | ||
| 23 | if (opt_cwd) |cwd| run.setCwd(cwd); | ||
| 24 | run.addFileArg(b.path("file_that_exists.txt")); | ||
| 25 | run.setName(b.fmt("check in '{s}'", .{cwd_name})); | ||
| 26 | run.expectExitCode(0); | ||
| 27 | return &run.step; | ||
| 28 | } | ||
| 29 | |||
| 30 | const Build = @import("std").Build; | ||
test/standalone/run_cwd/check_file_exists.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | pub fn main() !void { | ||
| 2 | var arena_state: std.heap.ArenaAllocator = .init(std.heap.page_allocator); | ||
| 3 | defer arena_state.deinit(); | ||
| 4 | const arena = arena_state.allocator(); | ||
| 5 | |||
| 6 | const args = try std.process.argsAlloc(arena); | ||
| 7 | |||
| 8 | if (args.len != 2) return error.BadUsage; | ||
| 9 | const path = args[1]; | ||
| 10 | |||
| 11 | std.fs.cwd().access(path, .{}) catch return error.AccessFailed; | ||
| 12 | } | ||
| 13 | |||
| 14 | const std = @import("std"); | ||
test/standalone/run_cwd/empty_dir/make_git_happy createdtest/standalone/run_cwd/file_that_exists.txt created