| author | |
| committer | |
| log | 60a5552d414ffedf84117df57963fd5bf099c2ea |
| tree | 586178dc0f24bf9875e58a830af1e2fdde51af2f |
| parent | f2bf1390a29a9decaa5ca49d3ae720b360583b35 |
| parent | 509fe33d10e4e89a351678f4d466f30a7870ebcf |
| signature |
Add minimal support to Zig toolchain to support building iOS binaries14 files changed, 724 insertions(+), 596 deletions(-)
lib/std/build.zig+11-1| ... | @@ -2672,7 +2672,11 @@ pub const LibExeObjStep = struct { | ... | @@ -2672,7 +2672,11 @@ pub const LibExeObjStep = struct { |
| 2672 | try zig_args.append(self.builder.pathFromRoot(include_path)); | 2672 | try zig_args.append(self.builder.pathFromRoot(include_path)); |
| 2673 | }, | 2673 | }, |
| 2674 | .raw_path_system => |include_path| { | 2674 | .raw_path_system => |include_path| { |
| 2675 | try zig_args.append("-isystem"); | 2675 | if (builder.sysroot != null) { |
| 2676 | try zig_args.append("-iwithsysroot"); | ||
| 2677 | } else { | ||
| 2678 | try zig_args.append("-isystem"); | ||
| 2679 | } | ||
| 2676 | try zig_args.append(self.builder.pathFromRoot(include_path)); | 2680 | try zig_args.append(self.builder.pathFromRoot(include_path)); |
| 2677 | }, | 2681 | }, |
| 2678 | .other_step => |other| if (other.emit_h) { | 2682 | .other_step => |other| if (other.emit_h) { |
| ... | @@ -2700,6 +2704,12 @@ pub const LibExeObjStep = struct { | ... | @@ -2700,6 +2704,12 @@ pub const LibExeObjStep = struct { |
| 2700 | 2704 | ||
| 2701 | if (self.target.isDarwin()) { | 2705 | if (self.target.isDarwin()) { |
| 2702 | for (self.framework_dirs.items) |dir| { | 2706 | for (self.framework_dirs.items) |dir| { |
| 2707 | if (builder.sysroot != null) { | ||
| 2708 | try zig_args.append("-iframeworkwithsysroot"); | ||
| 2709 | } else { | ||
| 2710 | try zig_args.append("-iframework"); | ||
| 2711 | } | ||
| 2712 | try zig_args.append(dir); | ||
| 2703 | try zig_args.append("-F"); | 2713 | try zig_args.append("-F"); |
| 2704 | try zig_args.append(dir); | 2714 | try zig_args.append(dir); |
| 2705 | } | 2715 | } |
lib/std/macho.zig+15| ... | @@ -116,6 +116,21 @@ pub const build_tool_version = extern struct { | ... | @@ -116,6 +116,21 @@ pub const build_tool_version = extern struct { |
| 116 | version: u32, | 116 | version: u32, |
| 117 | }; | 117 | }; |
| 118 | 118 | ||
| 119 | pub const PLATFORM_MACOS: u32 = 0x1; | ||
| 120 | pub const PLATFORM_IOS: u32 = 0x2; | ||
| 121 | pub const PLATFORM_TVOS: u32 = 0x3; | ||
| 122 | pub const PLATFORM_WATCHOS: u32 = 0x4; | ||
| 123 | pub const PLATFORM_BRIDGEOS: u32 = 0x5; | ||
| 124 | pub const PLATFORM_MACCATALYST: u32 = 0x6; | ||
| 125 | pub const PLATFORM_IOSSIMULATOR: u32 = 0x7; | ||
| 126 | pub const PLATFORM_TVOSSIMULATOR: u32 = 0x8; | ||
| 127 | pub const PLATFORM_WATCHOSSIMULATOR: u32 = 0x9; | ||
| 128 | pub const PLATFORM_DRIVERKIT: u32 = 0x10; | ||
| 129 | |||
| 130 | pub const TOOL_CLANG: u32 = 0x1; | ||
| 131 | pub const TOOL_SWIFT: u32 = 0x2; | ||
| 132 | pub const TOOL_LD: u32 = 0x3; | ||
| 133 | |||
| 119 | /// The entry_point_command is a replacement for thread_command. | 134 | /// The entry_point_command is a replacement for thread_command. |
| 120 | /// It is used for main executables to specify the location (file offset) | 135 | /// It is used for main executables to specify the location (file offset) |
| 121 | /// of main(). If -stack_size was used at link time, the stacksize | 136 | /// of main(). If -stack_size was used at link time, the stacksize |
lib/std/zig/system.zig+4-6| ... | @@ -13,12 +13,10 @@ const assert = std.debug.assert; | ... | @@ -13,12 +13,10 @@ const assert = std.debug.assert; |
| 13 | const process = std.process; | 13 | const process = std.process; |
| 14 | const Target = std.Target; | 14 | const Target = std.Target; |
| 15 | const CrossTarget = std.zig.CrossTarget; | 15 | const CrossTarget = std.zig.CrossTarget; |
| 16 | const macos = @import("system/macos.zig"); | ||
| 17 | const native_endian = std.Target.current.cpu.arch.endian(); | 16 | const native_endian = std.Target.current.cpu.arch.endian(); |
| 18 | const linux = @import("system/linux.zig"); | 17 | const linux = @import("system/linux.zig"); |
| 19 | pub const windows = @import("system/windows.zig"); | 18 | pub const windows = @import("system/windows.zig"); |
| 20 | 19 | pub const darwin = @import("system/darwin.zig"); | |
| 21 | pub const getSDKPath = macos.getSDKPath; | ||
| 22 | 20 | ||
| 23 | pub const NativePaths = struct { | 21 | pub const NativePaths = struct { |
| 24 | include_dirs: ArrayList([:0]u8), | 22 | include_dirs: ArrayList([:0]u8), |
| ... | @@ -255,7 +253,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -255,7 +253,7 @@ pub const NativeTargetInfo = struct { |
| 255 | os.version_range.windows.min = detected_version; | 253 | os.version_range.windows.min = detected_version; |
| 256 | os.version_range.windows.max = detected_version; | 254 | os.version_range.windows.max = detected_version; |
| 257 | }, | 255 | }, |
| 258 | .macos => try macos.detect(&os), | 256 | .macos => try darwin.macos.detect(&os), |
| 259 | .freebsd, .netbsd, .dragonfly => { | 257 | .freebsd, .netbsd, .dragonfly => { |
| 260 | const key = switch (Target.current.os.tag) { | 258 | const key = switch (Target.current.os.tag) { |
| 261 | .freebsd => "kern.osreldate", | 259 | .freebsd => "kern.osreldate", |
| ... | @@ -972,7 +970,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -972,7 +970,7 @@ pub const NativeTargetInfo = struct { |
| 972 | 970 | ||
| 973 | switch (std.Target.current.os.tag) { | 971 | switch (std.Target.current.os.tag) { |
| 974 | .linux => return linux.detectNativeCpuAndFeatures(), | 972 | .linux => return linux.detectNativeCpuAndFeatures(), |
| 975 | .macos => return macos.detectNativeCpuAndFeatures(), | 973 | .macos => return darwin.macos.detectNativeCpuAndFeatures(), |
| 976 | else => {}, | 974 | else => {}, |
| 977 | } | 975 | } |
| 978 | 976 | ||
| ... | @@ -983,6 +981,6 @@ pub const NativeTargetInfo = struct { | ... | @@ -983,6 +981,6 @@ pub const NativeTargetInfo = struct { |
| 983 | }; | 981 | }; |
| 984 | 982 | ||
| 985 | test { | 983 | test { |
| 986 | _ = @import("system/macos.zig"); | 984 | _ = @import("system/darwin.zig"); |
| 987 | _ = @import("system/linux.zig"); | 985 | _ = @import("system/linux.zig"); |
| 988 | } | 986 | } |
lib/std/zig/system/darwin.zig created+44| ... | @@ -0,0 +1,44 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2021 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | const std = @import("std"); | ||
| 7 | const mem = std.mem; | ||
| 8 | const Allocator = mem.Allocator; | ||
| 9 | const Target = std.Target; | ||
| 10 | |||
| 11 | pub const macos = @import("darwin/macos.zig"); | ||
| 12 | |||
| 13 | /// Detect SDK path on Darwin. | ||
| 14 | /// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which result can be used to specify | ||
| 15 | /// `--sysroot` of the compiler. | ||
| 16 | /// The caller needs to free the resulting path slice. | ||
| 17 | pub fn getSDKPath(allocator: *Allocator, target: Target) !?[]u8 { | ||
| 18 | const is_simulator_abi = target.abi == .simulator; | ||
| 19 | const sdk = switch (target.os.tag) { | ||
| 20 | .macos => "macosx", | ||
| 21 | .ios => if (is_simulator_abi) "iphonesimulator" else "iphoneos", | ||
| 22 | .watchos => if (is_simulator_abi) "watchsimulator" else "watchos", | ||
| 23 | .tvos => if (is_simulator_abi) "appletvsimulator" else "appletvos", | ||
| 24 | else => return null, | ||
| 25 | }; | ||
| 26 | |||
| 27 | const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" }; | ||
| 28 | const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }); | ||
| 29 | defer { | ||
| 30 | allocator.free(result.stderr); | ||
| 31 | allocator.free(result.stdout); | ||
| 32 | } | ||
| 33 | if (result.stderr.len != 0 or result.term.Exited != 0) { | ||
| 34 | // We don't actually care if there were errors as this is best-effort check anyhow | ||
| 35 | // and in the worst case the user can specify the sysroot manually. | ||
| 36 | return null; | ||
| 37 | } | ||
| 38 | const sysroot = try allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n")); | ||
| 39 | return sysroot; | ||
| 40 | } | ||
| 41 | |||
| 42 | test "" { | ||
| 43 | _ = @import("darwin/macos.zig"); | ||
| 44 | } | ||
lib/std/zig/system/darwin/macos.zig created+447| ... | @@ -0,0 +1,447 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2021 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | const std = @import("std"); | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const mem = std.mem; | ||
| 9 | const testing = std.testing; | ||
| 10 | const os = std.os; | ||
| 11 | |||
| 12 | const Target = std.Target; | ||
| 13 | |||
| 14 | /// Detect macOS version. | ||
| 15 | /// `target_os` is not modified in case of error. | ||
| 16 | pub fn detect(target_os: *Target.Os) !void { | ||
| 17 | // Drop use of osproductversion sysctl because: | ||
| 18 | // 1. only available 10.13.4 High Sierra and later | ||
| 19 | // 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version | ||
| 20 | // | ||
| 21 | // NEW APPROACH, STEP 1, parse file: | ||
| 22 | // | ||
| 23 | // /System/Library/CoreServices/SystemVersion.plist | ||
| 24 | // | ||
| 25 | // NOTE: Historically `SystemVersion.plist` first appeared circa '2003 | ||
| 26 | // with the release of Mac OS X 10.3.0 Panther. | ||
| 27 | // | ||
| 28 | // and if it contains a `10.16` value where the `16` is `>= 16` then it is non-canonical, | ||
| 29 | // discarded, and we move on to next step. Otherwise we accept the version. | ||
| 30 | // | ||
| 31 | // BACKGROUND: `10.(16+)` is not a proper version and does not have enough fidelity to | ||
| 32 | // indicate minor/point version of Big Sur and later. It is a context-sensitive result | ||
| 33 | // issued by the kernel for backwards compatibility purposes. Likely the kernel checks | ||
| 34 | // if the executable was linked against an SDK older than Big Sur. | ||
| 35 | // | ||
| 36 | // STEP 2, parse next file: | ||
| 37 | // | ||
| 38 | // /System/Library/CoreServices/.SystemVersionPlatform.plist | ||
| 39 | // | ||
| 40 | // NOTE: Historically `SystemVersionPlatform.plist` first appeared circa '2020 | ||
| 41 | // with the release of macOS 11.0 Big Sur. | ||
| 42 | // | ||
| 43 | // Accessing the content via this path circumvents a context-sensitive result and | ||
| 44 | // yields a canonical Big Sur version. | ||
| 45 | // | ||
| 46 | // At this time there is no other known way for a < SDK 11.0 executable to obtain a | ||
| 47 | // canonical Big Sur version. | ||
| 48 | // | ||
| 49 | // This implementation uses a reasonably simplified approach to parse .plist file | ||
| 50 | // that while it is an xml document, we have good history on the file and its format | ||
| 51 | // such that I am comfortable with implementing a minimalistic parser. | ||
| 52 | // Things like string and general escapes are not supported. | ||
| 53 | const prefixSlash = "/System/Library/CoreServices/"; | ||
| 54 | const paths = [_][]const u8{ | ||
| 55 | prefixSlash ++ "SystemVersion.plist", | ||
| 56 | prefixSlash ++ ".SystemVersionPlatform.plist", | ||
| 57 | }; | ||
| 58 | for (paths) |path| { | ||
| 59 | // approx. 4 times historical file size | ||
| 60 | var buf: [2048]u8 = undefined; | ||
| 61 | |||
| 62 | if (std.fs.cwd().readFile(path, &buf)) |bytes| { | ||
| 63 | if (parseSystemVersion(bytes)) |ver| { | ||
| 64 | // never return non-canonical `10.(16+)` | ||
| 65 | if (!(ver.major == 10 and ver.minor >= 16)) { | ||
| 66 | target_os.version_range.semver.min = ver; | ||
| 67 | target_os.version_range.semver.max = ver; | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | continue; | ||
| 71 | } else |_| { | ||
| 72 | return error.OSVersionDetectionFail; | ||
| 73 | } | ||
| 74 | } else |_| { | ||
| 75 | return error.OSVersionDetectionFail; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return error.OSVersionDetectionFail; | ||
| 79 | } | ||
| 80 | |||
| 81 | fn parseSystemVersion(buf: []const u8) !std.builtin.Version { | ||
| 82 | var svt = SystemVersionTokenizer{ .bytes = buf }; | ||
| 83 | try svt.skipUntilTag(.start, "dict"); | ||
| 84 | while (true) { | ||
| 85 | try svt.skipUntilTag(.start, "key"); | ||
| 86 | const content = try svt.expectContent(); | ||
| 87 | try svt.skipUntilTag(.end, "key"); | ||
| 88 | if (std.mem.eql(u8, content, "ProductVersion")) break; | ||
| 89 | } | ||
| 90 | try svt.skipUntilTag(.start, "string"); | ||
| 91 | const ver = try svt.expectContent(); | ||
| 92 | try svt.skipUntilTag(.end, "string"); | ||
| 93 | |||
| 94 | return std.builtin.Version.parse(ver); | ||
| 95 | } | ||
| 96 | |||
| 97 | const SystemVersionTokenizer = struct { | ||
| 98 | bytes: []const u8, | ||
| 99 | index: usize = 0, | ||
| 100 | state: State = .begin, | ||
| 101 | |||
| 102 | fn next(self: *@This()) !?Token { | ||
| 103 | var mark: usize = self.index; | ||
| 104 | var tag = Tag{}; | ||
| 105 | var content: []const u8 = ""; | ||
| 106 | |||
| 107 | while (self.index < self.bytes.len) { | ||
| 108 | const char = self.bytes[self.index]; | ||
| 109 | switch (self.state) { | ||
| 110 | .begin => switch (char) { | ||
| 111 | '<' => { | ||
| 112 | self.state = .tag0; | ||
| 113 | self.index += 1; | ||
| 114 | tag = Tag{}; | ||
| 115 | mark = self.index; | ||
| 116 | }, | ||
| 117 | '>' => { | ||
| 118 | return error.BadToken; | ||
| 119 | }, | ||
| 120 | else => { | ||
| 121 | self.state = .content; | ||
| 122 | content = ""; | ||
| 123 | mark = self.index; | ||
| 124 | }, | ||
| 125 | }, | ||
| 126 | .tag0 => switch (char) { | ||
| 127 | '<' => { | ||
| 128 | return error.BadToken; | ||
| 129 | }, | ||
| 130 | '>' => { | ||
| 131 | self.state = .begin; | ||
| 132 | self.index += 1; | ||
| 133 | tag.name = self.bytes[mark..self.index]; | ||
| 134 | return Token{ .tag = tag }; | ||
| 135 | }, | ||
| 136 | '"' => { | ||
| 137 | self.state = .tag_string; | ||
| 138 | self.index += 1; | ||
| 139 | }, | ||
| 140 | '/' => { | ||
| 141 | self.state = .tag0_end_or_empty; | ||
| 142 | self.index += 1; | ||
| 143 | }, | ||
| 144 | 'A'...'Z', 'a'...'z' => { | ||
| 145 | self.state = .tagN; | ||
| 146 | tag.kind = .start; | ||
| 147 | self.index += 1; | ||
| 148 | }, | ||
| 149 | else => { | ||
| 150 | self.state = .tagN; | ||
| 151 | self.index += 1; | ||
| 152 | }, | ||
| 153 | }, | ||
| 154 | .tag0_end_or_empty => switch (char) { | ||
| 155 | '<' => { | ||
| 156 | return error.BadToken; | ||
| 157 | }, | ||
| 158 | '>' => { | ||
| 159 | self.state = .begin; | ||
| 160 | tag.kind = .empty; | ||
| 161 | tag.name = self.bytes[self.index..self.index]; | ||
| 162 | self.index += 1; | ||
| 163 | return Token{ .tag = tag }; | ||
| 164 | }, | ||
| 165 | else => { | ||
| 166 | self.state = .tagN; | ||
| 167 | tag.kind = .end; | ||
| 168 | mark = self.index; | ||
| 169 | self.index += 1; | ||
| 170 | }, | ||
| 171 | }, | ||
| 172 | .tagN => switch (char) { | ||
| 173 | '<' => { | ||
| 174 | return error.BadToken; | ||
| 175 | }, | ||
| 176 | '>' => { | ||
| 177 | self.state = .begin; | ||
| 178 | tag.name = self.bytes[mark..self.index]; | ||
| 179 | self.index += 1; | ||
| 180 | return Token{ .tag = tag }; | ||
| 181 | }, | ||
| 182 | '"' => { | ||
| 183 | self.state = .tag_string; | ||
| 184 | self.index += 1; | ||
| 185 | }, | ||
| 186 | '/' => { | ||
| 187 | self.state = .tagN_end; | ||
| 188 | tag.kind = .end; | ||
| 189 | self.index += 1; | ||
| 190 | }, | ||
| 191 | else => { | ||
| 192 | self.index += 1; | ||
| 193 | }, | ||
| 194 | }, | ||
| 195 | .tagN_end => switch (char) { | ||
| 196 | '>' => { | ||
| 197 | self.state = .begin; | ||
| 198 | tag.name = self.bytes[mark..self.index]; | ||
| 199 | self.index += 1; | ||
| 200 | return Token{ .tag = tag }; | ||
| 201 | }, | ||
| 202 | else => { | ||
| 203 | return error.BadToken; | ||
| 204 | }, | ||
| 205 | }, | ||
| 206 | .tag_string => switch (char) { | ||
| 207 | '"' => { | ||
| 208 | self.state = .tagN; | ||
| 209 | self.index += 1; | ||
| 210 | }, | ||
| 211 | else => { | ||
| 212 | self.index += 1; | ||
| 213 | }, | ||
| 214 | }, | ||
| 215 | .content => switch (char) { | ||
| 216 | '<' => { | ||
| 217 | self.state = .tag0; | ||
| 218 | content = self.bytes[mark..self.index]; | ||
| 219 | self.index += 1; | ||
| 220 | tag = Tag{}; | ||
| 221 | mark = self.index; | ||
| 222 | return Token{ .content = content }; | ||
| 223 | }, | ||
| 224 | '>' => { | ||
| 225 | return error.BadToken; | ||
| 226 | }, | ||
| 227 | else => { | ||
| 228 | self.index += 1; | ||
| 229 | }, | ||
| 230 | }, | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | return null; | ||
| 235 | } | ||
| 236 | |||
| 237 | fn expectContent(self: *@This()) ![]const u8 { | ||
| 238 | if (try self.next()) |tok| { | ||
| 239 | switch (tok) { | ||
| 240 | .content => |content| { | ||
| 241 | return content; | ||
| 242 | }, | ||
| 243 | else => {}, | ||
| 244 | } | ||
| 245 | } | ||
| 246 | return error.UnexpectedToken; | ||
| 247 | } | ||
| 248 | |||
| 249 | fn skipUntilTag(self: *@This(), kind: Tag.Kind, name: []const u8) !void { | ||
| 250 | while (try self.next()) |tok| { | ||
| 251 | switch (tok) { | ||
| 252 | .tag => |tag| { | ||
| 253 | if (tag.kind == kind and std.mem.eql(u8, tag.name, name)) return; | ||
| 254 | }, | ||
| 255 | else => {}, | ||
| 256 | } | ||
| 257 | } | ||
| 258 | return error.TagNotFound; | ||
| 259 | } | ||
| 260 | |||
| 261 | const State = enum { | ||
| 262 | begin, | ||
| 263 | tag0, | ||
| 264 | tag0_end_or_empty, | ||
| 265 | tagN, | ||
| 266 | tagN_end, | ||
| 267 | tag_string, | ||
| 268 | content, | ||
| 269 | }; | ||
| 270 | |||
| 271 | const Token = union(enum) { | ||
| 272 | tag: Tag, | ||
| 273 | content: []const u8, | ||
| 274 | }; | ||
| 275 | |||
| 276 | const Tag = struct { | ||
| 277 | kind: Kind = .unknown, | ||
| 278 | name: []const u8 = "", | ||
| 279 | |||
| 280 | const Kind = enum { unknown, start, end, empty }; | ||
| 281 | }; | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "detect" { | ||
| 285 | const cases = .{ | ||
| 286 | .{ | ||
| 287 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 288 | \\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 289 | \\<plist version="1.0"> | ||
| 290 | \\<dict> | ||
| 291 | \\ <key>ProductBuildVersion</key> | ||
| 292 | \\ <string>7B85</string> | ||
| 293 | \\ <key>ProductCopyright</key> | ||
| 294 | \\ <string>Apple Computer, Inc. 1983-2003</string> | ||
| 295 | \\ <key>ProductName</key> | ||
| 296 | \\ <string>Mac OS X</string> | ||
| 297 | \\ <key>ProductUserVisibleVersion</key> | ||
| 298 | \\ <string>10.3</string> | ||
| 299 | \\ <key>ProductVersion</key> | ||
| 300 | \\ <string>10.3</string> | ||
| 301 | \\</dict> | ||
| 302 | \\</plist> | ||
| 303 | , | ||
| 304 | .{ .major = 10, .minor = 3 }, | ||
| 305 | }, | ||
| 306 | .{ | ||
| 307 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 308 | \\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 309 | \\<plist version="1.0"> | ||
| 310 | \\<dict> | ||
| 311 | \\	<key>ProductBuildVersion</key> | ||
| 312 | \\	<string>7W98</string> | ||
| 313 | \\	<key>ProductCopyright</key> | ||
| 314 | \\	<string>Apple Computer, Inc. 1983-2004</string> | ||
| 315 | \\	<key>ProductName</key> | ||
| 316 | \\	<string>Mac OS X</string> | ||
| 317 | \\	<key>ProductUserVisibleVersion</key> | ||
| 318 | \\	<string>10.3.9</string> | ||
| 319 | \\	<key>ProductVersion</key> | ||
| 320 | \\	<string>10.3.9</string> | ||
| 321 | \\</dict> | ||
| 322 | \\</plist> | ||
| 323 | , | ||
| 324 | .{ .major = 10, .minor = 3, .patch = 9 }, | ||
| 325 | }, | ||
| 326 | .{ | ||
| 327 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 328 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 329 | \\<plist version="1.0"> | ||
| 330 | \\<dict> | ||
| 331 | \\	<key>ProductBuildVersion</key> | ||
| 332 | \\	<string>19G68</string> | ||
| 333 | \\	<key>ProductCopyright</key> | ||
| 334 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 335 | \\	<key>ProductName</key> | ||
| 336 | \\	<string>Mac OS X</string> | ||
| 337 | \\	<key>ProductUserVisibleVersion</key> | ||
| 338 | \\	<string>10.15.6</string> | ||
| 339 | \\	<key>ProductVersion</key> | ||
| 340 | \\	<string>10.15.6</string> | ||
| 341 | \\	<key>iOSSupportVersion</key> | ||
| 342 | \\	<string>13.6</string> | ||
| 343 | \\</dict> | ||
| 344 | \\</plist> | ||
| 345 | , | ||
| 346 | .{ .major = 10, .minor = 15, .patch = 6 }, | ||
| 347 | }, | ||
| 348 | .{ | ||
| 349 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 350 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 351 | \\<plist version="1.0"> | ||
| 352 | \\<dict> | ||
| 353 | \\	<key>ProductBuildVersion</key> | ||
| 354 | \\	<string>20A2408</string> | ||
| 355 | \\	<key>ProductCopyright</key> | ||
| 356 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 357 | \\	<key>ProductName</key> | ||
| 358 | \\	<string>macOS</string> | ||
| 359 | \\	<key>ProductUserVisibleVersion</key> | ||
| 360 | \\	<string>11.0</string> | ||
| 361 | \\	<key>ProductVersion</key> | ||
| 362 | \\	<string>11.0</string> | ||
| 363 | \\	<key>iOSSupportVersion</key> | ||
| 364 | \\	<string>14.2</string> | ||
| 365 | \\</dict> | ||
| 366 | \\</plist> | ||
| 367 | , | ||
| 368 | .{ .major = 11, .minor = 0 }, | ||
| 369 | }, | ||
| 370 | .{ | ||
| 371 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 372 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 373 | \\<plist version="1.0"> | ||
| 374 | \\<dict> | ||
| 375 | \\	<key>ProductBuildVersion</key> | ||
| 376 | \\	<string>20C63</string> | ||
| 377 | \\	<key>ProductCopyright</key> | ||
| 378 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 379 | \\	<key>ProductName</key> | ||
| 380 | \\	<string>macOS</string> | ||
| 381 | \\	<key>ProductUserVisibleVersion</key> | ||
| 382 | \\	<string>11.1</string> | ||
| 383 | \\	<key>ProductVersion</key> | ||
| 384 | \\	<string>11.1</string> | ||
| 385 | \\	<key>iOSSupportVersion</key> | ||
| 386 | \\	<string>14.3</string> | ||
| 387 | \\</dict> | ||
| 388 | \\</plist> | ||
| 389 | , | ||
| 390 | .{ .major = 11, .minor = 1 }, | ||
| 391 | }, | ||
| 392 | }; | ||
| 393 | |||
| 394 | inline for (cases) |case| { | ||
| 395 | const ver0 = try parseSystemVersion(case[0]); | ||
| 396 | const ver1: std.builtin.Version = case[1]; | ||
| 397 | try testVersionEquality(ver1, ver0); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version) !void { | ||
| 402 | var b_expected: [64]u8 = undefined; | ||
| 403 | const s_expected: []const u8 = try std.fmt.bufPrint(b_expected[0..], "{}", .{expected}); | ||
| 404 | |||
| 405 | var b_got: [64]u8 = undefined; | ||
| 406 | const s_got: []const u8 = try std.fmt.bufPrint(b_got[0..], "{}", .{got}); | ||
| 407 | |||
| 408 | try testing.expectEqualStrings(s_expected, s_got); | ||
| 409 | } | ||
| 410 | |||
| 411 | pub fn detectNativeCpuAndFeatures() ?Target.Cpu { | ||
| 412 | var cpu_family: os.CPUFAMILY = undefined; | ||
| 413 | var len: usize = @sizeOf(os.CPUFAMILY); | ||
| 414 | os.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) { | ||
| 415 | error.NameTooLong => unreachable, // constant, known good value | ||
| 416 | error.PermissionDenied => unreachable, // only when setting values, | ||
| 417 | error.SystemResources => unreachable, // memory already on the stack | ||
| 418 | error.UnknownName => unreachable, // constant, known good value | ||
| 419 | error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value | ||
| 420 | }; | ||
| 421 | |||
| 422 | const current_arch = Target.current.cpu.arch; | ||
| 423 | switch (current_arch) { | ||
| 424 | .aarch64, .aarch64_be, .aarch64_32 => { | ||
| 425 | const model = switch (cpu_family) { | ||
| 426 | .ARM_FIRESTORM_ICESTORM => &Target.aarch64.cpu.apple_a14, | ||
| 427 | .ARM_LIGHTNING_THUNDER => &Target.aarch64.cpu.apple_a13, | ||
| 428 | .ARM_VORTEX_TEMPEST => &Target.aarch64.cpu.apple_a12, | ||
| 429 | .ARM_MONSOON_MISTRAL => &Target.aarch64.cpu.apple_a11, | ||
| 430 | .ARM_HURRICANE => &Target.aarch64.cpu.apple_a10, | ||
| 431 | .ARM_TWISTER => &Target.aarch64.cpu.apple_a9, | ||
| 432 | .ARM_TYPHOON => &Target.aarch64.cpu.apple_a8, | ||
| 433 | .ARM_CYCLONE => &Target.aarch64.cpu.cyclone, | ||
| 434 | else => return null, | ||
| 435 | }; | ||
| 436 | |||
| 437 | return Target.Cpu{ | ||
| 438 | .arch = current_arch, | ||
| 439 | .model = model, | ||
| 440 | .features = model.features, | ||
| 441 | }; | ||
| 442 | }, | ||
| 443 | else => {}, | ||
| 444 | } | ||
| 445 | |||
| 446 | return null; | ||
| 447 | } | ||
lib/std/zig/system/macos.zig deleted-469| ... | @@ -1,469 +0,0 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2021 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software. | ||
| 6 | const std = @import("std"); | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const mem = std.mem; | ||
| 9 | const testing = std.testing; | ||
| 10 | const os = std.os; | ||
| 11 | |||
| 12 | const Target = std.Target; | ||
| 13 | |||
| 14 | /// Detect macOS version. | ||
| 15 | /// `target_os` is not modified in case of error. | ||
| 16 | pub fn detect(target_os: *Target.Os) !void { | ||
| 17 | // Drop use of osproductversion sysctl because: | ||
| 18 | // 1. only available 10.13.4 High Sierra and later | ||
| 19 | // 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version | ||
| 20 | // | ||
| 21 | // NEW APPROACH, STEP 1, parse file: | ||
| 22 | // | ||
| 23 | // /System/Library/CoreServices/SystemVersion.plist | ||
| 24 | // | ||
| 25 | // NOTE: Historically `SystemVersion.plist` first appeared circa '2003 | ||
| 26 | // with the release of Mac OS X 10.3.0 Panther. | ||
| 27 | // | ||
| 28 | // and if it contains a `10.16` value where the `16` is `>= 16` then it is non-canonical, | ||
| 29 | // discarded, and we move on to next step. Otherwise we accept the version. | ||
| 30 | // | ||
| 31 | // BACKGROUND: `10.(16+)` is not a proper version and does not have enough fidelity to | ||
| 32 | // indicate minor/point version of Big Sur and later. It is a context-sensitive result | ||
| 33 | // issued by the kernel for backwards compatibility purposes. Likely the kernel checks | ||
| 34 | // if the executable was linked against an SDK older than Big Sur. | ||
| 35 | // | ||
| 36 | // STEP 2, parse next file: | ||
| 37 | // | ||
| 38 | // /System/Library/CoreServices/.SystemVersionPlatform.plist | ||
| 39 | // | ||
| 40 | // NOTE: Historically `SystemVersionPlatform.plist` first appeared circa '2020 | ||
| 41 | // with the release of macOS 11.0 Big Sur. | ||
| 42 | // | ||
| 43 | // Accessing the content via this path circumvents a context-sensitive result and | ||
| 44 | // yields a canonical Big Sur version. | ||
| 45 | // | ||
| 46 | // At this time there is no other known way for a < SDK 11.0 executable to obtain a | ||
| 47 | // canonical Big Sur version. | ||
| 48 | // | ||
| 49 | // This implementation uses a reasonably simplified approach to parse .plist file | ||
| 50 | // that while it is an xml document, we have good history on the file and its format | ||
| 51 | // such that I am comfortable with implementing a minimalistic parser. | ||
| 52 | // Things like string and general escapes are not supported. | ||
| 53 | const prefixSlash = "/System/Library/CoreServices/"; | ||
| 54 | const paths = [_][]const u8{ | ||
| 55 | prefixSlash ++ "SystemVersion.plist", | ||
| 56 | prefixSlash ++ ".SystemVersionPlatform.plist", | ||
| 57 | }; | ||
| 58 | for (paths) |path| { | ||
| 59 | // approx. 4 times historical file size | ||
| 60 | var buf: [2048]u8 = undefined; | ||
| 61 | |||
| 62 | if (std.fs.cwd().readFile(path, &buf)) |bytes| { | ||
| 63 | if (parseSystemVersion(bytes)) |ver| { | ||
| 64 | // never return non-canonical `10.(16+)` | ||
| 65 | if (!(ver.major == 10 and ver.minor >= 16)) { | ||
| 66 | target_os.version_range.semver.min = ver; | ||
| 67 | target_os.version_range.semver.max = ver; | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | continue; | ||
| 71 | } else |_| { | ||
| 72 | return error.OSVersionDetectionFail; | ||
| 73 | } | ||
| 74 | } else |_| { | ||
| 75 | return error.OSVersionDetectionFail; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | return error.OSVersionDetectionFail; | ||
| 79 | } | ||
| 80 | |||
| 81 | fn parseSystemVersion(buf: []const u8) !std.builtin.Version { | ||
| 82 | var svt = SystemVersionTokenizer{ .bytes = buf }; | ||
| 83 | try svt.skipUntilTag(.start, "dict"); | ||
| 84 | while (true) { | ||
| 85 | try svt.skipUntilTag(.start, "key"); | ||
| 86 | const content = try svt.expectContent(); | ||
| 87 | try svt.skipUntilTag(.end, "key"); | ||
| 88 | if (std.mem.eql(u8, content, "ProductVersion")) break; | ||
| 89 | } | ||
| 90 | try svt.skipUntilTag(.start, "string"); | ||
| 91 | const ver = try svt.expectContent(); | ||
| 92 | try svt.skipUntilTag(.end, "string"); | ||
| 93 | |||
| 94 | return std.builtin.Version.parse(ver); | ||
| 95 | } | ||
| 96 | |||
| 97 | const SystemVersionTokenizer = struct { | ||
| 98 | bytes: []const u8, | ||
| 99 | index: usize = 0, | ||
| 100 | state: State = .begin, | ||
| 101 | |||
| 102 | fn next(self: *@This()) !?Token { | ||
| 103 | var mark: usize = self.index; | ||
| 104 | var tag = Tag{}; | ||
| 105 | var content: []const u8 = ""; | ||
| 106 | |||
| 107 | while (self.index < self.bytes.len) { | ||
| 108 | const char = self.bytes[self.index]; | ||
| 109 | switch (self.state) { | ||
| 110 | .begin => switch (char) { | ||
| 111 | '<' => { | ||
| 112 | self.state = .tag0; | ||
| 113 | self.index += 1; | ||
| 114 | tag = Tag{}; | ||
| 115 | mark = self.index; | ||
| 116 | }, | ||
| 117 | '>' => { | ||
| 118 | return error.BadToken; | ||
| 119 | }, | ||
| 120 | else => { | ||
| 121 | self.state = .content; | ||
| 122 | content = ""; | ||
| 123 | mark = self.index; | ||
| 124 | }, | ||
| 125 | }, | ||
| 126 | .tag0 => switch (char) { | ||
| 127 | '<' => { | ||
| 128 | return error.BadToken; | ||
| 129 | }, | ||
| 130 | '>' => { | ||
| 131 | self.state = .begin; | ||
| 132 | self.index += 1; | ||
| 133 | tag.name = self.bytes[mark..self.index]; | ||
| 134 | return Token{ .tag = tag }; | ||
| 135 | }, | ||
| 136 | '"' => { | ||
| 137 | self.state = .tag_string; | ||
| 138 | self.index += 1; | ||
| 139 | }, | ||
| 140 | '/' => { | ||
| 141 | self.state = .tag0_end_or_empty; | ||
| 142 | self.index += 1; | ||
| 143 | }, | ||
| 144 | 'A'...'Z', 'a'...'z' => { | ||
| 145 | self.state = .tagN; | ||
| 146 | tag.kind = .start; | ||
| 147 | self.index += 1; | ||
| 148 | }, | ||
| 149 | else => { | ||
| 150 | self.state = .tagN; | ||
| 151 | self.index += 1; | ||
| 152 | }, | ||
| 153 | }, | ||
| 154 | .tag0_end_or_empty => switch (char) { | ||
| 155 | '<' => { | ||
| 156 | return error.BadToken; | ||
| 157 | }, | ||
| 158 | '>' => { | ||
| 159 | self.state = .begin; | ||
| 160 | tag.kind = .empty; | ||
| 161 | tag.name = self.bytes[self.index..self.index]; | ||
| 162 | self.index += 1; | ||
| 163 | return Token{ .tag = tag }; | ||
| 164 | }, | ||
| 165 | else => { | ||
| 166 | self.state = .tagN; | ||
| 167 | tag.kind = .end; | ||
| 168 | mark = self.index; | ||
| 169 | self.index += 1; | ||
| 170 | }, | ||
| 171 | }, | ||
| 172 | .tagN => switch (char) { | ||
| 173 | '<' => { | ||
| 174 | return error.BadToken; | ||
| 175 | }, | ||
| 176 | '>' => { | ||
| 177 | self.state = .begin; | ||
| 178 | tag.name = self.bytes[mark..self.index]; | ||
| 179 | self.index += 1; | ||
| 180 | return Token{ .tag = tag }; | ||
| 181 | }, | ||
| 182 | '"' => { | ||
| 183 | self.state = .tag_string; | ||
| 184 | self.index += 1; | ||
| 185 | }, | ||
| 186 | '/' => { | ||
| 187 | self.state = .tagN_end; | ||
| 188 | tag.kind = .end; | ||
| 189 | self.index += 1; | ||
| 190 | }, | ||
| 191 | else => { | ||
| 192 | self.index += 1; | ||
| 193 | }, | ||
| 194 | }, | ||
| 195 | .tagN_end => switch (char) { | ||
| 196 | '>' => { | ||
| 197 | self.state = .begin; | ||
| 198 | tag.name = self.bytes[mark..self.index]; | ||
| 199 | self.index += 1; | ||
| 200 | return Token{ .tag = tag }; | ||
| 201 | }, | ||
| 202 | else => { | ||
| 203 | return error.BadToken; | ||
| 204 | }, | ||
| 205 | }, | ||
| 206 | .tag_string => switch (char) { | ||
| 207 | '"' => { | ||
| 208 | self.state = .tagN; | ||
| 209 | self.index += 1; | ||
| 210 | }, | ||
| 211 | else => { | ||
| 212 | self.index += 1; | ||
| 213 | }, | ||
| 214 | }, | ||
| 215 | .content => switch (char) { | ||
| 216 | '<' => { | ||
| 217 | self.state = .tag0; | ||
| 218 | content = self.bytes[mark..self.index]; | ||
| 219 | self.index += 1; | ||
| 220 | tag = Tag{}; | ||
| 221 | mark = self.index; | ||
| 222 | return Token{ .content = content }; | ||
| 223 | }, | ||
| 224 | '>' => { | ||
| 225 | return error.BadToken; | ||
| 226 | }, | ||
| 227 | else => { | ||
| 228 | self.index += 1; | ||
| 229 | }, | ||
| 230 | }, | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | return null; | ||
| 235 | } | ||
| 236 | |||
| 237 | fn expectContent(self: *@This()) ![]const u8 { | ||
| 238 | if (try self.next()) |tok| { | ||
| 239 | switch (tok) { | ||
| 240 | .content => |content| { | ||
| 241 | return content; | ||
| 242 | }, | ||
| 243 | else => {}, | ||
| 244 | } | ||
| 245 | } | ||
| 246 | return error.UnexpectedToken; | ||
| 247 | } | ||
| 248 | |||
| 249 | fn skipUntilTag(self: *@This(), kind: Tag.Kind, name: []const u8) !void { | ||
| 250 | while (try self.next()) |tok| { | ||
| 251 | switch (tok) { | ||
| 252 | .tag => |tag| { | ||
| 253 | if (tag.kind == kind and std.mem.eql(u8, tag.name, name)) return; | ||
| 254 | }, | ||
| 255 | else => {}, | ||
| 256 | } | ||
| 257 | } | ||
| 258 | return error.TagNotFound; | ||
| 259 | } | ||
| 260 | |||
| 261 | const State = enum { | ||
| 262 | begin, | ||
| 263 | tag0, | ||
| 264 | tag0_end_or_empty, | ||
| 265 | tagN, | ||
| 266 | tagN_end, | ||
| 267 | tag_string, | ||
| 268 | content, | ||
| 269 | }; | ||
| 270 | |||
| 271 | const Token = union(enum) { | ||
| 272 | tag: Tag, | ||
| 273 | content: []const u8, | ||
| 274 | }; | ||
| 275 | |||
| 276 | const Tag = struct { | ||
| 277 | kind: Kind = .unknown, | ||
| 278 | name: []const u8 = "", | ||
| 279 | |||
| 280 | const Kind = enum { unknown, start, end, empty }; | ||
| 281 | }; | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "detect" { | ||
| 285 | const cases = .{ | ||
| 286 | .{ | ||
| 287 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 288 | \\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 289 | \\<plist version="1.0"> | ||
| 290 | \\<dict> | ||
| 291 | \\ <key>ProductBuildVersion</key> | ||
| 292 | \\ <string>7B85</string> | ||
| 293 | \\ <key>ProductCopyright</key> | ||
| 294 | \\ <string>Apple Computer, Inc. 1983-2003</string> | ||
| 295 | \\ <key>ProductName</key> | ||
| 296 | \\ <string>Mac OS X</string> | ||
| 297 | \\ <key>ProductUserVisibleVersion</key> | ||
| 298 | \\ <string>10.3</string> | ||
| 299 | \\ <key>ProductVersion</key> | ||
| 300 | \\ <string>10.3</string> | ||
| 301 | \\</dict> | ||
| 302 | \\</plist> | ||
| 303 | , | ||
| 304 | .{ .major = 10, .minor = 3 }, | ||
| 305 | }, | ||
| 306 | .{ | ||
| 307 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 308 | \\<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 309 | \\<plist version="1.0"> | ||
| 310 | \\<dict> | ||
| 311 | \\	<key>ProductBuildVersion</key> | ||
| 312 | \\	<string>7W98</string> | ||
| 313 | \\	<key>ProductCopyright</key> | ||
| 314 | \\	<string>Apple Computer, Inc. 1983-2004</string> | ||
| 315 | \\	<key>ProductName</key> | ||
| 316 | \\	<string>Mac OS X</string> | ||
| 317 | \\	<key>ProductUserVisibleVersion</key> | ||
| 318 | \\	<string>10.3.9</string> | ||
| 319 | \\	<key>ProductVersion</key> | ||
| 320 | \\	<string>10.3.9</string> | ||
| 321 | \\</dict> | ||
| 322 | \\</plist> | ||
| 323 | , | ||
| 324 | .{ .major = 10, .minor = 3, .patch = 9 }, | ||
| 325 | }, | ||
| 326 | .{ | ||
| 327 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 328 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 329 | \\<plist version="1.0"> | ||
| 330 | \\<dict> | ||
| 331 | \\	<key>ProductBuildVersion</key> | ||
| 332 | \\	<string>19G68</string> | ||
| 333 | \\	<key>ProductCopyright</key> | ||
| 334 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 335 | \\	<key>ProductName</key> | ||
| 336 | \\	<string>Mac OS X</string> | ||
| 337 | \\	<key>ProductUserVisibleVersion</key> | ||
| 338 | \\	<string>10.15.6</string> | ||
| 339 | \\	<key>ProductVersion</key> | ||
| 340 | \\	<string>10.15.6</string> | ||
| 341 | \\	<key>iOSSupportVersion</key> | ||
| 342 | \\	<string>13.6</string> | ||
| 343 | \\</dict> | ||
| 344 | \\</plist> | ||
| 345 | , | ||
| 346 | .{ .major = 10, .minor = 15, .patch = 6 }, | ||
| 347 | }, | ||
| 348 | .{ | ||
| 349 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 350 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 351 | \\<plist version="1.0"> | ||
| 352 | \\<dict> | ||
| 353 | \\	<key>ProductBuildVersion</key> | ||
| 354 | \\	<string>20A2408</string> | ||
| 355 | \\	<key>ProductCopyright</key> | ||
| 356 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 357 | \\	<key>ProductName</key> | ||
| 358 | \\	<string>macOS</string> | ||
| 359 | \\	<key>ProductUserVisibleVersion</key> | ||
| 360 | \\	<string>11.0</string> | ||
| 361 | \\	<key>ProductVersion</key> | ||
| 362 | \\	<string>11.0</string> | ||
| 363 | \\	<key>iOSSupportVersion</key> | ||
| 364 | \\	<string>14.2</string> | ||
| 365 | \\</dict> | ||
| 366 | \\</plist> | ||
| 367 | , | ||
| 368 | .{ .major = 11, .minor = 0 }, | ||
| 369 | }, | ||
| 370 | .{ | ||
| 371 | \\<?xml version="1.0" encoding="UTF-8"?> | ||
| 372 | \\<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 373 | \\<plist version="1.0"> | ||
| 374 | \\<dict> | ||
| 375 | \\	<key>ProductBuildVersion</key> | ||
| 376 | \\	<string>20C63</string> | ||
| 377 | \\	<key>ProductCopyright</key> | ||
| 378 | \\	<string>1983-2020 Apple Inc.</string> | ||
| 379 | \\	<key>ProductName</key> | ||
| 380 | \\	<string>macOS</string> | ||
| 381 | \\	<key>ProductUserVisibleVersion</key> | ||
| 382 | \\	<string>11.1</string> | ||
| 383 | \\	<key>ProductVersion</key> | ||
| 384 | \\	<string>11.1</string> | ||
| 385 | \\	<key>iOSSupportVersion</key> | ||
| 386 | \\	<string>14.3</string> | ||
| 387 | \\</dict> | ||
| 388 | \\</plist> | ||
| 389 | , | ||
| 390 | .{ .major = 11, .minor = 1 }, | ||
| 391 | }, | ||
| 392 | }; | ||
| 393 | |||
| 394 | inline for (cases) |case| { | ||
| 395 | const ver0 = try parseSystemVersion(case[0]); | ||
| 396 | const ver1: std.builtin.Version = case[1]; | ||
| 397 | try testVersionEquality(ver1, ver0); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version) !void { | ||
| 402 | var b_expected: [64]u8 = undefined; | ||
| 403 | const s_expected: []const u8 = try std.fmt.bufPrint(b_expected[0..], "{}", .{expected}); | ||
| 404 | |||
| 405 | var b_got: [64]u8 = undefined; | ||
| 406 | const s_got: []const u8 = try std.fmt.bufPrint(b_got[0..], "{}", .{got}); | ||
| 407 | |||
| 408 | try testing.expectEqualStrings(s_expected, s_got); | ||
| 409 | } | ||
| 410 | |||
| 411 | /// Detect SDK path on Darwin. | ||
| 412 | /// Calls `xcrun --show-sdk-path` which result can be used to specify | ||
| 413 | /// `-syslibroot` param of the linker. | ||
| 414 | /// The caller needs to free the resulting path slice. | ||
| 415 | pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 { | ||
| 416 | assert(Target.current.isDarwin()); | ||
| 417 | const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" }; | ||
| 418 | const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }); | ||
| 419 | defer { | ||
| 420 | allocator.free(result.stderr); | ||
| 421 | allocator.free(result.stdout); | ||
| 422 | } | ||
| 423 | if (result.stderr.len != 0) { | ||
| 424 | std.log.err("unexpected 'xcrun --show-sdk-path' stderr: {s}", .{result.stderr}); | ||
| 425 | } | ||
| 426 | if (result.term.Exited != 0) { | ||
| 427 | return error.ProcessTerminated; | ||
| 428 | } | ||
| 429 | const syslibroot = mem.trimRight(u8, result.stdout, "\r\n"); | ||
| 430 | return mem.dupe(allocator, u8, syslibroot); | ||
| 431 | } | ||
| 432 | |||
| 433 | pub fn detectNativeCpuAndFeatures() ?Target.Cpu { | ||
| 434 | var cpu_family: os.CPUFAMILY = undefined; | ||
| 435 | var len: usize = @sizeOf(os.CPUFAMILY); | ||
| 436 | os.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) { | ||
| 437 | error.NameTooLong => unreachable, // constant, known good value | ||
| 438 | error.PermissionDenied => unreachable, // only when setting values, | ||
| 439 | error.SystemResources => unreachable, // memory already on the stack | ||
| 440 | error.UnknownName => unreachable, // constant, known good value | ||
| 441 | error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value | ||
| 442 | }; | ||
| 443 | |||
| 444 | const current_arch = Target.current.cpu.arch; | ||
| 445 | switch (current_arch) { | ||
| 446 | .aarch64, .aarch64_be, .aarch64_32 => { | ||
| 447 | const model = switch (cpu_family) { | ||
| 448 | .ARM_FIRESTORM_ICESTORM => &Target.aarch64.cpu.apple_a14, | ||
| 449 | .ARM_LIGHTNING_THUNDER => &Target.aarch64.cpu.apple_a13, | ||
| 450 | .ARM_VORTEX_TEMPEST => &Target.aarch64.cpu.apple_a12, | ||
| 451 | .ARM_MONSOON_MISTRAL => &Target.aarch64.cpu.apple_a11, | ||
| 452 | .ARM_HURRICANE => &Target.aarch64.cpu.apple_a10, | ||
| 453 | .ARM_TWISTER => &Target.aarch64.cpu.apple_a9, | ||
| 454 | .ARM_TYPHOON => &Target.aarch64.cpu.apple_a8, | ||
| 455 | .ARM_CYCLONE => &Target.aarch64.cpu.cyclone, | ||
| 456 | else => return null, | ||
| 457 | }; | ||
| 458 | |||
| 459 | return Target.Cpu{ | ||
| 460 | .arch = current_arch, | ||
| 461 | .model = model, | ||
| 462 | .features = model.features, | ||
| 463 | }; | ||
| 464 | }, | ||
| 465 | else => {}, | ||
| 466 | } | ||
| 467 | |||
| 468 | return null; | ||
| 469 | } | ||
src/Compilation.zig+1-2| ... | @@ -944,8 +944,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -944,8 +944,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 944 | if (options.sysroot) |sysroot| { | 944 | if (options.sysroot) |sysroot| { |
| 945 | break :blk sysroot; | 945 | break :blk sysroot; |
| 946 | } else if (darwin_can_use_system_sdk) { | 946 | } else if (darwin_can_use_system_sdk) { |
| 947 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; | 947 | break :blk try std.zig.system.darwin.getSDKPath(arena, options.target); |
| 948 | break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; | ||
| 949 | } else { | 948 | } else { |
| 950 | break :blk null; | 949 | break :blk null; |
| 951 | } | 950 | } |
src/link/MachO.zig+86-67| ... | @@ -82,8 +82,8 @@ data_in_code_cmd_index: ?u16 = null, | ... | @@ -82,8 +82,8 @@ data_in_code_cmd_index: ?u16 = null, |
| 82 | function_starts_cmd_index: ?u16 = null, | 82 | function_starts_cmd_index: ?u16 = null, |
| 83 | main_cmd_index: ?u16 = null, | 83 | main_cmd_index: ?u16 = null, |
| 84 | dylib_id_cmd_index: ?u16 = null, | 84 | dylib_id_cmd_index: ?u16 = null, |
| 85 | version_min_cmd_index: ?u16 = null, | ||
| 86 | source_version_cmd_index: ?u16 = null, | 85 | source_version_cmd_index: ?u16 = null, |
| 86 | build_version_cmd_index: ?u16 = null, | ||
| 87 | uuid_cmd_index: ?u16 = null, | 87 | uuid_cmd_index: ?u16 = null, |
| 88 | code_signature_cmd_index: ?u16 = null, | 88 | code_signature_cmd_index: ?u16 = null, |
| 89 | /// Path to libSystem | 89 | /// Path to libSystem |
| ... | @@ -794,15 +794,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -794,15 +794,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 794 | } | 794 | } |
| 795 | } | 795 | } |
| 796 | 796 | ||
| 797 | // If we're compiling native and we can find libSystem.B.{dylib, tbd}, | 797 | // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}. |
| 798 | // we link against that instead of embedded libSystem.B.tbd file. | 798 | var libsystem_available = false; |
| 799 | var native_libsystem_available = false; | 799 | if (self.base.options.sysroot != null) blk: { |
| 800 | if (self.base.options.is_native_os) blk: { | ||
| 801 | // Try stub file first. If we hit it, then we're done as the stub file | 800 | // Try stub file first. If we hit it, then we're done as the stub file |
| 802 | // re-exports every single symbol definition. | 801 | // re-exports every single symbol definition. |
| 803 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { | 802 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { |
| 804 | try libs.append(full_path); | 803 | try libs.append(full_path); |
| 805 | native_libsystem_available = true; | 804 | libsystem_available = true; |
| 806 | break :blk; | 805 | break :blk; |
| 807 | } | 806 | } |
| 808 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib | 807 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| ... | @@ -811,12 +810,12 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -811,12 +810,12 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 811 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { | 810 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { |
| 812 | try libs.append(libsystem_path); | 811 | try libs.append(libsystem_path); |
| 813 | try libs.append(libc_path); | 812 | try libs.append(libc_path); |
| 814 | native_libsystem_available = true; | 813 | libsystem_available = true; |
| 815 | break :blk; | 814 | break :blk; |
| 816 | } | 815 | } |
| 817 | } | 816 | } |
| 818 | } | 817 | } |
| 819 | if (!native_libsystem_available) { | 818 | if (!libsystem_available) { |
| 820 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ | 819 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 821 | "libc", "darwin", "libSystem.B.tbd", | 820 | "libc", "darwin", "libSystem.B.tbd", |
| 822 | }); | 821 | }); |
| ... | @@ -841,7 +840,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -841,7 +840,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 841 | break; | 840 | break; |
| 842 | } | 841 | } |
| 843 | } else { | 842 | } else { |
| 844 | log.warn("framework not found for '-f{s}'", .{framework}); | 843 | log.warn("framework not found for '-framework {s}'", .{framework}); |
| 845 | framework_not_found = true; | 844 | framework_not_found = true; |
| 846 | } | 845 | } |
| 847 | } | 846 | } |
| ... | @@ -901,10 +900,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -901,10 +900,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 901 | try argv.append("-o"); | 900 | try argv.append("-o"); |
| 902 | try argv.append(full_out_path); | 901 | try argv.append(full_out_path); |
| 903 | 902 | ||
| 904 | if (native_libsystem_available) { | 903 | try argv.append("-lSystem"); |
| 905 | try argv.append("-lSystem"); | 904 | try argv.append("-lc"); |
| 906 | try argv.append("-lc"); | ||
| 907 | } | ||
| 908 | 905 | ||
| 909 | for (search_lib_names.items) |l_name| { | 906 | for (search_lib_names.items) |l_name| { |
| 910 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); | 907 | try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name})); |
| ... | @@ -914,6 +911,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -914,6 +911,14 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 914 | try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); | 911 | try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); |
| 915 | } | 912 | } |
| 916 | 913 | ||
| 914 | for (self.base.options.frameworks) |framework| { | ||
| 915 | try argv.append(try std.fmt.allocPrint(arena, "-framework {s}", .{framework})); | ||
| 916 | } | ||
| 917 | |||
| 918 | for (self.base.options.framework_dirs) |framework_dir| { | ||
| 919 | try argv.append(try std.fmt.allocPrint(arena, "-F{s}", .{framework_dir})); | ||
| 920 | } | ||
| 921 | |||
| 917 | Compilation.dump_argv(argv.items); | 922 | Compilation.dump_argv(argv.items); |
| 918 | } | 923 | } |
| 919 | 924 | ||
| ... | @@ -990,7 +995,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { | ... | @@ -990,7 +995,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 990 | } | 995 | } |
| 991 | 996 | ||
| 992 | fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const u8) !void { | 997 | fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const u8) !void { |
| 993 | const arch = self.base.options.target.cpu.arch; | ||
| 994 | for (files) |file_name| { | 998 | for (files) |file_name| { |
| 995 | const full_path = full_path: { | 999 | const full_path = full_path: { |
| 996 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; | 1000 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; |
| ... | @@ -999,17 +1003,17 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const | ... | @@ -999,17 +1003,17 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 999 | }; | 1003 | }; |
| 1000 | defer self.base.allocator.free(full_path); | 1004 | defer self.base.allocator.free(full_path); |
| 1001 | 1005 | ||
| 1002 | if (try Object.createAndParseFromPath(self.base.allocator, arch, full_path)) |object| { | 1006 | if (try Object.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path)) |object| { |
| 1003 | try self.objects.append(self.base.allocator, object); | 1007 | try self.objects.append(self.base.allocator, object); |
| 1004 | continue; | 1008 | continue; |
| 1005 | } | 1009 | } |
| 1006 | 1010 | ||
| 1007 | if (try Archive.createAndParseFromPath(self.base.allocator, arch, full_path)) |archive| { | 1011 | if (try Archive.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path)) |archive| { |
| 1008 | try self.archives.append(self.base.allocator, archive); | 1012 | try self.archives.append(self.base.allocator, archive); |
| 1009 | continue; | 1013 | continue; |
| 1010 | } | 1014 | } |
| 1011 | 1015 | ||
| 1012 | if (try Dylib.createAndParseFromPath(self.base.allocator, arch, full_path, .{ | 1016 | if (try Dylib.createAndParseFromPath(self.base.allocator, self.base.options.target, full_path, .{ |
| 1013 | .syslibroot = syslibroot, | 1017 | .syslibroot = syslibroot, |
| 1014 | })) |dylibs| { | 1018 | })) |dylibs| { |
| 1015 | defer self.base.allocator.free(dylibs); | 1019 | defer self.base.allocator.free(dylibs); |
| ... | @@ -1027,9 +1031,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const | ... | @@ -1027,9 +1031,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 1027 | } | 1031 | } |
| 1028 | 1032 | ||
| 1029 | fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void { | 1033 | fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void { |
| 1030 | const arch = self.base.options.target.cpu.arch; | ||
| 1031 | for (libs) |lib| { | 1034 | for (libs) |lib| { |
| 1032 | if (try Dylib.createAndParseFromPath(self.base.allocator, arch, lib, .{ | 1035 | if (try Dylib.createAndParseFromPath(self.base.allocator, self.base.options.target, lib, .{ |
| 1033 | .syslibroot = syslibroot, | 1036 | .syslibroot = syslibroot, |
| 1034 | })) |dylibs| { | 1037 | })) |dylibs| { |
| 1035 | defer self.base.allocator.free(dylibs); | 1038 | defer self.base.allocator.free(dylibs); |
| ... | @@ -1042,7 +1045,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v | ... | @@ -1042,7 +1045,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v |
| 1042 | continue; | 1045 | continue; |
| 1043 | } | 1046 | } |
| 1044 | 1047 | ||
| 1045 | if (try Archive.createAndParseFromPath(self.base.allocator, arch, lib)) |archive| { | 1048 | if (try Archive.createAndParseFromPath(self.base.allocator, self.base.options.target, lib)) |archive| { |
| 1046 | try self.archives.append(self.base.allocator, archive); | 1049 | try self.archives.append(self.base.allocator, archive); |
| 1047 | continue; | 1050 | continue; |
| 1048 | } | 1051 | } |
| ... | @@ -2231,11 +2234,7 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2231,11 +2234,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2231 | 2234 | ||
| 2232 | const object_id = @intCast(u16, self.objects.items.len); | 2235 | const object_id = @intCast(u16, self.objects.items.len); |
| 2233 | const object = try self.objects.addOne(self.base.allocator); | 2236 | const object = try self.objects.addOne(self.base.allocator); |
| 2234 | object.* = try archive.parseObject( | 2237 | object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]); |
| 2235 | self.base.allocator, | ||
| 2236 | self.base.options.target.cpu.arch, | ||
| 2237 | offsets.items[0], | ||
| 2238 | ); | ||
| 2239 | try self.resolveSymbolsInObject(object_id); | 2238 | try self.resolveSymbolsInObject(object_id); |
| 2240 | 2239 | ||
| 2241 | continue :loop; | 2240 | continue :loop; |
| ... | @@ -2717,27 +2716,6 @@ fn populateMetadata(self: *MachO) !void { | ... | @@ -2717,27 +2716,6 @@ fn populateMetadata(self: *MachO) !void { |
| 2717 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | 2716 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); |
| 2718 | } | 2717 | } |
| 2719 | 2718 | ||
| 2720 | if (self.version_min_cmd_index == null) { | ||
| 2721 | self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); | ||
| 2722 | const cmd: u32 = switch (self.base.options.target.os.tag) { | ||
| 2723 | .macos => macho.LC_VERSION_MIN_MACOSX, | ||
| 2724 | .ios => macho.LC_VERSION_MIN_IPHONEOS, | ||
| 2725 | .tvos => macho.LC_VERSION_MIN_TVOS, | ||
| 2726 | .watchos => macho.LC_VERSION_MIN_WATCHOS, | ||
| 2727 | else => unreachable, // wrong OS | ||
| 2728 | }; | ||
| 2729 | const ver = self.base.options.target.os.version_range.semver.min; | ||
| 2730 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; | ||
| 2731 | try self.load_commands.append(self.base.allocator, .{ | ||
| 2732 | .VersionMin = .{ | ||
| 2733 | .cmd = cmd, | ||
| 2734 | .cmdsize = @sizeOf(macho.version_min_command), | ||
| 2735 | .version = version, | ||
| 2736 | .sdk = version, | ||
| 2737 | }, | ||
| 2738 | }); | ||
| 2739 | } | ||
| 2740 | |||
| 2741 | if (self.source_version_cmd_index == null) { | 2719 | if (self.source_version_cmd_index == null) { |
| 2742 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); | 2720 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2743 | try self.load_commands.append(self.base.allocator, .{ | 2721 | try self.load_commands.append(self.base.allocator, .{ |
| ... | @@ -2749,6 +2727,40 @@ fn populateMetadata(self: *MachO) !void { | ... | @@ -2749,6 +2727,40 @@ fn populateMetadata(self: *MachO) !void { |
| 2749 | }); | 2727 | }); |
| 2750 | } | 2728 | } |
| 2751 | 2729 | ||
| 2730 | if (self.build_version_cmd_index == null) { | ||
| 2731 | self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len); | ||
| 2732 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | ||
| 2733 | u64, | ||
| 2734 | @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version), | ||
| 2735 | @sizeOf(u64), | ||
| 2736 | )); | ||
| 2737 | const ver = self.base.options.target.os.version_range.semver.min; | ||
| 2738 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; | ||
| 2739 | const is_simulator_abi = self.base.options.target.abi == .simulator; | ||
| 2740 | var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{ | ||
| 2741 | .cmd = macho.LC_BUILD_VERSION, | ||
| 2742 | .cmdsize = cmdsize, | ||
| 2743 | .platform = switch (self.base.options.target.os.tag) { | ||
| 2744 | .macos => macho.PLATFORM_MACOS, | ||
| 2745 | .ios => if (is_simulator_abi) macho.PLATFORM_IOSSIMULATOR else macho.PLATFORM_IOS, | ||
| 2746 | .watchos => if (is_simulator_abi) macho.PLATFORM_WATCHOSSIMULATOR else macho.PLATFORM_WATCHOS, | ||
| 2747 | .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS, | ||
| 2748 | else => unreachable, | ||
| 2749 | }, | ||
| 2750 | .minos = version, | ||
| 2751 | .sdk = version, | ||
| 2752 | .ntools = 1, | ||
| 2753 | }); | ||
| 2754 | const ld_ver = macho.build_tool_version{ | ||
| 2755 | .tool = macho.TOOL_LD, | ||
| 2756 | .version = 0x0, | ||
| 2757 | }; | ||
| 2758 | cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command)); | ||
| 2759 | mem.set(u8, cmd.data, 0); | ||
| 2760 | mem.copy(u8, cmd.data, mem.asBytes(&ld_ver)); | ||
| 2761 | try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd }); | ||
| 2762 | } | ||
| 2763 | |||
| 2752 | if (self.uuid_cmd_index == null) { | 2764 | if (self.uuid_cmd_index == null) { |
| 2753 | self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len); | 2765 | self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2754 | var uuid_cmd: macho.uuid_command = .{ | 2766 | var uuid_cmd: macho.uuid_command = .{ |
| ... | @@ -2880,11 +2892,6 @@ fn flushZld(self: *MachO) !void { | ... | @@ -2880,11 +2892,6 @@ fn flushZld(self: *MachO) !void { |
| 2880 | if (self.base.options.target.cpu.arch == .aarch64) { | 2892 | if (self.base.options.target.cpu.arch == .aarch64) { |
| 2881 | try self.writeCodeSignature(); | 2893 | try self.writeCodeSignature(); |
| 2882 | } | 2894 | } |
| 2883 | |||
| 2884 | // if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) { | ||
| 2885 | // const out_path = self.output.?.path; | ||
| 2886 | // try fs.cwd().copyFile(out_path, fs.cwd(), out_path, .{}); | ||
| 2887 | // } | ||
| 2888 | } | 2895 | } |
| 2889 | 2896 | ||
| 2890 | fn writeGotEntries(self: *MachO) !void { | 2897 | fn writeGotEntries(self: *MachO) !void { |
| ... | @@ -4340,26 +4347,38 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4340,26 +4347,38 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4340 | }); | 4347 | }); |
| 4341 | self.load_commands_dirty = true; | 4348 | self.load_commands_dirty = true; |
| 4342 | } | 4349 | } |
| 4343 | if (self.version_min_cmd_index == null) { | 4350 | if (self.build_version_cmd_index == null) { |
| 4344 | self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); | 4351 | self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4345 | const cmd: u32 = switch (self.base.options.target.os.tag) { | 4352 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( |
| 4346 | .macos => macho.LC_VERSION_MIN_MACOSX, | 4353 | u64, |
| 4347 | .ios => macho.LC_VERSION_MIN_IPHONEOS, | 4354 | @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version), |
| 4348 | .tvos => macho.LC_VERSION_MIN_TVOS, | 4355 | @sizeOf(u64), |
| 4349 | .watchos => macho.LC_VERSION_MIN_WATCHOS, | 4356 | )); |
| 4350 | else => unreachable, // wrong OS | ||
| 4351 | }; | ||
| 4352 | const ver = self.base.options.target.os.version_range.semver.min; | 4357 | const ver = self.base.options.target.os.version_range.semver.min; |
| 4353 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; | 4358 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; |
| 4354 | try self.load_commands.append(self.base.allocator, .{ | 4359 | const is_simulator_abi = self.base.options.target.abi == .simulator; |
| 4355 | .VersionMin = .{ | 4360 | var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{ |
| 4356 | .cmd = cmd, | 4361 | .cmd = macho.LC_BUILD_VERSION, |
| 4357 | .cmdsize = @sizeOf(macho.version_min_command), | 4362 | .cmdsize = cmdsize, |
| 4358 | .version = version, | 4363 | .platform = switch (self.base.options.target.os.tag) { |
| 4359 | .sdk = version, | 4364 | .macos => macho.PLATFORM_MACOS, |
| 4365 | .ios => if (is_simulator_abi) macho.PLATFORM_IOSSIMULATOR else macho.PLATFORM_IOS, | ||
| 4366 | .watchos => if (is_simulator_abi) macho.PLATFORM_WATCHOSSIMULATOR else macho.PLATFORM_WATCHOS, | ||
| 4367 | .tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS, | ||
| 4368 | else => unreachable, | ||
| 4360 | }, | 4369 | }, |
| 4370 | .minos = version, | ||
| 4371 | .sdk = version, | ||
| 4372 | .ntools = 1, | ||
| 4361 | }); | 4373 | }); |
| 4362 | self.load_commands_dirty = true; | 4374 | const ld_ver = macho.build_tool_version{ |
| 4375 | .tool = macho.TOOL_LD, | ||
| 4376 | .version = 0x0, | ||
| 4377 | }; | ||
| 4378 | cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command)); | ||
| 4379 | mem.set(u8, cmd.data, 0); | ||
| 4380 | mem.copy(u8, cmd.data, mem.asBytes(&ld_ver)); | ||
| 4381 | try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd }); | ||
| 4363 | } | 4382 | } |
| 4364 | if (self.source_version_cmd_index == null) { | 4383 | if (self.source_version_cmd_index == null) { |
| 4365 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); | 4384 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
src/link/MachO/Archive.zig+6-7| ... | @@ -9,7 +9,6 @@ const mem = std.mem; | ... | @@ -9,7 +9,6 @@ const mem = std.mem; |
| 9 | const fat = @import("fat.zig"); | 9 | const fat = @import("fat.zig"); |
| 10 | 10 | ||
| 11 | const Allocator = mem.Allocator; | 11 | const Allocator = mem.Allocator; |
| 12 | const Arch = std.Target.Cpu.Arch; | ||
| 13 | const Object = @import("Object.zig"); | 12 | const Object = @import("Object.zig"); |
| 14 | 13 | ||
| 15 | file: fs.File, | 14 | file: fs.File, |
| ... | @@ -104,7 +103,7 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void { | ... | @@ -104,7 +103,7 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void { |
| 104 | allocator.free(self.name); | 103 | allocator.free(self.name); |
| 105 | } | 104 | } |
| 106 | 105 | ||
| 107 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?Archive { | 106 | pub fn createAndParseFromPath(allocator: *Allocator, target: std.Target, path: []const u8) !?Archive { |
| 108 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | 107 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 109 | error.FileNotFound => return null, | 108 | error.FileNotFound => return null, |
| 110 | else => |e| return e, | 109 | else => |e| return e, |
| ... | @@ -119,7 +118,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -119,7 +118,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 119 | .file = file, | 118 | .file = file, |
| 120 | }; | 119 | }; |
| 121 | 120 | ||
| 122 | archive.parse(allocator, arch) catch |err| switch (err) { | 121 | archive.parse(allocator, target) catch |err| switch (err) { |
| 123 | error.EndOfStream, error.NotArchive => { | 122 | error.EndOfStream, error.NotArchive => { |
| 124 | archive.deinit(allocator); | 123 | archive.deinit(allocator); |
| 125 | return null; | 124 | return null; |
| ... | @@ -130,9 +129,9 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -130,9 +129,9 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 130 | return archive; | 129 | return archive; |
| 131 | } | 130 | } |
| 132 | 131 | ||
| 133 | pub fn parse(self: *Archive, allocator: *Allocator, arch: Arch) !void { | 132 | pub fn parse(self: *Archive, allocator: *Allocator, target: std.Target) !void { |
| 134 | const reader = self.file.reader(); | 133 | const reader = self.file.reader(); |
| 135 | self.library_offset = try fat.getLibraryOffset(reader, arch); | 134 | self.library_offset = try fat.getLibraryOffset(reader, target); |
| 136 | try self.file.seekTo(self.library_offset); | 135 | try self.file.seekTo(self.library_offset); |
| 137 | 136 | ||
| 138 | const magic = try reader.readBytesNoEof(SARMAG); | 137 | const magic = try reader.readBytesNoEof(SARMAG); |
| ... | @@ -215,7 +214,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype) | ... | @@ -215,7 +214,7 @@ fn parseTableOfContents(self: *Archive, allocator: *Allocator, reader: anytype) |
| 215 | } | 214 | } |
| 216 | } | 215 | } |
| 217 | 216 | ||
| 218 | pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32) !Object { | 217 | pub fn parseObject(self: Archive, allocator: *Allocator, target: std.Target, offset: u32) !Object { |
| 219 | const reader = self.file.reader(); | 218 | const reader = self.file.reader(); |
| 220 | try reader.context.seekTo(offset + self.library_offset); | 219 | try reader.context.seekTo(offset + self.library_offset); |
| 221 | 220 | ||
| ... | @@ -244,7 +243,7 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32 | ... | @@ -244,7 +243,7 @@ pub fn parseObject(self: Archive, allocator: *Allocator, arch: Arch, offset: u32 |
| 244 | .mtime = try self.header.?.date(), | 243 | .mtime = try self.header.?.date(), |
| 245 | }; | 244 | }; |
| 246 | 245 | ||
| 247 | try object.parse(allocator, arch); | 246 | try object.parse(allocator, target); |
| 248 | try reader.context.seekTo(0); | 247 | try reader.context.seekTo(0); |
| 249 | 248 | ||
| 250 | return object; | 249 | return object; |
src/link/MachO/Dylib.zig+74-23| ... | @@ -12,7 +12,6 @@ const fat = @import("fat.zig"); | ... | @@ -12,7 +12,6 @@ const fat = @import("fat.zig"); |
| 12 | const commands = @import("commands.zig"); | 12 | const commands = @import("commands.zig"); |
| 13 | 13 | ||
| 14 | const Allocator = mem.Allocator; | 14 | const Allocator = mem.Allocator; |
| 15 | const Arch = std.Target.Cpu.Arch; | ||
| 16 | const LibStub = @import("../tapi.zig").LibStub; | 15 | const LibStub = @import("../tapi.zig").LibStub; |
| 17 | const LoadCommand = commands.LoadCommand; | 16 | const LoadCommand = commands.LoadCommand; |
| 18 | const MachO = @import("../MachO.zig"); | 17 | const MachO = @import("../MachO.zig"); |
| ... | @@ -139,11 +138,12 @@ pub const Error = error{ | ... | @@ -139,11 +138,12 @@ pub const Error = error{ |
| 139 | pub const CreateOpts = struct { | 138 | pub const CreateOpts = struct { |
| 140 | syslibroot: ?[]const u8 = null, | 139 | syslibroot: ?[]const u8 = null, |
| 141 | id: ?Id = null, | 140 | id: ?Id = null, |
| 141 | target: ?std.Target = null, | ||
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| 144 | pub fn createAndParseFromPath( | 144 | pub fn createAndParseFromPath( |
| 145 | allocator: *Allocator, | 145 | allocator: *Allocator, |
| 146 | arch: Arch, | 146 | target: std.Target, |
| 147 | path: []const u8, | 147 | path: []const u8, |
| 148 | opts: CreateOpts, | 148 | opts: CreateOpts, |
| 149 | ) Error!?[]Dylib { | 149 | ) Error!?[]Dylib { |
| ... | @@ -161,7 +161,7 @@ pub fn createAndParseFromPath( | ... | @@ -161,7 +161,7 @@ pub fn createAndParseFromPath( |
| 161 | .file = file, | 161 | .file = file, |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | dylib.parse(allocator, arch) catch |err| switch (err) { | 164 | dylib.parse(allocator, target) catch |err| switch (err) { |
| 165 | error.EndOfStream, error.NotDylib => { | 165 | error.EndOfStream, error.NotDylib => { |
| 166 | try file.seekTo(0); | 166 | try file.seekTo(0); |
| 167 | 167 | ||
| ... | @@ -171,7 +171,7 @@ pub fn createAndParseFromPath( | ... | @@ -171,7 +171,7 @@ pub fn createAndParseFromPath( |
| 171 | }; | 171 | }; |
| 172 | defer lib_stub.deinit(); | 172 | defer lib_stub.deinit(); |
| 173 | 173 | ||
| 174 | try dylib.parseFromStub(allocator, arch, lib_stub); | 174 | try dylib.parseFromStub(allocator, target, lib_stub); |
| 175 | }, | 175 | }, |
| 176 | else => |e| return e, | 176 | else => |e| return e, |
| 177 | }; | 177 | }; |
| ... | @@ -195,7 +195,7 @@ pub fn createAndParseFromPath( | ... | @@ -195,7 +195,7 @@ pub fn createAndParseFromPath( |
| 195 | try dylibs.append(dylib); | 195 | try dylibs.append(dylib); |
| 196 | // TODO this should not be performed if the user specifies `-flat_namespace` flag. | 196 | // TODO this should not be performed if the user specifies `-flat_namespace` flag. |
| 197 | // See ld64 manpages. | 197 | // See ld64 manpages. |
| 198 | try dylib.parseDependentLibs(allocator, arch, &dylibs, opts.syslibroot); | 198 | try dylib.parseDependentLibs(allocator, target, &dylibs, opts.syslibroot); |
| 199 | 199 | ||
| 200 | return dylibs.toOwnedSlice(); | 200 | return dylibs.toOwnedSlice(); |
| 201 | } | 201 | } |
| ... | @@ -222,10 +222,10 @@ pub fn deinit(self: *Dylib, allocator: *Allocator) void { | ... | @@ -222,10 +222,10 @@ pub fn deinit(self: *Dylib, allocator: *Allocator) void { |
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | pub fn parse(self: *Dylib, allocator: *Allocator, arch: Arch) !void { | 225 | pub fn parse(self: *Dylib, allocator: *Allocator, target: std.Target) !void { |
| 226 | log.debug("parsing shared library '{s}'", .{self.name}); | 226 | log.debug("parsing shared library '{s}'", .{self.name}); |
| 227 | 227 | ||
| 228 | self.library_offset = try fat.getLibraryOffset(self.file.reader(), arch); | 228 | self.library_offset = try fat.getLibraryOffset(self.file.reader(), target); |
| 229 | 229 | ||
| 230 | try self.file.seekTo(self.library_offset); | 230 | try self.file.seekTo(self.library_offset); |
| 231 | 231 | ||
| ... | @@ -237,10 +237,10 @@ pub fn parse(self: *Dylib, allocator: *Allocator, arch: Arch) !void { | ... | @@ -237,10 +237,10 @@ pub fn parse(self: *Dylib, allocator: *Allocator, arch: Arch) !void { |
| 237 | return error.NotDylib; | 237 | return error.NotDylib; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | const this_arch: Arch = try fat.decodeArch(self.header.?.cputype, true); | 240 | const this_arch: std.Target.Cpu.Arch = try fat.decodeArch(self.header.?.cputype, true); |
| 241 | 241 | ||
| 242 | if (this_arch != arch) { | 242 | if (this_arch != target.cpu.arch) { |
| 243 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); | 243 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch }); |
| 244 | return error.MismatchedCpuArchitecture; | 244 | return error.MismatchedCpuArchitecture; |
| 245 | } | 245 | } |
| 246 | 246 | ||
| ... | @@ -334,7 +334,61 @@ fn addObjCClassSymbols(self: *Dylib, allocator: *Allocator, sym_name: []const u8 | ... | @@ -334,7 +334,61 @@ fn addObjCClassSymbols(self: *Dylib, allocator: *Allocator, sym_name: []const u8 |
| 334 | } | 334 | } |
| 335 | } | 335 | } |
| 336 | 336 | ||
| 337 | pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: LibStub) !void { | 337 | fn targetToAppleString(allocator: *Allocator, target: std.Target) ![]const u8 { |
| 338 | const arch = switch (target.cpu.arch) { | ||
| 339 | .aarch64 => "arm64", | ||
| 340 | .x86_64 => "x86_64", | ||
| 341 | else => unreachable, | ||
| 342 | }; | ||
| 343 | const os = @tagName(target.os.tag); | ||
| 344 | const abi: ?[]const u8 = switch (target.abi) { | ||
| 345 | .gnu => null, | ||
| 346 | .simulator => "simulator", | ||
| 347 | else => unreachable, | ||
| 348 | }; | ||
| 349 | if (abi) |x| { | ||
| 350 | return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ arch, os, x }); | ||
| 351 | } | ||
| 352 | return std.fmt.allocPrint(allocator, "{s}-{s}", .{ arch, os }); | ||
| 353 | } | ||
| 354 | |||
| 355 | const TargetMatcher = struct { | ||
| 356 | allocator: *Allocator, | ||
| 357 | target_strings: std.ArrayListUnmanaged([]const u8) = .{}, | ||
| 358 | |||
| 359 | fn init(allocator: *Allocator, target: std.Target) !TargetMatcher { | ||
| 360 | var self = TargetMatcher{ .allocator = allocator }; | ||
| 361 | try self.target_strings.append(allocator, try targetToAppleString(allocator, target)); | ||
| 362 | |||
| 363 | if (target.abi == .simulator) { | ||
| 364 | // For Apple simulator targets, linking gets tricky as we need to link against the simulator | ||
| 365 | // hosts dylibs too. | ||
| 366 | const host_target = try targetToAppleString(allocator, (std.zig.CrossTarget{ | ||
| 367 | .cpu_arch = target.cpu.arch, | ||
| 368 | .os_tag = .macos, | ||
| 369 | }).toTarget()); | ||
| 370 | try self.target_strings.append(allocator, host_target); | ||
| 371 | } | ||
| 372 | |||
| 373 | return self; | ||
| 374 | } | ||
| 375 | |||
| 376 | fn deinit(self: *TargetMatcher) void { | ||
| 377 | for (self.target_strings.items) |t| { | ||
| 378 | self.allocator.free(t); | ||
| 379 | } | ||
| 380 | self.target_strings.deinit(self.allocator); | ||
| 381 | } | ||
| 382 | |||
| 383 | fn matches(self: TargetMatcher, targets: []const []const u8) bool { | ||
| 384 | for (self.target_strings.items) |t| { | ||
| 385 | if (hasTarget(targets, t)) return true; | ||
| 386 | } | ||
| 387 | return false; | ||
| 388 | } | ||
| 389 | }; | ||
| 390 | |||
| 391 | pub fn parseFromStub(self: *Dylib, allocator: *Allocator, target: std.Target, lib_stub: LibStub) !void { | ||
| 338 | if (lib_stub.inner.len == 0) return error.EmptyStubFile; | 392 | if (lib_stub.inner.len == 0) return error.EmptyStubFile; |
| 339 | 393 | ||
| 340 | log.debug("parsing shared library from stub '{s}'", .{self.name}); | 394 | log.debug("parsing shared library from stub '{s}'", .{self.name}); |
| ... | @@ -350,17 +404,14 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: | ... | @@ -350,17 +404,14 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 350 | } | 404 | } |
| 351 | self.id = id; | 405 | self.id = id; |
| 352 | 406 | ||
| 353 | const target_string: []const u8 = switch (arch) { | 407 | var matcher = try TargetMatcher.init(allocator, target); |
| 354 | .aarch64 => "arm64-macos", | 408 | defer matcher.deinit(); |
| 355 | .x86_64 => "x86_64-macos", | ||
| 356 | else => unreachable, | ||
| 357 | }; | ||
| 358 | 409 | ||
| 359 | var umbrella_libs = std.StringHashMap(void).init(allocator); | 410 | var umbrella_libs = std.StringHashMap(void).init(allocator); |
| 360 | defer umbrella_libs.deinit(); | 411 | defer umbrella_libs.deinit(); |
| 361 | 412 | ||
| 362 | for (lib_stub.inner) |stub, stub_index| { | 413 | for (lib_stub.inner) |stub, stub_index| { |
| 363 | if (!hasTarget(stub.targets, target_string)) continue; | 414 | if (!matcher.matches(stub.targets)) continue; |
| 364 | 415 | ||
| 365 | if (stub_index > 0) { | 416 | if (stub_index > 0) { |
| 366 | // TODO I thought that we could switch on presence of `parent-umbrella` map; | 417 | // TODO I thought that we could switch on presence of `parent-umbrella` map; |
| ... | @@ -371,7 +422,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: | ... | @@ -371,7 +422,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 371 | 422 | ||
| 372 | if (stub.exports) |exports| { | 423 | if (stub.exports) |exports| { |
| 373 | for (exports) |exp| { | 424 | for (exports) |exp| { |
| 374 | if (!hasTarget(exp.targets, target_string)) continue; | 425 | if (!matcher.matches(exp.targets)) continue; |
| 375 | 426 | ||
| 376 | if (exp.symbols) |symbols| { | 427 | if (exp.symbols) |symbols| { |
| 377 | for (symbols) |sym_name| { | 428 | for (symbols) |sym_name| { |
| ... | @@ -390,7 +441,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: | ... | @@ -390,7 +441,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 390 | 441 | ||
| 391 | if (stub.reexports) |reexports| { | 442 | if (stub.reexports) |reexports| { |
| 392 | for (reexports) |reexp| { | 443 | for (reexports) |reexp| { |
| 393 | if (!hasTarget(reexp.targets, target_string)) continue; | 444 | if (!matcher.matches(reexp.targets)) continue; |
| 394 | 445 | ||
| 395 | if (reexp.symbols) |symbols| { | 446 | if (reexp.symbols) |symbols| { |
| 396 | for (symbols) |sym_name| { | 447 | for (symbols) |sym_name| { |
| ... | @@ -418,11 +469,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: | ... | @@ -418,11 +469,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 418 | 469 | ||
| 419 | // TODO track which libs were already parsed in different steps | 470 | // TODO track which libs were already parsed in different steps |
| 420 | for (lib_stub.inner) |stub| { | 471 | for (lib_stub.inner) |stub| { |
| 421 | if (!hasTarget(stub.targets, target_string)) continue; | 472 | if (!matcher.matches(stub.targets)) continue; |
| 422 | 473 | ||
| 423 | if (stub.reexported_libraries) |reexports| { | 474 | if (stub.reexported_libraries) |reexports| { |
| 424 | for (reexports) |reexp| { | 475 | for (reexports) |reexp| { |
| 425 | if (!hasTarget(reexp.targets, target_string)) continue; | 476 | if (!matcher.matches(reexp.targets)) continue; |
| 426 | 477 | ||
| 427 | for (reexp.libraries) |lib| { | 478 | for (reexp.libraries) |lib| { |
| 428 | if (umbrella_libs.contains(lib)) { | 479 | if (umbrella_libs.contains(lib)) { |
| ... | @@ -443,7 +494,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: | ... | @@ -443,7 +494,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 443 | pub fn parseDependentLibs( | 494 | pub fn parseDependentLibs( |
| 444 | self: *Dylib, | 495 | self: *Dylib, |
| 445 | allocator: *Allocator, | 496 | allocator: *Allocator, |
| 446 | arch: Arch, | 497 | target: std.Target, |
| 447 | out: *std.ArrayList(Dylib), | 498 | out: *std.ArrayList(Dylib), |
| 448 | syslibroot: ?[]const u8, | 499 | syslibroot: ?[]const u8, |
| 449 | ) !void { | 500 | ) !void { |
| ... | @@ -475,7 +526,7 @@ pub fn parseDependentLibs( | ... | @@ -475,7 +526,7 @@ pub fn parseDependentLibs( |
| 475 | 526 | ||
| 476 | const dylibs = (try createAndParseFromPath( | 527 | const dylibs = (try createAndParseFromPath( |
| 477 | allocator, | 528 | allocator, |
| 478 | arch, | 529 | target, |
| 479 | full_path, | 530 | full_path, |
| 480 | .{ | 531 | .{ |
| 481 | .id = id, | 532 | .id = id, |
src/link/MachO/Object.zig+6-7| ... | @@ -15,7 +15,6 @@ const segmentName = commands.segmentName; | ... | @@ -15,7 +15,6 @@ const segmentName = commands.segmentName; |
| 15 | const sectionName = commands.sectionName; | 15 | const sectionName = commands.sectionName; |
| 16 | 16 | ||
| 17 | const Allocator = mem.Allocator; | 17 | const Allocator = mem.Allocator; |
| 18 | const Arch = std.Target.Cpu.Arch; | ||
| 19 | const LoadCommand = commands.LoadCommand; | 18 | const LoadCommand = commands.LoadCommand; |
| 20 | const MachO = @import("../MachO.zig"); | 19 | const MachO = @import("../MachO.zig"); |
| 21 | const TextBlock = @import("TextBlock.zig"); | 20 | const TextBlock = @import("TextBlock.zig"); |
| ... | @@ -154,7 +153,7 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { | ... | @@ -154,7 +153,7 @@ pub fn deinit(self: *Object, allocator: *Allocator) void { |
| 154 | } | 153 | } |
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?Object { | 156 | pub fn createAndParseFromPath(allocator: *Allocator, target: std.Target, path: []const u8) !?Object { |
| 158 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | 157 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 159 | error.FileNotFound => return null, | 158 | error.FileNotFound => return null, |
| 160 | else => |e| return e, | 159 | else => |e| return e, |
| ... | @@ -169,7 +168,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -169,7 +168,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 169 | .file = file, | 168 | .file = file, |
| 170 | }; | 169 | }; |
| 171 | 170 | ||
| 172 | object.parse(allocator, arch) catch |err| switch (err) { | 171 | object.parse(allocator, target) catch |err| switch (err) { |
| 173 | error.EndOfStream, error.NotObject => { | 172 | error.EndOfStream, error.NotObject => { |
| 174 | object.deinit(allocator); | 173 | object.deinit(allocator); |
| 175 | return null; | 174 | return null; |
| ... | @@ -180,7 +179,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u | ... | @@ -180,7 +179,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 180 | return object; | 179 | return object; |
| 181 | } | 180 | } |
| 182 | 181 | ||
| 183 | pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { | 182 | pub fn parse(self: *Object, allocator: *Allocator, target: std.Target) !void { |
| 184 | const reader = self.file.reader(); | 183 | const reader = self.file.reader(); |
| 185 | if (self.file_offset) |offset| { | 184 | if (self.file_offset) |offset| { |
| 186 | try reader.context.seekTo(offset); | 185 | try reader.context.seekTo(offset); |
| ... | @@ -195,7 +194,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { | ... | @@ -195,7 +194,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 195 | return error.NotObject; | 194 | return error.NotObject; |
| 196 | } | 195 | } |
| 197 | 196 | ||
| 198 | const this_arch: Arch = switch (header.cputype) { | 197 | const this_arch: std.Target.Cpu.Arch = switch (header.cputype) { |
| 199 | macho.CPU_TYPE_ARM64 => .aarch64, | 198 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 200 | macho.CPU_TYPE_X86_64 => .x86_64, | 199 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 201 | else => |value| { | 200 | else => |value| { |
| ... | @@ -203,8 +202,8 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { | ... | @@ -203,8 +202,8 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 203 | return error.UnsupportedCpuArchitecture; | 202 | return error.UnsupportedCpuArchitecture; |
| 204 | }, | 203 | }, |
| 205 | }; | 204 | }; |
| 206 | if (this_arch != arch) { | 205 | if (this_arch != target.cpu.arch) { |
| 207 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); | 206 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch }); |
| 208 | return error.MismatchedCpuArchitecture; | 207 | return error.MismatchedCpuArchitecture; |
| 209 | } | 208 | } |
| 210 | 209 |
src/link/MachO/commands.zig+9| ... | @@ -43,6 +43,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -43,6 +43,7 @@ pub const LoadCommand = union(enum) { |
| 43 | Main: macho.entry_point_command, | 43 | Main: macho.entry_point_command, |
| 44 | VersionMin: macho.version_min_command, | 44 | VersionMin: macho.version_min_command, |
| 45 | SourceVersion: macho.source_version_command, | 45 | SourceVersion: macho.source_version_command, |
| 46 | BuildVersion: GenericCommandWithData(macho.build_version_command), | ||
| 46 | Uuid: macho.uuid_command, | 47 | Uuid: macho.uuid_command, |
| 47 | LinkeditData: macho.linkedit_data_command, | 48 | LinkeditData: macho.linkedit_data_command, |
| 48 | Rpath: GenericCommandWithData(macho.rpath_command), | 49 | Rpath: GenericCommandWithData(macho.rpath_command), |
| ... | @@ -97,6 +98,9 @@ pub const LoadCommand = union(enum) { | ... | @@ -97,6 +98,9 @@ pub const LoadCommand = union(enum) { |
| 97 | macho.LC_SOURCE_VERSION => LoadCommand{ | 98 | macho.LC_SOURCE_VERSION => LoadCommand{ |
| 98 | .SourceVersion = try stream.reader().readStruct(macho.source_version_command), | 99 | .SourceVersion = try stream.reader().readStruct(macho.source_version_command), |
| 99 | }, | 100 | }, |
| 101 | macho.LC_BUILD_VERSION => LoadCommand{ | ||
| 102 | .BuildVersion = try GenericCommandWithData(macho.build_version_command).read(allocator, stream.reader()), | ||
| 103 | }, | ||
| 100 | macho.LC_UUID => LoadCommand{ | 104 | macho.LC_UUID => LoadCommand{ |
| 101 | .Uuid = try stream.reader().readStruct(macho.uuid_command), | 105 | .Uuid = try stream.reader().readStruct(macho.uuid_command), |
| 102 | }, | 106 | }, |
| ... | @@ -129,6 +133,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -129,6 +133,7 @@ pub const LoadCommand = union(enum) { |
| 129 | .Dylinker => |x| x.write(writer), | 133 | .Dylinker => |x| x.write(writer), |
| 130 | .Dylib => |x| x.write(writer), | 134 | .Dylib => |x| x.write(writer), |
| 131 | .Rpath => |x| x.write(writer), | 135 | .Rpath => |x| x.write(writer), |
| 136 | .BuildVersion => |x| x.write(writer), | ||
| 132 | .Unknown => |x| x.write(writer), | 137 | .Unknown => |x| x.write(writer), |
| 133 | }; | 138 | }; |
| 134 | } | 139 | } |
| ... | @@ -147,6 +152,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -147,6 +152,7 @@ pub const LoadCommand = union(enum) { |
| 147 | .Dylinker => |x| x.inner.cmd, | 152 | .Dylinker => |x| x.inner.cmd, |
| 148 | .Dylib => |x| x.inner.cmd, | 153 | .Dylib => |x| x.inner.cmd, |
| 149 | .Rpath => |x| x.inner.cmd, | 154 | .Rpath => |x| x.inner.cmd, |
| 155 | .BuildVersion => |x| x.inner.cmd, | ||
| 150 | .Unknown => |x| x.inner.cmd, | 156 | .Unknown => |x| x.inner.cmd, |
| 151 | }; | 157 | }; |
| 152 | } | 158 | } |
| ... | @@ -165,6 +171,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -165,6 +171,7 @@ pub const LoadCommand = union(enum) { |
| 165 | .Dylinker => |x| x.inner.cmdsize, | 171 | .Dylinker => |x| x.inner.cmdsize, |
| 166 | .Dylib => |x| x.inner.cmdsize, | 172 | .Dylib => |x| x.inner.cmdsize, |
| 167 | .Rpath => |x| x.inner.cmdsize, | 173 | .Rpath => |x| x.inner.cmdsize, |
| 174 | .BuildVersion => |x| x.inner.cmdsize, | ||
| 168 | .Unknown => |x| x.inner.cmdsize, | 175 | .Unknown => |x| x.inner.cmdsize, |
| 169 | }; | 176 | }; |
| 170 | } | 177 | } |
| ... | @@ -175,6 +182,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -175,6 +182,7 @@ pub const LoadCommand = union(enum) { |
| 175 | .Dylinker => |*x| x.deinit(allocator), | 182 | .Dylinker => |*x| x.deinit(allocator), |
| 176 | .Dylib => |*x| x.deinit(allocator), | 183 | .Dylib => |*x| x.deinit(allocator), |
| 177 | .Rpath => |*x| x.deinit(allocator), | 184 | .Rpath => |*x| x.deinit(allocator), |
| 185 | .BuildVersion => |*x| x.deinit(allocator), | ||
| 178 | .Unknown => |*x| x.deinit(allocator), | 186 | .Unknown => |*x| x.deinit(allocator), |
| 179 | else => {}, | 187 | else => {}, |
| 180 | }; | 188 | }; |
| ... | @@ -193,6 +201,7 @@ pub const LoadCommand = union(enum) { | ... | @@ -193,6 +201,7 @@ pub const LoadCommand = union(enum) { |
| 193 | .Main => |x| meta.eql(x, other.Main), | 201 | .Main => |x| meta.eql(x, other.Main), |
| 194 | .VersionMin => |x| meta.eql(x, other.VersionMin), | 202 | .VersionMin => |x| meta.eql(x, other.VersionMin), |
| 195 | .SourceVersion => |x| meta.eql(x, other.SourceVersion), | 203 | .SourceVersion => |x| meta.eql(x, other.SourceVersion), |
| 204 | .BuildVersion => |x| x.eql(other.BuildVersion), | ||
| 196 | .Uuid => |x| meta.eql(x, other.Uuid), | 205 | .Uuid => |x| meta.eql(x, other.Uuid), |
| 197 | .LinkeditData => |x| meta.eql(x, other.LinkeditData), | 206 | .LinkeditData => |x| meta.eql(x, other.LinkeditData), |
| 198 | .Segment => |x| x.eql(other.Segment), | 207 | .Segment => |x| x.eql(other.Segment), |
src/link/MachO/fat.zig+4-6| ... | @@ -5,10 +5,8 @@ const macho = std.macho; | ... | @@ -5,10 +5,8 @@ const macho = std.macho; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const native_endian = builtin.target.cpu.arch.endian(); | 6 | const native_endian = builtin.target.cpu.arch.endian(); |
| 7 | 7 | ||
| 8 | const Arch = std.Target.Cpu.Arch; | ||
| 9 | |||
| 10 | pub fn decodeArch(cputype: macho.cpu_type_t, comptime logError: bool) !std.Target.Cpu.Arch { | 8 | pub fn decodeArch(cputype: macho.cpu_type_t, comptime logError: bool) !std.Target.Cpu.Arch { |
| 11 | const arch: Arch = switch (cputype) { | 9 | const arch: std.Target.Cpu.Arch = switch (cputype) { |
| 12 | macho.CPU_TYPE_ARM64 => .aarch64, | 10 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 13 | macho.CPU_TYPE_X86_64 => .x86_64, | 11 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 14 | else => { | 12 | else => { |
| ... | @@ -31,7 +29,7 @@ fn readFatStruct(reader: anytype, comptime T: type) !T { | ... | @@ -31,7 +29,7 @@ fn readFatStruct(reader: anytype, comptime T: type) !T { |
| 31 | return res; | 29 | return res; |
| 32 | } | 30 | } |
| 33 | 31 | ||
| 34 | pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 { | 32 | pub fn getLibraryOffset(reader: anytype, target: std.Target) !u64 { |
| 35 | const fat_header = try readFatStruct(reader, macho.fat_header); | 33 | const fat_header = try readFatStruct(reader, macho.fat_header); |
| 36 | if (fat_header.magic != macho.FAT_MAGIC) return 0; | 34 | if (fat_header.magic != macho.FAT_MAGIC) return 0; |
| 37 | 35 | ||
| ... | @@ -44,12 +42,12 @@ pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 { | ... | @@ -44,12 +42,12 @@ pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 { |
| 44 | error.UnsupportedCpuArchitecture => continue, | 42 | error.UnsupportedCpuArchitecture => continue, |
| 45 | else => |e| return e, | 43 | else => |e| return e, |
| 46 | }; | 44 | }; |
| 47 | if (lib_arch == arch) { | 45 | if (lib_arch == target.cpu.arch) { |
| 48 | // We have found a matching architecture! | 46 | // We have found a matching architecture! |
| 49 | return fat_arch.offset; | 47 | return fat_arch.offset; |
| 50 | } | 48 | } |
| 51 | } else { | 49 | } else { |
| 52 | log.err("Could not find matching cpu architecture in fat library: expected {s}", .{arch}); | 50 | log.err("Could not find matching cpu architecture in fat library: expected {s}", .{target.cpu.arch}); |
| 53 | return error.MismatchedCpuArchitecture; | 51 | return error.MismatchedCpuArchitecture; |
| 54 | } | 52 | } |
| 55 | } | 53 | } |
src/main.zig+17-8| ... | @@ -830,7 +830,10 @@ fn buildOutputType( | ... | @@ -830,7 +830,10 @@ fn buildOutputType( |
| 830 | } else if (mem.eql(u8, arg, "-D") or | 830 | } else if (mem.eql(u8, arg, "-D") or |
| 831 | mem.eql(u8, arg, "-isystem") or | 831 | mem.eql(u8, arg, "-isystem") or |
| 832 | mem.eql(u8, arg, "-I") or | 832 | mem.eql(u8, arg, "-I") or |
| 833 | mem.eql(u8, arg, "-dirafter")) | 833 | mem.eql(u8, arg, "-dirafter") or |
| 834 | mem.eql(u8, arg, "-iwithsysroot") or | ||
| 835 | mem.eql(u8, arg, "-iframework") or | ||
| 836 | mem.eql(u8, arg, "-iframeworkwithsysroot")) | ||
| 834 | { | 837 | { |
| 835 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 838 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 836 | i += 1; | 839 | i += 1; |
| ... | @@ -873,6 +876,8 @@ fn buildOutputType( | ... | @@ -873,6 +876,8 @@ fn buildOutputType( |
| 873 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 876 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 874 | i += 1; | 877 | i += 1; |
| 875 | sysroot = args[i]; | 878 | sysroot = args[i]; |
| 879 | try clang_argv.append("-isysroot"); | ||
| 880 | try clang_argv.append(args[i]); | ||
| 876 | } else if (mem.eql(u8, arg, "--libc")) { | 881 | } else if (mem.eql(u8, arg, "--libc")) { |
| 877 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); | 882 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 878 | i += 1; | 883 | i += 1; |
| ... | @@ -1673,7 +1678,9 @@ fn buildOutputType( | ... | @@ -1673,7 +1678,9 @@ fn buildOutputType( |
| 1673 | want_native_include_dirs = true; | 1678 | want_native_include_dirs = true; |
| 1674 | } | 1679 | } |
| 1675 | 1680 | ||
| 1676 | if (sysroot == null and cross_target.isNativeOs() and | 1681 | const is_darwin_on_darwin = (comptime std.Target.current.isDarwin()) and cross_target.isDarwin(); |
| 1682 | |||
| 1683 | if (sysroot == null and (cross_target.isNativeOs() or is_darwin_on_darwin) and | ||
| 1677 | (system_libs.items.len != 0 or want_native_include_dirs)) | 1684 | (system_libs.items.len != 0 or want_native_include_dirs)) |
| 1678 | { | 1685 | { |
| 1679 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { | 1686 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { |
| ... | @@ -1684,16 +1691,18 @@ fn buildOutputType( | ... | @@ -1684,16 +1691,18 @@ fn buildOutputType( |
| 1684 | } | 1691 | } |
| 1685 | 1692 | ||
| 1686 | const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: { | 1693 | const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: { |
| 1687 | const min = target_info.target.os.getVersionRange().semver.min; | 1694 | const should_get_sdk_path = if (cross_target.isNativeOs() and target_info.target.os.tag == .macos) inner: { |
| 1688 | const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14); | 1695 | const min = target_info.target.os.getVersionRange().semver.min; |
| 1689 | if (at_least_mojave) { | 1696 | const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14); |
| 1690 | const sdk_path = try std.zig.system.getSDKPath(arena); | 1697 | break :inner at_least_mojave; |
| 1698 | } else true; | ||
| 1699 | if (!should_get_sdk_path) break :outer false; | ||
| 1700 | if (try std.zig.system.darwin.getSDKPath(arena, target_info.target)) |sdk_path| { | ||
| 1691 | try clang_argv.ensureCapacity(clang_argv.items.len + 2); | 1701 | try clang_argv.ensureCapacity(clang_argv.items.len + 2); |
| 1692 | clang_argv.appendAssumeCapacity("-isysroot"); | 1702 | clang_argv.appendAssumeCapacity("-isysroot"); |
| 1693 | clang_argv.appendAssumeCapacity(sdk_path); | 1703 | clang_argv.appendAssumeCapacity(sdk_path); |
| 1694 | break :outer true; | 1704 | break :outer true; |
| 1695 | } | 1705 | } else break :outer false; |
| 1696 | break :outer false; | ||
| 1697 | } else false; | 1706 | } else false; |
| 1698 | 1707 | ||
| 1699 | try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2); | 1708 | try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2); |