| author | |
| committer | |
| log | fa26566867cddbb0cd067cbc1d41bd41e68002a1 |
| tree | 43bc4abdf7a328e36d54333df462108dc01c06f5 |
| parent | c57bf9904396c365191d25b9ce6410bb47daa96a |
10 files changed, 215 insertions(+), 327 deletions(-)
BRANCH_TODO-1| ... | @@ -26,7 +26,6 @@ | ... | @@ -26,7 +26,6 @@ |
| 26 | - but artifact install steps also add paths for dyn libs on windows | 26 | - but artifact install steps also add paths for dyn libs on windows |
| 27 | * no more "artifact arg" to run step. if you want to run the post-install binary, get the lazy path | 27 | * no more "artifact arg" to run step. if you want to run the post-install binary, get the lazy path |
| 28 | from the install step. | 28 | from the install step. |
| 29 | * -D options which are files need to be accounted for in the configure cache | ||
| 30 | 29 | ||
| 31 | 30 | ||
| 32 | ## Release Notes | 31 | ## Release Notes |
build.zig+8-5| ... | @@ -208,7 +208,8 @@ pub fn build(b: *std.Build) !void { | ... | @@ -208,7 +208,8 @@ pub fn build(b: *std.Build) !void { |
| 208 | .single_threaded = single_threaded, | 208 | .single_threaded = single_threaded, |
| 209 | }); | 209 | }); |
| 210 | exe.pie = pie; | 210 | exe.pie = pie; |
| 211 | exe.entitlements = entitlements; | 211 | // https://codeberg.org/ziglang/zig/issues/32173 |
| 212 | exe.entitlements = if (entitlements) |p| .{ .cwd_relative = p } else null; | ||
| 212 | exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); | 213 | exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); |
| 213 | 214 | ||
| 214 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); | 215 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); |
| ... | @@ -1498,11 +1499,13 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath { | ... | @@ -1498,11 +1499,13 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath { |
| 1498 | }), | 1499 | }), |
| 1499 | }); | 1500 | }); |
| 1500 | 1501 | ||
| 1501 | var dir = b.build_root.handle.openDir(io, "doc/langref", .{ .iterate = true }) catch |err| { | 1502 | const langref_path: std.Build.Cache.Path = .{ |
| 1502 | std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{ | 1503 | .root_dir = b.build_root, |
| 1503 | b.build_root, @errorName(err), | 1504 | .sub_path = "doc/langref", |
| 1504 | }); | ||
| 1505 | }; | 1505 | }; |
| 1506 | |||
| 1507 | var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err| | ||
| 1508 | std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err }); | ||
| 1506 | defer dir.close(io); | 1509 | defer dir.close(io); |
| 1507 | 1510 | ||
| 1508 | var wf = b.addWriteFiles(); | 1511 | var wf = b.addWriteFiles(); |
lib/compiler/Maker/Step/InstallDir.zig created+66| ... | @@ -0,0 +1,66 @@ | ||
| 1 | const InstallDir = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const Configuration = std.Build.Configuration; | ||
| 5 | |||
| 6 | const Step = @import("../Step.zig"); | ||
| 7 | const Maker = @import("../../Maker.zig"); | ||
| 8 | |||
| 9 | pub fn make( | ||
| 10 | install_dir: *InstallDir, | ||
| 11 | step_index: Configuration.Step.Index, | ||
| 12 | maker: *Maker, | ||
| 13 | progress_node: std.Progress.Node, | ||
| 14 | ) !void { | ||
| 15 | const graph = maker.graph; | ||
| 16 | const arena = maker.graph.arena; // TODO don't leak into process arena | ||
| 17 | const io = graph.io; | ||
| 18 | const step = maker.stepByIndex(step_index); | ||
| 19 | |||
| 20 | step.clearWatchInputs(); | ||
| 21 | const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir); | ||
| 22 | const src_dir_path = install_dir.options.source_dir.getPath3(b, step); | ||
| 23 | const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir); | ||
| 24 | var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { | ||
| 25 | return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err }); | ||
| 26 | }; | ||
| 27 | defer src_dir.close(io); | ||
| 28 | var it = try src_dir.walk(arena); | ||
| 29 | var all_cached = true; | ||
| 30 | next_entry: while (try it.next(io)) |entry| { | ||
| 31 | for (install_dir.options.exclude_extensions) |ext| { | ||
| 32 | if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry; | ||
| 33 | } | ||
| 34 | if (install_dir.options.include_extensions) |incs| { | ||
| 35 | for (incs) |inc| { | ||
| 36 | if (std.mem.endsWith(u8, entry.path, inc)) break; | ||
| 37 | } else { | ||
| 38 | continue :next_entry; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | const src_path = try install_dir.options.source_dir.join(arena, entry.path); | ||
| 43 | const dest_path = b.pathJoin(&.{ dest_prefix, entry.path }); | ||
| 44 | switch (entry.kind) { | ||
| 45 | .directory => { | ||
| 46 | if (need_derived_inputs) _ = try step.addDirectoryWatchInput(src_path); | ||
| 47 | const p = try step.installDir(dest_path); | ||
| 48 | all_cached = all_cached and p == .existed; | ||
| 49 | }, | ||
| 50 | .file => { | ||
| 51 | for (install_dir.options.blank_extensions) |ext| { | ||
| 52 | if (std.mem.endsWith(u8, entry.path, ext)) { | ||
| 53 | try b.truncateFile(dest_path); | ||
| 54 | continue :next_entry; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | const p = try step.installFile(src_path, dest_path); | ||
| 59 | all_cached = all_cached and p == .fresh; | ||
| 60 | }, | ||
| 61 | else => continue, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | step.result_cached = all_cached; | ||
| 66 | } | ||
lib/compiler/Maker/Step/InstallFile.zig+1| ... | @@ -19,6 +19,7 @@ pub fn make( | ... | @@ -19,6 +19,7 @@ pub fn make( |
| 19 | const conf = &maker.scanned_config.configuration; | 19 | const conf = &maker.scanned_config.configuration; |
| 20 | const conf_step = step_index.ptr(conf); | 20 | const conf_step = step_index.ptr(conf); |
| 21 | const conf_if = conf_step.extended.get(conf.extra).install_file; | 21 | const conf_if = conf_step.extended.get(conf.extra).install_file; |
| 22 | |||
| 22 | try step.singleUnchangingWatchInput(maker, arena, conf_if.source.get(conf)); | 23 | try step.singleUnchangingWatchInput(maker, arena, conf_if.source.get(conf)); |
| 23 | const p = try maker.installLazyPathSub(arena, conf_if.source, conf_if.dest_dir, conf_if.dest_sub_path.slice(conf), step_index); | 24 | const p = try maker.installLazyPathSub(arena, conf_if.source, conf_if.dest_dir, conf_if.dest_sub_path.slice(conf), step_index); |
| 24 | step.result_cached = p == .fresh; | 25 | step.result_cached = p == .fresh; |
lib/compiler/Maker/Step/Options.zig created+84| ... | @@ -0,0 +1,84 @@ | ||
| 1 | const Options = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const Configuration = std.Build.Configuration; | ||
| 5 | |||
| 6 | const Step = @import("../Step.zig"); | ||
| 7 | const Maker = @import("../../Maker.zig"); | ||
| 8 | |||
| 9 | |||
| 10 | fn make( | ||
| 11 | options: *Options, | ||
| 12 | step_index: Configuration.Step.Index, | ||
| 13 | maker: *Maker, | ||
| 14 | progress_node: std.Progress.Node, | ||
| 15 | ) !void { | ||
| 16 | // This step completes so quickly that no progress reporting is necessary. | ||
| 17 | _ = progress_node; | ||
| 18 | |||
| 19 | const graph = maker.graph; | ||
| 20 | const step = maker.stepByIndex(step_index); | ||
| 21 | const io = graph.io; | ||
| 22 | const cache_root = graph.local_cache_root; | ||
| 23 | |||
| 24 | for (options.args.items) |arg| { | ||
| 25 | options.addOption( | ||
| 26 | []const u8, | ||
| 27 | arg.name, | ||
| 28 | arg.path.getPath2(b, step), | ||
| 29 | ); | ||
| 30 | } | ||
| 31 | if (!step.inputs.populated()) for (options.args.items) |arg| { | ||
| 32 | try step.addWatchInput(arg.path); | ||
| 33 | }; | ||
| 34 | |||
| 35 | const basename = "options.zig"; | ||
| 36 | |||
| 37 | // Hash contents to file name. | ||
| 38 | var hash = graph.cache.hash; | ||
| 39 | // Random bytes to make unique. Refresh this with new random bytes when | ||
| 40 | // implementation is modified in a non-backwards-compatible way. | ||
| 41 | hash.add(@as(u32, 0xad95e922)); | ||
| 42 | hash.addBytes(options.contents.items); | ||
| 43 | const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; | ||
| 44 | |||
| 45 | options.generated_file.path = try cache_root.join(arena, &.{sub_path}); | ||
| 46 | |||
| 47 | // Optimize for the hot path. Stat the file, and if it already exists, | ||
| 48 | // cache hit. | ||
| 49 | if (cache_root.handle.access(io, sub_path, .{})) |_| { | ||
| 50 | // This is the hot path, success. | ||
| 51 | step.result_cached = true; | ||
| 52 | return; | ||
| 53 | } else |outer_err| switch (outer_err) { | ||
| 54 | error.FileNotFound => { | ||
| 55 | var atomic_file = cache_root.handle.createFileAtomic(io, sub_path, .{ | ||
| 56 | .replace = false, | ||
| 57 | .make_path = true, | ||
| 58 | }) catch |err| return step.fail("failed to create temporary path for '{f}{s}': {t}", .{ | ||
| 59 | cache_root, sub_path, err, | ||
| 60 | }); | ||
| 61 | defer atomic_file.deinit(io); | ||
| 62 | |||
| 63 | atomic_file.file.writeStreamingAll(io, options.contents.items) catch |err| { | ||
| 64 | return step.fail("failed to write options to temporary path for '{f}{s}': {t}", .{ | ||
| 65 | cache_root, sub_path, err, | ||
| 66 | }); | ||
| 67 | }; | ||
| 68 | |||
| 69 | atomic_file.link(io) catch |err| switch (err) { | ||
| 70 | error.PathAlreadyExists => { | ||
| 71 | step.result_cached = true; | ||
| 72 | return; | ||
| 73 | }, | ||
| 74 | else => return step.fail("failed to link temporary file into '{f}{s}': {t}", .{ | ||
| 75 | cache_root, sub_path, err, | ||
| 76 | }), | ||
| 77 | }; | ||
| 78 | }, | ||
| 79 | else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{ | ||
| 80 | cache_root, sub_path, e, | ||
| 81 | }), | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
lib/std/Build.zig+7-7| ... | @@ -99,19 +99,19 @@ pub const Graph = struct { | ... | @@ -99,19 +99,19 @@ pub const Graph = struct { |
| 99 | return @enumFromInt(graph.generated_files.items.len - 1); | 99 | return @enumFromInt(graph.generated_files.items.len - 1); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | pub fn dupeString(graph: *Graph, bytes: []const u8) []const u8 { | 102 | pub fn dupeString(graph: *const Graph, bytes: []const u8) []const u8 { |
| 103 | return graph.arena.dupe(u8, bytes) catch @panic("OOM"); | 103 | return graph.arena.dupe(u8, bytes) catch @panic("OOM"); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | pub fn dupePath(graph: *Graph, bytes: []const u8) []const u8 { | 106 | pub fn dupePath(graph: *const Graph, bytes: []const u8) []const u8 { |
| 107 | const arena = graph.arena; | 107 | const arena = graph.arena; |
| 108 | if (builtin.os.tag != .windows) return graph.arena.dupe(u8, bytes) catch @panic("OOM"); | 108 | if (builtin.os.tag != .windows) return arena.dupe(u8, bytes) catch @panic("OOM"); |
| 109 | const the_copy = arena.dupe(u8, bytes) catch @panic("OOM"); | 109 | const the_copy = arena.dupe(u8, bytes) catch @panic("OOM"); |
| 110 | mem.replaceScalar(u8, the_copy, '/', '\\'); | 110 | mem.replaceScalar(u8, the_copy, '/', '\\'); |
| 111 | return the_copy; | 111 | return the_copy; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | pub fn dupeStrings(graph: *Graph, strings: []const []const u8) []const []const u8 { | 114 | pub fn dupeStrings(graph: *const Graph, strings: []const []const u8) []const []const u8 { |
| 115 | const arena = graph.arena; | 115 | const arena = graph.arena; |
| 116 | const array = arena.alloc([]const u8, strings.len) catch @panic("OOM"); | 116 | const array = arena.alloc([]const u8, strings.len) catch @panic("OOM"); |
| 117 | for (array, strings) |*dest, source| dest.* = dupeString(graph, source); | 117 | for (array, strings) |*dest, source| dest.* = dupeString(graph, source); |
| ... | @@ -2186,7 +2186,7 @@ pub const LazyPath = union(enum) { | ... | @@ -2186,7 +2186,7 @@ pub const LazyPath = union(enum) { |
| 2186 | /// | 2186 | /// |
| 2187 | /// The `b` parameter is only used for its allocator. All *Build instances | 2187 | /// The `b` parameter is only used for its allocator. All *Build instances |
| 2188 | /// share the same allocator. | 2188 | /// share the same allocator. |
| 2189 | pub fn dupe(lazy_path: LazyPath, graph: *Graph) LazyPath { | 2189 | pub fn dupe(lazy_path: LazyPath, graph: *const Graph) LazyPath { |
| 2190 | return switch (lazy_path) { | 2190 | return switch (lazy_path) { |
| 2191 | .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } }, | 2191 | .src_path => |sp| .{ .src_path = .{ .owner = sp.owner, .sub_path = sp.owner.dupePath(sp.sub_path) } }, |
| 2192 | .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) }, | 2192 | .cwd_relative => |p| .{ .cwd_relative = graph.dupePath(p) }, |
| ... | @@ -2245,9 +2245,9 @@ pub const InstallDir = union(enum) { | ... | @@ -2245,9 +2245,9 @@ pub const InstallDir = union(enum) { |
| 2245 | custom: []const u8, | 2245 | custom: []const u8, |
| 2246 | 2246 | ||
| 2247 | /// Duplicates the install directory including the path if set to custom. | 2247 | /// Duplicates the install directory including the path if set to custom. |
| 2248 | pub fn dupe(dir: InstallDir, builder: *Build) InstallDir { | 2248 | pub fn dupe(dir: InstallDir, graph: *const Graph) InstallDir { |
| 2249 | if (dir == .custom) { | 2249 | if (dir == .custom) { |
| 2250 | return .{ .custom = builder.dupe(dir.custom) }; | 2250 | return .{ .custom = graph.dupeString(dir.custom) }; |
| 2251 | } else { | 2251 | } else { |
| 2252 | return dir; | 2252 | return dir; |
| 2253 | } | 2253 | } |
lib/std/Build/Configuration.zig+21-2| ... | @@ -1039,10 +1039,20 @@ pub const Step = extern struct { | ... | @@ -1039,10 +1039,20 @@ pub const Step = extern struct { |
| 1039 | 1039 | ||
| 1040 | pub const InstallDir = struct { | 1040 | pub const InstallDir = struct { |
| 1041 | flags: @This().Flags, | 1041 | flags: @This().Flags, |
| 1042 | source_dir: LazyPath.Index, | ||
| 1043 | dest_dir: InstallDestDir, | ||
| 1044 | dest_sub_path: Storage.FlagOptional(.flags, .dest_sub_path, String), | ||
| 1045 | exclude_extensions: Storage.FlagLengthPrefixedList(.flags, .exclude_extensions, String), | ||
| 1046 | include_extensions: Storage.FlagLengthPrefixedList(.flags, .include_extensions, String), | ||
| 1047 | blank_extensions: Storage.FlagLengthPrefixedList(.flags, .blank_extensions, String), | ||
| 1042 | 1048 | ||
| 1043 | pub const Flags = packed struct(u32) { | 1049 | pub const Flags = packed struct(u32) { |
| 1044 | tag: Tag = .install_dir, | 1050 | tag: Tag = .install_dir, |
| 1045 | _: u27 = 0, | 1051 | dest_sub_path: bool, |
| 1052 | exclude_extensions: bool, | ||
| 1053 | include_extensions: bool, | ||
| 1054 | blank_extensions: bool, | ||
| 1055 | _: u23 = 0, | ||
| 1046 | }; | 1056 | }; |
| 1047 | }; | 1057 | }; |
| 1048 | 1058 | ||
| ... | @@ -1069,10 +1079,19 @@ pub const Step = extern struct { | ... | @@ -1069,10 +1079,19 @@ pub const Step = extern struct { |
| 1069 | 1079 | ||
| 1070 | pub const Options = struct { | 1080 | pub const Options = struct { |
| 1071 | flags: @This().Flags, | 1081 | flags: @This().Flags, |
| 1082 | generated_file: GeneratedFileIndex, | ||
| 1083 | contents: Bytes, | ||
| 1084 | args: Storage.FlagLengthPrefixedList(.flags, .args, Arg), | ||
| 1085 | |||
| 1086 | pub const Arg = extern struct { | ||
| 1087 | name: String, | ||
| 1088 | path: LazyPath.Index, | ||
| 1089 | }; | ||
| 1072 | 1090 | ||
| 1073 | pub const Flags = packed struct(u32) { | 1091 | pub const Flags = packed struct(u32) { |
| 1074 | tag: Tag = .options, | 1092 | tag: Tag = .options, |
| 1075 | _: u27 = 0, | 1093 | args: bool, |
| 1094 | _: u26 = 0, | ||
| 1076 | }; | 1095 | }; |
| 1077 | }; | 1096 | }; |
| 1078 | 1097 |
lib/std/Build/Step/InstallDir.zig+11-64| ... | @@ -1,9 +1,10 @@ | ... | @@ -1,9 +1,10 @@ |
| 1 | const InstallDir = @This(); | ||
| 2 | |||
| 1 | const std = @import("std"); | 3 | const std = @import("std"); |
| 2 | const mem = std.mem; | 4 | const mem = std.mem; |
| 3 | const fs = std.fs; | 5 | const fs = std.fs; |
| 4 | const Step = std.Build.Step; | 6 | const Step = std.Build.Step; |
| 5 | const LazyPath = std.Build.LazyPath; | 7 | const LazyPath = std.Build.LazyPath; |
| 6 | const InstallDir = @This(); | ||
| 7 | 8 | ||
| 8 | step: Step, | 9 | step: Step, |
| 9 | options: Options, | 10 | options: Options, |
| ... | @@ -28,83 +29,29 @@ pub const Options = struct { | ... | @@ -28,83 +29,29 @@ pub const Options = struct { |
| 28 | /// `@import("test.zig")` would be a compile error. | 29 | /// `@import("test.zig")` would be a compile error. |
| 29 | blank_extensions: []const []const u8 = &.{}, | 30 | blank_extensions: []const []const u8 = &.{}, |
| 30 | 31 | ||
| 31 | fn dupe(opts: Options, b: *std.Build) Options { | 32 | fn dupe(opts: Options, graph: *const std.Build.Graph) Options { |
| 32 | return .{ | 33 | return .{ |
| 33 | .source_dir = opts.source_dir.dupe(b), | 34 | .source_dir = opts.source_dir.dupe(graph), |
| 34 | .install_dir = opts.install_dir.dupe(b), | 35 | .install_dir = opts.install_dir.dupe(graph), |
| 35 | .install_subdir = b.dupe(opts.install_subdir), | 36 | .install_subdir = graph.dupeString(opts.install_subdir), |
| 36 | .exclude_extensions = b.dupeStrings(opts.exclude_extensions), | 37 | .exclude_extensions = graph.dupeStrings(opts.exclude_extensions), |
| 37 | .include_extensions = if (opts.include_extensions) |incs| b.dupeStrings(incs) else null, | 38 | .include_extensions = if (opts.include_extensions) |incs| graph.dupeStrings(incs) else null, |
| 38 | .blank_extensions = b.dupeStrings(opts.blank_extensions), | 39 | .blank_extensions = graph.dupeStrings(opts.blank_extensions), |
| 39 | }; | 40 | }; |
| 40 | } | 41 | } |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | pub fn create(owner: *std.Build, options: Options) *InstallDir { | 44 | pub fn create(owner: *std.Build, options: Options) *InstallDir { |
| 44 | const install_dir = owner.allocator.create(InstallDir) catch @panic("OOM"); | 45 | const install_dir = owner.allocator.create(InstallDir) catch @panic("OOM"); |
| 46 | const graph = owner.graph; | ||
| 45 | install_dir.* = .{ | 47 | install_dir.* = .{ |
| 46 | .step = Step.init(.{ | 48 | .step = Step.init(.{ |
| 47 | .tag = base_tag, | 49 | .tag = base_tag, |
| 48 | .name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}), | 50 | .name = owner.fmt("install {s}/", .{options.source_dir.getDisplayName()}), |
| 49 | .owner = owner, | 51 | .owner = owner, |
| 50 | .makeFn = make, | ||
| 51 | }), | 52 | }), |
| 52 | .options = options.dupe(owner), | 53 | .options = options.dupe(graph), |
| 53 | }; | 54 | }; |
| 54 | options.source_dir.addStepDependencies(&install_dir.step); | 55 | options.source_dir.addStepDependencies(&install_dir.step); |
| 55 | return install_dir; | 56 | return install_dir; |
| 56 | } | 57 | } |
| 57 | |||
| 58 | fn make(step: *Step, options: Step.MakeOptions) !void { | ||
| 59 | _ = options; | ||
| 60 | const b = step.owner; | ||
| 61 | const io = b.graph.io; | ||
| 62 | const install_dir: *InstallDir = @fieldParentPtr("step", step); | ||
| 63 | step.clearWatchInputs(); | ||
| 64 | const arena = b.allocator; | ||
| 65 | const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir); | ||
| 66 | const src_dir_path = install_dir.options.source_dir.getPath3(b, step); | ||
| 67 | const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir); | ||
| 68 | var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { | ||
| 69 | return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err }); | ||
| 70 | }; | ||
| 71 | defer src_dir.close(io); | ||
| 72 | var it = try src_dir.walk(arena); | ||
| 73 | var all_cached = true; | ||
| 74 | next_entry: while (try it.next(io)) |entry| { | ||
| 75 | for (install_dir.options.exclude_extensions) |ext| { | ||
| 76 | if (mem.endsWith(u8, entry.path, ext)) continue :next_entry; | ||
| 77 | } | ||
| 78 | if (install_dir.options.include_extensions) |incs| { | ||
| 79 | for (incs) |inc| { | ||
| 80 | if (mem.endsWith(u8, entry.path, inc)) break; | ||
| 81 | } else { | ||
| 82 | continue :next_entry; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | const src_path = try install_dir.options.source_dir.join(b.allocator, entry.path); | ||
| 87 | const dest_path = b.pathJoin(&.{ dest_prefix, entry.path }); | ||
| 88 | switch (entry.kind) { | ||
| 89 | .directory => { | ||
| 90 | if (need_derived_inputs) _ = try step.addDirectoryWatchInput(src_path); | ||
| 91 | const p = try step.installDir(dest_path); | ||
| 92 | all_cached = all_cached and p == .existed; | ||
| 93 | }, | ||
| 94 | .file => { | ||
| 95 | for (install_dir.options.blank_extensions) |ext| { | ||
| 96 | if (mem.endsWith(u8, entry.path, ext)) { | ||
| 97 | try b.truncateFile(dest_path); | ||
| 98 | continue :next_entry; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | const p = try step.installFile(src_path, dest_path); | ||
| 103 | all_cached = all_cached and p == .fresh; | ||
| 104 | }, | ||
| 105 | else => continue, | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | step.result_cached = all_cached; | ||
| 110 | } |
lib/std/Build/Step/InstallFile.zig+10-7| ... | @@ -1,17 +1,18 @@ | ... | @@ -1,17 +1,18 @@ |
| 1 | const InstallFile = @This(); | ||
| 2 | |||
| 1 | const std = @import("std"); | 3 | const std = @import("std"); |
| 2 | const Step = std.Build.Step; | 4 | const Step = std.Build.Step; |
| 3 | const LazyPath = std.Build.LazyPath; | 5 | const LazyPath = std.Build.LazyPath; |
| 4 | const InstallDir = std.Build.InstallDir; | 6 | const InstallDir = std.Build.InstallDir; |
| 5 | const InstallFile = @This(); | ||
| 6 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 7 | 8 | ||
| 8 | pub const base_tag: Step.Tag = .install_file; | ||
| 9 | |||
| 10 | step: Step, | 9 | step: Step, |
| 11 | source: LazyPath, | 10 | source: LazyPath, |
| 12 | dir: InstallDir, | 11 | dir: InstallDir, |
| 13 | dest_rel_path: []const u8, | 12 | dest_rel_path: []const u8, |
| 14 | 13 | ||
| 14 | pub const base_tag: Step.Tag = .install_file; | ||
| 15 | |||
| 15 | pub fn create( | 16 | pub fn create( |
| 16 | owner: *std.Build, | 17 | owner: *std.Build, |
| 17 | source: LazyPath, | 18 | source: LazyPath, |
| ... | @@ -19,16 +20,18 @@ pub fn create( | ... | @@ -19,16 +20,18 @@ pub fn create( |
| 19 | dest_rel_path: []const u8, | 20 | dest_rel_path: []const u8, |
| 20 | ) *InstallFile { | 21 | ) *InstallFile { |
| 21 | assert(dest_rel_path.len != 0); | 22 | assert(dest_rel_path.len != 0); |
| 22 | const install_file = owner.allocator.create(InstallFile) catch @panic("OOM"); | 23 | const graph = owner.graph; |
| 24 | const arena = graph.arena; | ||
| 25 | const install_file = arena.create(InstallFile) catch @panic("OOM"); | ||
| 23 | install_file.* = .{ | 26 | install_file.* = .{ |
| 24 | .step = Step.init(.{ | 27 | .step = Step.init(.{ |
| 25 | .tag = base_tag, | 28 | .tag = base_tag, |
| 26 | .name = owner.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), | 29 | .name = owner.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), |
| 27 | .owner = owner, | 30 | .owner = owner, |
| 28 | }), | 31 | }), |
| 29 | .source = source.dupe(owner), | 32 | .source = source.dupe(graph), |
| 30 | .dir = dir.dupe(owner), | 33 | .dir = dir.dupe(graph), |
| 31 | .dest_rel_path = owner.dupePath(dest_rel_path), | 34 | .dest_rel_path = graph.dupePath(dest_rel_path), |
| 32 | }; | 35 | }; |
| 33 | source.addStepDependencies(&install_file.step); | 36 | source.addStepDependencies(&install_file.step); |
| 34 | return install_file; | 37 | return install_file; |
lib/std/Build/Step/Options.zig+7-241| ... | @@ -9,15 +9,19 @@ const Step = std.Build.Step; | ... | @@ -9,15 +9,19 @@ const Step = std.Build.Step; |
| 9 | const LazyPath = std.Build.LazyPath; | 9 | const LazyPath = std.Build.LazyPath; |
| 10 | const Configuration = std.Build.Configuration; | 10 | const Configuration = std.Build.Configuration; |
| 11 | 11 | ||
| 12 | pub const base_tag: Step.Tag = .options; | ||
| 13 | |||
| 14 | step: Step, | 12 | step: Step, |
| 15 | generated_file: Configuration.GeneratedFileIndex, | 13 | generated_file: Configuration.GeneratedFileIndex, |
| 16 | |||
| 17 | contents: std.ArrayList(u8), | 14 | contents: std.ArrayList(u8), |
| 18 | args: std.ArrayList(Arg), | 15 | args: std.ArrayList(Arg), |
| 19 | encountered_types: std.StringHashMapUnmanaged(void), | 16 | encountered_types: std.StringHashMapUnmanaged(void), |
| 20 | 17 | ||
| 18 | pub const base_tag: Step.Tag = .options; | ||
| 19 | |||
| 20 | pub const Arg = struct { | ||
| 21 | name: []const u8, | ||
| 22 | path: LazyPath, | ||
| 23 | }; | ||
| 24 | |||
| 21 | pub fn create(owner: *std.Build) *Options { | 25 | pub fn create(owner: *std.Build) *Options { |
| 22 | const graph = owner.graph; | 26 | const graph = owner.graph; |
| 23 | const arena = graph.arena; | 27 | const arena = graph.arena; |
| ... | @@ -28,7 +32,6 @@ pub fn create(owner: *std.Build) *Options { | ... | @@ -28,7 +32,6 @@ pub fn create(owner: *std.Build) *Options { |
| 28 | .tag = base_tag, | 32 | .tag = base_tag, |
| 29 | .name = "options", | 33 | .name = "options", |
| 30 | .owner = owner, | 34 | .owner = owner, |
| 31 | .makeFn = make, | ||
| 32 | }), | 35 | }), |
| 33 | .generated_file = graph.addGeneratedFile(&options.step), | 36 | .generated_file = graph.addGeneratedFile(&options.step), |
| 34 | .contents = .empty, | 37 | .contents = .empty, |
| ... | @@ -439,240 +442,3 @@ pub fn createModule(options: *Options) *std.Build.Module { | ... | @@ -439,240 +442,3 @@ pub fn createModule(options: *Options) *std.Build.Module { |
| 439 | pub fn getOutput(options: *Options) LazyPath { | 442 | pub fn getOutput(options: *Options) LazyPath { |
| 440 | return .{ .generated = .{ .index = options.generated_file } }; | 443 | return .{ .generated = .{ .index = options.generated_file } }; |
| 441 | } | 444 | } |
| 442 | |||
| 443 | fn make(step: *Step, make_options: Step.MakeOptions) !void { | ||
| 444 | // This step completes so quickly that no progress reporting is necessary. | ||
| 445 | _ = make_options; | ||
| 446 | |||
| 447 | const b = step.owner; | ||
| 448 | const io = b.graph.io; | ||
| 449 | const options: *Options = @fieldParentPtr("step", step); | ||
| 450 | |||
| 451 | for (options.args.items) |item| { | ||
| 452 | options.addOption( | ||
| 453 | []const u8, | ||
| 454 | item.name, | ||
| 455 | item.path.getPath2(b, step), | ||
| 456 | ); | ||
| 457 | } | ||
| 458 | if (!step.inputs.populated()) for (options.args.items) |item| { | ||
| 459 | try step.addWatchInput(item.path); | ||
| 460 | }; | ||
| 461 | |||
| 462 | const basename = "options.zig"; | ||
| 463 | |||
| 464 | // Hash contents to file name. | ||
| 465 | var hash = b.graph.cache.hash; | ||
| 466 | // Random bytes to make unique. Refresh this with new random bytes when | ||
| 467 | // implementation is modified in a non-backwards-compatible way. | ||
| 468 | hash.add(@as(u32, 0xad95e922)); | ||
| 469 | hash.addBytes(options.contents.items); | ||
| 470 | const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; | ||
| 471 | |||
| 472 | options.generated_file.path = try b.cache_root.join(b.allocator, &.{sub_path}); | ||
| 473 | |||
| 474 | // Optimize for the hot path. Stat the file, and if it already exists, | ||
| 475 | // cache hit. | ||
| 476 | if (b.cache_root.handle.access(io, sub_path, .{})) |_| { | ||
| 477 | // This is the hot path, success. | ||
| 478 | step.result_cached = true; | ||
| 479 | return; | ||
| 480 | } else |outer_err| switch (outer_err) { | ||
| 481 | error.FileNotFound => { | ||
| 482 | var atomic_file = b.cache_root.handle.createFileAtomic(io, sub_path, .{ | ||
| 483 | .replace = false, | ||
| 484 | .make_path = true, | ||
| 485 | }) catch |err| return step.fail("failed to create temporary path for '{f}{s}': {t}", .{ | ||
| 486 | b.cache_root, sub_path, err, | ||
| 487 | }); | ||
| 488 | defer atomic_file.deinit(io); | ||
| 489 | |||
| 490 | atomic_file.file.writeStreamingAll(io, options.contents.items) catch |err| { | ||
| 491 | return step.fail("failed to write options to temporary path for '{f}{s}': {t}", .{ | ||
| 492 | b.cache_root, sub_path, err, | ||
| 493 | }); | ||
| 494 | }; | ||
| 495 | |||
| 496 | atomic_file.link(io) catch |err| switch (err) { | ||
| 497 | error.PathAlreadyExists => { | ||
| 498 | step.result_cached = true; | ||
| 499 | return; | ||
| 500 | }, | ||
| 501 | else => return step.fail("failed to link temporary file into '{f}{s}': {t}", .{ | ||
| 502 | b.cache_root, sub_path, err, | ||
| 503 | }), | ||
| 504 | }; | ||
| 505 | }, | ||
| 506 | else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{ | ||
| 507 | b.cache_root, sub_path, e, | ||
| 508 | }), | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | const Arg = struct { | ||
| 513 | name: []const u8, | ||
| 514 | path: LazyPath, | ||
| 515 | }; | ||
| 516 | |||
| 517 | test Options { | ||
| 518 | if (builtin.os.tag == .wasi) return error.SkipZigTest; | ||
| 519 | |||
| 520 | const io = std.testing.io; | ||
| 521 | |||
| 522 | var arena = std.heap.ArenaAllocator.init(std.testing.allocator); | ||
| 523 | defer arena.deinit(); | ||
| 524 | |||
| 525 | const cwd = try std.process.currentPathAlloc(io, std.testing.allocator); | ||
| 526 | defer std.testing.allocator.free(cwd); | ||
| 527 | |||
| 528 | var graph: std.Build.Graph = .{ | ||
| 529 | .io = io, | ||
| 530 | .arena = arena.allocator(), | ||
| 531 | .cache = .{ | ||
| 532 | .io = io, | ||
| 533 | .gpa = arena.allocator(), | ||
| 534 | .manifest_dir = Io.Dir.cwd(), | ||
| 535 | .cwd = cwd, | ||
| 536 | }, | ||
| 537 | .zig_exe = "test", | ||
| 538 | .environ_map = std.process.Environ.Map.init(arena.allocator()), | ||
| 539 | .global_cache_root = .{ .path = "test", .handle = Io.Dir.cwd() }, | ||
| 540 | .host = .{ | ||
| 541 | .query = .{}, | ||
| 542 | .result = try std.zig.system.resolveTargetQuery(io, .{}), | ||
| 543 | }, | ||
| 544 | .zig_lib_directory = std.Build.Cache.Directory.cwd(), | ||
| 545 | .time_report = false, | ||
| 546 | }; | ||
| 547 | |||
| 548 | var builder = try std.Build.create( | ||
| 549 | &graph, | ||
| 550 | .{ .path = "test", .handle = Io.Dir.cwd() }, | ||
| 551 | .{ .path = "test", .handle = Io.Dir.cwd() }, | ||
| 552 | &.{}, | ||
| 553 | ); | ||
| 554 | |||
| 555 | const options = builder.addOptions(); | ||
| 556 | |||
| 557 | const KeywordEnum = enum { | ||
| 558 | @"0.8.1", | ||
| 559 | }; | ||
| 560 | |||
| 561 | const NormalEnum = enum { | ||
| 562 | foo, | ||
| 563 | bar, | ||
| 564 | }; | ||
| 565 | |||
| 566 | const nested_array = [2][2]u16{ | ||
| 567 | [2]u16{ 300, 200 }, | ||
| 568 | [2]u16{ 300, 200 }, | ||
| 569 | }; | ||
| 570 | const nested_slice: []const []const u16 = &[_][]const u16{ &nested_array[0], &nested_array[1] }; | ||
| 571 | |||
| 572 | const NormalStruct = struct { | ||
| 573 | hello: ?[]const u8, | ||
| 574 | world: bool = true, | ||
| 575 | }; | ||
| 576 | |||
| 577 | const NestedStruct = struct { | ||
| 578 | normal_struct: NormalStruct, | ||
| 579 | normal_enum: NormalEnum = .foo, | ||
| 580 | }; | ||
| 581 | |||
| 582 | options.addOption(usize, "option1", 1); | ||
| 583 | options.addOption(?usize, "option2", null); | ||
| 584 | options.addOption(?usize, "option3", 3); | ||
| 585 | options.addOption(comptime_int, "option4", 4); | ||
| 586 | options.addOption(comptime_float, "option5", 5.01); | ||
| 587 | options.addOption([]const u8, "string", "zigisthebest"); | ||
| 588 | options.addOption(?[]const u8, "optional_string", null); | ||
| 589 | options.addOption([2][2]u16, "nested_array", nested_array); | ||
| 590 | options.addOption([]const []const u16, "nested_slice", nested_slice); | ||
| 591 | options.addOption(KeywordEnum, "keyword_enum", .@"0.8.1"); | ||
| 592 | options.addOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar")); | ||
| 593 | options.addOption(NormalEnum, "normal1_enum", NormalEnum.foo); | ||
| 594 | options.addOption(NormalEnum, "normal2_enum", NormalEnum.bar); | ||
| 595 | options.addOption(NormalStruct, "normal1_struct", NormalStruct{ | ||
| 596 | .hello = "foo", | ||
| 597 | }); | ||
| 598 | options.addOption(NormalStruct, "normal2_struct", NormalStruct{ | ||
| 599 | .hello = null, | ||
| 600 | .world = false, | ||
| 601 | }); | ||
| 602 | options.addOption(NestedStruct, "nested_struct", NestedStruct{ | ||
| 603 | .normal_struct = .{ .hello = "bar" }, | ||
| 604 | }); | ||
| 605 | |||
| 606 | try std.testing.expectEqualStrings( | ||
| 607 | \\pub const option1: usize = 1; | ||
| 608 | \\pub const option2: ?usize = null; | ||
| 609 | \\pub const option3: ?usize = 3; | ||
| 610 | \\pub const option4: comptime_int = 4; | ||
| 611 | \\pub const option5: comptime_float = 5.01; | ||
| 612 | \\pub const string: []const u8 = "zigisthebest"; | ||
| 613 | \\pub const optional_string: ?[]const u8 = null; | ||
| 614 | \\pub const nested_array: [2][2]u16 = [2][2]u16 { | ||
| 615 | \\ [2]u16 { | ||
| 616 | \\ 300, | ||
| 617 | \\ 200, | ||
| 618 | \\ }, | ||
| 619 | \\ [2]u16 { | ||
| 620 | \\ 300, | ||
| 621 | \\ 200, | ||
| 622 | \\ }, | ||
| 623 | \\}; | ||
| 624 | \\pub const nested_slice: []const []const u16 = &[_][]const u16 { | ||
| 625 | \\ &[_]u16 { | ||
| 626 | \\ 300, | ||
| 627 | \\ 200, | ||
| 628 | \\ }, | ||
| 629 | \\ &[_]u16 { | ||
| 630 | \\ 300, | ||
| 631 | \\ 200, | ||
| 632 | \\ }, | ||
| 633 | \\}; | ||
| 634 | \\pub const @"Build.Step.Options.decltest.Options.KeywordEnum" = enum (u0) { | ||
| 635 | \\ @"0.8.1" = 0, | ||
| 636 | \\}; | ||
| 637 | \\pub const keyword_enum: @"Build.Step.Options.decltest.Options.KeywordEnum" = .@"0.8.1"; | ||
| 638 | \\pub const semantic_version: @import("std").SemanticVersion = .{ | ||
| 639 | \\ .major = 0, | ||
| 640 | \\ .minor = 1, | ||
| 641 | \\ .patch = 2, | ||
| 642 | \\ .pre = "foo", | ||
| 643 | \\ .build = "bar", | ||
| 644 | \\}; | ||
| 645 | \\pub const @"Build.Step.Options.decltest.Options.NormalEnum" = enum (u1) { | ||
| 646 | \\ foo = 0, | ||
| 647 | \\ bar = 1, | ||
| 648 | \\}; | ||
| 649 | \\pub const normal1_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .foo; | ||
| 650 | \\pub const normal2_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .bar; | ||
| 651 | \\pub const @"Build.Step.Options.decltest.Options.NormalStruct" = struct { | ||
| 652 | \\ hello: ?[]const u8, | ||
| 653 | \\ world: bool = true, | ||
| 654 | \\}; | ||
| 655 | \\pub const normal1_struct: @"Build.Step.Options.decltest.Options.NormalStruct" = .{ | ||
| 656 | \\ .hello = "foo", | ||
| 657 | \\ .world = true, | ||
| 658 | \\}; | ||
| 659 | \\pub const normal2_struct: @"Build.Step.Options.decltest.Options.NormalStruct" = .{ | ||
| 660 | \\ .hello = null, | ||
| 661 | \\ .world = false, | ||
| 662 | \\}; | ||
| 663 | \\pub const @"Build.Step.Options.decltest.Options.NestedStruct" = struct { | ||
| 664 | \\ normal_struct: @"Build.Step.Options.decltest.Options.NormalStruct", | ||
| 665 | \\ normal_enum: @"Build.Step.Options.decltest.Options.NormalEnum" = .foo, | ||
| 666 | \\}; | ||
| 667 | \\pub const nested_struct: @"Build.Step.Options.decltest.Options.NestedStruct" = .{ | ||
| 668 | \\ .normal_struct = .{ | ||
| 669 | \\ .hello = "bar", | ||
| 670 | \\ .world = true, | ||
| 671 | \\ }, | ||
| 672 | \\ .normal_enum = .foo, | ||
| 673 | \\}; | ||
| 674 | \\ | ||
| 675 | , options.contents.items); | ||
| 676 | |||
| 677 | _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(arena.allocator(), 0), .zig); | ||
| 678 | } |