authorgravatar for michael.dusan@gmail.comMichael Dusan <michael.dusan@gmail.com> 2020-04-22 15:57:29-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-04-22 15:57:29-04:00
log9a06f966cdea84baca4a7e8a274d2b5e88f50041
treeb4997adf62d262962b60c000ca8064f069eb1346
parente8545db9d4ced8978c5594c637d9bf76dc26209d
parent3df0a3a528ad28dc1ff0c79e2c9860515f5c5826
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5125 from mikdusan/kern.osproductversion

macos: add fallback version detection

2 files changed, 477 insertions(+), 24 deletions(-)

lib/std/zig/system.zig+33-24
...@@ -8,6 +8,7 @@ const assert = std.debug.assert;...@@ -8,6 +8,7 @@ const assert = std.debug.assert;
8const process = std.process;8const process = std.process;
9const Target = std.Target;9const Target = std.Target;
10const CrossTarget = std.zig.CrossTarget;10const CrossTarget = std.zig.CrossTarget;
11const macos = @import("system/macos.zig");
1112
12const is_windows = Target.current.os.tag == .windows;13const is_windows = Target.current.os.tag == .windows;
1314
...@@ -259,31 +260,35 @@ pub const NativeTargetInfo = struct {...@@ -259,31 +260,35 @@ pub const NativeTargetInfo = struct {
259 os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version);260 os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version);
260 },261 },
261 .macosx => {262 .macosx => {
262 var product_version: [32]u8 = undefined;263 var scbuf: [32]u8 = undefined;
263 var size: usize = product_version.len;264 var size: usize = undefined;
264265
265 // The osproductversion sysctl was introduced first with266 // The osproductversion sysctl was introduced first with 10.13.4 High Sierra.
266 // High Sierra, thankfully that's also the baseline that Zig267 const key_osproductversion = "kern.osproductversion"; // eg. "10.15.4"
267 // supports268 size = scbuf.len;
268 std.os.sysctlbynameZ(269 if (std.os.sysctlbynameZ(key_osproductversion, &scbuf, &size, null, 0)) |_| {
269 "kern.osproductversion",270 const string_version = scbuf[0 .. size - 1];
270 &product_version,271 if (std.builtin.Version.parse(string_version)) |ver| {
271 &size,272 os.version_range.semver.min = ver;
272 null,273 os.version_range.semver.max = ver;
273 0,274 } else |err| switch (err) {
274 ) catch |err| switch (err) {275 error.Overflow => {},
275 error.UnknownName => unreachable,276 error.InvalidCharacter => {},
276 else => unreachable,277 error.InvalidVersion => {},
277 };278 }
278
279 const string_version = product_version[0 .. size - 1 :0];
280 if (std.builtin.Version.parse(string_version)) |ver| {
281 os.version_range.semver.min = ver;
282 os.version_range.semver.max = ver;
283 } else |err| switch (err) {279 } else |err| switch (err) {
284 error.Overflow => {},280 error.UnknownName => {
285 error.InvalidCharacter => {},281 const key_osversion = "kern.osversion"; // eg. "19E287"
286 error.InvalidVersion => {},282 size = scbuf.len;
283 std.os.sysctlbynameZ(key_osversion, &scbuf, &size, null, 0) catch {
284 @panic("unable to detect macOS version: " ++ key_osversion);
285 };
286 if (macos.version_from_build(scbuf[0 .. size - 1])) |ver| {
287 os.version_range.semver.min = ver;
288 os.version_range.semver.max = ver;
289 } else |_| {}
290 },
291 else => @panic("unable to detect macOS version: " ++ key_osproductversion),
287 }292 }
288 },293 },
289 .freebsd => {294 .freebsd => {
...@@ -888,3 +893,7 @@ pub const NativeTargetInfo = struct {...@@ -888,3 +893,7 @@ pub const NativeTargetInfo = struct {
888 }893 }
889 }894 }
890};895};
896
897test "" {
898 _ = @import("system/macos.zig");
899}
lib/std/zig/system/macos.zig created+444
...@@ -0,0 +1,444 @@
1const std = @import("std");
2
3pub fn version_from_build(build: []const u8) !std.builtin.Version {
4 // build format:
5 // 19E287 (example)
6 // xxyzzz
7 //
8 // major = 10
9 // minor = x - 4 = 19 - 4 = 15
10 // patch = ascii(y) - 'A' = 'E' - 'A' = 69 - 65 = 4
11 // answer: 10.15.4
12 //
13 // note: patch is typical but with some older releases (before 10.8) zzz is considered
14
15 // never return anything below 10.0.0
16 var result = std.builtin.Version{ .major = 10, .minor = 0, .patch = 0 };
17
18 // parse format-x
19 var yindex: usize = 0;
20 {
21 while (yindex < build.len) : (yindex += 1) {
22 if (build[yindex] < '0' or build[yindex] > '9') break;
23 }
24 if (yindex == 0) return result;
25 const x = std.fmt.parseUnsigned(u16, build[0..yindex], 10) catch return error.InvalidVersion;
26 if (x < 4) return result;
27 result.minor = x - 4;
28 }
29
30 // parse format-y, format-z
31 {
32 // expect two more
33 if (build.len < yindex + 2) return error.InvalidVersion;
34 const y = build[yindex];
35 if (y < 'A') return error.InvalidVersion;
36 var zend = yindex + 1;
37 while (zend < build.len) {
38 if (build[zend] < '0' or build[zend] > '9') break;
39 zend += 1;
40 }
41 if (zend == yindex + 1) return error.InvalidVersion;
42 const z = std.fmt.parseUnsigned(u16, build[yindex + 1..zend], 10) catch return error.InvalidVersion;
43
44 result.patch = switch (result.minor) {
45 // TODO: compiler complains without explicit @as() coercion
46 0 => @as(u32, switch (y) { // Cheetah: 10.0
47 'K' => 0,
48 'L' => 1,
49 'P' => @as(u32, block: {
50 if (z < 13) break :block 2;
51 break :block 3;
52 }),
53 'Q' => 4,
54 else => return error.InvalidVersion,
55 }),
56 1 => @as(u32, switch (y) { // Puma: 10.1
57 'G' => 0,
58 'M' => 1,
59 'P' => 2,
60 'Q' => @as(u32, block: {
61 if (z < 125) break :block 3;
62 break :block 4;
63 }),
64 'S' => 5,
65 else => return error.InvalidVersion,
66 }),
67 2 => @as(u32, switch (y) { // Jaguar: 10.2
68 'C' => 0,
69 'D' => 1,
70 'F' => 2,
71 'G' => 3,
72 'I' => 4,
73 'L' => @as(u32, block: {
74 if (z < 60) break :block 5;
75 break :block 6;
76 }),
77 'R' => @as(u32, block: {
78 if (z < 73) break :block 7;
79 break :block 8;
80 }),
81 'S' => 8,
82 else => return error.InvalidVersion,
83 }),
84 3 => @as(u32, switch (y) { // Panther: 10.3
85 'B' => 0,
86 'C' => 1,
87 'D' => 2,
88 'F' => 3,
89 'H' => 4,
90 'M' => 5,
91 'R' => 6,
92 'S' => 7,
93 'U' => 8,
94 'W' => 9,
95 else => return error.InvalidVersion,
96 }),
97 4 => @as(u32, switch (y) { // Tiger: 10.4
98 'A' => 0,
99 'B' => 1,
100 'C', 'E', => 2,
101 'F' => 3,
102 'G' => @as(u32, block: {
103 if (z >= 1454) break :block 5;
104 break :block 4;
105 }),
106 'H' => 5,
107 'I' => 6,
108 'J', 'K', 'N', => 7,
109 'L' => 8,
110 'P' => 9,
111 'R' => 10,
112 'S' => 11,
113 else => return error.InvalidVersion,
114 }),
115 5 => @as(u32, switch (y) { // Leopard: 10.5
116 'A' => 0,
117 'B' => 1,
118 'C' => 2,
119 'D' => 3,
120 'E' => 4,
121 'F' => 5,
122 'G' => 6,
123 'J' => 7,
124 'L' => 8,
125 else => return error.InvalidVersion,
126 }),
127 6 => @as(u32, switch (y) { // Snow Leopard: 10.6
128 'A' => 0,
129 'B' => 1,
130 'C' => 2,
131 'D' => 3,
132 'F' => 4,
133 'H' => 5,
134 'J' => @as(u32, block: {
135 if (z < 869) break :block 6;
136 break :block 7;
137 }),
138 'K' => 8,
139 else => return error.InvalidVersion,
140 }),
141 7 => @as(u32, switch (y) { // Snow Leopard: 10.6
142 'A' => 0,
143 'B' => 1,
144 'C' => 2,
145 'D' => 3,
146 'E' => 4,
147 'G' => 5,
148 else => return error.InvalidVersion,
149 }),
150 else => y - 'A',
151 };
152 }
153 return result;
154}
155
156test "version_from_build" {
157 // see https://en.wikipedia.org/wiki/MacOS_version_history#Releases
158 const known = [_][2][]const u8{
159 .{ "4K78", "10.0.0" },
160 .{ "4L13", "10.0.1" },
161 .{ "4P12", "10.0.2" },
162 .{ "4P13", "10.0.3" },
163 .{ "4Q12", "10.0.4" },
164
165 .{ "5G64", "10.1.0" },
166 .{ "5M28", "10.1.1" },
167 .{ "5P48", "10.1.2" },
168 .{ "5Q45", "10.1.3" },
169 .{ "5Q125", "10.1.4" },
170 .{ "5S60", "10.1.5" },
171
172 .{ "6C115", "10.2.0" },
173 .{ "6C115a", "10.2.0" },
174 .{ "6D52", "10.2.1" },
175 .{ "6F21", "10.2.2" },
176 .{ "6G30", "10.2.3" },
177 .{ "6G37", "10.2.3" },
178 .{ "6G50", "10.2.3" },
179 .{ "6I32", "10.2.4" },
180 .{ "6L29", "10.2.5" },
181 .{ "6L60", "10.2.6" },
182 .{ "6R65", "10.2.7" },
183 .{ "6R73", "10.2.8" },
184 .{ "6S90", "10.2.8" },
185
186 .{ "7B85", "10.3.0" },
187 .{ "7B86", "10.3.0" },
188 .{ "7C107", "10.3.1" },
189 .{ "7D24", "10.3.2" },
190 .{ "7D28", "10.3.2" },
191 .{ "7F44", "10.3.3" },
192 .{ "7H63", "10.3.4" },
193 .{ "7M34", "10.3.5" },
194 .{ "7R28", "10.3.6" },
195 .{ "7S215", "10.3.7" },
196 .{ "7U16", "10.3.8" },
197 .{ "7W98", "10.3.9" },
198
199 .{ "8A428", "10.4.0" },
200 .{ "8A432", "10.4.0" },
201 .{ "8B15", "10.4.1" },
202 .{ "8B17", "10.4.1" },
203 .{ "8C46", "10.4.2" },
204 .{ "8C47", "10.4.2" },
205 .{ "8E102", "10.4.2" },
206 .{ "8E45", "10.4.2" },
207 .{ "8E90", "10.4.2" },
208 .{ "8F46", "10.4.3" },
209 .{ "8G32", "10.4.4" },
210 .{ "8G1165", "10.4.4" },
211 .{ "8H14", "10.4.5" },
212 .{ "8G1454", "10.4.5" },
213 .{ "8I127", "10.4.6" },
214 .{ "8I1119", "10.4.6" },
215 .{ "8J135", "10.4.7" },
216 .{ "8J2135a", "10.4.7" },
217 .{ "8K1079", "10.4.7" },
218 .{ "8N5107", "10.4.7" },
219 .{ "8L127", "10.4.8" },
220 .{ "8L2127", "10.4.8" },
221 .{ "8P135", "10.4.9" },
222 .{ "8P2137", "10.4.9" },
223 .{ "8R218", "10.4.10" },
224 .{ "8R2218", "10.4.10" },
225 .{ "8R2232", "10.4.10" },
226 .{ "8S165", "10.4.11" },
227 .{ "8S2167", "10.4.11" },
228
229 .{ "9A581", "10.5.0" },
230 .{ "9B18", "10.5.1" },
231 .{ "9C31", "10.5.2" },
232 .{ "9C7010", "10.5.2" },
233 .{ "9D34", "10.5.3" },
234 .{ "9E17", "10.5.4" },
235 .{ "9F33", "10.5.5" },
236 .{ "9G55", "10.5.6" },
237 .{ "9G66", "10.5.6" },
238 .{ "9J61", "10.5.7" },
239 .{ "9L30", "10.5.8" },
240
241 .{ "10A432", "10.6.0" },
242 .{ "10A433", "10.6.0" },
243 .{ "10B504", "10.6.1" },
244 .{ "10C540", "10.6.2" },
245 .{ "10D573", "10.6.3" },
246 .{ "10D575", "10.6.3" },
247 .{ "10D578", "10.6.3" },
248 .{ "10F569", "10.6.4" },
249 .{ "10H574", "10.6.5" },
250 .{ "10J567", "10.6.6" },
251 .{ "10J869", "10.6.7" },
252 .{ "10J3250", "10.6.7" },
253 .{ "10J4138", "10.6.7" },
254 .{ "10K540", "10.6.8" },
255 .{ "10K549", "10.6.8" },
256
257 .{ "11A511", "10.7.0" },
258 .{ "11A511s", "10.7.0" },
259 .{ "11A2061", "10.7.0" },
260 .{ "11A2063", "10.7.0" },
261 .{ "11B26", "10.7.1" },
262 .{ "11B2118", "10.7.1" },
263 .{ "11C74", "10.7.2" },
264 .{ "11D50", "10.7.3" },
265 .{ "11E53", "10.7.4" },
266 .{ "11G56", "10.7.5" },
267 .{ "11G63", "10.7.5" },
268
269 .{ "12A269", "10.8.0" },
270 .{ "12B19", "10.8.1" },
271 .{ "12C54", "10.8.2" },
272 .{ "12C60", "10.8.2" },
273 .{ "12C2034", "10.8.2" },
274 .{ "12C3104", "10.8.2" },
275 .{ "12D78", "10.8.3" },
276 .{ "12E55", "10.8.4" },
277 .{ "12E3067", "10.8.4" },
278 .{ "12E4022", "10.8.4" },
279 .{ "12F37", "10.8.5" },
280 .{ "12F45", "10.8.5" },
281 .{ "12F2501", "10.8.5" },
282 .{ "12F2518", "10.8.5" },
283 .{ "12F2542", "10.8.5" },
284 .{ "12F2560", "10.8.5" },
285
286 .{ "13A603", "10.9.0" },
287 .{ "13B42", "10.9.1" },
288 .{ "13C64", "10.9.2" },
289 .{ "13C1021", "10.9.2" },
290 .{ "13D65", "10.9.3" },
291 .{ "13E28", "10.9.4" },
292 .{ "13F34", "10.9.5" },
293 .{ "13F1066", "10.9.5" },
294 .{ "13F1077", "10.9.5" },
295 .{ "13F1096", "10.9.5" },
296 .{ "13F1112", "10.9.5" },
297 .{ "13F1134", "10.9.5" },
298 .{ "13F1507", "10.9.5" },
299 .{ "13F1603", "10.9.5" },
300 .{ "13F1712", "10.9.5" },
301 .{ "13F1808", "10.9.5" },
302 .{ "13F1911", "10.9.5" },
303
304 .{ "14A389", "10.10.0" },
305 .{ "14B25", "10.10.1" },
306 .{ "14C109", "10.10.2" },
307 .{ "14C1510", "10.10.2" },
308 .{ "14C1514", "10.10.2" },
309 .{ "14C2043", "10.10.2" },
310 .{ "14C2513", "10.10.2" },
311 .{ "14D131", "10.10.3" },
312 .{ "14D136", "10.10.3" },
313 .{ "14E46", "10.10.4" },
314 .{ "14F27", "10.10.5" },
315 .{ "14F1021", "10.10.5" },
316 .{ "14F1505", "10.10.5" },
317 .{ "14F1509", "10.10.5" },
318 .{ "14F1605", "10.10.5" },
319 .{ "14F1713", "10.10.5" },
320 .{ "14F1808", "10.10.5" },
321 .{ "14F1909", "10.10.5" },
322 .{ "14F1912", "10.10.5" },
323 .{ "14F2009", "10.10.5" },
324 .{ "14F2109", "10.10.5" },
325 .{ "14F2315", "10.10.5" },
326 .{ "14F2411", "10.10.5" },
327 .{ "14F2511", "10.10.5" },
328
329 .{ "15A284", "10.11.0" },
330 .{ "15B42", "10.11.1" },
331 .{ "15C50", "10.11.2" },
332 .{ "15D21", "10.11.3" },
333 .{ "15E65", "10.11.4" },
334 .{ "15F34", "10.11.5" },
335 .{ "15G31", "10.11.6" },
336 .{ "15G1004", "10.11.6" },
337 .{ "15G1011", "10.11.6" },
338 .{ "15G1108", "10.11.6" },
339 .{ "15G1212", "10.11.6" },
340 .{ "15G1217", "10.11.6" },
341 .{ "15G1421", "10.11.6" },
342 .{ "15G1510", "10.11.6" },
343 .{ "15G1611", "10.11.6" },
344 .{ "15G17023", "10.11.6" },
345 .{ "15G18013", "10.11.6" },
346 .{ "15G19009", "10.11.6" },
347 .{ "15G20015", "10.11.6" },
348 .{ "15G21013", "10.11.6" },
349 .{ "15G22010", "10.11.6" },
350
351 .{ "16A323", "10.12.0" },
352 .{ "16B2555", "10.12.1" },
353 .{ "16B2657", "10.12.1" },
354 .{ "16C67", "10.12.2" },
355 .{ "16C68", "10.12.2" },
356 .{ "16D32", "10.12.3" },
357 .{ "16E195", "10.12.4" },
358 .{ "16F73", "10.12.5" },
359 .{ "16F2073", "10.12.5" },
360 .{ "16G29", "10.12.6" },
361 .{ "16G1036", "10.12.6" },
362 .{ "16G1114", "10.12.6" },
363 .{ "16G1212", "10.12.6" },
364 .{ "16G1314", "10.12.6" },
365 .{ "16G1408", "10.12.6" },
366 .{ "16G1510", "10.12.6" },
367 .{ "16G1618", "10.12.6" },
368 .{ "16G1710", "10.12.6" },
369 .{ "16G1815", "10.12.6" },
370 .{ "16G1917", "10.12.6" },
371 .{ "16G1918", "10.12.6" },
372 .{ "16G2016", "10.12.6" },
373 .{ "16G2127", "10.12.6" },
374 .{ "16G2128", "10.12.6" },
375 .{ "16G2136", "10.12.6" },
376
377 .{ "17A365", "10.13.0" },
378 .{ "17A405", "10.13.0" },
379 .{ "17B48", "10.13.1" },
380 .{ "17B1002", "10.13.1" },
381 .{ "17B1003", "10.13.1" },
382 .{ "17C88", "10.13.2" },
383 .{ "17C89", "10.13.2" },
384 .{ "17C205", "10.13.2" },
385 .{ "17C2205", "10.13.2" },
386 .{ "17D47", "10.13.3" },
387 .{ "17D2047", "10.13.3" },
388 .{ "17D102", "10.13.3" },
389 .{ "17D2102", "10.13.3" },
390 .{ "17E199", "10.13.4" },
391 .{ "17E202", "10.13.4" },
392 .{ "17F77", "10.13.5" },
393 .{ "17G65", "10.13.6" },
394 .{ "17G2208", "10.13.6" },
395 .{ "17G3025", "10.13.6" },
396 .{ "17G4015", "10.13.6" },
397 .{ "17G5019", "10.13.6" },
398 .{ "17G6029", "10.13.6" },
399 .{ "17G6030", "10.13.6" },
400 .{ "17G7024", "10.13.6" },
401 .{ "17G8029", "10.13.6" },
402 .{ "17G8030", "10.13.6" },
403 .{ "17G8037", "10.13.6" },
404 .{ "17G9016", "10.13.6" },
405 .{ "17G10021", "10.13.6" },
406 .{ "17G11023", "10.13.6" },
407 .{ "17G12034", "10.13.6" },
408
409 .{ "18A391", "10.14.0" },
410 .{ "18B75", "10.14.1" },
411 .{ "18B2107", "10.14.1" },
412 .{ "18B3094", "10.14.1" },
413 .{ "18C54", "10.14.2" },
414 .{ "18D42", "10.14.3" },
415 .{ "18D43", "10.14.3" },
416 .{ "18D109", "10.14.3" },
417 .{ "18E226", "10.14.4" },
418 .{ "18E227", "10.14.4" },
419 .{ "18F132", "10.14.5" },
420 .{ "18G84", "10.14.6" },
421 .{ "18G87", "10.14.6" },
422 .{ "18G95", "10.14.6" },
423 .{ "18G103", "10.14.6" },
424 .{ "18G1012", "10.14.6" },
425 .{ "18G2022", "10.14.6" },
426 .{ "18G3020", "10.14.6" },
427 .{ "18G4032", "10.14.6" },
428
429 .{ "19A583", "10.15.0" },
430 .{ "19A602", "10.15.0" },
431 .{ "19A603", "10.15.0" },
432 .{ "19B88", "10.15.1" },
433 .{ "19C57", "10.15.2" },
434 .{ "19D76", "10.15.3" },
435 .{ "19E266", "10.15.4" },
436 .{ "19E287", "10.15.4" },
437 };
438 for (known) |pair| {
439 var buf: [32]u8 = undefined;
440 const ver = try version_from_build(pair[0]);
441 const sver = try std.fmt.bufPrint(buf[0..], "{}.{}.{}", .{ver.major, ver.minor, ver.patch});
442 std.testing.expect(std.mem.eql(u8, sver, pair[1]));
443 }
444}