authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-03 19:19:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-04 17:42:22-07:00
log1c31826ef78783918c9af9a2608895b786d004a4
treeb2cb04ffd25b2d4831f1385c06677be5cf9d7ddb
parent61e2e70b1e8c3e3ee9b6f524187c4453308f98f5

std.Build.Cache: fix adding files

no longer adding unwanted padding bytes

3 files changed, 41 insertions(+), 47 deletions(-)

lib/std/Build.zig+8-4
...@@ -58,7 +58,8 @@ available_deps: AvailableDeps,...@@ -58,7 +58,8 @@ available_deps: AvailableDeps,
5858
59pub const ConfigureDependency = struct {59pub const ConfigureDependency = struct {
60 lazy_path: LazyPath,60 lazy_path: LazyPath,
61 mode: std.Build.Configuration.PathDep.Mode,61 is_directory: bool,
62 metadata_only: bool,
62};63};
6364
64pub const ReleaseMode = enum {65pub const ReleaseMode = enum {
...@@ -102,7 +103,8 @@ pub const Graph = struct {...@@ -102,7 +103,8 @@ pub const Graph = struct {
102 /// Populated by calling one of:103 /// Populated by calling one of:
103 /// * `dependOnFileContents`104 /// * `dependOnFileContents`
104 /// * `dependOnFileMetadata`105 /// * `dependOnFileMetadata`
105 /// * `dependOnDirectory`106 /// * `dependOnDirectoryContents`
107 /// * `dependOnDirectoryMetadata`
106 configure_dependencies: ArrayList(ConfigureDependency) = .empty,108 configure_dependencies: ArrayList(ConfigureDependency) = .empty,
107109
108 /// If the cache is poisoned means that the **configure logic** had side110 /// If the cache is poisoned means that the **configure logic** had side
...@@ -2602,7 +2604,8 @@ pub fn dependOnFileContents(b: *Build, lazy_path: LazyPath) void {...@@ -2602,7 +2604,8 @@ pub fn dependOnFileContents(b: *Build, lazy_path: LazyPath) void {
2602 const graph = b.graph;2604 const graph = b.graph;
2603 graph.configure_dependencies.append(graph.arena, .{2605 graph.configure_dependencies.append(graph.arena, .{
2604 .lazy_path = lazy_path.dupe(graph),2606 .lazy_path = lazy_path.dupe(graph),
2605 .mode = .contents,2607 .is_directory = false,
2608 .metadata_only = false,
2606 }) catch @panic("OOM");2609 }) catch @panic("OOM");
2607}2610}
26082611
...@@ -2627,7 +2630,8 @@ pub fn dependOnFileMetadata(b: *Build, lazy_path: LazyPath) void {...@@ -2627,7 +2630,8 @@ pub fn dependOnFileMetadata(b: *Build, lazy_path: LazyPath) void {
2627 const graph = b.graph;2630 const graph = b.graph;
2628 graph.configure_dependencies.append(graph.arena, .{2631 graph.configure_dependencies.append(graph.arena, .{
2629 .lazy_path = lazy_path.dupe(graph),2632 .lazy_path = lazy_path.dupe(graph),
2630 .mode = .metadata,2633 .is_directory = false,
2634 .metadata_only = true,
2631 }) catch @panic("OOM");2635 }) catch @panic("OOM");
2632}2636}
26332637
lib/std/Build/Cache.zig+31-42
...@@ -363,9 +363,9 @@ pub const Manifest = struct {...@@ -363,9 +363,9 @@ pub const Manifest = struct {
363 pub const File = extern struct {363 pub const File = extern struct {
364 size: u64,364 size: u64,
365 inode: u64,365 inode: u64,
366 digest: BinDigest,
367 /// Nanoseconds.366 /// Nanoseconds.
368 mtime: i64,367 mtime: i64,
368 digest: BinDigest,
369 /// Starting with this field and continuing into the path, excluding the null byte,369 /// Starting with this field and continuing into the path, excluding the null byte,
370 /// is the string that is hashed for the manifest digest.370 /// is the string that is hashed for the manifest digest.
371 flags: Flags,371 flags: Flags,
...@@ -546,35 +546,29 @@ pub const Manifest = struct {...@@ -546,35 +546,29 @@ pub const Manifest = struct {
546 pub fn addInputPath(m: *Manifest, path: Path, options: AddInputPathOptions) Allocator.Error!InputPath.Index {546 pub fn addInputPath(m: *Manifest, path: Path, options: AddInputPathOptions) Allocator.Error!InputPath.Index {
547 const cache = m.cache;547 const cache = m.cache;
548 const gpa = cache.gpa;548 const gpa = cache.gpa;
549 const is_directory = options.handle.isDirectory();
550
549 try m.files.ensureUnusedCapacityContext(gpa, 1, .{ .contents = m.contents.items });551 try m.files.ensureUnusedCapacityContext(gpa, 1, .{ .contents = m.contents.items });
550 try m.input_paths.ensureUnusedCapacity(gpa, 1);552 try m.input_paths.ensureUnusedCapacity(gpa, 1);
551553
552 const prev_contents_len = m.contents.items.len;554 const new_file_offset: File.Offset = @fromBackingInt(@intCast(m.contents.items.len));
553 const header: *File = @ptrCast(@alignCast(try m.contents.addManyAsSlice(gpa, @sizeOf(File))));555 try m.contents.appendNTimes(gpa, 0, @offsetOf(File, "path_start"));
554 errdefer m.contents.shrinkRetainingCapacity(prev_contents_len);556 errdefer m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));
555557
556 header.* = .{558 const new_prefix = try cache.resolveAppendPath(&m.contents, path);
557 .flags = .{
558 .prefix = try cache.resolveAppendPath(&m.contents, path),
559 .is_directory = options.handle.isDirectory(),
560 .metadata_only = options.metadata_only,
561 },
562 .size = undefined,
563 .inode = undefined,
564 .mtime = undefined,
565 .digest = undefined,
566 .path_start = .{},
567 };
568 assert(mem.isAligned(m.contents.items.len, @alignOf(File)));559 assert(mem.isAligned(m.contents.items.len, @alignOf(File)));
560 new_file_offset.get(m.contents.items).flags = .{
561 .prefix = new_prefix,
562 .is_directory = is_directory,
563 .metadata_only = options.metadata_only,
564 };
569565
570 const gop = m.files.getOrPutAssumeCapacityContext(@fromBackingInt(@intCast(prev_contents_len)), .{566 const gop = m.files.getOrPutAssumeCapacityContext(new_file_offset, .{ .contents = m.contents.items });
571 .contents = m.contents.items,
572 });
573 m.files.lockPointers();567 m.files.lockPointers();
574 defer m.files.unlockPointers();568 defer m.files.unlockPointers();
575569
576 if (gop.found_existing) {570 if (gop.found_existing) {
577 m.contents.shrinkRetainingCapacity(prev_contents_len);571 m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));
578 const existing_input_file = &m.input_paths.items[gop.index];572 const existing_input_file = &m.input_paths.items[gop.index];
579 switch (options.handle) {573 switch (options.handle) {
580 .file => |opt_file| if (opt_file) |file| {574 .file => |opt_file| if (opt_file) |file| {
...@@ -600,7 +594,7 @@ pub const Manifest = struct {...@@ -600,7 +594,7 @@ pub const Manifest = struct {
600 // If it trips, the same file path has been added to the cache594 // If it trips, the same file path has been added to the cache
601 // manifest both as a directory and as a normal file, making the595 // manifest both as a directory and as a normal file, making the
602 // intended caching behavior ambiguous.596 // intended caching behavior ambiguous.
603 assert(existing_header.flags.is_directory == options.handle.isDirectory());597 assert(existing_header.flags.is_directory == is_directory);
604 if (!options.metadata_only)598 if (!options.metadata_only)
605 existing_header.flags.metadata_only = false;599 existing_header.flags.metadata_only = false;
606 } else {600 } else {
...@@ -617,6 +611,7 @@ pub const Manifest = struct {...@@ -617,6 +611,7 @@ pub const Manifest = struct {
617 });611 });
618 assert(m.input_paths.items.len - 1 == gop.index);612 assert(m.input_paths.items.len - 1 == gop.index);
619 if (options.stat) |stat| {613 if (options.stat) |stat| {
614 const header = new_file_offset.get(m.contents.items);
620 header.size = stat.size;615 header.size = stat.size;
621 header.inode = stat.inode;616 header.inode = stat.inode;
622 header.mtime = @intCast(stat.mtime.toNanoseconds());617 header.mtime = @intCast(stat.mtime.toNanoseconds());
...@@ -1134,33 +1129,25 @@ pub const Manifest = struct {...@@ -1134,33 +1129,25 @@ pub const Manifest = struct {
1134 try m.files.ensureUnusedCapacityContext(gpa, 1, .{ .contents = m.contents.items });1129 try m.files.ensureUnusedCapacityContext(gpa, 1, .{ .contents = m.contents.items });
11351130
1136 const new_file_offset: File.Offset = @fromBackingInt(@intCast(m.contents.items.len));1131 const new_file_offset: File.Offset = @fromBackingInt(@intCast(m.contents.items.len));
1137 const new_header: *File = @ptrCast(@alignCast(try m.contents.addManyAsSlice(gpa, @sizeOf(File))));1132 try m.contents.appendNTimes(gpa, 0, @offsetOf(File, "path_start"));
1138 errdefer m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));1133 errdefer m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));
11391134
1140 new_header.* = .{1135 const new_prefix = switch (options.path) {
1141 .flags = .{1136 .unresolved => |unresolved| try cache.resolveAppendPath(&m.contents, unresolved),
1142 .prefix = switch (options.path) {1137 .prefixed => |prefixed| try cache.appendPrefixedPath(&m.contents, prefixed),
1143 .unresolved => |unresolved| try cache.resolveAppendPath(&m.contents, unresolved),
1144 .prefixed => |prefixed| try cache.appendPrefixedPath(&m.contents, prefixed),
1145 },
1146 .is_directory = is_directory,
1147 .metadata_only = options.metadata_only,
1148 },
1149 .size = undefined,
1150 .inode = undefined,
1151 .mtime = undefined,
1152 .digest = @splat(0),
1153 .path_start = .{},
1154 };1138 };
1155 assert(mem.isAligned(m.contents.items.len, @alignOf(File)));1139 assert(mem.isAligned(m.contents.items.len, @alignOf(File)));
1140 new_file_offset.get(m.contents.items).flags = .{
1141 .prefix = new_prefix,
1142 .is_directory = is_directory,
1143 .metadata_only = options.metadata_only,
1144 };
11561145
1157 const gop = m.files.getOrPutAssumeCapacityContext(new_file_offset, .{1146 const gop = m.files.getOrPutAssumeCapacityContext(new_file_offset, .{ .contents = m.contents.items });
1158 .contents = m.contents.items,
1159 });
1160 m.files.lockPointers();1147 m.files.lockPointers();
1161 defer m.files.unlockPointers();1148 defer m.files.unlockPointers();
11621149
1163 const header, const file_offset = if (gop.found_existing) h: {1150 const file_offset = if (gop.found_existing) h: {
1164 m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));1151 m.contents.shrinkRetainingCapacity(@backingInt(new_file_offset));
1165 const existing_off = gop.key_ptr.*;1152 const existing_off = gop.key_ptr.*;
1166 const header = existing_off.get(m.contents.items);1153 const header = existing_off.get(m.contents.items);
...@@ -1170,8 +1157,10 @@ pub const Manifest = struct {...@@ -1170,8 +1157,10 @@ pub const Manifest = struct {
1170 assert(header.flags.is_directory == is_directory);1157 assert(header.flags.is_directory == is_directory);
1171 if (!options.metadata_only)1158 if (!options.metadata_only)
1172 header.flags.metadata_only = false;1159 header.flags.metadata_only = false;
1173 break :h .{ header, existing_off };1160 break :h existing_off;
1174 } else .{ new_header, new_file_offset };1161 } else new_file_offset;
1162
1163 const header = file_offset.get(m.contents.items);
11751164
1176 if (options.stat) |stat| {1165 if (options.stat) |stat| {
1177 try header.setStat(m, stat);1166 try header.setStat(m, stat);
lib/std/Build/Serialize.zig+2-1
...@@ -34,7 +34,8 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi...@@ -34,7 +34,8 @@ pub fn write(b: *std.Build, wc: *Configuration.Wip, writer: *std.Io.Writer) !voi
34 .cwd_relative => .cwd,34 .cwd_relative => .cwd,
35 .relative => |r| r.base,35 .relative => |r| r.base,
36 },36 },
37 .mode = src.mode,37 .is_directory = src.is_directory,
38 .metadata_only = src.metadata_only,
38 },39 },
39 .sub = switch (src.lazy_path) {40 .sub = switch (src.lazy_path) {
40 .src_path => |sp| try wc.addString(sp.sub_path),41 .src_path => |sp| try wc.addString(sp.sub_path),