From dee9f82f69db0d034251b844e0bc4083a1b25fdd Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 4 May 2024 15:12:24 -0400 Subject: [PATCH] Run: add output directory arguments This allows running commands that take an output directory argument. The main thing that was needed for this feature was generated file subpaths, to allow access to the files in a generated directory. Additionally, a minor change was required to so that the correct directory is created for output directory args. --- lib/std/Build.zig | 163 +++++++++--------- lib/std/Build/Step/Compile.zig | 6 +- lib/std/Build/Step/ConfigHeader.zig | 5 +- lib/std/Build/Step/ObjCopy.zig | 4 +- lib/std/Build/Step/Options.zig | 2 +- lib/std/Build/Step/Run.zig | 139 ++++++++++++--- lib/std/Build/Step/TranslateC.zig | 2 +- lib/std/Build/Step/WriteFile.zig | 6 +- test/standalone/build.zig.zon | 3 + test/standalone/run_output_paths/build.zig | 40 +++++ .../run_output_paths/create_file.zig | 19 ++ test/standalone/windows_resources/build.zig | 2 +- 12 files changed, 272 insertions(+), 119 deletions(-) create mode 100644 test/standalone/run_output_paths/build.zig create mode 100644 test/standalone/run_output_paths/create_file.zig diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 474dce3e12..6c8ba75730 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -2131,28 +2131,23 @@ test dirnameAllowEmpty { /// A reference to an existing or future path. pub const LazyPath = union(enum) { - /// Deprecated; use the `path` function instead. - path: []const u8, - /// A source file path relative to build root. src_path: struct { owner: *std.Build, sub_path: []const u8, }, - /// A file that is generated by an interface. Those files usually are - /// not available until built by a build step. - generated: *const GeneratedFile, - - /// One of the parent directories of a file generated by an interface. - /// The path is not available until built by a build step. - generated_dirname: struct { - generated: *const GeneratedFile, + generated: struct { + file: *const GeneratedFile, /// The number of parent directories to go up. - /// 0 means the directory of the generated file, - /// 1 means the parent of that directory, and so on. - up: usize, + /// 0 means the generated file itself. + /// 1 means the directory of the generated file. + /// 2 means the parent of that directory, and so on. + up: usize = 0, + + /// Applied after `up`. + sub_path: []const u8 = "", }, /// An absolute path or a path relative to the current working directory of @@ -2168,12 +2163,6 @@ pub const LazyPath = union(enum) { sub_path: []const u8, }, - /// Deprecated. Call `path` instead. - pub fn relative(sub_path: []const u8) LazyPath { - std.log.warn("deprecated. call std.Build.path instead", .{}); - return .{ .path = sub_path }; - } - /// Returns a lazy path referring to the directory containing this path. /// /// The dirname is not allowed to escape the logical root for underlying path. @@ -2183,8 +2172,6 @@ pub const LazyPath = union(enum) { /// the dirname is not allowed to traverse outside of zig-cache. pub fn dirname(lazy_path: LazyPath) LazyPath { return switch (lazy_path) { - .generated => |gen| .{ .generated_dirname = .{ .generated = gen, .up = 0 } }, - .generated_dirname => |gen| .{ .generated_dirname = .{ .generated = gen.generated, .up = gen.up + 1 } }, .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = dirnameAllowEmpty(sp.sub_path) orelse { @@ -2192,12 +2179,15 @@ pub const LazyPath = union(enum) { @panic("misconfigured build script"); }, } }, - .path => |sub_path| .{ - .path = dirnameAllowEmpty(sub_path) orelse { - dumpBadDirnameHelp(null, null, "dirname() attempted to traverse outside the build root\n", .{}) catch {}; - @panic("misconfigured build script"); - }, - }, + .generated => |generated| .{ .generated = if (dirnameAllowEmpty(generated.sub_path)) |sub_dirname| .{ + .file = generated.file, + .up = generated.up, + .sub_path = sub_dirname, + } else .{ + .file = generated.file, + .up = generated.up + 1, + .sub_path = "", + } }, .cwd_relative => |rel_path| .{ .cwd_relative = dirnameAllowEmpty(rel_path) orelse { // If we get null, it means one of two things: @@ -2234,14 +2224,34 @@ pub const LazyPath = union(enum) { }; } + pub fn path(lazy_path: LazyPath, b: *Build, sub_path: []const u8) LazyPath { + return switch (lazy_path) { + .src_path => |src| .{ .src_path = .{ + .owner = src.owner, + .sub_path = b.pathResolve(&.{ src.sub_path, sub_path }), + } }, + .generated => |gen| .{ .generated = .{ + .file = gen.file, + .up = gen.up, + .sub_path = b.pathResolve(&.{ gen.sub_path, sub_path }), + } }, + .cwd_relative => |cwd_relative| .{ + .cwd_relative = b.pathResolve(&.{ cwd_relative, sub_path }), + }, + .dependency => |dep| .{ .dependency = .{ + .dependency = dep.dependency, + .sub_path = b.pathResolve(&.{ dep.sub_path, sub_path }), + } }, + }; + } + /// Returns a string that can be shown to represent the file source. - /// Either returns the path or `"generated"`. + /// Either returns the path, `"generated"`, or `"dependency"`. pub fn getDisplayName(lazy_path: LazyPath) []const u8 { return switch (lazy_path) { - .src_path => |src_path| src_path.sub_path, - .path, .cwd_relative => |sub_path| sub_path, + .src_path => |sp| sp.sub_path, + .cwd_relative => |p| p, .generated => "generated", - .generated_dirname => "generated", .dependency => "dependency", }; } @@ -2249,9 +2259,8 @@ pub const LazyPath = union(enum) { /// Adds dependencies this file source implies to the given step. pub fn addStepDependencies(lazy_path: LazyPath, other_step: *Step) void { switch (lazy_path) { - .src_path, .path, .cwd_relative, .dependency => {}, - .generated => |gen| other_step.dependOn(gen.step), - .generated_dirname => |gen| other_step.dependOn(gen.generated.step), + .src_path, .cwd_relative, .dependency => {}, + .generated => |gen| other_step.dependOn(gen.file.step), } } @@ -2268,47 +2277,48 @@ pub const LazyPath = union(enum) { /// run that is asking for the path. pub fn getPath2(lazy_path: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 { switch (lazy_path) { - .path => |p| return src_builder.pathFromRoot(p), .src_path => |sp| return sp.owner.pathFromRoot(sp.sub_path), .cwd_relative => |p| return src_builder.pathFromCwd(p), - .generated => |gen| return gen.step.owner.pathFromRoot(gen.path orelse { - std.debug.getStderrMutex().lock(); - const stderr = std.io.getStdErr(); - dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {}; - @panic("misconfigured build script"); - }), - .generated_dirname => |gen| { - const cache_root_path = src_builder.cache_root.path orelse - (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM")); + .generated => |gen| { + var file_path: []const u8 = gen.file.step.owner.pathFromRoot(gen.file.path orelse { + std.debug.getStderrMutex().lock(); + const stderr = std.io.getStdErr(); + dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {}; + std.debug.getStderrMutex().unlock(); + @panic("misconfigured build script"); + }); - const gen_step = gen.generated.step; - var p = getPath2(LazyPath{ .generated = gen.generated }, src_builder, asking_step); - var i: usize = 0; - while (i <= gen.up) : (i += 1) { - // path is absolute. - // dirname will return null only if we're at root. - // Typically, we'll stop well before that at the cache root. - p = fs.path.dirname(p) orelse { - dumpBadDirnameHelp(gen_step, asking_step, - \\dirname() reached root. - \\No more directories left to go up. - \\ - , .{}) catch {}; - @panic("misconfigured build script"); - }; + if (gen.up > 0) { + const cache_root_path = src_builder.cache_root.path orelse + (src_builder.cache_root.join(src_builder.allocator, &.{"."}) catch @panic("OOM")); - if (mem.eql(u8, p, cache_root_path) and i < gen.up) { - // If we hit the cache root and there's still more to go, - // the script attempted to go too far. - dumpBadDirnameHelp(gen_step, asking_step, - \\dirname() attempted to traverse outside the cache root. - \\This is not allowed. - \\ - , .{}) catch {}; - @panic("misconfigured build script"); + for (0..gen.up) |_| { + if (mem.eql(u8, file_path, cache_root_path)) { + // If we hit the cache root and there's still more to go, + // the script attempted to go too far. + dumpBadDirnameHelp(gen.file.step, asking_step, + \\dirname() attempted to traverse outside the cache root. + \\This is not allowed. + \\ + , .{}) catch {}; + @panic("misconfigured build script"); + } + + // path is absolute. + // dirname will return null only if we're at root. + // Typically, we'll stop well before that at the cache root. + file_path = fs.path.dirname(file_path) orelse { + dumpBadDirnameHelp(gen.file.step, asking_step, + \\dirname() reached root. + \\No more directories left to go up. + \\ + , .{}) catch {}; + @panic("misconfigured build script"); + }; } } - return p; + + return src_builder.pathResolve(&.{ file_path, gen.sub_path }); }, .dependency => |dep| return dep.dependency.builder.pathFromRoot(dep.sub_path), } @@ -2324,15 +2334,12 @@ pub const LazyPath = union(enum) { .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path), } }, - .path => |p| .{ .path = b.dupePath(p) }, .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) }, - .generated => |gen| .{ .generated = gen }, - .generated_dirname => |gen| .{ - .generated_dirname = .{ - .generated = gen.generated, - .up = gen.up, - }, - }, + .generated => |gen| .{ .generated = .{ + .file = gen.file, + .up = gen.up, + .sub_path = b.dupePath(gen.sub_path), + } }, .dependency => |dep| .{ .dependency = dep }, }; } diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index d8f2c73311..f660ef64a6 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -806,14 +806,12 @@ pub fn setLibCFile(compile: *Compile, libc_file: ?LazyPath) void { } fn getEmittedFileGeneric(compile: *Compile, output_file: *?*GeneratedFile) LazyPath { - if (output_file.*) |g| { - return .{ .generated = g }; - } + if (output_file.*) |file| return .{ .generated = .{ .file = file } }; const arena = compile.step.owner.allocator; const generated_file = arena.create(GeneratedFile) catch @panic("OOM"); generated_file.* = .{ .step = &compile.step }; output_file.* = generated_file; - return .{ .generated = generated_file }; + return .{ .generated = .{ .file = generated_file } }; } /// Returns the path to the directory that contains the emitted binary file. diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index bf8f941b16..4a0e64e8d0 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -59,8 +59,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { if (options.style.getPath()) |s| default_include_path: { const sub_path = switch (s) { .src_path => |sp| sp.sub_path, - .path => |path| path, - .generated, .generated_dirname => break :default_include_path, + .generated => break :default_include_path, .cwd_relative => |sub_path| sub_path, .dependency => |dependency| dependency.sub_path, }; @@ -106,7 +105,7 @@ pub fn addValues(config_header: *ConfigHeader, values: anytype) void { } pub fn getOutput(config_header: *ConfigHeader) std.Build.LazyPath { - return .{ .generated = &config_header.output_file }; + return .{ .generated = .{ .file = &config_header.output_file } }; } fn addValuesInner(config_header: *ConfigHeader, values: anytype) !void { diff --git a/lib/std/Build/Step/ObjCopy.zig b/lib/std/Build/Step/ObjCopy.zig index 6e18ae3066..515736dbc1 100644 --- a/lib/std/Build/Step/ObjCopy.zig +++ b/lib/std/Build/Step/ObjCopy.zig @@ -84,10 +84,10 @@ pub fn create( pub const getOutputSource = getOutput; pub fn getOutput(objcopy: *const ObjCopy) std.Build.LazyPath { - return .{ .generated = &objcopy.output_file }; + return .{ .generated = .{ .file = &objcopy.output_file } }; } pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath { - return if (objcopy.output_file_debug) |*file| .{ .generated = file } else null; + return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null; } fn make(step: *Step, prog_node: *std.Progress.Node) !void { diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index fe1833249b..c4daed73ff 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -407,7 +407,7 @@ pub const getSource = getOutput; /// Returns the main artifact of this Build Step which is a Zig source file /// generated from the key-value pairs of the Options. pub fn getOutput(options: *Options) LazyPath { - return .{ .generated = &options.generated_file }; + return .{ .generated = .{ .file = &options.generated_file } }; } fn make(step: *Step, prog_node: *std.Progress.Node) !void { diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index ffe19425cb..3b223f9b13 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -125,7 +125,8 @@ pub const Arg = union(enum) { lazy_path: PrefixedLazyPath, directory_source: PrefixedLazyPath, bytes: []u8, - output: *Output, + output_file: *Output, + output_directory: *Output, }; pub const PrefixedLazyPath = struct { @@ -225,13 +226,13 @@ pub fn addPrefixedOutputFileArg( .basename = b.dupe(basename), .generated_file = .{ .step = &run.step }, }; - run.argv.append(b.allocator, .{ .output = output }) catch @panic("OOM"); + run.argv.append(b.allocator, .{ .output_file = output }) catch @panic("OOM"); if (run.rename_step_with_output_arg) { run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename })); } - return .{ .generated = &output.generated_file }; + return .{ .generated = .{ .file = &output.generated_file } }; } /// Appends an input file to the command line arguments. @@ -270,6 +271,56 @@ pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) lp.addStepDependencies(&run.step); } +/// Provides a directory path as a command line argument to the command being run. +/// +/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs +/// throughout the build system. +/// +/// Related: +/// * `addPrefixedOutputDirectoryArg` - same thing but prepends a string to the argument +/// * `addDirectoryArg` - for input directories given to the child process +pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath { + return run.addPrefixedOutputDirectoryArg("", basename); +} + +/// Provides a directory path as a command line argument to the command being run. +/// Asserts `basename` is not empty. +/// +/// For example, a prefix of "-o" and basename of "output_dir" will result in +/// the child process seeing something like this: "-ozig-cache/.../output_dir" +/// +/// The child process will see a single argument, regardless of whether the +/// prefix or basename have spaces. +/// +/// The returned `std.Build.LazyPath` can be used as inputs to other APIs +/// throughout the build system. +/// +/// Related: +/// * `addOutputDirectoryArg` - same thing but without the prefix +/// * `addDirectoryArg` - for input directories given to the child process +pub fn addPrefixedOutputDirectoryArg( + run: *Run, + prefix: []const u8, + basename: []const u8, +) std.Build.LazyPath { + if (basename.len == 0) @panic("basename must not be empty"); + const b = run.step.owner; + + const output = b.allocator.create(Output) catch @panic("OOM"); + output.* = .{ + .prefix = b.dupe(prefix), + .basename = b.dupe(basename), + .generated_file = .{ .step = &run.step }, + }; + run.argv.append(b.allocator, .{ .output_directory = output }) catch @panic("OOM"); + + if (run.rename_step_with_output_arg) { + run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename })); + } + + return .{ .generated = .{ .file = &output.generated_file } }; +} + /// deprecated: use `addDirectoryArg` pub const addDirectorySourceArg = addDirectoryArg; @@ -314,9 +365,9 @@ pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []co run.dep_output_file = dep_file; - run.argv.append(b.allocator, .{ .output = dep_file }) catch @panic("OOM"); + run.argv.append(b.allocator, .{ .output_file = dep_file }) catch @panic("OOM"); - return .{ .generated = &dep_file.generated_file }; + return .{ .generated = .{ .file = &dep_file.generated_file } }; } pub fn addArg(run: *Run, arg: []const u8) void { @@ -432,7 +483,7 @@ pub fn addCheck(run: *Run, new_check: StdIo.Check) void { pub fn captureStdErr(run: *Run) std.Build.LazyPath { assert(run.stdio != .inherit); - if (run.captured_stderr) |output| return .{ .generated = &output.generated_file }; + if (run.captured_stderr) |output| return .{ .generated = .{ .file = &output.generated_file } }; const output = run.step.owner.allocator.create(Output) catch @panic("OOM"); output.* = .{ @@ -441,13 +492,13 @@ pub fn captureStdErr(run: *Run) std.Build.LazyPath { .generated_file = .{ .step = &run.step }, }; run.captured_stderr = output; - return .{ .generated = &output.generated_file }; + return .{ .generated = .{ .file = &output.generated_file } }; } pub fn captureStdOut(run: *Run) std.Build.LazyPath { assert(run.stdio != .inherit); - if (run.captured_stdout) |output| return .{ .generated = &output.generated_file }; + if (run.captured_stdout) |output| return .{ .generated = .{ .file = &output.generated_file } }; const output = run.step.owner.allocator.create(Output) catch @panic("OOM"); output.* = .{ @@ -456,7 +507,7 @@ pub fn captureStdOut(run: *Run) std.Build.LazyPath { .generated_file = .{ .step = &run.step }, }; run.captured_stdout = output; - return .{ .generated = &output.generated_file }; + return .{ .generated = .{ .file = &output.generated_file } }; } /// Adds an additional input files that, when modified, indicates that this Run @@ -484,7 +535,7 @@ fn hasAnyOutputArgs(run: Run) bool { if (run.captured_stdout != null) return true; if (run.captured_stderr != null) return true; for (run.argv.items) |arg| switch (arg) { - .output => return true, + .output_file, .output_directory => return true, else => continue, }; return false; @@ -520,6 +571,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { const IndexedOutput = struct { index: usize, + tag: @typeInfo(Arg).Union.tag_type.?, output: *Output, }; fn make(step: *Step, prog_node: *std.Progress.Node) !void { @@ -563,17 +615,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { _ = try man.addFile(file_path, null); }, - .output => |output| { + .output_file, .output_directory => |output| { man.hash.addBytes(output.prefix); man.hash.addBytes(output.basename); // Add a placeholder into the argument list because we need the // manifest hash to be updated with all arguments before the // object directory is computed. - try argv_list.append(""); try output_placeholders.append(.{ - .index = argv_list.items.len - 1, + .index = argv_list.items.len, + .tag = arg, .output = output, }); + _ = try argv_list.addOne(); }, } } @@ -599,11 +652,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { hashStdIo(&man.hash, run.stdio); - if (has_side_effects) { - try runCommand(run, argv_list.items, has_side_effects, null, prog_node); - return; - } - for (run.extra_file_dependencies) |file_path| { _ = try man.addFile(b.pathFromRoot(file_path), null); } @@ -611,7 +659,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { _ = try man.addFile(lazy_path.getPath2(b, step), null); } - if (try step.cacheHit(&man)) { + if (try step.cacheHit(&man) and !has_side_effects) { // cache hit, skip running command const digest = man.final(); @@ -628,13 +676,54 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { return; } + const dep_output_file = run.dep_output_file orelse { + // We already know the final output paths, use them directly. + const digest = man.final(); + + try populateGeneratedPaths( + arena, + output_placeholders.items, + run.captured_stdout, + run.captured_stderr, + b.cache_root, + &digest, + ); + + const output_dir_path = "o" ++ fs.path.sep_str ++ &digest; + for (output_placeholders.items) |placeholder| { + const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename }); + const output_sub_dir_path = switch (placeholder.tag) { + .output_file => fs.path.dirname(output_sub_path).?, + .output_directory => output_sub_path, + else => unreachable, + }; + b.cache_root.handle.makePath(output_sub_dir_path) catch |err| { + return step.fail("unable to make path '{}{s}': {s}", .{ + b.cache_root, output_sub_dir_path, @errorName(err), + }); + }; + const output_path = placeholder.output.generated_file.path.?; + argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0) + output_path + else + b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path }); + } + + return runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node); + }; + + // We do not know the final output paths yet, use temp paths to run the command. const rand_int = std.crypto.random.int(u64); const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int); for (output_placeholders.items) |placeholder| { const output_components = .{ tmp_dir_path, placeholder.output.basename }; const output_sub_path = b.pathJoin(&output_components); - const output_sub_dir_path = fs.path.dirname(output_sub_path).?; + const output_sub_dir_path = switch (placeholder.tag) { + .output_file => fs.path.dirname(output_sub_path).?, + .output_directory => output_sub_path, + else => unreachable, + }; b.cache_root.handle.makePath(output_sub_dir_path) catch |err| { return step.fail("unable to make path '{}{s}': {s}", .{ b.cache_root, output_sub_dir_path, @errorName(err), @@ -642,17 +731,15 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }; const output_path = try b.cache_root.join(arena, &output_components); placeholder.output.generated_file.path = output_path; - const cli_arg = if (placeholder.output.prefix.len == 0) + argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0) output_path else b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path }); - argv_list.items[placeholder.index] = cli_arg; } try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, prog_node); - if (run.dep_output_file) |dep_output_file| - try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath()); + try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath()); const digest = man.final(); @@ -777,7 +864,7 @@ fn runCommand( run: *Run, argv: []const []const u8, has_side_effects: bool, - tmp_dir_path: ?[]const u8, + output_dir_path: []const u8, prog_node: *std.Progress.Node, ) !void { const step = &run.step; @@ -950,7 +1037,7 @@ fn runCommand( }, }) |stream| { if (stream.captured) |output| { - const output_components = .{ tmp_dir_path.?, output.basename }; + const output_components = .{ output_dir_path, output.basename }; const output_path = try b.cache_root.join(arena, &output_components); output.generated_file.path = output_path; diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig index 30a3988d4e..cb1b48e3c0 100644 --- a/lib/std/Build/Step/TranslateC.zig +++ b/lib/std/Build/Step/TranslateC.zig @@ -59,7 +59,7 @@ pub const AddExecutableOptions = struct { }; pub fn getOutput(translate_c: *TranslateC) std.Build.LazyPath { - return .{ .generated = &translate_c.output_file }; + return .{ .generated = .{ .file = &translate_c.output_file } }; } /// Creates a step to build an executable from the translated source. diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 875ddbfdbe..401c5b78ec 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -31,7 +31,7 @@ pub const File = struct { contents: Contents, pub fn getPath(file: *File) std.Build.LazyPath { - return .{ .generated = &file.generated_file }; + return .{ .generated = .{ .file = &file.generated_file } }; } }; @@ -58,7 +58,7 @@ pub const Directory = struct { }; pub fn getPath(dir: *Directory) std.Build.LazyPath { - return .{ .generated = &dir.generated_dir }; + return .{ .generated = .{ .file = &dir.generated_dir } }; } }; @@ -181,7 +181,7 @@ pub fn addBytesToSource(write_file: *WriteFile, bytes: []const u8, sub_path: []c /// Returns a `LazyPath` representing the base directory that contains all the /// files from this `WriteFile`. pub fn getDirectory(write_file: *WriteFile) std.Build.LazyPath { - return .{ .generated = &write_file.generated_directory }; + return .{ .generated = .{ .file = &write_file.generated_directory } }; } fn maybeUpdateName(write_file: *WriteFile) void { diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 7ddde1611a..e1b856a4be 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -164,6 +164,9 @@ .dependencyFromBuildZig = .{ .path = "dependencyFromBuildZig", }, + .run_output_paths = .{ + .path = "run_output_paths", + }, }, .paths = .{ "build.zig", diff --git a/test/standalone/run_output_paths/build.zig b/test/standalone/run_output_paths/build.zig new file mode 100644 index 0000000000..f4c7254d8f --- /dev/null +++ b/test/standalone/run_output_paths/build.zig @@ -0,0 +1,40 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test it"); + b.default_step = test_step; + + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const create_file_exe = b.addExecutable(.{ + .name = "create_file", + .root_source_file = b.path("create_file.zig"), + .target = target, + .optimize = optimize, + }); + + const create_first = b.addRunArtifact(create_file_exe); + const first_dir = create_first.addOutputDirectoryArg("first"); + create_first.addArg("hello1.txt"); + test_step.dependOn(&b.addCheckFile(first_dir.path(b, "hello1.txt"), .{ .expected_matches = &.{ + std.fs.path.sep_str ++ + \\first + \\hello1.txt + \\Hello, world! + \\ + , + } }).step); + + const create_second = b.addRunArtifact(create_file_exe); + const second_dir = create_second.addPrefixedOutputDirectoryArg("--dir=", "second"); + create_second.addArg("hello2.txt"); + test_step.dependOn(&b.addCheckFile(second_dir.path(b, "hello2.txt"), .{ .expected_matches = &.{ + std.fs.path.sep_str ++ + \\second + \\hello2.txt + \\Hello, world! + \\ + , + } }).step); +} diff --git a/test/standalone/run_output_paths/create_file.zig b/test/standalone/run_output_paths/create_file.zig new file mode 100644 index 0000000000..041ebc3e50 --- /dev/null +++ b/test/standalone/run_output_paths/create_file.zig @@ -0,0 +1,19 @@ +const std = @import("std"); + +pub fn main() !void { + var args = try std.process.argsWithAllocator(std.heap.page_allocator); + _ = args.skip(); + const dir_name = args.next().?; + const dir = try std.fs.cwd().openDir(if (std.mem.startsWith(u8, dir_name, "--dir=")) + dir_name["--dir=".len..] + else + dir_name, .{}); + const file_name = args.next().?; + const file = try dir.createFile(file_name, .{}); + try file.writer().print( + \\{s} + \\{s} + \\Hello, world! + \\ + , .{ dir_name, file_name }); +} diff --git a/test/standalone/windows_resources/build.zig b/test/standalone/windows_resources/build.zig index 15130d3b87..da88659b4d 100644 --- a/test/standalone/windows_resources/build.zig +++ b/test/standalone/windows_resources/build.zig @@ -36,7 +36,7 @@ fn add( .file = b.path("res/zig.rc"), .flags = &.{"/c65001"}, // UTF-8 code page .include_paths = &.{ - .{ .generated = &generated_h_step.generated_directory }, + .{ .generated = .{ .file = &generated_h_step.generated_directory } }, }, }); exe.rc_includes = switch (rc_includes) {