╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ update-linux-headers.zig ─────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
200 error.AccessDenied => continue :search, 201 else => return err, 202 }; 203 defer dir.close(io); 204 205 var dir_it = dir.iterate(); 206 207 while (try dir_it.next(io)) |entry| { 208 const full_path = try Dir.path.join(arena, &[_][]const u8{ full_dir_name, entry.name }); 209 switch (entry.kind) { 210 .directory => try dir_stack.append(full_path), 211 .file => { 212 const rel_path = try Dir.path.relative(arena, cwd, environ_map, target_include_dir, full_path); 213 const max_size = 2 * 1024 * 1024 * 1024; 214 const raw_bytes = try Dir.cwd().readFileAlloc(io, full_path, arena, .limited(max_size)); 215 const trimmed = std.mem.trim(u8, raw_bytes, " \r\n\t"); 216 total_bytes += raw_bytes.len; 217 const hash = try arena.alloc(u8, 32); 218 hasher = Blake3.init(.{}); 219 hasher.update(rel_path); 220 hasher.update(trimmed); 221 hasher.final(hash); 222 const gop = try hash_to_contents.getOrPut(hash); 223 if (gop.found_existing) { 224 max_bytes_saved += raw_bytes.len; 225 gop.value_ptr.hit_count += 1; 226 std.debug.print("duplicate: {s} {s} ({B})\n", .{ 227 linux_target.name, 228 rel_path, 229 raw_bytes.len, 230 }); 231 } else { 232 gop.value_ptr.* = Contents{ 233 .bytes = trimmed, 234 .hit_count = 1, 235 .hash = hash, 236 .is_generic = false, 237 }; 238 } 239 const path_gop = try path_table.getOrPut(rel_path); 240 const target_to_hash = if (path_gop.found_existing) path_gop.value_ptr.* else blk: { 241 const ptr = try arena.create(TargetToHash); 242 ptr.* = .empty; 243 path_gop.value_ptr.* = ptr; 244 break :blk ptr; 245 }; 246 try target_to_hash.putNoClobber(arena, dest_target, hash); 247 }, 248 else => std.debug.print("warning: weird file: {s}\n", .{full_path}), 249 } 250 } 251 } 252 break; 253 } else { 254 std.debug.print("warning: libc target not found: {s}\n", .{linux_target.name}); 255 } 256 } 257 std.debug.print("summary: {B} could be reduced to {B}\n", .{ 258 total_bytes, 259 total_bytes - max_bytes_saved, 260 }); 261 try Dir.cwd().createDirPath(io, out_dir); 262 263 var missed_opportunity_bytes: usize = 0; 264 // iterate path_table. for each path, put all the hashes into a list. sort by hit_count. 265 // the hash with the highest hit_count gets to be the "generic" one. everybody else 266 // gets their header in a separate arch directory. 267 var path_it = path_table.iterator(); 268 while (path_it.next()) |path_kv| { 269 var contents_list = std.array_list.Managed(*Contents).init(arena); 270 { 271 var hash_it = path_kv.value_ptr.*.iterator(); 272 while (hash_it.next()) |hash_kv| { 273 const contents = hash_to_contents.getPtr(hash_kv.value_ptr.*).?; 274 try contents_list.append(contents); 275 } 276 } 277 std.mem.sort(*Contents, contents_list.items, {}, Contents.hitCountLessThan); 278 const best_contents = contents_list.pop().?; 279 if (best_contents.hit_count > 1) { 280 // worth it to make it generic 281 const full_path = try Dir.path.join(arena, &[_][]const u8{ out_dir, generic_name, path_kv.key_ptr.* }); 282 try Dir.cwd().createDirPath(io, Dir.path.dirname(full_path).?); 283 try Dir.cwd().writeFile(io, .{ .sub_path = full_path, .data = best_contents.bytes }); 284 best_contents.is_generic = true; 285 while (contents_list.pop()) |contender| { 286 if (contender.hit_count > 1) { 287 const this_missed_bytes = contender.hit_count * contender.bytes.len; 288 missed_opportunity_bytes += this_missed_bytes; 289 std.debug.print("Missed opportunity ({B}): {s}\n", .{ 290 this_missed_bytes, 291 path_kv.key_ptr.*, 292 }); 293 } else break; 294 } 295 } 296 var hash_it = path_kv.value_ptr.*.iterator(); 297 while (hash_it.next()) |hash_kv| { 298 const contents = hash_to_contents.get(hash_kv.value_ptr.*).?; 299 if (contents.is_generic) continue; 300 301 const dest_target = hash_kv.key_ptr.*; 302 const arch_name = switch (dest_target.arch) { 303 .specific => |a| @tagName(a), 304 else => @tagName(dest_target.arch), 305 }; 306 const out_subpath = try std.fmt.allocPrint(arena, "{s}-linux-any", .{arch_name}); 307 const full_path = try Dir.path.join(arena, &[_][]const u8{ out_dir, out_subpath, path_kv.key_ptr.* }); 308 try Dir.cwd().createDirPath(io, Dir.path.dirname(full_path).?); 309 try Dir.cwd().writeFile(io, .{ .sub_path = full_path, .data = contents.bytes }); 310 } 311 } 312 313 const bad_files = [_][]const u8{ 314 "any-linux-any/linux/netfilter/xt_CONNMARK.h", 315 "any-linux-any/linux/netfilter/xt_DSCP.h", 316 "any-linux-any/linux/netfilter/xt_MARK.h", 317 "any-linux-any/linux/netfilter/xt_RATEEST.h", 318 "any-linux-any/linux/netfilter/xt_TCPMSS.h", 319 "any-linux-any/linux/netfilter_ipv4/ipt_ECN.h", 320 "any-linux-any/linux/netfilter_ipv4/ipt_TTL.h", 321 "any-linux-any/linux/netfilter_ipv6/ip6t_HL.h", 322 }; 323 for (bad_files) |bad_file| { 324 const full_path = try Dir.path.join(arena, &[_][]const u8{ out_dir, bad_file }); 325 try Dir.cwd().deleteFile(io, full_path); 326 } 327 } 328 329 fn usageAndExit(arg0: []const u8) noreturn { 330 std.debug.print("Usage: {s} [--search-path <dir>] --out <dir> --abi <name>\n", .{arg0}); 331 std.debug.print("--search-path can be used any number of times.\n", .{}); 332 std.debug.print(" subdirectories of search paths look like, e.g. x86_64-linux-gnu\n", .{}); 333 std.debug.print("--out is a dir that will be created, and populated with the results\n", .{}); 334 std.process.exit(1); 335 } 336