╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ fetch_them_macos_headers.zig ─────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
130 const macos_version = try std.fmt.allocPrint(arena, "-mmacosx-version-min={d}.{d}", .{ 131 ver.major, 132 ver.minor, 133 }); 134 135 var cc_argv = std.array_list.Managed([]const u8).init(arena); 136 try cc_argv.appendSlice(&[_][]const u8{ 137 "cc", 138 "-arch", 139 switch (target.arch) { 140 .x86_64 => "x86_64", 141 .aarch64 => "arm64", 142 }, 143 macos_version, 144 "-isysroot", 145 sysroot, 146 "-iwithsysroot", 147 "/usr/include", 148 "-o", 149 tmp_file_path, 150 "macos-headers.c", 151 "-MD", 152 "-MV", 153 "-MF", 154 headers_list_path, 155 }); 156 try cc_argv.appendSlice(args); 157 158 const res = try std.process.run(arena, io, .{ .argv = cc_argv.items }); 159 160 if (res.stderr.len != 0) { 161 std.log.err("{s}", .{res.stderr}); 162 } 163 164 // Read in the contents of `macos-headers.o.d` 165 const headers_list_file = try tmp_dir.openFile(io, headers_list_filename, .{}); 166 defer headers_list_file.close(io); 167 168 var headers_dir = Dir.cwd().openDir(io, headers_source_prefix, .{}) catch |err| switch (err) { 169 error.FileNotFound, 170 error.NotDir, 171 => fatal("path '{s}' not found or not a directory. Did you accidentally delete it?", .{ 172 headers_source_prefix, 173 }), 174 else => return err, 175 }; 176 defer headers_dir.close(io); 177 178 const dest_path = try target.fullName(arena); 179 try headers_dir.deleteTree(io, dest_path); 180 181 var dest_dir = try headers_dir.createDirPathOpen(io, dest_path, .{}); 182 var dirs = std.StringHashMap(Dir).init(arena); 183 try dirs.putNoClobber(".", dest_dir); 184 185 var headers_list_file_reader = headers_list_file.reader(io, &.{}); 186 const headers_list_str = try headers_list_file_reader.interface.allocRemaining(arena, .unlimited); 187 const prefix = "/usr/include"; 188 189 var it = mem.splitScalar(u8, headers_list_str, '\n'); 190 while (it.next()) |line| { 191 if (mem.findLast(u8, line, "clang") != null) continue; 192 if (mem.findLast(u8, line, prefix[0..])) |idx| { 193 const out_rel_path = line[idx + prefix.len + 1 ..]; 194 const out_rel_path_stripped = mem.trim(u8, out_rel_path, " \\"); 195 const dirname = Dir.path.dirname(out_rel_path_stripped) orelse "."; 196 const maybe_dir = try dirs.getOrPut(dirname); 197 if (!maybe_dir.found_existing) { 198 maybe_dir.value_ptr.* = try dest_dir.createDirPathOpen(io, dirname, .{}); 199 } 200 const basename = Dir.path.basename(out_rel_path_stripped); 201 202 const line_stripped = mem.trim(u8, line, " \\"); 203 const abs_dirname = Dir.path.dirname(line_stripped).?; 204 var orig_subdir = try Dir.cwd().openDir(io, abs_dirname, .{}); 205 defer orig_subdir.close(io); 206 207 try orig_subdir.copyFile(basename, maybe_dir.value_ptr.*, basename, io, .{}); 208 } 209 } 210 211 var dir_it = dirs.iterator(); 212 while (dir_it.next()) |entry| { 213 entry.value_ptr.close(io); 214 } 215 } 216 217 const ArgsIterator = struct { 218 args: []const []const u8, 219 i: usize = 0, 220 221 fn next(it: *@This()) ?[]const u8 { 222 if (it.i >= it.args.len) { 223 return null; 224 } 225 defer it.i += 1; 226 return it.args[it.i]; 227 } 228 229 fn nextOrFatal(it: *@This()) []const u8 { 230 const arg = it.next() orelse fatal("expected parameter after '{s}'", .{it.args[it.i - 1]}); 231 return arg; 232 } 233 }; 234 235 const Version = struct { 236 major: u16, 237 minor: u8, 238 patch: u8, 239 240 fn parse(raw: []const u8) ?Version { 241 var parsed: [3]u16 = @splat(0); 242 var count: usize = 0; 243 var it = std.mem.splitAny(u8, raw, "."); 244 while (it.next()) |comp| { 245 if (count >= 3) return null; 246 parsed[count] = std.fmt.parseInt(u16, comp, 10) catch return null; 247 count += 1; 248 } 249 if (count == 0) return null; 250 const major = parsed[0]; 251 const minor = std.math.cast(u8, parsed[1]) orelse return null; 252 const patch = std.math.cast(u8, parsed[2]) orelse return null; 253 return .{ .major = major, .minor = minor, .patch = patch }; 254 } 255 256 pub fn format( 257 v: Version, 258 writer: *Io.Writer, 259 ) Io.Writer.Error!void { 260 try writer.print("{d}.{d}.{d}", .{ v.major, v.minor, v.patch }); 261 } 262 }; 263