| author | |
| committer | |
| log | a04f90c35b116ede4d81c8f03f08d0f79a908dea |
| tree | d360736177123470808f30e57145b5c3bf40805f |
| parent | c616c00db613c2a6fe7d5acfdfb884c006baa600 |
8 files changed, 275 insertions(+), 98 deletions(-)
build.zig+2-3| ... | ... | @@ -264,9 +264,8 @@ pub fn build(b: *std.Build) !void { |
| 264 | 264 | std.process.exit(1); |
| 265 | 265 | } |
| 266 | 266 | |
| 267 | // Ensure git version changes get picked up | |
| 268 | // https://codeberg.org/ziglang/zig/issues/35473 | |
| 269 | b.graph.poisonCache(); | |
| 267 | // Ensure git version changes get picked up. | |
| 268 | b.dependOnFileContents(b.graph.path(.build_root, ".git/HEAD")); | |
| 270 | 269 | |
| 271 | 270 | const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch }); |
| 272 | 271 |
lib/compiler/configurer.zig+32-1| ... | ... | @@ -133,7 +133,7 @@ pub fn main(init: process.Init.Minimal) !void { |
| 133 | 133 | .off => .no_color, |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | try builder.runBuild(root); | |
| 136 | builder.runBuild(root); | |
| 137 | 137 | |
| 138 | 138 | if (builder.validateUserInputDidItFail()) { |
| 139 | 139 | fatal(" access the help menu with 'zig build -h'", .{}); |
| ... | ... | @@ -632,6 +632,37 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { |
| 632 | 632 | |
| 633 | 633 | var s: Serialize = .{ .wc = wc, .arena = arena }; |
| 634 | 634 | |
| 635 | try wc.path_deps.ensureTotalCapacityPrecise(gpa, graph.configure_dependencies.items.len); | |
| 636 | for ( | |
| 637 | graph.configure_dependencies.items, | |
| 638 | wc.path_deps.addManyAsSliceAssumeCapacity(graph.configure_dependencies.items.len), | |
| 639 | ) |src, *dest| { | |
| 640 | dest.* = .{ | |
| 641 | .flags = .{ | |
| 642 | .base = switch (src.lazy_path) { | |
| 643 | .src_path, .dependency => .build_root, | |
| 644 | .generated => unreachable, | |
| 645 | .cwd_relative => .cwd, | |
| 646 | .relative => |r| r.base, | |
| 647 | }, | |
| 648 | .mode = src.mode, | |
| 649 | }, | |
| 650 | .sub = switch (src.lazy_path) { | |
| 651 | .src_path => |sp| try wc.addString(sp.sub_path), | |
| 652 | .generated => unreachable, | |
| 653 | .cwd_relative => |sub_path| try wc.addString(sub_path), | |
| 654 | .dependency => |d| try wc.addString(d.sub_path), | |
| 655 | .relative => |r| try wc.addString(r.sub_path), | |
| 656 | }, | |
| 657 | .pkg = switch (src.lazy_path) { | |
| 658 | .src_path => |sp| .init(try s.builderToPackage(sp.owner)), | |
| 659 | .generated => unreachable, | |
| 660 | .cwd_relative, .relative => .none, | |
| 661 | .dependency => |d| .init(try s.builderToPackage(d.dependency.builder)), | |
| 662 | }, | |
| 663 | }; | |
| 664 | } | |
| 665 | ||
| 635 | 666 | // Starting from all top-level steps in `b`, traverse the entire step graph |
| 636 | 667 | // and add all step dependencies implied by module graphs. |
| 637 | 668 | const top_level_steps = b.top_level_steps.values(); |
lib/std/Build.zig+111-10| ... | ... | @@ -64,6 +64,11 @@ pkg_hash: []const u8, |
| 64 | 64 | /// A mapping from dependency names to package hashes. |
| 65 | 65 | available_deps: AvailableDeps, |
| 66 | 66 | |
| 67 | pub const ConfigureDependency = struct { | |
| 68 | lazy_path: LazyPath, | |
| 69 | mode: std.Build.Configuration.PathDep.Mode, | |
| 70 | }; | |
| 71 | ||
| 67 | 72 | pub const ReleaseMode = enum { |
| 68 | 73 | off, |
| 69 | 74 | any, |
| ... | ... | @@ -102,6 +107,12 @@ pub const Graph = struct { |
| 102 | 107 | /// Observing this data causes cache poisoning. See `CachePoison`. |
| 103 | 108 | search_prefixes: std.ArrayList([]const u8) = .empty, |
| 104 | 109 | |
| 110 | /// Populated by calling one of: | |
| 111 | /// * `dependOnFileContents` | |
| 112 | /// * `dependOnFileMetadata` | |
| 113 | /// * `dependOnDirectory` | |
| 114 | configure_dependencies: ArrayList(ConfigureDependency) = .empty, | |
| 115 | ||
| 105 | 116 | /// If the cache is poisoned means that the **configure logic** had side |
| 106 | 117 | /// effects, or otherwise did something that could not be tracked by the |
| 107 | 118 | /// cache system. |
| ... | ... | @@ -165,7 +176,7 @@ pub const Graph = struct { |
| 165 | 176 | |
| 166 | 177 | /// A path whose components and contents are known at some point during |
| 167 | 178 | /// `Step` resolution, relative to the provided base directory. |
| 168 | pub fn path(graph: *Graph, base: Configuration.Path.Base, sub_path: []const u8) LazyPath { | |
| 179 | pub fn path(graph: *Graph, base: Configuration.LazyPath.Relative.Base, sub_path: []const u8) LazyPath { | |
| 169 | 180 | return .{ .relative = .{ |
| 170 | 181 | .base = base, |
| 171 | 182 | .sub_path = @This().dupePath(graph, sub_path), |
| ... | ... | @@ -204,6 +215,9 @@ pub const Graph = struct { |
| 204 | 215 | /// did something that could not be tracked by the cache system. |
| 205 | 216 | /// |
| 206 | 217 | /// See `CachePoison` documentation for more details. |
| 218 | /// | |
| 219 | /// As an alternative to calling this function, consider these APIs instead: | |
| 220 | /// * `dependOnFileContents` | |
| 207 | 221 | pub fn poisonCache(graph: *Graph) void { |
| 208 | 222 | switch (graph.cache_poison) { |
| 209 | 223 | .pure => graph.cache_poison = .poisoned, |
| ... | ... | @@ -2318,14 +2332,13 @@ fn dependencyInner( |
| 2318 | 2332 | .root_dir = .{ |
| 2319 | 2333 | .path = build_root_string, |
| 2320 | 2334 | .handle = Io.Dir.cwd().openDir(io, build_root_string, .{}) catch |err| |
| 2321 | process.fatal("unable to open {s}: {t}", .{ build_root_string, err }), | |
| 2335 | process.fatal("failed to open {q}: {t}", .{ build_root_string, err }), | |
| 2322 | 2336 | }, |
| 2323 | 2337 | }; |
| 2324 | 2338 | |
| 2325 | const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch | |
| 2326 | @panic("unhandled error"); | |
| 2339 | const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch @panic("OOM"); | |
| 2327 | 2340 | if (build_zig) |bz| { |
| 2328 | sub_builder.runBuild(bz) catch @panic("unhandled error"); | |
| 2341 | sub_builder.runBuild(bz); | |
| 2329 | 2342 | |
| 2330 | 2343 | if (sub_builder.validateUserInputDidItFail()) { |
| 2331 | 2344 | std.debug.dumpCurrentStackTrace(.{ .first_address = @returnAddress() }); |
| ... | ... | @@ -2343,11 +2356,10 @@ fn dependencyInner( |
| 2343 | 2356 | } |
| 2344 | 2357 | |
| 2345 | 2358 | /// Build system implementation detail. |
| 2346 | pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void { | |
| 2359 | pub fn runBuild(b: *Build, build_zig: anytype) void { | |
| 2347 | 2360 | switch (@typeInfo(@typeInfo(@TypeOf(build_zig.build)).@"fn".return_type.?)) { |
| 2348 | .void => build_zig.build(b), | |
| 2349 | .error_union => try build_zig.build(b), | |
| 2350 | else => @compileError("expected return type of build to be 'void' or '!void'"), | |
| 2361 | .error_union => return build_zig.build(b) catch unreachable, | |
| 2362 | else => return build_zig.build(b), | |
| 2351 | 2363 | } |
| 2352 | 2364 | } |
| 2353 | 2365 | |
| ... | ... | @@ -2411,7 +2423,7 @@ pub const LazyPath = union(enum) { |
| 2411 | 2423 | }, |
| 2412 | 2424 | |
| 2413 | 2425 | relative: struct { |
| 2414 | base: Configuration.Path.Base, | |
| 2426 | base: Configuration.LazyPath.Relative.Base, | |
| 2415 | 2427 | sub_path: []const u8 = "", |
| 2416 | 2428 | |
| 2417 | 2429 | pub fn eql(a: @This(), b: @This()) bool { |
| ... | ... | @@ -2717,6 +2729,95 @@ pub fn systemIntegrationOption( |
| 2717 | 2729 | } |
| 2718 | 2730 | } |
| 2719 | 2731 | |
| 2732 | /// Indicates that the build.zig logic depends on a particular file's contents. | |
| 2733 | /// | |
| 2734 | /// If the file is created, deleted, or has its contents changed, the configure | |
| 2735 | /// phase will be repeated. If the inode or mtime change, but the file contents | |
| 2736 | /// remain the same, it will not cause the configure logic to be repeated. | |
| 2737 | /// | |
| 2738 | /// This is an alternative to `Graph.poisonCache` that avoids making every invocation | |
| 2739 | /// of `zig build` into a cache miss. | |
| 2740 | /// | |
| 2741 | /// Only a subset of `LazyPath` are supported: | |
| 2742 | /// - Relative to cwd | |
| 2743 | /// - Relative to any package root | |
| 2744 | /// - Relative to zig cache or zig installation | |
| 2745 | /// | |
| 2746 | /// If the file would be inside one of the search prefixes, then the dependency | |
| 2747 | /// cannot be tracked; `Graph.poisonCache` must be used instead. | |
| 2748 | pub fn dependOnFileContents(b: *Build, lazy_path: LazyPath) void { | |
| 2749 | validateConfigureDependency(lazy_path); | |
| 2750 | const graph = b.graph; | |
| 2751 | graph.configure_dependencies.append(graph.arena, .{ | |
| 2752 | .lazy_path = lazy_path.dupe(graph), | |
| 2753 | .mode = .contents, | |
| 2754 | }) catch @panic("OOM"); | |
| 2755 | } | |
| 2756 | ||
| 2757 | /// Indicates that the build.zig logic depends on a particular file's size, | |
| 2758 | /// inode, mtime, and contents. | |
| 2759 | /// | |
| 2760 | /// If the file is created, deleted, has its contents changed, or the inode | |
| 2761 | /// changes, or the mtime changes, the configure phase will be repeated. | |
| 2762 | /// | |
| 2763 | /// This is an alternative to `Graph.poisonCache` that avoids making every invocation | |
| 2764 | /// of `zig build` into a cache miss. | |
| 2765 | /// | |
| 2766 | /// Only a subset of `LazyPath` are supported: | |
| 2767 | /// - Relative to cwd | |
| 2768 | /// - Relative to any package root | |
| 2769 | /// - Relative to zig cache or zig installation | |
| 2770 | /// | |
| 2771 | /// If the file would be inside one of the search prefixes, then the dependency | |
| 2772 | /// cannot be tracked; `Graph.poisonCache` must be used instead. | |
| 2773 | pub fn dependOnFileMetadata(b: *Build, lazy_path: LazyPath) void { | |
| 2774 | validateConfigureDependency(lazy_path); | |
| 2775 | const graph = b.graph; | |
| 2776 | graph.configure_dependencies.append(graph.arena, .{ | |
| 2777 | .lazy_path = lazy_path.dupe(graph), | |
| 2778 | .mode = .metadata, | |
| 2779 | }) catch @panic("OOM"); | |
| 2780 | } | |
| 2781 | ||
| 2782 | /// Indicates that the build.zig logic depends on a particular directory's entries. | |
| 2783 | /// | |
| 2784 | /// This is an alternative to `Graph.poisonCache` that avoids making every invocation | |
| 2785 | /// of `zig build` into a cache miss. | |
| 2786 | /// | |
| 2787 | /// If any file is created, deleted, or renamed in this directory, the | |
| 2788 | /// configure phase will be repeated. | |
| 2789 | /// | |
| 2790 | /// Only a subset of `LazyPath` are supported: | |
| 2791 | /// - Relative to cwd | |
| 2792 | /// - Relative to any package root | |
| 2793 | /// - Relative to zig cache or zig installation | |
| 2794 | /// | |
| 2795 | /// If the directory would be inside one of the search prefixes, then the dependency | |
| 2796 | /// cannot be tracked; `Graph.poisonCache` must be used instead. | |
| 2797 | pub fn dependOnDirectory(b: *Build, lazy_path: LazyPath) void { | |
| 2798 | validateConfigureDependency(lazy_path); | |
| 2799 | const graph = b.graph; | |
| 2800 | graph.configure_dependencies.append(graph.arena, .{ | |
| 2801 | .lazy_path = lazy_path.dupe(graph), | |
| 2802 | .mode = .directory, | |
| 2803 | }) catch @panic("OOM"); | |
| 2804 | } | |
| 2805 | ||
| 2806 | fn validateConfigureDependency(lazy_path: LazyPath) void { | |
| 2807 | switch (lazy_path) { | |
| 2808 | .src_path, .cwd_relative, .dependency => {}, // OK | |
| 2809 | .generated => @panic("configure phase cannot depend on files generated during make phase"), | |
| 2810 | .relative => |relative| switch (relative.base) { | |
| 2811 | .cwd, .build_root, .local_cache, .global_cache, .zig_exe, .zig_lib => {}, // OK | |
| 2812 | .install_prefix, | |
| 2813 | .install_lib, | |
| 2814 | .install_bin, | |
| 2815 | .install_include, | |
| 2816 | => @panic("configure phase cannot depend on files installed during make phase"), | |
| 2817 | }, | |
| 2818 | } | |
| 2819 | } | |
| 2820 | ||
| 2720 | 2821 | test { |
| 2721 | 2822 | _ = Cache; |
| 2722 | 2823 | _ = Configuration; |
lib/std/Build/Cache.zig+16-12| ... | ... | @@ -57,7 +57,7 @@ pub fn prefixes(cache: *const Cache) []const Directory { |
| 57 | 57 | return cache.prefixes_buffer[0..cache.prefixes_len]; |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | const PrefixedPath = struct { | |
| 60 | pub const PrefixedPath = struct { | |
| 61 | 61 | prefix: u8, |
| 62 | 62 | sub_path: []const u8, |
| 63 | 63 | |
| ... | ... | @@ -1000,18 +1000,21 @@ pub const Manifest = struct { |
| 1000 | 1000 | /// other files will need to be recompiled if the imported file is changed. |
| 1001 | 1001 | pub fn addFilePost(self: *Manifest, file_path: []const u8) !void { |
| 1002 | 1002 | assert(self.manifest_file != null); |
| 1003 | ||
| 1004 | 1003 | const gpa = self.cache.gpa; |
| 1005 | 1004 | const prefixed_path = try self.cache.findPrefix(file_path); |
| 1006 | errdefer gpa.free(prefixed_path.sub_path); | |
| 1005 | var keep = false; | |
| 1006 | defer if (!keep) gpa.free(prefixed_path.sub_path); | |
| 1007 | keep = try addPrefixedPathPost(self, prefixed_path); | |
| 1008 | } | |
| 1007 | 1009 | |
| 1008 | const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); | |
| 1009 | errdefer _ = self.files.pop(); | |
| 1010 | pub fn addPrefixedPathPost(man: *Manifest, prefixed_path: PrefixedPath) !bool { | |
| 1011 | assert(man.manifest_file != null); | |
| 1012 | const gpa = man.cache.gpa; | |
| 1010 | 1013 | |
| 1011 | if (gop.found_existing) { | |
| 1012 | gpa.free(prefixed_path.sub_path); | |
| 1013 | return; | |
| 1014 | } | |
| 1014 | const gop = try man.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{}); | |
| 1015 | errdefer _ = man.files.pop(); | |
| 1016 | ||
| 1017 | if (gop.found_existing) return false; | |
| 1015 | 1018 | |
| 1016 | 1019 | gop.key_ptr.* = .{ |
| 1017 | 1020 | .prefixed_path = prefixed_path, |
| ... | ... | @@ -1022,10 +1025,11 @@ pub const Manifest = struct { |
| 1022 | 1025 | .contents = null, |
| 1023 | 1026 | }; |
| 1024 | 1027 | |
| 1025 | self.files.lockPointers(); | |
| 1026 | defer self.files.unlockPointers(); | |
| 1028 | man.files.lockPointers(); | |
| 1029 | defer man.files.unlockPointers(); | |
| 1027 | 1030 | |
| 1028 | try self.populateFileHash(gop.key_ptr); | |
| 1031 | try man.populateFileHash(gop.key_ptr); | |
| 1032 | return true; | |
| 1029 | 1033 | } |
| 1030 | 1034 | |
| 1031 | 1035 | pub fn addPathPost(man: *Manifest, path: Path) !void { |
lib/std/Build/Configuration.zig+50-25| ... | ... | @@ -10,8 +10,7 @@ const native_endian = builtin.target.cpu.arch.endian(); |
| 10 | 10 | |
| 11 | 11 | string_bytes: []u8, |
| 12 | 12 | steps: []Step, |
| 13 | path_deps_base: []Path.Base, | |
| 14 | path_deps_sub: []String, | |
| 13 | path_deps: []PathDep, | |
| 15 | 14 | unlazy_deps: []String, |
| 16 | 15 | system_integrations: []SystemIntegration, |
| 17 | 16 | available_options: []AvailableOption, |
| ... | ... | @@ -57,7 +56,7 @@ pub const Wip = struct { |
| 57 | 56 | system_integrations: std.ArrayList(SystemIntegration) = .empty, |
| 58 | 57 | available_options: std.ArrayList(AvailableOption) = .empty, |
| 59 | 58 | steps: std.ArrayList(Step) = .empty, |
| 60 | path_deps: std.MultiArrayList(Path) = .empty, | |
| 59 | path_deps: std.ArrayList(PathDep) = .empty, | |
| 61 | 60 | search_prefixes: std.ArrayList(String) = .empty, |
| 62 | 61 | extra: std.ArrayList(u32) = .empty, |
| 63 | 62 | next_generated_file_index: u32 = 0, |
| ... | ... | @@ -154,7 +153,7 @@ pub const Wip = struct { |
| 154 | 153 | const header: Header = .{ |
| 155 | 154 | .string_bytes_len = @intCast(wip.string_bytes.items.len), |
| 156 | 155 | .steps_len = @intCast(wip.steps.items.len), |
| 157 | .path_deps_len = @intCast(wip.path_deps.len), | |
| 156 | .path_deps_len = @intCast(wip.path_deps.items.len), | |
| 158 | 157 | .unlazy_deps_len = @intCast(wip.unlazy_deps.items.len), |
| 159 | 158 | .system_integrations_len = @intCast(wip.system_integrations.items.len), |
| 160 | 159 | .available_options_len = @intCast(wip.available_options.items.len), |
| ... | ... | @@ -171,8 +170,7 @@ pub const Wip = struct { |
| 171 | 170 | @ptrCast(&header), |
| 172 | 171 | wip.string_bytes.items, |
| 173 | 172 | @ptrCast(wip.steps.items), |
| 174 | @ptrCast(wip.path_deps.items(.base)), | |
| 175 | @ptrCast(wip.path_deps.items(.sub)), | |
| 173 | @ptrCast(wip.path_deps.items), | |
| 176 | 174 | @ptrCast(wip.unlazy_deps.items), |
| 177 | 175 | @ptrCast(wip.system_integrations.items), |
| 178 | 176 | @ptrCast(wip.available_options.items), |
| ... | ... | @@ -1551,9 +1549,22 @@ pub const LazyPath = union(@This().Tag) { |
| 1551 | 1549 | |
| 1552 | 1550 | pub const Flags = packed struct(u32) { |
| 1553 | 1551 | tag: Tag = .relative, |
| 1554 | base: Path.Base, | |
| 1552 | base: Base, | |
| 1555 | 1553 | _: u16 = 0, |
| 1556 | 1554 | }; |
| 1555 | ||
| 1556 | pub const Base = enum(u8) { | |
| 1557 | cwd, | |
| 1558 | local_cache, | |
| 1559 | global_cache, | |
| 1560 | build_root, | |
| 1561 | zig_exe, | |
| 1562 | zig_lib, | |
| 1563 | install_prefix, | |
| 1564 | install_lib, | |
| 1565 | install_bin, | |
| 1566 | install_include, | |
| 1567 | }; | |
| 1557 | 1568 | }; |
| 1558 | 1569 | }; |
| 1559 | 1570 | |
| ... | ... | @@ -1597,6 +1608,26 @@ pub const Package = struct { |
| 1597 | 1608 | return package.dep_prefix.slice(c); |
| 1598 | 1609 | } |
| 1599 | 1610 | }; |
| 1611 | ||
| 1612 | pub const OptionalIndex = enum(u32) { | |
| 1613 | none = max_u32 - 1, | |
| 1614 | root = max_u32, | |
| 1615 | _, | |
| 1616 | ||
| 1617 | pub fn init(i: Index) OptionalIndex { | |
| 1618 | const result: OptionalIndex = @enumFromInt(@intFromEnum(i)); | |
| 1619 | assert(result != .none); | |
| 1620 | return result; | |
| 1621 | } | |
| 1622 | ||
| 1623 | pub fn unwrap(this: @This()) ?Index { | |
| 1624 | return switch (this) { | |
| 1625 | .none => null, | |
| 1626 | .root => .root, | |
| 1627 | _ => @enumFromInt(@intFromEnum(this)), | |
| 1628 | }; | |
| 1629 | } | |
| 1630 | }; | |
| 1600 | 1631 | }; |
| 1601 | 1632 | |
| 1602 | 1633 | pub const Module = struct { |
| ... | ... | @@ -1833,24 +1864,20 @@ pub const OptionalStringList = enum(u32) { |
| 1833 | 1864 | } |
| 1834 | 1865 | }; |
| 1835 | 1866 | |
| 1836 | pub const Path = extern struct { | |
| 1837 | base: Base, | |
| 1867 | pub const PathDep = extern struct { | |
| 1868 | flags: Flags, | |
| 1838 | 1869 | sub: String, |
| 1870 | pkg: Package.OptionalIndex, | |
| 1839 | 1871 | |
| 1840 | pub const Base = enum(u8) { | |
| 1841 | cwd, | |
| 1842 | local_cache, | |
| 1843 | global_cache, | |
| 1844 | build_root, | |
| 1845 | zig_exe, | |
| 1846 | zig_lib, | |
| 1847 | install_prefix, | |
| 1848 | install_lib, | |
| 1849 | install_bin, | |
| 1850 | install_include, | |
| 1872 | pub const Flags = packed struct(u32) { | |
| 1873 | mode: Mode, | |
| 1874 | base: LazyPath.Relative.Base, | |
| 1875 | _: u16 = 0, | |
| 1851 | 1876 | }; |
| 1852 | 1877 | |
| 1853 | pub fn toCachePath(path: Path, c: *const Configuration, arena: Allocator) std.Build.Cache.Path { | |
| 1878 | pub const Mode = enum(u8) { directory, contents, metadata }; | |
| 1879 | ||
| 1880 | pub fn toCachePath(path: PathDep, c: *const Configuration, arena: Allocator) std.Build.Cache.Path { | |
| 1854 | 1881 | _ = c; |
| 1855 | 1882 | _ = arena; |
| 1856 | 1883 | _ = path; |
| ... | ... | @@ -3430,8 +3457,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { |
| 3430 | 3457 | const result: Configuration = .{ |
| 3431 | 3458 | .string_bytes = try arena.alloc(u8, header.string_bytes_len), |
| 3432 | 3459 | .steps = try arena.alloc(Step, header.steps_len), |
| 3433 | .path_deps_sub = try arena.alloc(String, header.path_deps_len), | |
| 3434 | .path_deps_base = try arena.alloc(Path.Base, header.path_deps_len), | |
| 3460 | .path_deps = try arena.alloc(PathDep, header.path_deps_len), | |
| 3435 | 3461 | .unlazy_deps = try arena.alloc(String, header.unlazy_deps_len), |
| 3436 | 3462 | .system_integrations = try arena.alloc(SystemIntegration, header.system_integrations_len), |
| 3437 | 3463 | .available_options = try arena.alloc(AvailableOption, header.available_options_len), |
| ... | ... | @@ -3444,8 +3470,7 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { |
| 3444 | 3470 | var vecs = [_][]u8{ |
| 3445 | 3471 | result.string_bytes, |
| 3446 | 3472 | @ptrCast(result.steps), |
| 3447 | @ptrCast(result.path_deps_base), | |
| 3448 | @ptrCast(result.path_deps_sub), | |
| 3473 | @ptrCast(result.path_deps), | |
| 3449 | 3474 | @ptrCast(result.unlazy_deps), |
| 3450 | 3475 | @ptrCast(result.system_integrations), |
| 3451 | 3476 | @ptrCast(result.available_options), |
src/main.zig+35-29| ... | ... | @@ -5454,6 +5454,9 @@ fn cmdBuild( |
| 5454 | 5454 | } |
| 5455 | 5455 | defer Fork.deinitList(forks.items); |
| 5456 | 5456 | |
| 5457 | var file_system_inputs: std.ArrayList(u8) = .empty; | |
| 5458 | defer file_system_inputs.deinit(gpa); | |
| 5459 | ||
| 5457 | 5460 | // This loop is re-evaluated when the build script exits with an indication that it |
| 5458 | 5461 | // could not continue due to missing lazy dependencies. |
| 5459 | 5462 | const configuration_path: Path, const poisoned: bool = cp: while (true) { |
| ... | ... | @@ -5679,6 +5682,7 @@ fn cmdBuild( |
| 5679 | 5682 | |
| 5680 | 5683 | try root_mod.deps.put(arena, "@build", build_mod); |
| 5681 | 5684 | |
| 5685 | file_system_inputs.clearRetainingCapacity(); | |
| 5682 | 5686 | var create_diag: Compilation.CreateDiagnostic = undefined; |
| 5683 | 5687 | const comp = Compilation.create(gpa, arena, io, &create_diag, .{ |
| 5684 | 5688 | .libc_installation = libc_installation, |
| ... | ... | @@ -5702,6 +5706,7 @@ fn cmdBuild( |
| 5702 | 5706 | .reference_trace = reference_trace, |
| 5703 | 5707 | .debug_compile_errors = debug_compile_errors, |
| 5704 | 5708 | .environ_map = environ_map, |
| 5709 | .file_system_inputs = &file_system_inputs, | |
| 5705 | 5710 | }) catch |err| switch (err) { |
| 5706 | 5711 | error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}), |
| 5707 | 5712 | else => |e| fatal("failed to create compilation: {t}", .{e}), |
| ... | ... | @@ -5764,10 +5769,10 @@ fn cmdBuild( |
| 5764 | 5769 | .argv = configure_argv.items, |
| 5765 | 5770 | .stdout = .{ .file = config_tmp_file }, |
| 5766 | 5771 | .progress_node = child_node, |
| 5767 | }) catch |err| fatal("failed to spawn configure script {s}: {t}", .{ configure_argv.items[0], err }); | |
| 5772 | }) catch |err| fatal("failed to spawn configure script {q}: {t}", .{ configure_argv.items[0], err }); | |
| 5768 | 5773 | defer child.kill(io); |
| 5769 | 5774 | break :term child.wait(io) catch |err| |
| 5770 | fatal("failed to wait configure script {s}: {t}", .{ configure_argv.items[0], err }); | |
| 5775 | fatal("failed to wait configure script {q}: {t}", .{ configure_argv.items[0], err }); | |
| 5771 | 5776 | }; |
| 5772 | 5777 | if (!term.success()) { |
| 5773 | 5778 | // Failure to produce the configuration file. |
| ... | ... | @@ -5816,6 +5821,21 @@ fn cmdBuild( |
| 5816 | 5821 | try config_man.addPathPost(conf_path.toCachePath(&configuration, arena)); |
| 5817 | 5822 | } |
| 5818 | 5823 | |
| 5824 | // We need to add to the configuration cache the source files of | |
| 5825 | // configurer itself, so that the maker process can watch the file system | |
| 5826 | // for those changes and restart itself. By doing this, we make it | |
| 5827 | // possible to bypass creating a Compilation for configurer on | |
| 5828 | // Configuration cache hit. | |
| 5829 | { | |
| 5830 | var it = mem.splitScalar(u8, file_system_inputs.items, 0); | |
| 5831 | while (it.next()) |input| { | |
| 5832 | _ = try config_man.addPrefixedPathPost(.{ | |
| 5833 | .prefix = input[0], | |
| 5834 | .sub_path = input[1..], | |
| 5835 | }); | |
| 5836 | } | |
| 5837 | } | |
| 5838 | ||
| 5819 | 5839 | // If it is poisoned, there is no point in moving it to cached |
| 5820 | 5840 | // location. Just leave it in the tmp directory. |
| 5821 | 5841 | if (configuration.poisoned) { |
| ... | ... | @@ -6247,14 +6267,15 @@ fn jitCmdInner( |
| 6247 | 6267 | |
| 6248 | 6268 | child_argv.appendSliceAssumeCapacity(args); |
| 6249 | 6269 | |
| 6270 | if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map)) { | |
| 6271 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6272 | std.debug.print("{s}\n", .{cmd}); | |
| 6273 | } | |
| 6274 | ||
| 6250 | 6275 | if (process.can_replace and options.capture == null) { |
| 6251 | if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map)) { | |
| 6252 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6253 | std.debug.print("{s}\n", .{cmd}); | |
| 6254 | } | |
| 6255 | 6276 | const err = process.replace(io, .{ .argv = child_argv.items, .environ_map = environ_map }); |
| 6256 | 6277 | const cmd = try std.mem.join(arena, " ", child_argv.items); |
| 6257 | fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd }); | |
| 6278 | fatal("the following command failed to execve with {t}:\n{s}", .{ err, cmd }); | |
| 6258 | 6279 | } |
| 6259 | 6280 | |
| 6260 | 6281 | if (!process.can_spawn) { |
| ... | ... | @@ -6264,7 +6285,7 @@ fn jitCmdInner( |
| 6264 | 6285 | }); |
| 6265 | 6286 | } |
| 6266 | 6287 | |
| 6267 | switch (t: { | |
| 6288 | const term = t: { | |
| 6268 | 6289 | _ = try io.lockStderr(&.{}, .no_color); |
| 6269 | 6290 | defer io.unlockStderr(); |
| 6270 | 6291 | |
| ... | ... | @@ -6282,28 +6303,13 @@ fn jitCmdInner( |
| 6282 | 6303 | } |
| 6283 | 6304 | |
| 6284 | 6305 | break :t try child.wait(io); |
| 6285 | }) { | |
| 6286 | .exited => |code| { | |
| 6287 | if (code == 0) { | |
| 6288 | if (options.capture != null) return; | |
| 6289 | return cleanExit(io); | |
| 6290 | } | |
| 6291 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6292 | fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); | |
| 6293 | }, | |
| 6294 | .signal => |sig| { | |
| 6295 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6296 | fatal("the following build command terminated with signal {t}:\n{s}", .{ sig, cmd }); | |
| 6297 | }, | |
| 6298 | .stopped => |sig| { | |
| 6299 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6300 | fatal("the following build command stopped with signal {t}:\n{s}", .{ sig, cmd }); | |
| 6301 | }, | |
| 6302 | .unknown => { | |
| 6303 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6304 | fatal("the following build command crashed:\n{s}", .{cmd}); | |
| 6305 | }, | |
| 6306 | }; | |
| 6307 | if (term.success()) { | |
| 6308 | if (options.capture != null) return; | |
| 6309 | return cleanExit(io); | |
| 6306 | 6310 | } |
| 6311 | const cmd = try std.mem.join(arena, " ", child_argv.items); | |
| 6312 | fatal("the following build command {f}:\n{s}", .{ term, cmd }); | |
| 6307 | 6313 | } |
| 6308 | 6314 | |
| 6309 | 6315 | const info_zen = |
test/src/Cases.zig+17-10| ... | ... | @@ -316,20 +316,19 @@ pub fn addCompile( |
| 316 | 316 | /// Each file should include a test manifest as a contiguous block of comments at |
| 317 | 317 | /// the end of the file. The first line should be the test type, followed by a set of |
| 318 | 318 | /// key-value config values, followed by a blank line, then the expected output. |
| 319 | pub fn addFromDir(ctx: *Cases, dir: Io.Dir, b: *std.Build) void { | |
| 319 | pub fn addFromDir(ctx: *Cases, dir: Io.Dir, path_from_root: []const u8, b: *std.Build) void { | |
| 320 | 320 | var current_file: []const u8 = "none"; |
| 321 | ctx.addFromDirInner(dir, &current_file, b) catch |err| { | |
| 322 | std.debug.panicExtra( | |
| 323 | @returnAddress(), | |
| 324 | "test harness failed to process file '{s}': {s}\n", | |
| 325 | .{ current_file, @errorName(err) }, | |
| 326 | ); | |
| 321 | ctx.addFromDirInner(dir, path_from_root, &current_file, b) catch |err| { | |
| 322 | std.debug.panicExtra(@returnAddress(), "test harness failed to process file {q}: {t}\n", .{ | |
| 323 | current_file, err, | |
| 324 | }); | |
| 327 | 325 | }; |
| 328 | 326 | } |
| 329 | 327 | |
| 330 | 328 | fn addFromDirInner( |
| 331 | 329 | ctx: *Cases, |
| 332 | 330 | iterable_dir: Io.Dir, |
| 331 | path_from_root: []const u8, | |
| 333 | 332 | /// This is kept up to date with the currently being processed file so |
| 334 | 333 | /// that if any errors occur the caller knows it happened during this file. |
| 335 | 334 | current_file: *[]const u8, |
| ... | ... | @@ -340,11 +339,19 @@ fn addFromDirInner( |
| 340 | 339 | var filenames: ArrayList([]const u8) = .empty; |
| 341 | 340 | |
| 342 | 341 | while (try it.next(io)) |entry| { |
| 343 | if (entry.kind != .file) continue; | |
| 344 | ||
| 345 | 342 | // Ignore stuff such as .swp files |
| 346 | 343 | if (!knownFileExtension(entry.basename)) continue; |
| 347 | try filenames.append(ctx.arena, try ctx.arena.dupe(u8, entry.path)); | |
| 344 | ||
| 345 | switch (entry.kind) { | |
| 346 | .file => { | |
| 347 | b.dependOnFileContents(b.path(b.pathJoin(&.{ path_from_root, entry.path }))); | |
| 348 | try filenames.append(ctx.arena, try ctx.arena.dupe(u8, entry.path)); | |
| 349 | }, | |
| 350 | .directory => { | |
| 351 | b.dependOnDirectory(b.path(b.pathJoin(&.{ path_from_root, entry.path }))); | |
| 352 | }, | |
| 353 | else => continue, | |
| 354 | } | |
| 348 | 355 | } |
| 349 | 356 | |
| 350 | 357 | for (filenames.items) |filename| { |
test/tests.zig+12-8| ... | ... | @@ -3258,14 +3258,12 @@ pub fn addCases( |
| 3258 | 3258 | |
| 3259 | 3259 | var cases = @import("src/Cases.zig").init(gpa, arena, io); |
| 3260 | 3260 | |
| 3261 | // Ensure changes to these files get picked up | |
| 3262 | // https://codeberg.org/ziglang/zig/issues/35473 | |
| 3263 | b.graph.poisonCache(); | |
| 3261 | b.dependOnDirectory(b.path("test/cases")); | |
| 3264 | 3262 | |
| 3265 | 3263 | var dir = try b.root.openDir(io, "test/cases", .{ .iterate = true }); |
| 3266 | 3264 | defer dir.close(io); |
| 3267 | 3265 | |
| 3268 | cases.addFromDir(dir, b); | |
| 3266 | cases.addFromDir(dir, "test/cases", b); | |
| 3269 | 3267 | try @import("cases.zig").addCases(&cases, build_options, b); |
| 3270 | 3268 | |
| 3271 | 3269 | cases.lowerToBuildSteps( |
| ... | ... | @@ -3320,22 +3318,28 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons |
| 3320 | 3318 | }), |
| 3321 | 3319 | }); |
| 3322 | 3320 | |
| 3323 | // Ensure changes to these files get picked up | |
| 3324 | // https://codeberg.org/ziglang/zig/issues/35473 | |
| 3325 | b.graph.poisonCache(); | |
| 3321 | b.dependOnDirectory(b.path("test/incremental")); | |
| 3326 | 3322 | |
| 3327 | 3323 | var dir = try b.root.openDir(io, "test/incremental", .{ .iterate = true }); |
| 3328 | 3324 | defer dir.close(io); |
| 3329 | 3325 | |
| 3330 | 3326 | var it = try dir.walk(b.graph.arena); |
| 3331 | 3327 | while (try it.next(io)) |entry| { |
| 3332 | if (entry.kind != .file) continue; | |
| 3333 | 3328 | if (std.mem.endsWith(u8, entry.basename, ".swp")) continue; |
| 3334 | 3329 | |
| 3335 | 3330 | for (test_filters) |test_filter| { |
| 3336 | 3331 | if (std.mem.indexOf(u8, entry.path, test_filter)) |_| break; |
| 3337 | 3332 | } else if (test_filters.len > 0) continue; |
| 3338 | 3333 | |
| 3334 | switch (entry.kind) { | |
| 3335 | .file => {}, | |
| 3336 | .directory => { | |
| 3337 | b.dependOnDirectory(b.path(b.pathJoin(&.{ "test", "incremental", entry.path }))); | |
| 3338 | }, | |
| 3339 | else => continue, | |
| 3340 | } | |
| 3341 | b.dependOnFileContents(b.path(b.pathJoin(&.{ "test", "incremental", entry.path }))); | |
| 3342 | ||
| 3339 | 3343 | for (incremental_targets) |target_str| { |
| 3340 | 3344 | const run = b.addRunArtifact(incr_check); |
| 3341 | 3345 | run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename })); |