| ... | @@ -1,5 +1,4 @@ | ... | @@ -1,5 +1,4 @@ |
| 1 | base: File, | 1 | base: File, |
| 2 | entry_name: ?[]const u8, | | |
| 3 | | 2 | |
| 4 | /// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. | 3 | /// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. |
| 5 | llvm_object: ?*LlvmObject = null, | 4 | llvm_object: ?*LlvmObject = null, |
| ... | @@ -47,9 +46,9 @@ atoms: std.ArrayListUnmanaged(Atom) = .{}, | ... | @@ -47,9 +46,9 @@ atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 47 | | 46 | |
| 48 | sdk_layout: ?SdkLayout, | 47 | sdk_layout: ?SdkLayout, |
| 49 | /// Size of the __PAGEZERO segment. | 48 | /// Size of the __PAGEZERO segment. |
| 50 | pagezero_vmsize: u64, | 49 | pagezero_vmsize: ?u64, |
| 51 | /// Minimum space for future expansion of the load commands. | 50 | /// Minimum space for future expansion of the load commands. |
| 52 | headerpad_size: u32, | 51 | headerpad_size: ?u32, |
| 53 | /// Set enough space as if all paths were MATPATHLEN. | 52 | /// Set enough space as if all paths were MATPATHLEN. |
| 54 | headerpad_max_install_names: bool, | 53 | headerpad_max_install_names: bool, |
| 55 | /// Remove dylibs that are unreachable by the entry point or exported symbols. | 54 | /// Remove dylibs that are unreachable by the entry point or exported symbols. |
| ... | @@ -61,6 +60,8 @@ install_name: ?[]const u8, | ... | @@ -61,6 +60,8 @@ install_name: ?[]const u8, |
| 61 | /// Path to entitlements file. | 60 | /// Path to entitlements file. |
| 62 | entitlements: ?[]const u8, | 61 | entitlements: ?[]const u8, |
| 63 | compatibility_version: ?std.SemanticVersion, | 62 | compatibility_version: ?std.SemanticVersion, |
| | 63 | /// Entry name |
| | 64 | entry_name: ?[]const u8, |
| 64 | | 65 | |
| 65 | /// Hot-code swapping state. | 66 | /// Hot-code swapping state. |
| 66 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, | 67 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, |
| ... | @@ -128,8 +129,8 @@ pub fn createEmpty( | ... | @@ -128,8 +129,8 @@ pub fn createEmpty( |
| 128 | .build_id = options.build_id, | 129 | .build_id = options.build_id, |
| 129 | .rpath_list = options.rpath_list, | 130 | .rpath_list = options.rpath_list, |
| 130 | }, | 131 | }, |
| 131 | .pagezero_vmsize = options.pagezero_size orelse default_pagezero_vmsize, | 132 | .pagezero_vmsize = options.pagezero_size, |
| 132 | .headerpad_size = options.headerpad_size orelse default_headerpad_size, | 133 | .headerpad_size = options.headerpad_size, |
| 133 | .headerpad_max_install_names = options.headerpad_max_install_names, | 134 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 134 | .dead_strip_dylibs = options.dead_strip_dylibs, | 135 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 135 | .sdk_layout = options.darwin_sdk_layout, | 136 | .sdk_layout = options.darwin_sdk_layout, |
| ... | @@ -249,9 +250,173 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -249,9 +250,173 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 249 | | 250 | |
| 250 | /// --verbose-link output | 251 | /// --verbose-link output |
| 251 | fn dumpArgv(self: *MachO, comp: *Compilation) !void { | 252 | fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 252 | _ = self; | 253 | const gpa = self.base.comp.gpa; |
| 253 | _ = comp; | 254 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| 254 | @panic("TODO dumpArgv"); | 255 | defer arena_allocator.deinit(); |
| | 256 | const arena = arena_allocator.allocator(); |
| | 257 | |
| | 258 | const target = self.base.comp.root_mod.resolved_target.result; |
| | 259 | const directory = self.base.emit.directory; |
| | 260 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); |
| | 261 | const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { |
| | 262 | if (fs.path.dirname(full_out_path)) |dirname| { |
| | 263 | break :blk try fs.path.join(arena, &.{ dirname, path }); |
| | 264 | } else { |
| | 265 | break :blk path; |
| | 266 | } |
| | 267 | } else null; |
| | 268 | |
| | 269 | var argv = std.ArrayList([]const u8).init(arena); |
| | 270 | |
| | 271 | try argv.append("zig"); |
| | 272 | |
| | 273 | if (self.base.isStaticLib()) { |
| | 274 | try argv.append("ar"); |
| | 275 | } else { |
| | 276 | try argv.append("ld"); |
| | 277 | } |
| | 278 | |
| | 279 | if (self.base.isObject()) { |
| | 280 | try argv.append("-r"); |
| | 281 | } |
| | 282 | |
| | 283 | try argv.append("-o"); |
| | 284 | try argv.append(full_out_path); |
| | 285 | |
| | 286 | if (self.base.isRelocatable()) { |
| | 287 | for (comp.objects) |obj| { |
| | 288 | try argv.append(obj.path); |
| | 289 | } |
| | 290 | |
| | 291 | for (comp.c_object_table.keys()) |key| { |
| | 292 | try argv.append(key.status.success.object_path); |
| | 293 | } |
| | 294 | |
| | 295 | if (module_obj_path) |p| { |
| | 296 | try argv.append(p); |
| | 297 | } |
| | 298 | } else { |
| | 299 | if (!self.base.isStatic()) { |
| | 300 | try argv.append("-dynamic"); |
| | 301 | } |
| | 302 | |
| | 303 | if (self.base.isDynLib()) { |
| | 304 | try argv.append("-dylib"); |
| | 305 | |
| | 306 | if (self.install_name) |install_name| { |
| | 307 | try argv.append("-install_name"); |
| | 308 | try argv.append(install_name); |
| | 309 | } |
| | 310 | } |
| | 311 | |
| | 312 | { |
| | 313 | const platform = Platform.fromTarget(target); |
| | 314 | try argv.append("-platform_version"); |
| | 315 | try argv.append(@tagName(platform.os_tag)); |
| | 316 | try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version})); |
| | 317 | |
| | 318 | const sdk_version: ?std.SemanticVersion = self.inferSdkVersion(); |
| | 319 | if (sdk_version) |ver| { |
| | 320 | try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor })); |
| | 321 | } else { |
| | 322 | try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version})); |
| | 323 | } |
| | 324 | } |
| | 325 | |
| | 326 | if (comp.sysroot) |syslibroot| { |
| | 327 | try argv.append("-syslibroot"); |
| | 328 | try argv.append(syslibroot); |
| | 329 | } |
| | 330 | |
| | 331 | for (self.base.rpath_list) |rpath| { |
| | 332 | try argv.append("-rpath"); |
| | 333 | try argv.append(rpath); |
| | 334 | } |
| | 335 | |
| | 336 | if (self.pagezero_vmsize) |size| { |
| | 337 | try argv.append("-pagezero_size"); |
| | 338 | try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{size})); |
| | 339 | } |
| | 340 | |
| | 341 | if (self.headerpad_size) |size| { |
| | 342 | try argv.append("-headerpad_size"); |
| | 343 | try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{size})); |
| | 344 | } |
| | 345 | |
| | 346 | if (self.headerpad_max_install_names) { |
| | 347 | try argv.append("-headerpad_max_install_names"); |
| | 348 | } |
| | 349 | |
| | 350 | if (self.base.gc_sections) { |
| | 351 | try argv.append("-dead_strip"); |
| | 352 | } |
| | 353 | |
| | 354 | if (self.dead_strip_dylibs) { |
| | 355 | try argv.append("-dead_strip_dylibs"); |
| | 356 | } |
| | 357 | |
| | 358 | if (self.entry_name) |entry_name| { |
| | 359 | try argv.appendSlice(&.{ "-e", entry_name }); |
| | 360 | } |
| | 361 | |
| | 362 | for (comp.objects) |obj| { |
| | 363 | // TODO: verify this |
| | 364 | if (obj.must_link) { |
| | 365 | try argv.append("-force_load"); |
| | 366 | } |
| | 367 | try argv.append(obj.path); |
| | 368 | } |
| | 369 | |
| | 370 | for (comp.c_object_table.keys()) |key| { |
| | 371 | try argv.append(key.status.success.object_path); |
| | 372 | } |
| | 373 | |
| | 374 | if (module_obj_path) |p| { |
| | 375 | try argv.append(p); |
| | 376 | } |
| | 377 | |
| | 378 | if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path); |
| | 379 | if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path); |
| | 380 | |
| | 381 | if (comp.config.link_libcpp) { |
| | 382 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); |
| | 383 | try argv.append(comp.libcxx_static_lib.?.full_object_path); |
| | 384 | } |
| | 385 | |
| | 386 | try argv.append("-o"); |
| | 387 | try argv.append(full_out_path); |
| | 388 | |
| | 389 | try argv.append("-lSystem"); |
| | 390 | |
| | 391 | for (comp.system_libs.keys()) |l_name| { |
| | 392 | const info = comp.system_libs.get(l_name).?; |
| | 393 | const arg = if (info.needed) |
| | 394 | try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name}) |
| | 395 | else if (info.weak) |
| | 396 | try std.fmt.allocPrint(arena, "-weak-l{s}", .{l_name}) |
| | 397 | else |
| | 398 | try std.fmt.allocPrint(arena, "-l{s}", .{l_name}); |
| | 399 | try argv.append(arg); |
| | 400 | } |
| | 401 | |
| | 402 | for (self.frameworks) |framework| { |
| | 403 | const name = std.fs.path.stem(framework.path); |
| | 404 | const arg = if (framework.needed) |
| | 405 | try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name}) |
| | 406 | else if (framework.weak) |
| | 407 | try std.fmt.allocPrint(arena, "-weak_framework {s}", .{name}) |
| | 408 | else |
| | 409 | try std.fmt.allocPrint(arena, "-framework {s}", .{name}); |
| | 410 | try argv.append(arg); |
| | 411 | } |
| | 412 | |
| | 413 | if (self.base.isDynLib() and self.base.allow_shlib_undefined) { |
| | 414 | try argv.append("-undefined"); |
| | 415 | try argv.append("dynamic_lookup"); |
| | 416 | } |
| | 417 | } |
| | 418 | |
| | 419 | Compilation.dump_argv(argv.items); |
| 255 | } | 420 | } |
| 256 | | 421 | |
| 257 | /// XNU starting with Big Sur running on arm64 is caching inodes of running binaries. | 422 | /// XNU starting with Big Sur running on arm64 is caching inodes of running binaries. |
| ... | @@ -1034,38 +1199,6 @@ pub const Section = struct { | ... | @@ -1034,38 +1199,6 @@ pub const Section = struct { |
| 1034 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, | 1199 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 1035 | }; | 1200 | }; |
| 1036 | | 1201 | |
| 1037 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata); | | |
| 1038 | | | |
| 1039 | const LazySymbolMetadata = struct { | | |
| 1040 | const State = enum { unused, pending_flush, flushed }; | | |
| 1041 | text_atom: Atom.Index = undefined, | | |
| 1042 | data_const_atom: Atom.Index = undefined, | | |
| 1043 | text_state: State = .unused, | | |
| 1044 | data_const_state: State = .unused, | | |
| 1045 | }; | | |
| 1046 | | | |
| 1047 | const DeclMetadata = struct { | | |
| 1048 | atom: Atom.Index, | | |
| 1049 | section: u8, | | |
| 1050 | /// A list of all exports aliases of this Decl. | | |
| 1051 | /// TODO do we actually need this at all? | | |
| 1052 | exports: std.ArrayListUnmanaged(u32) = .{}, | | |
| 1053 | | | |
| 1054 | fn getExport(m: DeclMetadata, macho_file: *const MachO, name: []const u8) ?u32 { | | |
| 1055 | for (m.exports.items) |exp| { | | |
| 1056 | if (mem.eql(u8, name, macho_file.getSymbolName(.{ .sym_index = exp }))) return exp; | | |
| 1057 | } | | |
| 1058 | return null; | | |
| 1059 | } | | |
| 1060 | | | |
| 1061 | fn getExportPtr(m: *DeclMetadata, macho_file: *MachO, name: []const u8) ?*u32 { | | |
| 1062 | for (m.exports.items) |*exp| { | | |
| 1063 | if (mem.eql(u8, name, macho_file.getSymbolName(.{ .sym_index = exp.* }))) return exp; | | |
| 1064 | } | | |
| 1065 | return null; | | |
| 1066 | } | | |
| 1067 | }; | | |
| 1068 | | | |
| 1069 | const HotUpdateState = struct { | 1202 | const HotUpdateState = struct { |
| 1070 | mach_task: ?std.os.darwin.MachTask = null, | 1203 | mach_task: ?std.os.darwin.MachTask = null, |
| 1071 | }; | 1204 | }; |
| ... | @@ -1091,18 +1224,32 @@ pub const null_sym = macho.nlist_64{ | ... | @@ -1091,18 +1224,32 @@ pub const null_sym = macho.nlist_64{ |
| 1091 | }; | 1224 | }; |
| 1092 | | 1225 | |
| 1093 | pub const Platform = struct { | 1226 | pub const Platform = struct { |
| 1094 | platform: macho.PLATFORM, | 1227 | os_tag: std.Target.Os.Tag, |
| 1095 | version: Version, | 1228 | abi: std.Target.Abi, |
| | 1229 | version: std.SemanticVersion, |
| 1096 | | 1230 | |
| 1097 | /// Using Apple's ld64 as our blueprint, `min_version` as well as `sdk_version` are set to | 1231 | /// Using Apple's ld64 as our blueprint, `min_version` as well as `sdk_version` are set to |
| 1098 | /// the extracted minimum platform version. | 1232 | /// the extracted minimum platform version. |
| 1099 | pub fn fromLoadCommand(lc: macho.LoadCommandIterator.LoadCommand) Platform { | 1233 | pub fn fromLoadCommand(lc: macho.LoadCommandIterator.LoadCommand) Platform { |
| 1100 | switch (lc.cmd()) { | 1234 | switch (lc.cmd()) { |
| 1101 | .BUILD_VERSION => { | 1235 | .BUILD_VERSION => { |
| 1102 | const lc_cmd = lc.cast(macho.build_version_command).?; | 1236 | const cmd = lc.cast(macho.build_version_command).?; |
| 1103 | return .{ | 1237 | return .{ |
| 1104 | .platform = lc_cmd.platform, | 1238 | .os_tag = switch (cmd.platform) { |
| 1105 | .version = .{ .value = lc_cmd.minos }, | 1239 | .MACOS => .macos, |
| | 1240 | .IOS, .IOSSIMULATOR => .ios, |
| | 1241 | .TVOS, .TVOSSIMULATOR => .tvos, |
| | 1242 | .WATCHOS, .WATCHOSSIMULATOR => .watchos, |
| | 1243 | else => @panic("TODO"), |
| | 1244 | }, |
| | 1245 | .abi = switch (cmd.platform) { |
| | 1246 | .IOSSIMULATOR, |
| | 1247 | .TVOSSIMULATOR, |
| | 1248 | .WATCHOSSIMULATOR, |
| | 1249 | => .simulator, |
| | 1250 | else => .none, |
| | 1251 | }, |
| | 1252 | .version = appleVersionToSemanticVersion(cmd.minos), |
| 1106 | }; | 1253 | }; |
| 1107 | }, | 1254 | }, |
| 1108 | .VERSION_MIN_MACOSX, | 1255 | .VERSION_MIN_MACOSX, |
| ... | @@ -1110,22 +1257,45 @@ pub const Platform = struct { | ... | @@ -1110,22 +1257,45 @@ pub const Platform = struct { |
| 1110 | .VERSION_MIN_TVOS, | 1257 | .VERSION_MIN_TVOS, |
| 1111 | .VERSION_MIN_WATCHOS, | 1258 | .VERSION_MIN_WATCHOS, |
| 1112 | => { | 1259 | => { |
| 1113 | const lc_cmd = lc.cast(macho.version_min_command).?; | 1260 | const cmd = lc.cast(macho.version_min_command).?; |
| 1114 | return .{ | 1261 | return .{ |
| 1115 | .platform = switch (lc.cmd()) { | 1262 | .os_tag = switch (lc.cmd()) { |
| 1116 | .VERSION_MIN_MACOSX => .MACOS, | 1263 | .VERSION_MIN_MACOSX => .macos, |
| 1117 | .VERSION_MIN_IPHONEOS => .IOS, | 1264 | .VERSION_MIN_IPHONEOS => .ios, |
| 1118 | .VERSION_MIN_TVOS => .TVOS, | 1265 | .VERSION_MIN_TVOS => .tvos, |
| 1119 | .VERSION_MIN_WATCHOS => .WATCHOS, | 1266 | .VERSION_MIN_WATCHOS => .watchos, |
| 1120 | else => unreachable, | 1267 | else => unreachable, |
| 1121 | }, | 1268 | }, |
| 1122 | .version = .{ .value = lc_cmd.version }, | 1269 | .abi = .none, |
| | 1270 | .version = appleVersionToSemanticVersion(cmd.version), |
| 1123 | }; | 1271 | }; |
| 1124 | }, | 1272 | }, |
| 1125 | else => unreachable, | 1273 | else => unreachable, |
| 1126 | } | 1274 | } |
| 1127 | } | 1275 | } |
| 1128 | | 1276 | |
| | 1277 | pub fn fromTarget(target: std.Target) Platform { |
| | 1278 | return .{ |
| | 1279 | .os_tag = target.os.tag, |
| | 1280 | .abi = target.abi, |
| | 1281 | .version = target.os.version_range.semver.min, |
| | 1282 | }; |
| | 1283 | } |
| | 1284 | |
| | 1285 | pub fn toAppleVersion(plat: Platform) u32 { |
| | 1286 | return semanticVersionToAppleVersion(plat.version); |
| | 1287 | } |
| | 1288 | |
| | 1289 | pub fn toApplePlatform(plat: Platform) macho.PLATFORM { |
| | 1290 | return switch (plat.os_tag) { |
| | 1291 | .macos => .MACOS, |
| | 1292 | .ios => if (plat.abi == .simulator) .IOSSIMULATOR else .IOS, |
| | 1293 | .tvos => if (plat.abi == .simulator) .TVOSSIMULATOR else .TVOS, |
| | 1294 | .watchos => if (plat.abi == .simulator) .WATCHOSSIMULATOR else .WATCHOS, |
| | 1295 | else => unreachable, |
| | 1296 | }; |
| | 1297 | } |
| | 1298 | |
| 1129 | pub fn isBuildVersionCompatible(plat: Platform) bool { | 1299 | pub fn isBuildVersionCompatible(plat: Platform) bool { |
| 1130 | inline for (supported_platforms) |sup_plat| { | 1300 | inline for (supported_platforms) |sup_plat| { |
| 1131 | if (sup_plat[0] == plat.platform) { | 1301 | if (sup_plat[0] == plat.platform) { |
| ... | @@ -1134,76 +1304,152 @@ pub const Platform = struct { | ... | @@ -1134,76 +1304,152 @@ pub const Platform = struct { |
| 1134 | } | 1304 | } |
| 1135 | return false; | 1305 | return false; |
| 1136 | } | 1306 | } |
| 1137 | }; | | |
| 1138 | | | |
| 1139 | pub const Version = struct { | | |
| 1140 | value: u32, | | |
| 1141 | | | |
| 1142 | pub fn major(v: Version) u16 { | | |
| 1143 | return @as(u16, @truncate(v.value >> 16)); | | |
| 1144 | } | | |
| 1145 | | | |
| 1146 | pub fn minor(v: Version) u8 { | | |
| 1147 | return @as(u8, @truncate(v.value >> 8)); | | |
| 1148 | } | | |
| 1149 | | 1307 | |
| 1150 | pub fn patch(v: Version) u8 { | 1308 | pub fn isVersionMinCompatible(plat: Platform) bool { |
| 1151 | return @as(u8, @truncate(v.value)); | 1309 | inline for (supported_platforms) |sup_plat| { |
| 1152 | } | 1310 | if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) { |
| 1153 | | 1311 | return sup_plat[3] <= plat.toAppleVersion(); |
| 1154 | pub fn parse(raw: []const u8) ?Version { | 1312 | } |
| 1155 | var parsed: [3]u16 = [_]u16{0} ** 3; | | |
| 1156 | var count: usize = 0; | | |
| 1157 | var it = std.mem.splitAny(u8, raw, "."); | | |
| 1158 | while (it.next()) |comp| { | | |
| 1159 | if (count >= 3) return null; | | |
| 1160 | parsed[count] = std.fmt.parseInt(u16, comp, 10) catch return null; | | |
| 1161 | count += 1; | | |
| 1162 | } | 1313 | } |
| 1163 | if (count == 0) return null; | 1314 | return false; |
| 1164 | const maj = parsed[0]; | | |
| 1165 | const min = std.math.cast(u8, parsed[1]) orelse return null; | | |
| 1166 | const pat = std.math.cast(u8, parsed[2]) orelse return null; | | |
| 1167 | return Version.new(maj, min, pat); | | |
| 1168 | } | 1315 | } |
| 1169 | | 1316 | |
| 1170 | pub fn new(maj: u16, min: u8, pat: u8) Version { | 1317 | pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatTarget) { |
| 1171 | return .{ .value = (@as(u32, @intCast(maj)) << 16) | (@as(u32, @intCast(min)) << 8) | pat }; | 1318 | return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } }; |
| 1172 | } | 1319 | } |
| 1173 | | 1320 | |
| 1174 | pub fn format( | 1321 | const FmtCtx = struct { |
| 1175 | v: Version, | 1322 | platform: Platform, |
| | 1323 | cpu_arch: std.Target.Cpu.Arch, |
| | 1324 | }; |
| | 1325 | |
| | 1326 | pub fn formatTarget( |
| | 1327 | ctx: FmtCtx, |
| 1176 | comptime unused_fmt_string: []const u8, | 1328 | comptime unused_fmt_string: []const u8, |
| 1177 | options: std.fmt.FormatOptions, | 1329 | options: std.fmt.FormatOptions, |
| 1178 | writer: anytype, | 1330 | writer: anytype, |
| 1179 | ) !void { | 1331 | ) !void { |
| 1180 | _ = unused_fmt_string; | 1332 | _ = unused_fmt_string; |
| 1181 | _ = options; | 1333 | _ = options; |
| 1182 | try writer.print("{d}.{d}.{d}", .{ | 1334 | try writer.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) }); |
| 1183 | v.major(), | 1335 | if (ctx.platform.abi != .none) { |
| 1184 | v.minor(), | 1336 | try writer.print("-{s}", .{@tagName(ctx.platform.abi)}); |
| 1185 | v.patch(), | 1337 | } |
| 1186 | }); | 1338 | } |
| | 1339 | |
| | 1340 | /// Caller owns the memory. |
| | 1341 | pub fn allocPrintTarget(plat: Platform, gpa: Allocator, cpu_arch: std.Target.Cpu.Arch) error{OutOfMemory}![]u8 { |
| | 1342 | var buffer = std.ArrayList(u8).init(gpa); |
| | 1343 | defer buffer.deinit(); |
| | 1344 | try buffer.writer().print("{}", .{plat.fmtTarget(cpu_arch)}); |
| | 1345 | return buffer.toOwnedSlice(); |
| | 1346 | } |
| | 1347 | |
| | 1348 | pub fn eqlTarget(plat: Platform, other: Platform) bool { |
| | 1349 | return plat.os_tag == other.os_tag and plat.abi == other.abi; |
| 1187 | } | 1350 | } |
| 1188 | }; | 1351 | }; |
| 1189 | | 1352 | |
| 1190 | const SupportedPlatforms = struct { | 1353 | const SupportedPlatforms = struct { |
| 1191 | macho.PLATFORM, // Platform identifier | 1354 | std.Target.Os.Tag, |
| | 1355 | std.Target.Abi, |
| 1192 | u32, // Min platform version for which to emit LC_BUILD_VERSION | 1356 | u32, // Min platform version for which to emit LC_BUILD_VERSION |
| 1193 | u32, // Min supported platform version | 1357 | u32, // Min supported platform version |
| 1194 | ?[]const u8, // Env var to look for | | |
| 1195 | }; | 1358 | }; |
| 1196 | | 1359 | |
| 1197 | // Source: https://github.com/apple-oss-distributions/ld64/blob/59a99ab60399c5e6c49e6945a9e1049c42b71135/src/ld/PlatformSupport.cpp#L52 | 1360 | // Source: https://github.com/apple-oss-distributions/ld64/blob/59a99ab60399c5e6c49e6945a9e1049c42b71135/src/ld/PlatformSupport.cpp#L52 |
| | 1361 | // zig fmt: off |
| 1198 | const supported_platforms = [_]SupportedPlatforms{ | 1362 | const supported_platforms = [_]SupportedPlatforms{ |
| 1199 | .{ .MACOS, 0xA0E00, 0xA0800, "MACOSX_DEPLOYMENT_TARGET" }, | 1363 | .{ .macos, .none, 0xA0E00, 0xA0800 }, |
| 1200 | .{ .IOS, 0xC0000, 0x70000, "IPHONEOS_DEPLOYMENT_TARGET" }, | 1364 | .{ .ios, .none, 0xC0000, 0x70000 }, |
| 1201 | .{ .TVOS, 0xC0000, 0x70000, "TVOS_DEPLOYMENT_TARGET" }, | 1365 | .{ .tvos, .none, 0xC0000, 0x70000 }, |
| 1202 | .{ .WATCHOS, 0x50000, 0x20000, "WATCHOS_DEPLOYMENT_TARGET" }, | 1366 | .{ .watchos, .none, 0x50000, 0x20000 }, |
| 1203 | .{ .IOSSIMULATOR, 0xD0000, 0x80000, null }, | 1367 | .{ .ios, .simulator, 0xD0000, 0x80000 }, |
| 1204 | .{ .TVOSSIMULATOR, 0xD0000, 0x80000, null }, | 1368 | .{ .tvos, .simulator, 0xD0000, 0x80000 }, |
| 1205 | .{ .WATCHOSSIMULATOR, 0x60000, 0x20000, null }, | 1369 | .{ .watchos, .simulator, 0x60000, 0x20000 }, |
| 1206 | }; | 1370 | }; |
| | 1371 | // zig fmt: on |
| | 1372 | |
| | 1373 | inline fn semanticVersionToAppleVersion(version: std.SemanticVersion) u32 { |
| | 1374 | const major = version.major; |
| | 1375 | const minor = version.minor; |
| | 1376 | const patch = version.patch; |
| | 1377 | return (@as(u32, @intCast(major)) << 16) | (@as(u32, @intCast(minor)) << 8) | @as(u32, @intCast(patch)); |
| | 1378 | } |
| | 1379 | |
| | 1380 | pub inline fn appleVersionToSemanticVersion(version: u32) std.SemanticVersion { |
| | 1381 | return .{ |
| | 1382 | .major = @as(u16, @truncate(version >> 16)), |
| | 1383 | .minor = @as(u8, @truncate(version >> 8)), |
| | 1384 | .patch = @as(u8, @truncate(version)), |
| | 1385 | }; |
| | 1386 | } |
| | 1387 | |
| | 1388 | fn inferSdkVersion(self: *MachO) ?std.SemanticVersion { |
| | 1389 | const comp = self.base.comp; |
| | 1390 | const gpa = comp.gpa; |
| | 1391 | |
| | 1392 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); |
| | 1393 | defer arena_allocator.deinit(); |
| | 1394 | const arena = arena_allocator.allocator(); |
| | 1395 | |
| | 1396 | const sdk_layout = self.sdk_layout orelse return null; |
| | 1397 | const sdk_dir = switch (sdk_layout) { |
| | 1398 | .sdk => comp.sysroot.?, |
| | 1399 | .vendored => std.fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null, |
| | 1400 | }; |
| | 1401 | if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| { |
| | 1402 | return parseSdkVersion(ver); |
| | 1403 | } else |_| { |
| | 1404 | // Read from settings should always succeed when vendored. |
| | 1405 | if (sdk_layout == .vendored) @panic("zig installation bug: unable to parse SDK version"); |
| | 1406 | } |
| | 1407 | |
| | 1408 | // infer from pathname |
| | 1409 | const stem = std.fs.path.stem(sdk_dir); |
| | 1410 | const start = for (stem, 0..) |c, i| { |
| | 1411 | if (std.ascii.isDigit(c)) break i; |
| | 1412 | } else stem.len; |
| | 1413 | const end = for (stem[start..], start..) |c, i| { |
| | 1414 | if (std.ascii.isDigit(c) or c == '.') continue; |
| | 1415 | break i; |
| | 1416 | } else stem.len; |
| | 1417 | return parseSdkVersion(stem[start..end]); |
| | 1418 | } |
| | 1419 | |
| | 1420 | // Official Apple SDKs ship with a `SDKSettings.json` located at the top of SDK fs layout. |
| | 1421 | // Use property `MinimalDisplayName` to determine version. |
| | 1422 | // The file/property is also available with vendored libc. |
| | 1423 | fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 { |
| | 1424 | const sdk_path = try std.fs.path.join(arena, &.{ dir, "SDKSettings.json" }); |
| | 1425 | const contents = try std.fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16)); |
| | 1426 | const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{}); |
| | 1427 | if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string; |
| | 1428 | return error.SdkVersionFailure; |
| | 1429 | } |
| | 1430 | |
| | 1431 | // Versions reported by Apple aren't exactly semantically valid as they usually omit |
| | 1432 | // the patch component, so we parse SDK value by hand. |
| | 1433 | fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion { |
| | 1434 | var parsed: std.SemanticVersion = .{ |
| | 1435 | .major = 0, |
| | 1436 | .minor = 0, |
| | 1437 | .patch = 0, |
| | 1438 | }; |
| | 1439 | |
| | 1440 | const parseNext = struct { |
| | 1441 | fn parseNext(it: anytype) ?u16 { |
| | 1442 | const nn = it.next() orelse return null; |
| | 1443 | return std.fmt.parseInt(u16, nn, 10) catch null; |
| | 1444 | } |
| | 1445 | }.parseNext; |
| | 1446 | |
| | 1447 | var it = std.mem.splitAny(u8, raw, "."); |
| | 1448 | parsed.major = parseNext(&it) orelse return null; |
| | 1449 | parsed.minor = parseNext(&it) orelse return null; |
| | 1450 | parsed.patch = parseNext(&it) orelse 0; |
| | 1451 | return parsed; |
| | 1452 | } |
| 1207 | | 1453 | |
| 1208 | /// When allocating, the ideal_capacity is calculated by | 1454 | /// When allocating, the ideal_capacity is calculated by |
| 1209 | /// actual_capacity + (actual_capacity / ideal_factor) | 1455 | /// actual_capacity + (actual_capacity / ideal_factor) |