| 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 | 2672 | try zig_args.append(self.builder.pathFromRoot(include_path)); |
| 2673 | 2673 | }, |
| 2674 | 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 | 2680 | try zig_args.append(self.builder.pathFromRoot(include_path)); |
| 2677 | 2681 | }, |
| 2678 | 2682 | .other_step => |other| if (other.emit_h) { |
| ... | ... | @@ -2700,6 +2704,12 @@ pub const LibExeObjStep = struct { |
| 2700 | 2704 | |
| 2701 | 2705 | if (self.target.isDarwin()) { |
| 2702 | 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 | 2713 | try zig_args.append("-F"); |
| 2704 | 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 | 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 | 134 | /// The entry_point_command is a replacement for thread_command. |
| 120 | 135 | /// It is used for main executables to specify the location (file offset) |
| 121 | 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 | 13 | const process = std.process; |
| 14 | 14 | const Target = std.Target; |
| 15 | 15 | const CrossTarget = std.zig.CrossTarget; |
| 16 | const macos = @import("system/macos.zig"); | |
| 17 | 16 | const native_endian = std.Target.current.cpu.arch.endian(); |
| 18 | 17 | const linux = @import("system/linux.zig"); |
| 19 | 18 | pub const windows = @import("system/windows.zig"); |
| 20 | ||
| 21 | pub const getSDKPath = macos.getSDKPath; | |
| 19 | pub const darwin = @import("system/darwin.zig"); | |
| 22 | 20 | |
| 23 | 21 | pub const NativePaths = struct { |
| 24 | 22 | include_dirs: ArrayList([:0]u8), |
| ... | ... | @@ -255,7 +253,7 @@ pub const NativeTargetInfo = struct { |
| 255 | 253 | os.version_range.windows.min = detected_version; |
| 256 | 254 | os.version_range.windows.max = detected_version; |
| 257 | 255 | }, |
| 258 | .macos => try macos.detect(&os), | |
| 256 | .macos => try darwin.macos.detect(&os), | |
| 259 | 257 | .freebsd, .netbsd, .dragonfly => { |
| 260 | 258 | const key = switch (Target.current.os.tag) { |
| 261 | 259 | .freebsd => "kern.osreldate", |
| ... | ... | @@ -972,7 +970,7 @@ pub const NativeTargetInfo = struct { |
| 972 | 970 | |
| 973 | 971 | switch (std.Target.current.os.tag) { |
| 974 | 972 | .linux => return linux.detectNativeCpuAndFeatures(), |
| 975 | .macos => return macos.detectNativeCpuAndFeatures(), | |
| 973 | .macos => return darwin.macos.detectNativeCpuAndFeatures(), | |
| 976 | 974 | else => {}, |
| 977 | 975 | } |
| 978 | 976 | |
| ... | ... | @@ -983,6 +981,6 @@ pub const NativeTargetInfo = struct { |
| 983 | 981 | }; |
| 984 | 982 | |
| 985 | 983 | test { |
| 986 | _ = @import("system/macos.zig"); | |
| 984 | _ = @import("system/darwin.zig"); | |
| 987 | 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 | 944 | if (options.sysroot) |sysroot| { |
| 945 | 945 | break :blk sysroot; |
| 946 | 946 | } else if (darwin_can_use_system_sdk) { |
| 947 | const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11; | |
| 948 | break :blk if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null; | |
| 947 | break :blk try std.zig.system.darwin.getSDKPath(arena, options.target); | |
| 949 | 948 | } else { |
| 950 | 949 | break :blk null; |
| 951 | 950 | } |
src/link/MachO.zig+86-67| ... | ... | @@ -82,8 +82,8 @@ data_in_code_cmd_index: ?u16 = null, |
| 82 | 82 | function_starts_cmd_index: ?u16 = null, |
| 83 | 83 | main_cmd_index: ?u16 = null, |
| 84 | 84 | dylib_id_cmd_index: ?u16 = null, |
| 85 | version_min_cmd_index: ?u16 = null, | |
| 86 | 85 | source_version_cmd_index: ?u16 = null, |
| 86 | build_version_cmd_index: ?u16 = null, | |
| 87 | 87 | uuid_cmd_index: ?u16 = null, |
| 88 | 88 | code_signature_cmd_index: ?u16 = null, |
| 89 | 89 | /// Path to libSystem |
| ... | ... | @@ -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}, | |
| 798 | // we link against that instead of embedded libSystem.B.tbd file. | |
| 799 | var native_libsystem_available = false; | |
| 800 | if (self.base.options.is_native_os) blk: { | |
| 797 | // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}. | |
| 798 | var libsystem_available = false; | |
| 799 | if (self.base.options.sysroot != null) blk: { | |
| 801 | 800 | // Try stub file first. If we hit it, then we're done as the stub file |
| 802 | 801 | // re-exports every single symbol definition. |
| 803 | 802 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { |
| 804 | 803 | try libs.append(full_path); |
| 805 | native_libsystem_available = true; | |
| 804 | libsystem_available = true; | |
| 806 | 805 | break :blk; |
| 807 | 806 | } |
| 808 | 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 | 810 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { |
| 812 | 811 | try libs.append(libsystem_path); |
| 813 | 812 | try libs.append(libc_path); |
| 814 | native_libsystem_available = true; | |
| 813 | libsystem_available = true; | |
| 815 | 814 | break :blk; |
| 816 | 815 | } |
| 817 | 816 | } |
| 818 | 817 | } |
| 819 | if (!native_libsystem_available) { | |
| 818 | if (!libsystem_available) { | |
| 820 | 819 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 821 | 820 | "libc", "darwin", "libSystem.B.tbd", |
| 822 | 821 | }); |
| ... | ... | @@ -841,7 +840,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 841 | 840 | break; |
| 842 | 841 | } |
| 843 | 842 | } else { |
| 844 | log.warn("framework not found for '-f{s}'", .{framework}); | |
| 843 | log.warn("framework not found for '-framework {s}'", .{framework}); | |
| 845 | 844 | framework_not_found = true; |
| 846 | 845 | } |
| 847 | 846 | } |
| ... | ... | @@ -901,10 +900,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 901 | 900 | try argv.append("-o"); |
| 902 | 901 | try argv.append(full_out_path); |
| 903 | 902 | |
| 904 | if (native_libsystem_available) { | |
| 905 | try argv.append("-lSystem"); | |
| 906 | try argv.append("-lc"); | |
| 907 | } | |
| 903 | try argv.append("-lSystem"); | |
| 904 | try argv.append("-lc"); | |
| 908 | 905 | |
| 909 | 906 | for (search_lib_names.items) |l_name| { |
| 910 | 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 | 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 | 922 | Compilation.dump_argv(argv.items); |
| 918 | 923 | } |
| 919 | 924 | |
| ... | ... | @@ -990,7 +995,6 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void { |
| 990 | 995 | } |
| 991 | 996 | |
| 992 | 997 | fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const u8) !void { |
| 993 | const arch = self.base.options.target.cpu.arch; | |
| 994 | 998 | for (files) |file_name| { |
| 995 | 999 | const full_path = full_path: { |
| 996 | 1000 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; |
| ... | ... | @@ -999,17 +1003,17 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 999 | 1003 | }; |
| 1000 | 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 | 1007 | try self.objects.append(self.base.allocator, object); |
| 1004 | 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 | 1012 | try self.archives.append(self.base.allocator, archive); |
| 1009 | 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 | 1017 | .syslibroot = syslibroot, |
| 1014 | 1018 | })) |dylibs| { |
| 1015 | 1019 | defer self.base.allocator.free(dylibs); |
| ... | ... | @@ -1027,9 +1031,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 1027 | 1031 | } |
| 1028 | 1032 | |
| 1029 | 1033 | fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !void { |
| 1030 | const arch = self.base.options.target.cpu.arch; | |
| 1031 | 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 | 1036 | .syslibroot = syslibroot, |
| 1034 | 1037 | })) |dylibs| { |
| 1035 | 1038 | defer self.base.allocator.free(dylibs); |
| ... | ... | @@ -1042,7 +1045,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8) !v |
| 1042 | 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 | 1049 | try self.archives.append(self.base.allocator, archive); |
| 1047 | 1050 | continue; |
| 1048 | 1051 | } |
| ... | ... | @@ -2231,11 +2234,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2231 | 2234 | |
| 2232 | 2235 | const object_id = @intCast(u16, self.objects.items.len); |
| 2233 | 2236 | const object = try self.objects.addOne(self.base.allocator); |
| 2234 | object.* = try archive.parseObject( | |
| 2235 | self.base.allocator, | |
| 2236 | self.base.options.target.cpu.arch, | |
| 2237 | offsets.items[0], | |
| 2238 | ); | |
| 2237 | object.* = try archive.parseObject(self.base.allocator, self.base.options.target, offsets.items[0]); | |
| 2239 | 2238 | try self.resolveSymbolsInObject(object_id); |
| 2240 | 2239 | |
| 2241 | 2240 | continue :loop; |
| ... | ... | @@ -2717,27 +2716,6 @@ fn populateMetadata(self: *MachO) !void { |
| 2717 | 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 | 2719 | if (self.source_version_cmd_index == null) { |
| 2742 | 2720 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2743 | 2721 | try self.load_commands.append(self.base.allocator, .{ |
| ... | ... | @@ -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 | 2764 | if (self.uuid_cmd_index == null) { |
| 2753 | 2765 | self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 2754 | 2766 | var uuid_cmd: macho.uuid_command = .{ |
| ... | ... | @@ -2880,11 +2892,6 @@ fn flushZld(self: *MachO) !void { |
| 2880 | 2892 | if (self.base.options.target.cpu.arch == .aarch64) { |
| 2881 | 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 | 2897 | fn writeGotEntries(self: *MachO) !void { |
| ... | ... | @@ -4340,26 +4347,38 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4340 | 4347 | }); |
| 4341 | 4348 | self.load_commands_dirty = true; |
| 4342 | 4349 | } |
| 4343 | if (self.version_min_cmd_index == null) { | |
| 4344 | self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 4345 | const cmd: u32 = switch (self.base.options.target.os.tag) { | |
| 4346 | .macos => macho.LC_VERSION_MIN_MACOSX, | |
| 4347 | .ios => macho.LC_VERSION_MIN_IPHONEOS, | |
| 4348 | .tvos => macho.LC_VERSION_MIN_TVOS, | |
| 4349 | .watchos => macho.LC_VERSION_MIN_WATCHOS, | |
| 4350 | else => unreachable, // wrong OS | |
| 4351 | }; | |
| 4350 | if (self.build_version_cmd_index == null) { | |
| 4351 | self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len); | |
| 4352 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | |
| 4353 | u64, | |
| 4354 | @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version), | |
| 4355 | @sizeOf(u64), | |
| 4356 | )); | |
| 4352 | 4357 | const ver = self.base.options.target.os.version_range.semver.min; |
| 4353 | 4358 | const version = ver.major << 16 | ver.minor << 8 | ver.patch; |
| 4354 | try self.load_commands.append(self.base.allocator, .{ | |
| 4355 | .VersionMin = .{ | |
| 4356 | .cmd = cmd, | |
| 4357 | .cmdsize = @sizeOf(macho.version_min_command), | |
| 4358 | .version = version, | |
| 4359 | .sdk = version, | |
| 4359 | const is_simulator_abi = self.base.options.target.abi == .simulator; | |
| 4360 | var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{ | |
| 4361 | .cmd = macho.LC_BUILD_VERSION, | |
| 4362 | .cmdsize = cmdsize, | |
| 4363 | .platform = switch (self.base.options.target.os.tag) { | |
| 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 | 4383 | if (self.source_version_cmd_index == null) { |
| 4365 | 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 | 9 | const fat = @import("fat.zig"); |
| 10 | 10 | |
| 11 | 11 | const Allocator = mem.Allocator; |
| 12 | const Arch = std.Target.Cpu.Arch; | |
| 13 | 12 | const Object = @import("Object.zig"); |
| 14 | 13 | |
| 15 | 14 | file: fs.File, |
| ... | ... | @@ -104,7 +103,7 @@ pub fn deinit(self: *Archive, allocator: *Allocator) void { |
| 104 | 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 | 107 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 109 | 108 | error.FileNotFound => return null, |
| 110 | 109 | else => |e| return e, |
| ... | ... | @@ -119,7 +118,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 119 | 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 | 122 | error.EndOfStream, error.NotArchive => { |
| 124 | 123 | archive.deinit(allocator); |
| 125 | 124 | return null; |
| ... | ... | @@ -130,9 +129,9 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 130 | 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 | 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 | 135 | try self.file.seekTo(self.library_offset); |
| 137 | 136 | |
| 138 | 137 | const magic = try reader.readBytesNoEof(SARMAG); |
| ... | ... | @@ -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 | 218 | const reader = self.file.reader(); |
| 220 | 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 | 243 | .mtime = try self.header.?.date(), |
| 245 | 244 | }; |
| 246 | 245 | |
| 247 | try object.parse(allocator, arch); | |
| 246 | try object.parse(allocator, target); | |
| 248 | 247 | try reader.context.seekTo(0); |
| 249 | 248 | |
| 250 | 249 | return object; |
src/link/MachO/Dylib.zig+74-23| ... | ... | @@ -12,7 +12,6 @@ const fat = @import("fat.zig"); |
| 12 | 12 | const commands = @import("commands.zig"); |
| 13 | 13 | |
| 14 | 14 | const Allocator = mem.Allocator; |
| 15 | const Arch = std.Target.Cpu.Arch; | |
| 16 | 15 | const LibStub = @import("../tapi.zig").LibStub; |
| 17 | 16 | const LoadCommand = commands.LoadCommand; |
| 18 | 17 | const MachO = @import("../MachO.zig"); |
| ... | ... | @@ -139,11 +138,12 @@ pub const Error = error{ |
| 139 | 138 | pub const CreateOpts = struct { |
| 140 | 139 | syslibroot: ?[]const u8 = null, |
| 141 | 140 | id: ?Id = null, |
| 141 | target: ?std.Target = null, | |
| 142 | 142 | }; |
| 143 | 143 | |
| 144 | 144 | pub fn createAndParseFromPath( |
| 145 | 145 | allocator: *Allocator, |
| 146 | arch: Arch, | |
| 146 | target: std.Target, | |
| 147 | 147 | path: []const u8, |
| 148 | 148 | opts: CreateOpts, |
| 149 | 149 | ) Error!?[]Dylib { |
| ... | ... | @@ -161,7 +161,7 @@ pub fn createAndParseFromPath( |
| 161 | 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 | 165 | error.EndOfStream, error.NotDylib => { |
| 166 | 166 | try file.seekTo(0); |
| 167 | 167 | |
| ... | ... | @@ -171,7 +171,7 @@ pub fn createAndParseFromPath( |
| 171 | 171 | }; |
| 172 | 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 | 176 | else => |e| return e, |
| 177 | 177 | }; |
| ... | ... | @@ -195,7 +195,7 @@ pub fn createAndParseFromPath( |
| 195 | 195 | try dylibs.append(dylib); |
| 196 | 196 | // TODO this should not be performed if the user specifies `-flat_namespace` flag. |
| 197 | 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 | 200 | return dylibs.toOwnedSlice(); |
| 201 | 201 | } |
| ... | ... | @@ -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 | 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 | 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 | 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) { | |
| 243 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); | |
| 242 | if (this_arch != target.cpu.arch) { | |
| 243 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch }); | |
| 244 | 244 | return error.MismatchedCpuArchitecture; |
| 245 | 245 | } |
| 246 | 246 | |
| ... | ... | @@ -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 | 392 | if (lib_stub.inner.len == 0) return error.EmptyStubFile; |
| 339 | 393 | |
| 340 | 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 | 404 | } |
| 351 | 405 | self.id = id; |
| 352 | 406 | |
| 353 | const target_string: []const u8 = switch (arch) { | |
| 354 | .aarch64 => "arm64-macos", | |
| 355 | .x86_64 => "x86_64-macos", | |
| 356 | else => unreachable, | |
| 357 | }; | |
| 407 | var matcher = try TargetMatcher.init(allocator, target); | |
| 408 | defer matcher.deinit(); | |
| 358 | 409 | |
| 359 | 410 | var umbrella_libs = std.StringHashMap(void).init(allocator); |
| 360 | 411 | defer umbrella_libs.deinit(); |
| 361 | 412 | |
| 362 | 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 | 416 | if (stub_index > 0) { |
| 366 | 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 | 422 | |
| 372 | 423 | if (stub.exports) |exports| { |
| 373 | 424 | for (exports) |exp| { |
| 374 | if (!hasTarget(exp.targets, target_string)) continue; | |
| 425 | if (!matcher.matches(exp.targets)) continue; | |
| 375 | 426 | |
| 376 | 427 | if (exp.symbols) |symbols| { |
| 377 | 428 | for (symbols) |sym_name| { |
| ... | ... | @@ -390,7 +441,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 390 | 441 | |
| 391 | 442 | if (stub.reexports) |reexports| { |
| 392 | 443 | for (reexports) |reexp| { |
| 393 | if (!hasTarget(reexp.targets, target_string)) continue; | |
| 444 | if (!matcher.matches(reexp.targets)) continue; | |
| 394 | 445 | |
| 395 | 446 | if (reexp.symbols) |symbols| { |
| 396 | 447 | for (symbols) |sym_name| { |
| ... | ... | @@ -418,11 +469,11 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 418 | 469 | |
| 419 | 470 | // TODO track which libs were already parsed in different steps |
| 420 | 471 | for (lib_stub.inner) |stub| { |
| 421 | if (!hasTarget(stub.targets, target_string)) continue; | |
| 472 | if (!matcher.matches(stub.targets)) continue; | |
| 422 | 473 | |
| 423 | 474 | if (stub.reexported_libraries) |reexports| { |
| 424 | 475 | for (reexports) |reexp| { |
| 425 | if (!hasTarget(reexp.targets, target_string)) continue; | |
| 476 | if (!matcher.matches(reexp.targets)) continue; | |
| 426 | 477 | |
| 427 | 478 | for (reexp.libraries) |lib| { |
| 428 | 479 | if (umbrella_libs.contains(lib)) { |
| ... | ... | @@ -443,7 +494,7 @@ pub fn parseFromStub(self: *Dylib, allocator: *Allocator, arch: Arch, lib_stub: |
| 443 | 494 | pub fn parseDependentLibs( |
| 444 | 495 | self: *Dylib, |
| 445 | 496 | allocator: *Allocator, |
| 446 | arch: Arch, | |
| 497 | target: std.Target, | |
| 447 | 498 | out: *std.ArrayList(Dylib), |
| 448 | 499 | syslibroot: ?[]const u8, |
| 449 | 500 | ) !void { |
| ... | ... | @@ -475,7 +526,7 @@ pub fn parseDependentLibs( |
| 475 | 526 | |
| 476 | 527 | const dylibs = (try createAndParseFromPath( |
| 477 | 528 | allocator, |
| 478 | arch, | |
| 529 | target, | |
| 479 | 530 | full_path, |
| 480 | 531 | .{ |
| 481 | 532 | .id = id, |
src/link/MachO/Object.zig+6-7| ... | ... | @@ -15,7 +15,6 @@ const segmentName = commands.segmentName; |
| 15 | 15 | const sectionName = commands.sectionName; |
| 16 | 16 | |
| 17 | 17 | const Allocator = mem.Allocator; |
| 18 | const Arch = std.Target.Cpu.Arch; | |
| 19 | 18 | const LoadCommand = commands.LoadCommand; |
| 20 | 19 | const MachO = @import("../MachO.zig"); |
| 21 | 20 | const TextBlock = @import("TextBlock.zig"); |
| ... | ... | @@ -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 | 157 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 159 | 158 | error.FileNotFound => return null, |
| 160 | 159 | else => |e| return e, |
| ... | ... | @@ -169,7 +168,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 169 | 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 | 172 | error.EndOfStream, error.NotObject => { |
| 174 | 173 | object.deinit(allocator); |
| 175 | 174 | return null; |
| ... | ... | @@ -180,7 +179,7 @@ pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u |
| 180 | 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 | 183 | const reader = self.file.reader(); |
| 185 | 184 | if (self.file_offset) |offset| { |
| 186 | 185 | try reader.context.seekTo(offset); |
| ... | ... | @@ -195,7 +194,7 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 195 | 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 | 198 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 200 | 199 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 201 | 200 | else => |value| { |
| ... | ... | @@ -203,8 +202,8 @@ pub fn parse(self: *Object, allocator: *Allocator, arch: Arch) !void { |
| 203 | 202 | return error.UnsupportedCpuArchitecture; |
| 204 | 203 | }, |
| 205 | 204 | }; |
| 206 | if (this_arch != arch) { | |
| 207 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ arch, this_arch }); | |
| 205 | if (this_arch != target.cpu.arch) { | |
| 206 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ target.cpu.arch, this_arch }); | |
| 208 | 207 | return error.MismatchedCpuArchitecture; |
| 209 | 208 | } |
| 210 | 209 |
src/link/MachO/commands.zig+9| ... | ... | @@ -43,6 +43,7 @@ pub const LoadCommand = union(enum) { |
| 43 | 43 | Main: macho.entry_point_command, |
| 44 | 44 | VersionMin: macho.version_min_command, |
| 45 | 45 | SourceVersion: macho.source_version_command, |
| 46 | BuildVersion: GenericCommandWithData(macho.build_version_command), | |
| 46 | 47 | Uuid: macho.uuid_command, |
| 47 | 48 | LinkeditData: macho.linkedit_data_command, |
| 48 | 49 | Rpath: GenericCommandWithData(macho.rpath_command), |
| ... | ... | @@ -97,6 +98,9 @@ pub const LoadCommand = union(enum) { |
| 97 | 98 | macho.LC_SOURCE_VERSION => LoadCommand{ |
| 98 | 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 | 104 | macho.LC_UUID => LoadCommand{ |
| 101 | 105 | .Uuid = try stream.reader().readStruct(macho.uuid_command), |
| 102 | 106 | }, |
| ... | ... | @@ -129,6 +133,7 @@ pub const LoadCommand = union(enum) { |
| 129 | 133 | .Dylinker => |x| x.write(writer), |
| 130 | 134 | .Dylib => |x| x.write(writer), |
| 131 | 135 | .Rpath => |x| x.write(writer), |
| 136 | .BuildVersion => |x| x.write(writer), | |
| 132 | 137 | .Unknown => |x| x.write(writer), |
| 133 | 138 | }; |
| 134 | 139 | } |
| ... | ... | @@ -147,6 +152,7 @@ pub const LoadCommand = union(enum) { |
| 147 | 152 | .Dylinker => |x| x.inner.cmd, |
| 148 | 153 | .Dylib => |x| x.inner.cmd, |
| 149 | 154 | .Rpath => |x| x.inner.cmd, |
| 155 | .BuildVersion => |x| x.inner.cmd, | |
| 150 | 156 | .Unknown => |x| x.inner.cmd, |
| 151 | 157 | }; |
| 152 | 158 | } |
| ... | ... | @@ -165,6 +171,7 @@ pub const LoadCommand = union(enum) { |
| 165 | 171 | .Dylinker => |x| x.inner.cmdsize, |
| 166 | 172 | .Dylib => |x| x.inner.cmdsize, |
| 167 | 173 | .Rpath => |x| x.inner.cmdsize, |
| 174 | .BuildVersion => |x| x.inner.cmdsize, | |
| 168 | 175 | .Unknown => |x| x.inner.cmdsize, |
| 169 | 176 | }; |
| 170 | 177 | } |
| ... | ... | @@ -175,6 +182,7 @@ pub const LoadCommand = union(enum) { |
| 175 | 182 | .Dylinker => |*x| x.deinit(allocator), |
| 176 | 183 | .Dylib => |*x| x.deinit(allocator), |
| 177 | 184 | .Rpath => |*x| x.deinit(allocator), |
| 185 | .BuildVersion => |*x| x.deinit(allocator), | |
| 178 | 186 | .Unknown => |*x| x.deinit(allocator), |
| 179 | 187 | else => {}, |
| 180 | 188 | }; |
| ... | ... | @@ -193,6 +201,7 @@ pub const LoadCommand = union(enum) { |
| 193 | 201 | .Main => |x| meta.eql(x, other.Main), |
| 194 | 202 | .VersionMin => |x| meta.eql(x, other.VersionMin), |
| 195 | 203 | .SourceVersion => |x| meta.eql(x, other.SourceVersion), |
| 204 | .BuildVersion => |x| x.eql(other.BuildVersion), | |
| 196 | 205 | .Uuid => |x| meta.eql(x, other.Uuid), |
| 197 | 206 | .LinkeditData => |x| meta.eql(x, other.LinkeditData), |
| 198 | 207 | .Segment => |x| x.eql(other.Segment), |
src/link/MachO/fat.zig+4-6| ... | ... | @@ -5,10 +5,8 @@ const macho = std.macho; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | const native_endian = builtin.target.cpu.arch.endian(); |
| 7 | 7 | |
| 8 | const Arch = std.Target.Cpu.Arch; | |
| 9 | ||
| 10 | 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 | 10 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 13 | 11 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 14 | 12 | else => { |
| ... | ... | @@ -31,7 +29,7 @@ fn readFatStruct(reader: anytype, comptime T: type) !T { |
| 31 | 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 | 33 | const fat_header = try readFatStruct(reader, macho.fat_header); |
| 36 | 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 | 42 | error.UnsupportedCpuArchitecture => continue, |
| 45 | 43 | else => |e| return e, |
| 46 | 44 | }; |
| 47 | if (lib_arch == arch) { | |
| 45 | if (lib_arch == target.cpu.arch) { | |
| 48 | 46 | // We have found a matching architecture! |
| 49 | 47 | return fat_arch.offset; |
| 50 | 48 | } |
| 51 | 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 | 51 | return error.MismatchedCpuArchitecture; |
| 54 | 52 | } |
| 55 | 53 | } |
src/main.zig+17-8| ... | ... | @@ -830,7 +830,10 @@ fn buildOutputType( |
| 830 | 830 | } else if (mem.eql(u8, arg, "-D") or |
| 831 | 831 | mem.eql(u8, arg, "-isystem") or |
| 832 | 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 | 838 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 836 | 839 | i += 1; |
| ... | ... | @@ -873,6 +876,8 @@ fn buildOutputType( |
| 873 | 876 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 874 | 877 | i += 1; |
| 875 | 878 | sysroot = args[i]; |
| 879 | try clang_argv.append("-isysroot"); | |
| 880 | try clang_argv.append(args[i]); | |
| 876 | 881 | } else if (mem.eql(u8, arg, "--libc")) { |
| 877 | 882 | if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); |
| 878 | 883 | i += 1; |
| ... | ... | @@ -1673,7 +1678,9 @@ fn buildOutputType( |
| 1673 | 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 | 1684 | (system_libs.items.len != 0 or want_native_include_dirs)) |
| 1678 | 1685 | { |
| 1679 | 1686 | const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| { |
| ... | ... | @@ -1684,16 +1691,18 @@ fn buildOutputType( |
| 1684 | 1691 | } |
| 1685 | 1692 | |
| 1686 | 1693 | const has_sysroot = if (comptime std.Target.current.isDarwin()) outer: { |
| 1687 | const min = target_info.target.os.getVersionRange().semver.min; | |
| 1688 | const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14); | |
| 1689 | if (at_least_mojave) { | |
| 1690 | const sdk_path = try std.zig.system.getSDKPath(arena); | |
| 1694 | const should_get_sdk_path = if (cross_target.isNativeOs() and target_info.target.os.tag == .macos) inner: { | |
| 1695 | const min = target_info.target.os.getVersionRange().semver.min; | |
| 1696 | const at_least_mojave = min.major >= 11 or (min.major >= 10 and min.minor >= 14); | |
| 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 | 1701 | try clang_argv.ensureCapacity(clang_argv.items.len + 2); |
| 1692 | 1702 | clang_argv.appendAssumeCapacity("-isysroot"); |
| 1693 | 1703 | clang_argv.appendAssumeCapacity(sdk_path); |
| 1694 | 1704 | break :outer true; |
| 1695 | } | |
| 1696 | break :outer false; | |
| 1705 | } else break :outer false; | |
| 1697 | 1706 | } else false; |
| 1698 | 1707 | |
| 1699 | 1708 | try clang_argv.ensureCapacity(clang_argv.items.len + paths.include_dirs.items.len * 2); |