| author | |
| committer | |
| log | 5125399764909dcf19e861806e8a73688121461d |
| tree | 8b05147e9c661a3aa34576b89f2b5aa5389951b5 |
| parent | f8dd54d7d0e1f7ad71dcc7518659a9c30e09155d |
| signature | Commit is signed but in an unrecognized format. |
The SDK version is determined by parsing the `SDKSettings.json` file in
the Darwin SDK (or in `lib/libc/darwin/` when using our vendored libs).
(The old Mach-O linker also had a fallback strategy of determining the
version from the SDK path, but that seems unnecessary nowadays.)
Moving that parsing to `src/link.zig`, and calling into it at the same
time as handling libc (libSystem), turns out to simplify this logic
quite a bit!7 files changed, 220 insertions(+), 160 deletions(-)
lib/std/zig/LibCDirs.zig+5-25| ... | ... | @@ -11,15 +11,6 @@ libc_include_dir_list: []const []const u8, |
| 11 | 11 | libc_installation: ?*const LibCInstallation, |
| 12 | 12 | libc_framework_dir_list: []const []const u8, |
| 13 | 13 | sysroot: ?[]const u8, |
| 14 | darwin_sdk_layout: ?DarwinSdkLayout, | |
| 15 | ||
| 16 | /// The filesystem layout of darwin SDK elements. | |
| 17 | pub const DarwinSdkLayout = enum { | |
| 18 | /// macOS SDK layout: TOP { /usr/include, /usr/lib, /System/Library/Frameworks }. | |
| 19 | sdk, | |
| 20 | /// Shipped libc layout: TOP { /lib/libc/include, /lib/libc/darwin, <NONE> }. | |
| 21 | vendored, | |
| 22 | }; | |
| 23 | 14 | |
| 24 | 15 | pub fn detect( |
| 25 | 16 | arena: Allocator, |
| ... | ... | @@ -37,7 +28,6 @@ pub fn detect( |
| 37 | 28 | .libc_installation = null, |
| 38 | 29 | .libc_framework_dir_list = &.{}, |
| 39 | 30 | .sysroot = null, |
| 40 | .darwin_sdk_layout = null, | |
| 41 | 31 | }; |
| 42 | 32 | } |
| 43 | 33 | |
| ... | ... | @@ -102,13 +92,11 @@ pub fn detect( |
| 102 | 92 | .libc_installation = null, |
| 103 | 93 | .libc_framework_dir_list = &.{}, |
| 104 | 94 | .sysroot = null, |
| 105 | .darwin_sdk_layout = null, | |
| 106 | 95 | }; |
| 107 | 96 | } |
| 108 | 97 | |
| 109 | 98 | fn detectFromInstallation(arena: Allocator, target: *const std.Target, lci: *const LibCInstallation) !LibCDirs { |
| 110 | 99 | var list = try std.array_list.Managed([]const u8).initCapacity(arena, 5); |
| 111 | var framework_list = std.array_list.Managed([]const u8).init(arena); | |
| 112 | 100 | |
| 113 | 101 | list.appendAssumeCapacity(lci.include_dir.?); |
| 114 | 102 | |
| ... | ... | @@ -149,21 +137,15 @@ fn detectFromInstallation(arena: Allocator, target: *const std.Target, lci: *con |
| 149 | 137 | } |
| 150 | 138 | } |
| 151 | 139 | |
| 152 | var sysroot: ?[]const u8 = null; | |
| 153 | ||
| 154 | if (target.os.tag.isDarwin()) d: { | |
| 155 | const down1 = std.fs.path.dirname(lci.sys_include_dir.?) orelse break :d; | |
| 156 | const down2 = std.fs.path.dirname(down1) orelse break :d; | |
| 157 | try framework_list.append(try std.fs.path.join(arena, &.{ down2, "System", "Library", "Frameworks" })); | |
| 158 | sysroot = down2; | |
| 159 | } | |
| 140 | const frameworks: []const []const u8 = if (target.os.tag.isDarwin()) try arena.dupe([]const u8, &.{ | |
| 141 | try std.fs.path.join(arena, &.{ lci.darwin_sdk_dir.?, "System", "Library", "Frameworks" }), | |
| 142 | }) else &.{}; | |
| 160 | 143 | |
| 161 | 144 | return .{ |
| 162 | 145 | .libc_include_dir_list = list.items, |
| 163 | 146 | .libc_installation = lci, |
| 164 | .libc_framework_dir_list = framework_list.items, | |
| 165 | .sysroot = sysroot, | |
| 166 | .darwin_sdk_layout = if (sysroot == null) null else .sdk, | |
| 147 | .libc_framework_dir_list = frameworks, | |
| 148 | .sysroot = if (target.os.tag.isDarwin()) lci.darwin_sdk_dir.? else null, | |
| 167 | 149 | }; |
| 168 | 150 | } |
| 169 | 151 | |
| ... | ... | @@ -178,7 +160,6 @@ pub fn detectFromBuilding(arena: Allocator, zig_lib_dir: Path, target: *const st |
| 178 | 160 | .libc_installation = null, |
| 179 | 161 | .libc_framework_dir_list = &.{}, |
| 180 | 162 | .sysroot = null, |
| 181 | .darwin_sdk_layout = .vendored, | |
| 182 | 163 | }; |
| 183 | 164 | } |
| 184 | 165 | |
| ... | ... | @@ -230,7 +211,6 @@ pub fn detectFromBuilding(arena: Allocator, zig_lib_dir: Path, target: *const st |
| 230 | 211 | .libc_installation = null, |
| 231 | 212 | .libc_framework_dir_list = &.{}, |
| 232 | 213 | .sysroot = null, |
| 233 | .darwin_sdk_layout = .vendored, | |
| 234 | 214 | }; |
| 235 | 215 | } |
| 236 | 216 |
lib/std/zig/LibCInstallation.zig+18-15| ... | ... | @@ -23,6 +23,7 @@ crt_dir: ?[]const u8 = null, |
| 23 | 23 | msvc_lib_dir: ?[]const u8 = null, |
| 24 | 24 | kernel32_lib_dir: ?[]const u8 = null, |
| 25 | 25 | cc_dir: ?[]const u8 = null, |
| 26 | darwin_sdk_dir: ?[]const u8 = null, | |
| 26 | 27 | |
| 27 | 28 | pub const FindError = error{ |
| 28 | 29 | OutOfMemory, |
| ... | ... | @@ -121,19 +122,16 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const |
| 121 | 122 | }); |
| 122 | 123 | return error.ParseError; |
| 123 | 124 | } |
| 125 | if (self.darwin_sdk_dir == null and os_tag.isDarwin()) { | |
| 126 | log.err("darwin_sdk_dir may not be empty for {t}", .{os_tag}); | |
| 127 | return error.ParseError; | |
| 128 | } | |
| 124 | 129 | |
| 125 | 130 | return self; |
| 126 | 131 | } |
| 127 | 132 | |
| 128 | 133 | pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void { |
| 129 | 134 | @setEvalBranchQuota(4000); |
| 130 | const include_dir = self.include_dir orelse ""; | |
| 131 | const sys_include_dir = self.sys_include_dir orelse ""; | |
| 132 | const crt_dir = self.crt_dir orelse ""; | |
| 133 | const msvc_lib_dir = self.msvc_lib_dir orelse ""; | |
| 134 | const kernel32_lib_dir = self.kernel32_lib_dir orelse ""; | |
| 135 | const cc_dir = self.cc_dir orelse ""; | |
| 136 | ||
| 137 | 135 | try out.print( |
| 138 | 136 | \\# The directory that contains `stdlib.h`. |
| 139 | 137 | \\# On POSIX, can be found with: `cc -E -Wp,-v -xc /dev/null` |
| ... | ... | @@ -161,13 +159,18 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void { |
| 161 | 159 | \\# Only needed when targeting MSVC on Windows. |
| 162 | 160 | \\kernel32_lib_dir={s} |
| 163 | 161 | \\ |
| 162 | \\# The directory that contains `SDKSettings.json` | |
| 163 | \\# Only needed when targeting Darwin. | |
| 164 | \\darwin_sdk_dir={s} | |
| 165 | \\ | |
| 164 | 166 | , .{ |
| 165 | include_dir, | |
| 166 | sys_include_dir, | |
| 167 | crt_dir, | |
| 168 | msvc_lib_dir, | |
| 169 | kernel32_lib_dir, | |
| 170 | cc_dir, | |
| 167 | self.include_dir orelse "", | |
| 168 | self.sys_include_dir orelse "", | |
| 169 | self.cc_dir orelse "", | |
| 170 | self.crt_dir orelse "", | |
| 171 | self.msvc_lib_dir orelse "", | |
| 172 | self.kernel32_lib_dir orelse "", | |
| 173 | self.darwin_sdk_dir orelse "", | |
| 171 | 174 | }); |
| 172 | 175 | } |
| 173 | 176 | |
| ... | ... | @@ -186,10 +189,10 @@ pub fn findNative(gpa: Allocator, io: Io, args: FindNativeOptions) FindError!Lib |
| 186 | 189 | if (is_darwin and args.target.os.tag.isDarwin()) { |
| 187 | 190 | if (!std.zig.system.darwin.isSdkInstalled(gpa, io)) |
| 188 | 191 | return error.DarwinSdkNotFound; |
| 189 | const sdk = std.zig.system.darwin.getSdk(gpa, io, args.target) orelse | |
| 192 | self.darwin_sdk_dir = std.zig.system.darwin.getSdk(gpa, io, args.target) orelse | |
| 190 | 193 | return error.DarwinSdkNotFound; |
| 191 | defer gpa.free(sdk); | |
| 192 | 194 | |
| 195 | const sdk = self.darwin_sdk_dir.?; | |
| 193 | 196 | self.include_dir = try fs.path.join(gpa, &.{ sdk, "usr/include" }); |
| 194 | 197 | self.sys_include_dir = try fs.path.join(gpa, &.{ sdk, "usr/include" }); |
| 195 | 198 | self.crt_dir = try fs.path.join(gpa, &.{ sdk, "usr/lib" }); |
src/Compilation.zig+10-6| ... | ... | @@ -2208,7 +2208,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2208 | 2208 | .z_relro = options.linker_z_relro, |
| 2209 | 2209 | .z_common_page_size = options.linker_z_common_page_size, |
| 2210 | 2210 | .z_max_page_size = options.linker_z_max_page_size, |
| 2211 | .darwin_sdk_layout = libc_dirs.darwin_sdk_layout, | |
| 2212 | 2211 | .frameworks = options.frameworks, |
| 2213 | 2212 | .lib_directories = options.lib_directories, |
| 2214 | 2213 | .framework_dirs = options.framework_dirs, |
| ... | ... | @@ -2453,10 +2452,16 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2453 | 2452 | // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`. |
| 2454 | 2453 | comp.oneshot_prelink_tasks.appendAssumeCapacity(.load_host_libc); |
| 2455 | 2454 | } else if (target.isDarwinLibC()) { |
| 2456 | try comp.oneshot_prelink_tasks.append(gpa, .{ .load_tbd = .{ | |
| 2457 | .root_dir = comp.dirs.zig_lib, | |
| 2458 | .sub_path = "libc" ++ fs.path.sep_str ++ "darwin" ++ fs.path.sep_str ++ "libSystem.tbd", | |
| 2459 | } }); | |
| 2455 | try comp.oneshot_prelink_tasks.appendSlice(gpa, &.{ | |
| 2456 | .{ .load_tbd = .{ | |
| 2457 | .root_dir = comp.dirs.zig_lib, | |
| 2458 | .sub_path = "libc" ++ fs.path.sep_str ++ "darwin" ++ fs.path.sep_str ++ "libSystem.tbd", | |
| 2459 | } }, | |
| 2460 | .{ .load_darwin_sdk_settings = .{ | |
| 2461 | .root_dir = comp.dirs.zig_lib, | |
| 2462 | .sub_path = "libc" ++ fs.path.sep_str ++ "darwin" ++ fs.path.sep_str ++ "SDKSettings.json", | |
| 2463 | } }, | |
| 2464 | }); | |
| 2460 | 2465 | // TODO delete logic from MachO flush() and queue up tasks here instead. |
| 2461 | 2466 | } else if (target.isMuslLibC()) { |
| 2462 | 2467 | if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); |
| ... | ... | @@ -3487,7 +3492,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 3487 | 3492 | man.hash.add(opts.discard_local_symbols); |
| 3488 | 3493 | man.hash.addOptional(opts.compatibility_version); |
| 3489 | 3494 | man.hash.addOptionalBytes(opts.install_name); |
| 3490 | man.hash.addOptional(opts.darwin_sdk_layout); | |
| 3491 | 3495 | |
| 3492 | 3496 | // COFF specific stuff |
| 3493 | 3497 | man.hash.addOptional(opts.subsystem); |
src/link.zig+150-2| ... | ... | @@ -502,7 +502,6 @@ pub const File = struct { |
| 502 | 502 | /// Remove dylibs that are unreachable by the entry point or exported symbols |
| 503 | 503 | dead_strip_dylibs: bool, |
| 504 | 504 | frameworks: []const MachO.Framework, |
| 505 | darwin_sdk_layout: ?MachO.SdkLayout, | |
| 506 | 505 | /// Force load all members of static archives that implement an |
| 507 | 506 | /// Objective-C class or category |
| 508 | 507 | force_load_objc: bool, |
| ... | ... | @@ -1248,6 +1247,59 @@ pub const File = struct { |
| 1248 | 1247 | } |
| 1249 | 1248 | } |
| 1250 | 1249 | |
| 1250 | fn loadDarwinSdkSettings(base: *File, sdk_settings_path: Path) Error!void { | |
| 1251 | const comp = base.comp; | |
| 1252 | const io = comp.io; | |
| 1253 | const arena = comp.arena; | |
| 1254 | const diags = &comp.link_diags; | |
| 1255 | ||
| 1256 | const contents = sdk_settings_path.root_dir.handle.readFileAlloc( | |
| 1257 | io, | |
| 1258 | sdk_settings_path.sub_path, | |
| 1259 | arena, | |
| 1260 | .limited(1024 * 1024 * 256), | |
| 1261 | ) catch |err| switch (err) { | |
| 1262 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 1263 | else => |e| return diags.failParse(sdk_settings_path, "failed to parse Darwin SDK settings: {t}", .{e}), | |
| 1264 | }; | |
| 1265 | ||
| 1266 | const parsed = std.json.parseFromSlice(std.json.Value, arena, contents, .{}) catch |err| switch (err) { | |
| 1267 | error.OutOfMemory => |e| return e, | |
| 1268 | else => |e| return diags.failParse(sdk_settings_path, "failed to parse Darwin SDK settings: {t}", .{e}), | |
| 1269 | }; | |
| 1270 | const parsed_object = switch (parsed.value) { | |
| 1271 | .object => |obj| obj, | |
| 1272 | else => return diags.failParse(sdk_settings_path, "failed to parse Darwin SDK settings: file is not a JSON object", .{}), | |
| 1273 | }; | |
| 1274 | ||
| 1275 | const version_json = parsed_object.get("MinimalDisplayName") orelse return diags.failParse( | |
| 1276 | sdk_settings_path, | |
| 1277 | "failed to parse Darwin SDK settings: 'MinimalDisplayName' missing", | |
| 1278 | .{}, | |
| 1279 | ); | |
| 1280 | const version_str: []const u8 = switch (version_json) { | |
| 1281 | .string => |str| str, | |
| 1282 | else => return diags.failParse( | |
| 1283 | sdk_settings_path, | |
| 1284 | "failed to parse Darwin SDK settings: 'MinimalDisplayName' not a string", | |
| 1285 | .{}, | |
| 1286 | ), | |
| 1287 | }; | |
| 1288 | const version: DarwinSdkVersion = try .parse(diags, sdk_settings_path, version_str); | |
| 1289 | try base.setDarwinSdkVersion(version); | |
| 1290 | } | |
| 1291 | ||
| 1292 | fn setDarwinSdkVersion(base: *File, version: DarwinSdkVersion) Error!void { | |
| 1293 | assert(!base.post_prelink); | |
| 1294 | switch (base.tag) { | |
| 1295 | inline .macho, .macho2 => |tag| { | |
| 1296 | dev.check(tag.devFeature()); | |
| 1297 | return @as(*tag.Type(), @fieldParentPtr("base", base)).setDarwinSdkVersion(version); | |
| 1298 | }, | |
| 1299 | else => unreachable, | |
| 1300 | } | |
| 1301 | } | |
| 1302 | ||
| 1251 | 1303 | /// Called when all linker inputs have been sent via `loadInput`. After |
| 1252 | 1304 | /// this, `loadInput` will not be called anymore. |
| 1253 | 1305 | pub fn prelink(base: *File) Error!void { |
| ... | ... | @@ -1451,6 +1503,7 @@ pub const PrelinkTask = union(enum) { |
| 1451 | 1503 | /// GNU ld script. |
| 1452 | 1504 | load_dso: Path, |
| 1453 | 1505 | load_tbd: Path, |
| 1506 | load_darwin_sdk_settings: Path, | |
| 1454 | 1507 | }; |
| 1455 | 1508 | pub const ZcuTask = union(enum) { |
| 1456 | 1509 | /// Sent once per update, as the very first `ZcuTask` in the update. Indicates that all per-file |
| ... | ... | @@ -1589,7 +1642,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1589 | 1642 | error.FileNotFound => {}, |
| 1590 | 1643 | error.AlreadyReported => return, |
| 1591 | 1644 | error.Canceled => io.recancel(), |
| 1592 | else => |e| diags.addParseError(archive_path, "failed to parse archive {f}: {s}", .{ archive_path, @errorName(e) }), | |
| 1645 | else => |e| diags.addParseError(archive_path, "failed to parse archive: {s}", .{@errorName(e)}), | |
| 1593 | 1646 | } |
| 1594 | 1647 | |
| 1595 | 1648 | diags.addError("failed to find library '{s}'", .{lib_name}); |
| ... | ... | @@ -1612,6 +1665,19 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1612 | 1665 | } |
| 1613 | 1666 | } |
| 1614 | 1667 | |
| 1668 | if (target.os.tag.isDarwin()) { | |
| 1669 | const sdk_settings_path: Path = .initCwd(std.fmt.allocPrint( | |
| 1670 | comp.arena, | |
| 1671 | "{s}" ++ sep ++ "SDKSettings.json", | |
| 1672 | .{libc_installation.darwin_sdk_dir.?}, | |
| 1673 | ) catch return diags.setAllocFailure()); | |
| 1674 | base.loadDarwinSdkSettings(sdk_settings_path) catch |err| switch (err) { | |
| 1675 | error.OutOfMemory => return diags.setAllocFailure(), | |
| 1676 | error.Canceled => return io.recancel(), | |
| 1677 | error.AlreadyReported => return, | |
| 1678 | }; | |
| 1679 | } | |
| 1680 | ||
| 1615 | 1681 | if (target.os.tag == .windows and target.abi == .msvc) { |
| 1616 | 1682 | const inputs: []const struct { |
| 1617 | 1683 | dir: enum { crt, msvc_lib, kernel32_lib }, |
| ... | ... | @@ -1709,6 +1775,15 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1709 | 1775 | else => |e| diags.addParseError(path, "failed to parse tbd: {t}", .{e}), |
| 1710 | 1776 | } |
| 1711 | 1777 | }, |
| 1778 | .load_darwin_sdk_settings => |path| { | |
| 1779 | const prog_node = comp.link_prog_node.start("Parse SDK Settings", 0); | |
| 1780 | defer prog_node.end(); | |
| 1781 | base.loadDarwinSdkSettings(path) catch |err| switch (err) { | |
| 1782 | error.OutOfMemory => return diags.setAllocFailure(), | |
| 1783 | error.Canceled => return io.recancel(), | |
| 1784 | error.AlreadyReported => return, | |
| 1785 | }; | |
| 1786 | }, | |
| 1712 | 1787 | } |
| 1713 | 1788 | } |
| 1714 | 1789 | pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void { |
| ... | ... | @@ -2793,3 +2868,76 @@ pub fn firstObjectInput(inputs: []const Input) ?Input.Object { |
| 2793 | 2868 | }; |
| 2794 | 2869 | return null; |
| 2795 | 2870 | } |
| 2871 | ||
| 2872 | pub const DarwinSdkVersion = packed struct(u32) { | |
| 2873 | patch: u8, | |
| 2874 | minor: u8, | |
| 2875 | major: u16, | |
| 2876 | ||
| 2877 | fn parse( | |
| 2878 | diags: *Diags, | |
| 2879 | /// Passed to `Diags.failParse` on error. | |
| 2880 | sdk_settings_path: Path, | |
| 2881 | version_str: []const u8, | |
| 2882 | ) error{AlreadyReported}!DarwinSdkVersion { | |
| 2883 | var it = std.mem.splitScalar(u8, version_str, '.'); | |
| 2884 | ||
| 2885 | const major = try parseComponent( | |
| 2886 | .major, | |
| 2887 | diags, | |
| 2888 | sdk_settings_path, | |
| 2889 | version_str, | |
| 2890 | it.first(), | |
| 2891 | ); | |
| 2892 | const minor = if (it.next()) |component_str| try parseComponent( | |
| 2893 | .minor, | |
| 2894 | diags, | |
| 2895 | sdk_settings_path, | |
| 2896 | version_str, | |
| 2897 | component_str, | |
| 2898 | ) else return diags.failParse( | |
| 2899 | sdk_settings_path, | |
| 2900 | "failed to parse Darwin SDK version {q}: missing minor version", | |
| 2901 | .{version_str}, | |
| 2902 | ); | |
| 2903 | const patch = if (it.next()) |component_str| try parseComponent( | |
| 2904 | .patch, | |
| 2905 | diags, | |
| 2906 | sdk_settings_path, | |
| 2907 | version_str, | |
| 2908 | component_str, | |
| 2909 | ) else 0; // Apple sometimes omit the patch version | |
| 2910 | ||
| 2911 | if (it.next() != null) return diags.failParse( | |
| 2912 | sdk_settings_path, | |
| 2913 | "failed to parse Darwin SDK version {q}: too many version components", | |
| 2914 | .{version_str}, | |
| 2915 | ); | |
| 2916 | ||
| 2917 | return .{ .major = major, .minor = minor, .patch = patch }; | |
| 2918 | } | |
| 2919 | ||
| 2920 | fn parseComponent( | |
| 2921 | comptime component: enum { major, minor, patch }, | |
| 2922 | diags: *Diags, | |
| 2923 | /// Passed to `Diags.failParse` on error. | |
| 2924 | sdk_settings_path: Path, | |
| 2925 | /// Only used for error messages. | |
| 2926 | version_str: []const u8, | |
| 2927 | component_str: []const u8, | |
| 2928 | ) error{AlreadyReported}!@FieldType(DarwinSdkVersion, @tagName(component)) { | |
| 2929 | const Int = @FieldType(DarwinSdkVersion, @tagName(component)); | |
| 2930 | return std.fmt.parseInt(Int, component_str, 10) catch |err| switch (err) { | |
| 2931 | error.Overflow => return diags.failParse( | |
| 2932 | sdk_settings_path, | |
| 2933 | "failed to parse Darwin SDK version {q}: {t} version {q} too large", | |
| 2934 | .{ version_str, component, component_str }, | |
| 2935 | ), | |
| 2936 | error.InvalidCharacter => return diags.failParse( | |
| 2937 | sdk_settings_path, | |
| 2938 | "failed to parse Darwin SDK version {q}: invalid {t} version {q}", | |
| 2939 | .{ version_str, component, component_str }, | |
| 2940 | ), | |
| 2941 | }; | |
| 2942 | } | |
| 2943 | }; |
src/link/MachO.zig+26-100| ... | ... | @@ -106,9 +106,7 @@ has_tlv: AtomicBool = AtomicBool.init(false), |
| 106 | 106 | binds_to_weak: AtomicBool = AtomicBool.init(false), |
| 107 | 107 | weak_defines: AtomicBool = AtomicBool.init(false), |
| 108 | 108 | |
| 109 | /// Options | |
| 110 | /// SDK layout | |
| 111 | sdk_layout: ?SdkLayout, | |
| 109 | // Options | |
| 112 | 110 | /// Size of the __PAGEZERO segment. |
| 113 | 111 | pagezero_size: ?u64, |
| 114 | 112 | /// Minimum space for future expansion of the load commands. |
| ... | ... | @@ -134,7 +132,7 @@ compatibility_version: ?std.SemanticVersion, |
| 134 | 132 | /// Entry name |
| 135 | 133 | entry_name: ?[]const u8, |
| 136 | 134 | platform: Platform, |
| 137 | sdk_version: ?std.SemanticVersion, | |
| 135 | sdk_version: ?link.DarwinSdkVersion, | |
| 138 | 136 | /// When set to true, the linker will hoist all dylibs including system dependent dylibs. |
| 139 | 137 | no_implicit_dylibs: bool = false, |
| 140 | 138 | /// Whether the linker should parse and always force load objects containing ObjC in archives. |
| ... | ... | @@ -198,7 +196,6 @@ pub fn createEmpty( |
| 198 | 196 | .headerpad_size = options.headerpad_size, |
| 199 | 197 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 200 | 198 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 201 | .sdk_layout = options.darwin_sdk_layout, | |
| 202 | 199 | .frameworks = options.frameworks, |
| 203 | 200 | .install_name = options.install_name, |
| 204 | 201 | .entitlements = options.entitlements, |
| ... | ... | @@ -210,7 +207,7 @@ pub fn createEmpty( |
| 210 | 207 | .named => |name| name, |
| 211 | 208 | }, |
| 212 | 209 | .platform = Platform.fromTarget(target), |
| 213 | .sdk_version = if (options.darwin_sdk_layout) |layout| inferSdkVersion(comp, layout) else null, | |
| 210 | .sdk_version = null, | |
| 214 | 211 | .undefined_treatment = if (allow_shlib_undefined) .dynamic_lookup else .@"error", |
| 215 | 212 | // TODO delete this, directories must instead be resolved by the frontend |
| 216 | 213 | .lib_directories = options.lib_directories, |
| ... | ... | @@ -604,12 +601,20 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 604 | 601 | |
| 605 | 602 | try argv.append("-platform_version"); |
| 606 | 603 | try argv.append(@tagName(self.platform.os_tag)); |
| 607 | try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version})); | |
| 604 | try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ | |
| 605 | self.platform.version.major, | |
| 606 | self.platform.version.minor, | |
| 607 | self.platform.version.patch, | |
| 608 | })); | |
| 608 | 609 | |
| 609 | 610 | if (self.sdk_version) |ver| { |
| 610 | 611 | try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor })); |
| 611 | 612 | } else { |
| 612 | try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version})); | |
| 613 | try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}.{d}", .{ | |
| 614 | self.platform.version.major, | |
| 615 | self.platform.version.minor, | |
| 616 | self.platform.version.patch, | |
| 617 | })); | |
| 613 | 618 | } |
| 614 | 619 | |
| 615 | 620 | if (comp.sysroot) |syslibroot| { |
| ... | ... | @@ -4101,7 +4106,7 @@ pub const null_sym = macho.nlist_64{ |
| 4101 | 4106 | pub const Platform = struct { |
| 4102 | 4107 | os_tag: std.Target.Os.Tag, |
| 4103 | 4108 | abi: std.Target.Abi, |
| 4104 | version: std.SemanticVersion, | |
| 4109 | version: link.DarwinSdkVersion, | |
| 4105 | 4110 | |
| 4106 | 4111 | /// Using Apple's ld64 as our blueprint, `min_version` as well as `sdk_version` are set to |
| 4107 | 4112 | /// the extracted minimum platform version. |
| ... | ... | @@ -4128,7 +4133,7 @@ pub const Platform = struct { |
| 4128 | 4133 | => .simulator, |
| 4129 | 4134 | else => .none, |
| 4130 | 4135 | }, |
| 4131 | .version = appleVersionToSemanticVersion(cmd.minos), | |
| 4136 | .version = @fromBackingInt(cmd.minos), | |
| 4132 | 4137 | }; |
| 4133 | 4138 | }, |
| 4134 | 4139 | .VERSION_MIN_IPHONEOS, |
| ... | ... | @@ -4147,7 +4152,7 @@ pub const Platform = struct { |
| 4147 | 4152 | else => unreachable, |
| 4148 | 4153 | }, |
| 4149 | 4154 | .abi = .none, |
| 4150 | .version = appleVersionToSemanticVersion(cmd.version), | |
| 4155 | .version = @fromBackingInt(cmd.version), | |
| 4151 | 4156 | }; |
| 4152 | 4157 | }, |
| 4153 | 4158 | else => unreachable, |
| ... | ... | @@ -4155,17 +4160,18 @@ pub const Platform = struct { |
| 4155 | 4160 | } |
| 4156 | 4161 | |
| 4157 | 4162 | pub fn fromTarget(target: *const std.Target) Platform { |
| 4163 | const semver = target.os.version_range.semver.min; | |
| 4158 | 4164 | return .{ |
| 4159 | 4165 | .os_tag = target.os.tag, |
| 4160 | 4166 | .abi = target.abi, |
| 4161 | .version = target.os.version_range.semver.min, | |
| 4167 | .version = .{ | |
| 4168 | .major = @intCast(semver.major), | |
| 4169 | .minor = @intCast(semver.minor), | |
| 4170 | .patch = @intCast(semver.patch), | |
| 4171 | }, | |
| 4162 | 4172 | }; |
| 4163 | 4173 | } |
| 4164 | 4174 | |
| 4165 | pub fn toAppleVersion(plat: Platform) u32 { | |
| 4166 | return semanticVersionToAppleVersion(plat.version); | |
| 4167 | } | |
| 4168 | ||
| 4169 | 4175 | pub fn toApplePlatform(plat: Platform) macho.PLATFORM { |
| 4170 | 4176 | return switch (plat.os_tag) { |
| 4171 | 4177 | .driverkit => .DRIVERKIT, |
| ... | ... | @@ -4182,7 +4188,7 @@ pub const Platform = struct { |
| 4182 | 4188 | pub fn isBuildVersionCompatible(plat: Platform) bool { |
| 4183 | 4189 | inline for (supported_platforms) |sup_plat| { |
| 4184 | 4190 | if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) { |
| 4185 | return sup_plat[2] <= plat.toAppleVersion(); | |
| 4191 | return sup_plat[2] <= @backingInt(plat.version); | |
| 4186 | 4192 | } |
| 4187 | 4193 | } |
| 4188 | 4194 | return false; |
| ... | ... | @@ -4191,7 +4197,7 @@ pub const Platform = struct { |
| 4191 | 4197 | pub fn isVersionMinCompatible(plat: Platform) bool { |
| 4192 | 4198 | inline for (supported_platforms) |sup_plat| { |
| 4193 | 4199 | if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) { |
| 4194 | return sup_plat[3] <= plat.toAppleVersion(); | |
| 4200 | return sup_plat[3] <= @backingInt(plat.version); | |
| 4195 | 4201 | } |
| 4196 | 4202 | } |
| 4197 | 4203 | return false; |
| ... | ... | @@ -4250,86 +4256,8 @@ const supported_platforms = [_]SupportedPlatforms{ |
| 4250 | 4256 | }; |
| 4251 | 4257 | // zig fmt: on |
| 4252 | 4258 | |
| 4253 | pub inline fn semanticVersionToAppleVersion(version: std.SemanticVersion) u32 { | |
| 4254 | const major = version.major; | |
| 4255 | const minor = version.minor; | |
| 4256 | const patch = version.patch; | |
| 4257 | return (@as(u32, @intCast(major)) << 16) | (@as(u32, @intCast(minor)) << 8) | @as(u32, @intCast(patch)); | |
| 4258 | } | |
| 4259 | ||
| 4260 | pub inline fn appleVersionToSemanticVersion(version: u32) std.SemanticVersion { | |
| 4261 | return .{ | |
| 4262 | .major = @as(u16, @truncate(version >> 16)), | |
| 4263 | .minor = @as(u8, @truncate(version >> 8)), | |
| 4264 | .patch = @as(u8, @truncate(version)), | |
| 4265 | }; | |
| 4266 | } | |
| 4267 | ||
| 4268 | fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersion { | |
| 4269 | const gpa = comp.gpa; | |
| 4270 | ||
| 4271 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); | |
| 4272 | defer arena_allocator.deinit(); | |
| 4273 | const arena = arena_allocator.allocator(); | |
| 4274 | ||
| 4275 | const io = comp.io; | |
| 4276 | ||
| 4277 | const sdk_dir = switch (sdk_layout) { | |
| 4278 | .sdk => comp.sysroot.?, | |
| 4279 | .vendored => fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "libc", "darwin" }) catch return null, | |
| 4280 | }; | |
| 4281 | if (readSdkVersionFromSettings(arena, io, sdk_dir)) |ver| { | |
| 4282 | return parseSdkVersion(ver); | |
| 4283 | } else |_| { | |
| 4284 | // Read from settings should always succeed when vendored. | |
| 4285 | // TODO: convert to fatal linker error | |
| 4286 | if (sdk_layout == .vendored) @panic("zig installation bug: unable to parse SDK version"); | |
| 4287 | } | |
| 4288 | ||
| 4289 | // infer from pathname | |
| 4290 | const stem = fs.path.stem(sdk_dir); | |
| 4291 | const start = for (stem, 0..) |c, i| { | |
| 4292 | if (std.ascii.isDigit(c)) break i; | |
| 4293 | } else stem.len; | |
| 4294 | const end = for (stem[start..], start..) |c, i| { | |
| 4295 | if (std.ascii.isDigit(c) or c == '.') continue; | |
| 4296 | break i; | |
| 4297 | } else stem.len; | |
| 4298 | return parseSdkVersion(stem[start..end]); | |
| 4299 | } | |
| 4300 | ||
| 4301 | // Official Apple SDKs ship with a `SDKSettings.json` located at the top of SDK fs layout. | |
| 4302 | // Use property `MinimalDisplayName` to determine version. | |
| 4303 | // The file/property is also available with vendored libc. | |
| 4304 | fn readSdkVersionFromSettings(arena: Allocator, io: Io, dir: []const u8) ![]const u8 { | |
| 4305 | const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" }); | |
| 4306 | const contents = try Io.Dir.cwd().readFileAlloc(io, sdk_path, arena, .limited(std.math.maxInt(u16))); | |
| 4307 | const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{}); | |
| 4308 | if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string; | |
| 4309 | return error.SdkVersionFailure; | |
| 4310 | } | |
| 4311 | ||
| 4312 | // Versions reported by Apple aren't exactly semantically valid as they usually omit | |
| 4313 | // the patch component, so we parse SDK value by hand. | |
| 4314 | fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion { | |
| 4315 | var parsed: std.SemanticVersion = .{ | |
| 4316 | .major = 0, | |
| 4317 | .minor = 0, | |
| 4318 | .patch = 0, | |
| 4319 | }; | |
| 4320 | ||
| 4321 | const parseNext = struct { | |
| 4322 | fn parseNext(it: anytype) ?u16 { | |
| 4323 | const nn = it.next() orelse return null; | |
| 4324 | return std.fmt.parseInt(u16, nn, 10) catch null; | |
| 4325 | } | |
| 4326 | }.parseNext; | |
| 4327 | ||
| 4328 | var it = std.mem.splitAny(u8, raw, "."); | |
| 4329 | parsed.major = parseNext(&it) orelse return null; | |
| 4330 | parsed.minor = parseNext(&it) orelse return null; | |
| 4331 | parsed.patch = parseNext(&it) orelse 0; | |
| 4332 | return parsed; | |
| 4259 | pub fn setDarwinSdkVersion(self: *MachO, version: link.DarwinSdkVersion) link.Error!void { | |
| 4260 | self.sdk_version = version; | |
| 4333 | 4261 | } |
| 4334 | 4262 | |
| 4335 | 4263 | /// When allocating, the ideal_capacity is calculated by |
| ... | ... | @@ -4377,8 +4305,6 @@ const SystemLib = struct { |
| 4377 | 4305 | } |
| 4378 | 4306 | }; |
| 4379 | 4307 | |
| 4380 | pub const SdkLayout = std.zig.LibCDirs.DarwinSdkLayout; | |
| 4381 | ||
| 4382 | 4308 | const UndefinedTreatment = enum { |
| 4383 | 4309 | @"error", |
| 4384 | 4310 | warn, |
src/link/MachO/load_commands.zig+7-12| ... | ... | @@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator; |
| 9 | 9 | const DebugSymbols = @import("DebugSymbols.zig"); |
| 10 | 10 | const Dylib = @import("Dylib.zig"); |
| 11 | 11 | const MachO = @import("../MachO.zig"); |
| 12 | const link = @import("../../link.zig"); | |
| 12 | 13 | |
| 13 | 14 | pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; |
| 14 | 15 | |
| ... | ... | @@ -296,7 +297,7 @@ pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void { |
| 296 | 297 | } |
| 297 | 298 | } |
| 298 | 299 | |
| 299 | pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void { | |
| 300 | pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?link.DarwinSdkVersion, writer: *Writer) !void { | |
| 300 | 301 | const cmd: macho.LC = switch (platform.os_tag) { |
| 301 | 302 | .macos => .VERSION_MIN_MACOSX, |
| 302 | 303 | .ios, .maccatalyst => .VERSION_MIN_IPHONEOS, |
| ... | ... | @@ -306,24 +307,18 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer |
| 306 | 307 | }; |
| 307 | 308 | try writer.writeAll(mem.asBytes(&macho.version_min_command{ |
| 308 | 309 | .cmd = cmd, |
| 309 | .version = platform.toAppleVersion(), | |
| 310 | .sdk = if (sdk_version) |ver| | |
| 311 | MachO.semanticVersionToAppleVersion(ver) | |
| 312 | else | |
| 313 | platform.toAppleVersion(), | |
| 310 | .version = @backingInt(platform.version), | |
| 311 | .sdk = @backingInt(sdk_version orelse platform.version), | |
| 314 | 312 | })); |
| 315 | 313 | } |
| 316 | 314 | |
| 317 | pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void { | |
| 315 | pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?link.DarwinSdkVersion, writer: *Writer) !void { | |
| 318 | 316 | const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); |
| 319 | 317 | try writer.writeStruct(@as(macho.build_version_command, .{ |
| 320 | 318 | .cmdsize = cmdsize, |
| 321 | 319 | .platform = platform.toApplePlatform(), |
| 322 | .minos = platform.toAppleVersion(), | |
| 323 | .sdk = if (sdk_version) |ver| | |
| 324 | MachO.semanticVersionToAppleVersion(ver) | |
| 325 | else | |
| 326 | platform.toAppleVersion(), | |
| 320 | .minos = @backingInt(platform.version), | |
| 321 | .sdk = @backingInt(sdk_version orelse platform.version), | |
| 327 | 322 | .ntools = 1, |
| 328 | 323 | }), .little); |
| 329 | 324 | try writer.writeAll(mem.asBytes(&macho.build_tool_version{ |
src/link/MachO2.zig+4| ... | ... | @@ -138,6 +138,10 @@ pub fn loadInput(macho: *MachO, input: link.Input) link.Error!void { |
| 138 | 138 | _ = input; |
| 139 | 139 | @panic("TODO"); |
| 140 | 140 | } |
| 141 | pub fn setDarwinSdkVersion(macho: *MachO, version: link.DarwinSdkVersion) link.Error!void { | |
| 142 | _ = macho; | |
| 143 | std.log.err("MLUGG TODO: sdk version is '{d}.{d}.{d}'", .{ version.major, version.minor, version.patch }); | |
| 144 | } | |
| 141 | 145 | pub fn prelink(macho: *MachO, prog_node: std.Progress.Node) link.Error!void { |
| 142 | 146 | _ = macho; |
| 143 | 147 | _ = prog_node; |