| author | |
| committer | |
| log | 435cd6f129172733fdc4b9bd62abe3c94f91d583 |
| tree | 8346c38b5f579ec0ddfda202806e5e70b6b497ba |
| parent | 8e091047b5a8fd2f8a74d56a7353f16fd66dff25 |
| parent | c8ecfad41a322260fae38a4115a94345ed9f94b7 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/306837 files changed, 232 insertions(+), 213 deletions(-)
lib/compiler/build_runner.zig+15-1| ... | ... | @@ -82,7 +82,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 82 | 82 | .arena = arena, |
| 83 | 83 | .cache = .{ |
| 84 | 84 | .io = io, |
| 85 | .gpa = arena, | |
| 85 | .gpa = gpa, | |
| 86 | 86 | .manifest_dir = try local_cache_directory.handle.createDirPathOpen(io, "h", .{}), |
| 87 | 87 | .cwd = try process.getCwdAlloc(single_threaded_arena.allocator()), |
| 88 | 88 | }, |
| ... | ... | @@ -784,6 +784,9 @@ fn runStepNames( |
| 784 | 784 | var pending_count: usize = 0; |
| 785 | 785 | var total_compile_errors: usize = 0; |
| 786 | 786 | |
| 787 | var cleanup_task = io.async(cleanTmpFiles, .{ io, step_stack.keys() }); | |
| 788 | defer cleanup_task.await(io); | |
| 789 | ||
| 787 | 790 | for (step_stack.keys()) |s| { |
| 788 | 791 | test_pass_count += s.test_results.passCount(); |
| 789 | 792 | test_skip_count += s.test_results.skip_count; |
| ... | ... | @@ -1849,3 +1852,14 @@ fn initStdoutWriter(io: Io) *Writer { |
| 1849 | 1852 | stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation); |
| 1850 | 1853 | return &stdout_writer_allocation.interface; |
| 1851 | 1854 | } |
| 1855 | ||
| 1856 | fn cleanTmpFiles(io: Io, steps: []const *Step) void { | |
| 1857 | for (steps) |step| { | |
| 1858 | const wf = step.cast(std.Build.Step.WriteFile) orelse continue; | |
| 1859 | if (wf.mode != .tmp) continue; | |
| 1860 | const path = wf.generated_directory.path orelse continue; | |
| 1861 | Io.Dir.cwd().deleteTree(io, path) catch |err| { | |
| 1862 | std.log.warn("failed to delete {s}: {t}", .{ path, err }); | |
| 1863 | }; | |
| 1864 | } | |
| 1865 | } |
lib/std/Build.zig+42-19| ... | ... | @@ -111,6 +111,7 @@ pub const ReleaseMode = enum { |
| 111 | 111 | /// Settings that are here rather than in Build are not configurable per-package. |
| 112 | 112 | pub const Graph = struct { |
| 113 | 113 | io: Io, |
| 114 | /// Process lifetime. | |
| 114 | 115 | arena: Allocator, |
| 115 | 116 | system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .empty, |
| 116 | 117 | system_package_mode: bool = false, |
| ... | ... | @@ -1057,6 +1058,38 @@ pub fn addNamedLazyPath(b: *Build, name: []const u8, lp: LazyPath) void { |
| 1057 | 1058 | b.named_lazy_paths.put(b.dupe(name), lp.dupe(b)) catch @panic("OOM"); |
| 1058 | 1059 | } |
| 1059 | 1060 | |
| 1061 | /// Creates a step for mutating files inside a temporary directory created lazily | |
| 1062 | /// and automatically cleaned up upon successful build. | |
| 1063 | /// | |
| 1064 | /// The directory will be placed inside "tmp" rather than "o", and caching will | |
| 1065 | /// be skipped. During the `make` phase, the step will always do all the file | |
| 1066 | /// system operations, and on successful build completion, the dir will be | |
| 1067 | /// deleted along with all other tmp directories. The directory is therefore | |
| 1068 | /// eligible to be used for mutations by other steps. | |
| 1069 | /// | |
| 1070 | /// See also: | |
| 1071 | /// * `addWriteFiles` | |
| 1072 | /// * `addMutateFiles` | |
| 1073 | pub fn addTempFiles(b: *Build) *Step.WriteFile { | |
| 1074 | const wf = addWriteFiles(b); | |
| 1075 | wf.mode = .tmp; | |
| 1076 | return wf; | |
| 1077 | } | |
| 1078 | ||
| 1079 | /// Creates a step for mutating temporary directories created with `addTempFiles`. | |
| 1080 | /// | |
| 1081 | /// Consider instead `addWriteFiles` which is for creating a cached directory | |
| 1082 | /// of files to operate on. | |
| 1083 | /// | |
| 1084 | /// This should only be used with a `tmp_path` obtained via `addTempFiles` or | |
| 1085 | /// `tmpPath`. | |
| 1086 | pub fn addMutateFiles(b: *Build, tmp_path: LazyPath) *Step.WriteFile { | |
| 1087 | const wf = addWriteFiles(b); | |
| 1088 | wf.mode = .{ .mutate = tmp_path }; | |
| 1089 | tmp_path.addStepDependencies(&wf.step); | |
| 1090 | return wf; | |
| 1091 | } | |
| 1092 | ||
| 1060 | 1093 | pub fn addWriteFiles(b: *Build) *Step.WriteFile { |
| 1061 | 1094 | return Step.WriteFile.create(b); |
| 1062 | 1095 | } |
| ... | ... | @@ -1065,10 +1098,6 @@ pub fn addUpdateSourceFiles(b: *Build) *Step.UpdateSourceFiles { |
| 1065 | 1098 | return Step.UpdateSourceFiles.create(b); |
| 1066 | 1099 | } |
| 1067 | 1100 | |
| 1068 | pub fn addRemoveDirTree(b: *Build, dir_path: LazyPath) *Step.RemoveDir { | |
| 1069 | return Step.RemoveDir.create(b, dir_path); | |
| 1070 | } | |
| 1071 | ||
| 1072 | 1101 | pub fn addFail(b: *Build, error_msg: []const u8) *Step.Fail { |
| 1073 | 1102 | return Step.Fail.create(b, error_msg); |
| 1074 | 1103 | } |
| ... | ... | @@ -2235,9 +2264,8 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void { |
| 2235 | 2264 | /// A file that is generated by a build step. |
| 2236 | 2265 | /// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic. |
| 2237 | 2266 | pub const GeneratedFile = struct { |
| 2238 | /// The step that generates the file | |
| 2267 | /// The step that generates the file. | |
| 2239 | 2268 | step: *Step, |
| 2240 | ||
| 2241 | 2269 | /// The path to the generated file. Must be either absolute or relative to the build runner cwd. |
| 2242 | 2270 | /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. |
| 2243 | 2271 | path: ?[]const u8 = null, |
| ... | ... | @@ -2321,9 +2349,11 @@ pub const LazyPath = union(enum) { |
| 2321 | 2349 | |
| 2322 | 2350 | /// An absolute path or a path relative to the current working directory of |
| 2323 | 2351 | /// the build runner process. |
| 2352 | /// | |
| 2324 | 2353 | /// This is uncommon but used for system environment paths such as `--zig-lib-dir` which |
| 2325 | 2354 | /// ignore the file system path of build.zig and instead are relative to the directory from |
| 2326 | 2355 | /// which `zig build` was invoked. |
| 2356 | /// | |
| 2327 | 2357 | /// Use of this tag indicates a dependency on the host system. |
| 2328 | 2358 | cwd_relative: []const u8, |
| 2329 | 2359 | |
| ... | ... | @@ -2646,19 +2676,12 @@ pub const InstallDir = union(enum) { |
| 2646 | 2676 | } |
| 2647 | 2677 | }; |
| 2648 | 2678 | |
| 2649 | /// This function is intended to be called in the `configure` phase only. | |
| 2650 | /// It returns an absolute directory path, which is potentially going to be a | |
| 2651 | /// source of API breakage in the future, so keep that in mind when using this | |
| 2652 | /// function. | |
| 2653 | pub fn makeTempPath(b: *Build) []const u8 { | |
| 2654 | const io = b.graph.io; | |
| 2655 | const rand_int = std.crypto.random.int(u64); | |
| 2656 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int); | |
| 2657 | const result_path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM"); | |
| 2658 | b.cache_root.handle.createDirPath(io, tmp_dir_sub_path) catch |err| { | |
| 2659 | std.debug.print("unable to make tmp path '{s}': {t}\n", .{ result_path, err }); | |
| 2660 | }; | |
| 2661 | return result_path; | |
| 2679 | /// Creates a path leading to a directory inside "tmp" subdirectory of | |
| 2680 | /// `cache_root` which is created on demand and cleaned up by the build runner | |
| 2681 | /// upon success. | |
| 2682 | pub fn tmpPath(b: *Build) LazyPath { | |
| 2683 | const wf = b.addTempFiles(); | |
| 2684 | return wf.getDirectory(); | |
| 2662 | 2685 | } |
| 2663 | 2686 | |
| 2664 | 2687 | /// A pair of target query and fully resolved target. |
lib/std/Build/Step.zig-3| ... | ... | @@ -173,7 +173,6 @@ pub const Id = enum { |
| 173 | 173 | .install_artifact => InstallArtifact, |
| 174 | 174 | .install_file => InstallFile, |
| 175 | 175 | .install_dir => InstallDir, |
| 176 | .remove_dir => RemoveDir, | |
| 177 | 176 | .fail => Fail, |
| 178 | 177 | .fmt => Fmt, |
| 179 | 178 | .translate_c => TranslateC, |
| ... | ... | @@ -201,7 +200,6 @@ pub const InstallFile = @import("Step/InstallFile.zig"); |
| 201 | 200 | pub const ObjCopy = @import("Step/ObjCopy.zig"); |
| 202 | 201 | pub const Compile = @import("Step/Compile.zig"); |
| 203 | 202 | pub const Options = @import("Step/Options.zig"); |
| 204 | pub const RemoveDir = @import("Step/RemoveDir.zig"); | |
| 205 | 203 | pub const Run = @import("Step/Run.zig"); |
| 206 | 204 | pub const TranslateC = @import("Step/TranslateC.zig"); |
| 207 | 205 | pub const WriteFile = @import("Step/WriteFile.zig"); |
| ... | ... | @@ -1008,7 +1006,6 @@ test { |
| 1008 | 1006 | _ = ObjCopy; |
| 1009 | 1007 | _ = Compile; |
| 1010 | 1008 | _ = Options; |
| 1011 | _ = RemoveDir; | |
| 1012 | 1009 | _ = Run; |
| 1013 | 1010 | _ = TranslateC; |
| 1014 | 1011 | _ = WriteFile; |
lib/std/Build/Step/RemoveDir.zig deleted-45| ... | ... | @@ -1,45 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const fs = std.fs; | |
| 3 | const Step = std.Build.Step; | |
| 4 | const RemoveDir = @This(); | |
| 5 | const LazyPath = std.Build.LazyPath; | |
| 6 | ||
| 7 | pub const base_id: Step.Id = .remove_dir; | |
| 8 | ||
| 9 | step: Step, | |
| 10 | doomed_path: LazyPath, | |
| 11 | ||
| 12 | pub fn create(owner: *std.Build, doomed_path: LazyPath) *RemoveDir { | |
| 13 | const remove_dir = owner.allocator.create(RemoveDir) catch @panic("OOM"); | |
| 14 | remove_dir.* = .{ | |
| 15 | .step = Step.init(.{ | |
| 16 | .id = base_id, | |
| 17 | .name = owner.fmt("RemoveDir {s}", .{doomed_path.getDisplayName()}), | |
| 18 | .owner = owner, | |
| 19 | .makeFn = make, | |
| 20 | }), | |
| 21 | .doomed_path = doomed_path.dupe(owner), | |
| 22 | }; | |
| 23 | return remove_dir; | |
| 24 | } | |
| 25 | ||
| 26 | fn make(step: *Step, options: Step.MakeOptions) !void { | |
| 27 | _ = options; | |
| 28 | ||
| 29 | const b = step.owner; | |
| 30 | const io = b.graph.io; | |
| 31 | const remove_dir: *RemoveDir = @fieldParentPtr("step", step); | |
| 32 | ||
| 33 | step.clearWatchInputs(); | |
| 34 | try step.addWatchInput(remove_dir.doomed_path); | |
| 35 | ||
| 36 | const full_doomed_path = remove_dir.doomed_path.getPath2(b, step); | |
| 37 | ||
| 38 | b.build_root.handle.deleteTree(io, full_doomed_path) catch |err| { | |
| 39 | if (b.build_root.path) |base| { | |
| 40 | return step.fail("unable to recursively delete path '{s}/{s}': {t}", .{ base, full_doomed_path, err }); | |
| 41 | } else { | |
| 42 | return step.fail("unable to recursively delete path '{s}': {t}", .{ full_doomed_path, err }); | |
| 43 | } | |
| 44 | }; | |
| 45 | } |
lib/std/Build/Step/WriteFile.zig+142-84| ... | ... | @@ -1,22 +1,42 @@ |
| 1 | 1 | //! WriteFile is used to create a directory in an appropriate location inside |
| 2 | 2 | //! the local cache which has a set of files that have either been generated |
| 3 | 3 | //! during the build, or are copied from the source package. |
| 4 | const WriteFile = @This(); | |
| 5 | ||
| 4 | 6 | const std = @import("std"); |
| 5 | 7 | const Io = std.Io; |
| 8 | const Dir = std.Io.Dir; | |
| 6 | 9 | const Step = std.Build.Step; |
| 7 | const fs = std.fs; | |
| 8 | 10 | const ArrayList = std.ArrayList; |
| 9 | const WriteFile = @This(); | |
| 11 | const assert = std.debug.assert; | |
| 10 | 12 | |
| 11 | 13 | step: Step, |
| 12 | 14 | |
| 13 | // The elements here are pointers because we need stable pointers for the GeneratedFile field. | |
| 15 | /// The elements here are pointers because we need stable pointers for the GeneratedFile field. | |
| 14 | 16 | files: std.ArrayList(File), |
| 15 | 17 | directories: std.ArrayList(Directory), |
| 16 | 18 | generated_directory: std.Build.GeneratedFile, |
| 19 | mode: Mode = .whole_cached, | |
| 17 | 20 | |
| 18 | 21 | pub const base_id: Step.Id = .write_file; |
| 19 | 22 | |
| 23 | pub const Mode = union(enum) { | |
| 24 | /// Default mode. Integrates with the cache system. The directory should be | |
| 25 | /// read-only during the make phase. Any different inputs result in | |
| 26 | /// different "o" subdirectory. | |
| 27 | whole_cached, | |
| 28 | /// In this mode, the directory will be placed inside "tmp" rather than | |
| 29 | /// "o", and caching will be skipped. During the `make` phase, the step | |
| 30 | /// will always do all the file system operations, and on successful build | |
| 31 | /// completion, the dir will be deleted along with all other tmp | |
| 32 | /// directories. The directory is therefore eligible to be used for | |
| 33 | /// mutations by other steps. | |
| 34 | tmp, | |
| 35 | /// The operations will not be performed against a freshly created | |
| 36 | /// directory, but instead act against a temporary directory. | |
| 37 | mutate: std.Build.LazyPath, | |
| 38 | }; | |
| 39 | ||
| 20 | 40 | pub const File = struct { |
| 21 | 41 | sub_path: []const u8, |
| 22 | 42 | contents: Contents, |
| ... | ... | @@ -175,115 +195,155 @@ fn maybeUpdateName(write_file: *WriteFile) void { |
| 175 | 195 | fn make(step: *Step, options: Step.MakeOptions) !void { |
| 176 | 196 | _ = options; |
| 177 | 197 | const b = step.owner; |
| 178 | const io = b.graph.io; | |
| 198 | const graph = b.graph; | |
| 199 | const io = graph.io; | |
| 179 | 200 | const arena = b.allocator; |
| 180 | const gpa = arena; | |
| 201 | const gpa = graph.cache.gpa; | |
| 181 | 202 | const write_file: *WriteFile = @fieldParentPtr("step", step); |
| 182 | step.clearWatchInputs(); | |
| 183 | ||
| 184 | // The cache is used here not really as a way to speed things up - because writing | |
| 185 | // the data to a file would probably be very fast - but as a way to find a canonical | |
| 186 | // location to put build artifacts. | |
| 187 | 203 | |
| 188 | // If, for example, a hard-coded path was used as the location to put WriteFile | |
| 189 | // files, then two WriteFiles executing in parallel might clobber each other. | |
| 204 | const open_dir_cache = try arena.alloc(Io.Dir, write_file.directories.items.len); | |
| 205 | var open_dirs_count: usize = 0; | |
| 206 | defer Io.Dir.closeMany(io, open_dir_cache[0..open_dirs_count]); | |
| 190 | 207 | |
| 191 | var man = b.graph.cache.obtain(); | |
| 192 | defer man.deinit(); | |
| 208 | switch (write_file.mode) { | |
| 209 | .whole_cached => { | |
| 210 | step.clearWatchInputs(); | |
| 193 | 211 | |
| 194 | for (write_file.files.items) |file| { | |
| 195 | man.hash.addBytes(file.sub_path); | |
| 212 | // The cache is used here not really as a way to speed things up - because writing | |
| 213 | // the data to a file would probably be very fast - but as a way to find a canonical | |
| 214 | // location to put build artifacts. | |
| 196 | 215 | |
| 197 | switch (file.contents) { | |
| 198 | .bytes => |bytes| { | |
| 199 | man.hash.addBytes(bytes); | |
| 200 | }, | |
| 201 | .copy => |lazy_path| { | |
| 202 | const path = lazy_path.getPath3(b, step); | |
| 203 | _ = try man.addFilePath(path, null); | |
| 204 | try step.addWatchInput(lazy_path); | |
| 205 | }, | |
| 206 | } | |
| 207 | } | |
| 216 | // If, for example, a hard-coded path was used as the location to put WriteFile | |
| 217 | // files, then two WriteFiles executing in parallel might clobber each other. | |
| 208 | 218 | |
| 209 | const open_dir_cache = try arena.alloc(Io.Dir, write_file.directories.items.len); | |
| 210 | var open_dirs_count: usize = 0; | |
| 211 | defer Io.Dir.closeMany(io, open_dir_cache[0..open_dirs_count]); | |
| 219 | var man = b.graph.cache.obtain(); | |
| 220 | defer man.deinit(); | |
| 212 | 221 | |
| 213 | for (write_file.directories.items, open_dir_cache) |dir, *open_dir_cache_elem| { | |
| 214 | man.hash.addBytes(dir.sub_path); | |
| 215 | for (dir.options.exclude_extensions) |ext| man.hash.addBytes(ext); | |
| 216 | if (dir.options.include_extensions) |incs| for (incs) |inc| man.hash.addBytes(inc); | |
| 222 | for (write_file.files.items) |file| { | |
| 223 | man.hash.addBytes(file.sub_path); | |
| 217 | 224 | |
| 218 | const need_derived_inputs = try step.addDirectoryWatchInput(dir.source); | |
| 219 | const src_dir_path = dir.source.getPath3(b, step); | |
| 225 | switch (file.contents) { | |
| 226 | .bytes => |bytes| { | |
| 227 | man.hash.addBytes(bytes); | |
| 228 | }, | |
| 229 | .copy => |lazy_path| { | |
| 230 | const path = lazy_path.getPath3(b, step); | |
| 231 | _ = try man.addFilePath(path, null); | |
| 232 | try step.addWatchInput(lazy_path); | |
| 233 | }, | |
| 234 | } | |
| 235 | } | |
| 220 | 236 | |
| 221 | var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { | |
| 222 | return step.fail("unable to open source directory '{f}': {s}", .{ | |
| 223 | src_dir_path, @errorName(err), | |
| 224 | }); | |
| 225 | }; | |
| 226 | open_dir_cache_elem.* = src_dir; | |
| 227 | open_dirs_count += 1; | |
| 237 | for (write_file.directories.items, open_dir_cache) |dir, *open_dir_cache_elem| { | |
| 238 | man.hash.addBytes(dir.sub_path); | |
| 239 | for (dir.options.exclude_extensions) |ext| man.hash.addBytes(ext); | |
| 240 | if (dir.options.include_extensions) |incs| for (incs) |inc| man.hash.addBytes(inc); | |
| 228 | 241 | |
| 229 | var it = try src_dir.walk(gpa); | |
| 230 | defer it.deinit(); | |
| 231 | while (try it.next(io)) |entry| { | |
| 232 | if (!dir.options.pathIncluded(entry.path)) continue; | |
| 242 | const need_derived_inputs = try step.addDirectoryWatchInput(dir.source); | |
| 243 | const src_dir_path = dir.source.getPath3(b, step); | |
| 233 | 244 | |
| 234 | switch (entry.kind) { | |
| 235 | .directory => { | |
| 236 | if (need_derived_inputs) { | |
| 237 | const entry_path = try src_dir_path.join(arena, entry.path); | |
| 238 | try step.addDirectoryWatchInputFromPath(entry_path); | |
| 245 | var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { | |
| 246 | return step.fail("unable to open source directory '{f}': {s}", .{ | |
| 247 | src_dir_path, @errorName(err), | |
| 248 | }); | |
| 249 | }; | |
| 250 | open_dir_cache_elem.* = src_dir; | |
| 251 | open_dirs_count += 1; | |
| 252 | ||
| 253 | var it = try src_dir.walk(gpa); | |
| 254 | defer it.deinit(); | |
| 255 | while (try it.next(io)) |entry| { | |
| 256 | if (!dir.options.pathIncluded(entry.path)) continue; | |
| 257 | ||
| 258 | switch (entry.kind) { | |
| 259 | .directory => { | |
| 260 | if (need_derived_inputs) { | |
| 261 | const entry_path = try src_dir_path.join(arena, entry.path); | |
| 262 | try step.addDirectoryWatchInputFromPath(entry_path); | |
| 263 | } | |
| 264 | }, | |
| 265 | .file => { | |
| 266 | const entry_path = try src_dir_path.join(arena, entry.path); | |
| 267 | _ = try man.addFilePath(entry_path, null); | |
| 268 | }, | |
| 269 | else => continue, | |
| 239 | 270 | } |
| 240 | }, | |
| 241 | .file => { | |
| 242 | const entry_path = try src_dir_path.join(arena, entry.path); | |
| 243 | _ = try man.addFilePath(entry_path, null); | |
| 244 | }, | |
| 245 | else => continue, | |
| 271 | } | |
| 246 | 272 | } |
| 247 | } | |
| 248 | } | |
| 249 | 273 | |
| 250 | if (try step.cacheHit(&man)) { | |
| 251 | const digest = man.final(); | |
| 252 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); | |
| 253 | step.result_cached = true; | |
| 254 | return; | |
| 255 | } | |
| 274 | if (try step.cacheHit(&man)) { | |
| 275 | const digest = man.final(); | |
| 276 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); | |
| 277 | assert(step.result_cached); | |
| 278 | return; | |
| 279 | } | |
| 280 | ||
| 281 | const digest = man.final(); | |
| 282 | const cache_path = "o" ++ Dir.path.sep_str ++ digest; | |
| 283 | ||
| 284 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{cache_path}); | |
| 285 | ||
| 286 | try operate(write_file, open_dir_cache, .{ | |
| 287 | .root_dir = b.cache_root, | |
| 288 | .sub_path = cache_path, | |
| 289 | }); | |
| 290 | ||
| 291 | try step.writeManifest(&man); | |
| 292 | }, | |
| 293 | .tmp => { | |
| 294 | step.result_cached = false; | |
| 295 | ||
| 296 | const rand_int = std.crypto.random.int(u64); | |
| 297 | const tmp_dir_sub_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int); | |
| 256 | 298 | |
| 257 | const digest = man.final(); | |
| 258 | const cache_path = "o" ++ fs.path.sep_str ++ digest; | |
| 299 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{tmp_dir_sub_path}); | |
| 300 | ||
| 301 | try operate(write_file, open_dir_cache, .{ | |
| 302 | .root_dir = b.cache_root, | |
| 303 | .sub_path = tmp_dir_sub_path, | |
| 304 | }); | |
| 305 | }, | |
| 306 | .mutate => |lp| { | |
| 307 | step.result_cached = false; | |
| 308 | const root_path = try lp.getPath4(b, step); | |
| 309 | write_file.generated_directory.path = try root_path.toString(arena); | |
| 310 | try operate(write_file, open_dir_cache, root_path); | |
| 311 | }, | |
| 312 | } | |
| 313 | } | |
| 259 | 314 | |
| 260 | write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); | |
| 315 | fn operate(write_file: *WriteFile, open_dir_cache: []const Io.Dir, root_path: std.Build.Cache.Path) !void { | |
| 316 | const step = &write_file.step; | |
| 317 | const b = step.owner; | |
| 318 | const io = b.graph.io; | |
| 319 | const gpa = b.graph.cache.gpa; | |
| 320 | const arena = b.allocator; | |
| 261 | 321 | |
| 262 | var cache_dir = b.cache_root.handle.createDirPathOpen(io, cache_path, .{}) catch |err| | |
| 263 | return step.fail("unable to make path '{f}{s}': {t}", .{ b.cache_root, cache_path, err }); | |
| 322 | var cache_dir = root_path.root_dir.handle.createDirPathOpen(io, root_path.sub_path, .{}) catch |err| | |
| 323 | return step.fail("unable to make path {f}: {t}", .{ root_path, err }); | |
| 264 | 324 | defer cache_dir.close(io); |
| 265 | 325 | |
| 266 | 326 | for (write_file.files.items) |file| { |
| 267 | if (fs.path.dirname(file.sub_path)) |dirname| { | |
| 327 | if (Dir.path.dirname(file.sub_path)) |dirname| { | |
| 268 | 328 | cache_dir.createDirPath(io, dirname) catch |err| { |
| 269 | return step.fail("unable to make path '{f}{s}{c}{s}': {t}", .{ | |
| 270 | b.cache_root, cache_path, fs.path.sep, dirname, err, | |
| 329 | return step.fail("unable to make path '{f}{c}{s}': {t}", .{ | |
| 330 | root_path, Dir.path.sep, dirname, err, | |
| 271 | 331 | }); |
| 272 | 332 | }; |
| 273 | 333 | } |
| 274 | 334 | switch (file.contents) { |
| 275 | 335 | .bytes => |bytes| { |
| 276 | 336 | cache_dir.writeFile(io, .{ .sub_path = file.sub_path, .data = bytes }) catch |err| { |
| 277 | return step.fail("unable to write file '{f}{s}{c}{s}': {t}", .{ | |
| 278 | b.cache_root, cache_path, fs.path.sep, file.sub_path, err, | |
| 337 | return step.fail("unable to write file '{f}{c}{s}': {t}", .{ | |
| 338 | root_path, Dir.path.sep, file.sub_path, err, | |
| 279 | 339 | }); |
| 280 | 340 | }; |
| 281 | 341 | }, |
| 282 | 342 | .copy => |file_source| { |
| 283 | 343 | const source_path = file_source.getPath2(b, step); |
| 284 | 344 | const prev_status = Io.Dir.updateFile(.cwd(), io, source_path, cache_dir, file.sub_path, .{}) catch |err| { |
| 285 | return step.fail("unable to update file from '{s}' to '{f}{s}{c}{s}': {t}", .{ | |
| 286 | source_path, b.cache_root, cache_path, fs.path.sep, file.sub_path, err, | |
| 345 | return step.fail("unable to update file from '{s}' to '{f}{c}{s}': {t}", .{ | |
| 346 | source_path, root_path, Dir.path.sep, file.sub_path, err, | |
| 287 | 347 | }); |
| 288 | 348 | }; |
| 289 | 349 | // At this point we already will mark the step as a cache miss. |
| ... | ... | @@ -301,8 +361,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 301 | 361 | |
| 302 | 362 | if (dest_dirname.len != 0) { |
| 303 | 363 | cache_dir.createDirPath(io, dest_dirname) catch |err| { |
| 304 | return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{ | |
| 305 | b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err), | |
| 364 | return step.fail("unable to make path '{f}{c}{s}': {t}", .{ | |
| 365 | root_path, Dir.path.sep, dest_dirname, err, | |
| 306 | 366 | }); |
| 307 | 367 | }; |
| 308 | 368 | } |
| ... | ... | @@ -325,8 +385,8 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 325 | 385 | dest_path, |
| 326 | 386 | .{}, |
| 327 | 387 | ) catch |err| { |
| 328 | return step.fail("unable to update file from '{f}' to '{f}{s}{c}{s}': {s}", .{ | |
| 329 | src_entry_path, b.cache_root, cache_path, fs.path.sep, dest_path, @errorName(err), | |
| 388 | return step.fail("unable to update file from '{f}' to '{f}{c}{s}': {t}", .{ | |
| 389 | src_entry_path, root_path, Dir.path.sep, dest_path, err, | |
| 330 | 390 | }); |
| 331 | 391 | }; |
| 332 | 392 | _ = prev_status; |
| ... | ... | @@ -335,6 +395,4 @@ fn make(step: *Step, options: Step.MakeOptions) !void { |
| 335 | 395 | } |
| 336 | 396 | } |
| 337 | 397 | } |
| 338 | ||
| 339 | try step.writeManifest(&man); | |
| 340 | 398 | } |
test/standalone/dirname/build.zig+3-13| ... | ... | @@ -58,19 +58,9 @@ pub fn build(b: *std.Build) void { |
| 58 | 58 | ); |
| 59 | 59 | |
| 60 | 60 | // Absolute path: |
| 61 | const abs_path = setup_abspath: { | |
| 62 | // TODO this is a bad pattern, don't do this | |
| 63 | const io = b.graph.io; | |
| 64 | const temp_dir = b.makeTempPath(); | |
| 65 | ||
| 66 | var dir = std.Io.Dir.cwd().openDir(io, temp_dir, .{}) catch @panic("failed to open temp dir"); | |
| 67 | defer dir.close(io); | |
| 68 | ||
| 69 | var file = dir.createFile(io, "foo.txt", .{}) catch @panic("failed to create file"); | |
| 70 | file.close(io); | |
| 71 | ||
| 72 | break :setup_abspath std.Build.LazyPath{ .cwd_relative = temp_dir }; | |
| 73 | }; | |
| 61 | const write_files = b.addWriteFiles(); | |
| 62 | _ = write_files.add("foo.txt", ""); | |
| 63 | const abs_path = write_files.getDirectory(); | |
| 74 | 64 | addTestRun(test_step, exists_in, abs_path, &.{"foo.txt"}); |
| 75 | 65 | } |
| 76 | 66 |
test/tests.zig+30-48| ... | ... | @@ -2026,13 +2026,12 @@ pub fn addLinkTests( |
| 2026 | 2026 | pub fn addCliTests(b: *std.Build) *Step { |
| 2027 | 2027 | const step = b.step("test-cli", "Test the command line interface"); |
| 2028 | 2028 | const s = std.fs.path.sep_str; |
| 2029 | const io = b.graph.io; | |
| 2030 | 2029 | |
| 2031 | 2030 | { |
| 2032 | 2031 | // Test `zig init`. |
| 2033 | const tmp_path = b.makeTempPath(); | |
| 2032 | const tmp_path = b.tmpPath(); | |
| 2034 | 2033 | const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" }); |
| 2035 | init_exe.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2034 | init_exe.setCwd(tmp_path); | |
| 2036 | 2035 | init_exe.setName("zig init"); |
| 2037 | 2036 | init_exe.expectStdOutEqual(""); |
| 2038 | 2037 | init_exe.expectStdErrEqual("info: created build.zig\n" ++ |
| ... | ... | @@ -2053,31 +2052,28 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2053 | 2052 | run_bad.step.dependOn(&init_exe.step); |
| 2054 | 2053 | |
| 2055 | 2054 | const run_test = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test" }); |
| 2056 | run_test.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2055 | run_test.setCwd(tmp_path); | |
| 2057 | 2056 | run_test.setName("zig build test"); |
| 2058 | 2057 | run_test.expectStdOutEqual(""); |
| 2059 | 2058 | run_test.step.dependOn(&init_exe.step); |
| 2060 | 2059 | |
| 2061 | 2060 | const run_run = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "run" }); |
| 2062 | run_run.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2061 | run_run.setCwd(tmp_path); | |
| 2063 | 2062 | run_run.setName("zig build run"); |
| 2064 | 2063 | run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n"); |
| 2065 | 2064 | run_run.expectStdErrMatch("All your codebase are belong to us.\n"); |
| 2066 | 2065 | run_run.step.dependOn(&init_exe.step); |
| 2067 | 2066 | |
| 2068 | const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path }); | |
| 2069 | cleanup.step.dependOn(&run_test.step); | |
| 2070 | cleanup.step.dependOn(&run_run.step); | |
| 2071 | cleanup.step.dependOn(&run_bad.step); | |
| 2072 | ||
| 2073 | step.dependOn(&cleanup.step); | |
| 2067 | step.dependOn(&run_test.step); | |
| 2068 | step.dependOn(&run_run.step); | |
| 2069 | step.dependOn(&run_bad.step); | |
| 2074 | 2070 | } |
| 2075 | 2071 | |
| 2076 | 2072 | { |
| 2077 | 2073 | // Test `zig init -m`. |
| 2078 | const tmp_path = b.makeTempPath(); | |
| 2074 | const tmp_path = b.tmpPath(); | |
| 2079 | 2075 | const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init", "-m" }); |
| 2080 | init_exe.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2076 | init_exe.setCwd(tmp_path); | |
| 2081 | 2077 | init_exe.setName("zig init -m"); |
| 2082 | 2078 | init_exe.expectStdOutEqual(""); |
| 2083 | 2079 | init_exe.expectStdErrEqual("info: successfully populated 'build.zig.zon' and 'build.zig'\n"); |
| ... | ... | @@ -2085,7 +2081,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2085 | 2081 | |
| 2086 | 2082 | // Test Godbolt API |
| 2087 | 2083 | if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) { |
| 2088 | const tmp_path = b.makeTempPath(); | |
| 2084 | const tmp_path = b.tmpPath(); | |
| 2089 | 2085 | |
| 2090 | 2086 | const example_zig = b.addWriteFiles().add("example.zig", |
| 2091 | 2087 | \\// Type your code here, or load an example. |
| ... | ... | @@ -2101,13 +2097,9 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2101 | 2097 | ); |
| 2102 | 2098 | |
| 2103 | 2099 | // This is intended to be the exact CLI usage used by godbolt.org. |
| 2104 | const run = b.addSystemCommand(&.{ | |
| 2105 | b.graph.zig_exe, "build-obj", | |
| 2106 | "--cache-dir", tmp_path, | |
| 2107 | "--name", "example", | |
| 2108 | "-fno-emit-bin", "-fno-emit-h", | |
| 2109 | "-fstrip", "-OReleaseFast", | |
| 2110 | }); | |
| 2100 | const run = b.addSystemCommand(&.{ b.graph.zig_exe, "build-obj", "--cache-dir" }); | |
| 2101 | run.addDirectoryArg(tmp_path); | |
| 2102 | run.addArgs(&.{ "--name", "example", "-fno-emit-bin", "-fno-emit-h", "-fstrip", "-OReleaseFast" }); | |
| 2111 | 2103 | run.addFileArg(example_zig); |
| 2112 | 2104 | const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s"); |
| 2113 | 2105 | |
| ... | ... | @@ -2120,10 +2112,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2120 | 2112 | }); |
| 2121 | 2113 | checkfile.setName("check godbolt.org CLI usage generating valid asm"); |
| 2122 | 2114 | |
| 2123 | const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path }); | |
| 2124 | cleanup.step.dependOn(&checkfile.step); | |
| 2125 | ||
| 2126 | step.dependOn(&cleanup.step); | |
| 2115 | step.dependOn(&checkfile.step); | |
| 2127 | 2116 | } |
| 2128 | 2117 | |
| 2129 | 2118 | { |
| ... | ... | @@ -2132,22 +2121,19 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2132 | 2121 | // directory because this test will be mutating the files. The cache |
| 2133 | 2122 | // system relies on cache directories being mutated only by their |
| 2134 | 2123 | // owners. |
| 2135 | const tmp_path = b.makeTempPath(); | |
| 2124 | const tmp_wf = b.addTempFiles(); | |
| 2136 | 2125 | const unformatted_code = " // no reason for indent"; |
| 2137 | 2126 | |
| 2138 | var dir = std.Io.Dir.cwd().openDir(io, tmp_path, .{}) catch @panic("unhandled"); | |
| 2139 | defer dir.close(io); | |
| 2140 | dir.writeFile(io, .{ .sub_path = "fmt1.zig", .data = unformatted_code }) catch @panic("unhandled"); | |
| 2141 | dir.writeFile(io, .{ .sub_path = "fmt2.zig", .data = unformatted_code }) catch @panic("unhandled"); | |
| 2142 | dir.createDir(io, "subdir", .default_dir) catch @panic("unhandled"); | |
| 2143 | var subdir = dir.openDir(io, "subdir", .{}) catch @panic("unhandled"); | |
| 2144 | defer subdir.close(io); | |
| 2145 | subdir.writeFile(io, .{ .sub_path = "fmt3.zig", .data = unformatted_code }) catch @panic("unhandled"); | |
| 2127 | _ = tmp_wf.add("fmt1.zig", unformatted_code); | |
| 2128 | _ = tmp_wf.add("fmt2.zig", unformatted_code); | |
| 2129 | _ = tmp_wf.add("subdir/fmt3.zig", unformatted_code); | |
| 2130 | ||
| 2131 | const tmp_path = tmp_wf.getDirectory(); | |
| 2146 | 2132 | |
| 2147 | 2133 | // Test zig fmt affecting only the appropriate files. |
| 2148 | 2134 | const run1 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "fmt1.zig" }); |
| 2149 | 2135 | run1.setName("run zig fmt one file"); |
| 2150 | run1.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2136 | run1.setCwd(tmp_path); | |
| 2151 | 2137 | run1.has_side_effects = true; |
| 2152 | 2138 | // stdout should be file path + \n |
| 2153 | 2139 | run1.expectStdOutEqual("fmt1.zig\n"); |
| ... | ... | @@ -2155,7 +2141,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2155 | 2141 | // Test excluding files and directories from a run |
| 2156 | 2142 | const run2 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." }); |
| 2157 | 2143 | run2.setName("run zig fmt on directory with exclusions"); |
| 2158 | run2.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2144 | run2.setCwd(tmp_path); | |
| 2159 | 2145 | run2.has_side_effects = true; |
| 2160 | 2146 | run2.expectStdOutEqual(""); |
| 2161 | 2147 | run2.step.dependOn(&run1.step); |
| ... | ... | @@ -2163,7 +2149,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2163 | 2149 | // Test excluding non-existent file |
| 2164 | 2150 | const run3 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." }); |
| 2165 | 2151 | run3.setName("run zig fmt on directory with non-existent exclusion"); |
| 2166 | run3.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2152 | run3.setCwd(tmp_path); | |
| 2167 | 2153 | run3.has_side_effects = true; |
| 2168 | 2154 | run3.expectStdOutEqual("." ++ s ++ "subdir" ++ s ++ "fmt3.zig\n"); |
| 2169 | 2155 | run3.step.dependOn(&run2.step); |
| ... | ... | @@ -2171,7 +2157,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2171 | 2157 | // running it on the dir, only the new file should be changed |
| 2172 | 2158 | const run4 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); |
| 2173 | 2159 | run4.setName("run zig fmt the directory"); |
| 2174 | run4.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2160 | run4.setCwd(tmp_path); | |
| 2175 | 2161 | run4.has_side_effects = true; |
| 2176 | 2162 | run4.expectStdOutEqual("." ++ s ++ "fmt2.zig\n"); |
| 2177 | 2163 | run4.step.dependOn(&run3.step); |
| ... | ... | @@ -2179,37 +2165,33 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 2179 | 2165 | // both files have been formatted, nothing should change now |
| 2180 | 2166 | const run5 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); |
| 2181 | 2167 | run5.setName("run zig fmt with nothing to do"); |
| 2182 | run5.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2168 | run5.setCwd(tmp_path); | |
| 2183 | 2169 | run5.has_side_effects = true; |
| 2184 | 2170 | run5.expectStdOutEqual(""); |
| 2185 | 2171 | run5.step.dependOn(&run4.step); |
| 2186 | 2172 | |
| 2187 | 2173 | const unformatted_code_utf16 = "\xff\xfe \x00 \x00 \x00 \x00/\x00/\x00 \x00n\x00o\x00 \x00r\x00e\x00a\x00s\x00o\x00n\x00"; |
| 2188 | const fmt6_path = b.pathJoin(&.{ tmp_path, "fmt6.zig" }); | |
| 2189 | const write6 = b.addUpdateSourceFiles(); | |
| 2190 | write6.addBytesToSource(unformatted_code_utf16, fmt6_path); | |
| 2174 | const write6 = b.addMutateFiles(tmp_path); | |
| 2175 | const fmt6_path = write6.add("fmt6.zig", unformatted_code_utf16); | |
| 2191 | 2176 | write6.step.dependOn(&run5.step); |
| 2192 | 2177 | |
| 2193 | 2178 | // Test `zig fmt` handling UTF-16 decoding. |
| 2194 | 2179 | const run6 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); |
| 2195 | 2180 | run6.setName("run zig fmt convert UTF-16 to UTF-8"); |
| 2196 | run6.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2181 | run6.setCwd(tmp_path); | |
| 2197 | 2182 | run6.has_side_effects = true; |
| 2198 | 2183 | run6.expectStdOutEqual("." ++ s ++ "fmt6.zig\n"); |
| 2199 | 2184 | run6.step.dependOn(&write6.step); |
| 2200 | 2185 | |
| 2201 | 2186 | // TODO change this to an exact match |
| 2202 | const check6 = b.addCheckFile(.{ .cwd_relative = fmt6_path }, .{ | |
| 2187 | const check6 = b.addCheckFile(fmt6_path, .{ | |
| 2203 | 2188 | .expected_matches = &.{ |
| 2204 | 2189 | "// no reason", |
| 2205 | 2190 | }, |
| 2206 | 2191 | }); |
| 2207 | 2192 | check6.step.dependOn(&run6.step); |
| 2208 | 2193 | |
| 2209 | const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path }); | |
| 2210 | cleanup.step.dependOn(&check6.step); | |
| 2211 | ||
| 2212 | step.dependOn(&cleanup.step); | |
| 2194 | step.dependOn(&check6.step); | |
| 2213 | 2195 | } |
| 2214 | 2196 | |
| 2215 | 2197 | { |