authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-02 00:11:29+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-02 00:32:56+01:00
logcf4423bb33598f13a4842fbae4013c1c25d907e2
treee7d1e0ed37bd95564821d556e1cf8f788ed596d1
parent852841fd1f82bb5ba5ecdf9a85a1f15ef70e6dd0

Remove .disable_native for x86_64-macos as it's fixed now

Add `aarch64-macos-gnu` corresponding test case. Fix rebase gone wrong.

2 files changed, 8 insertions(+), 905 deletions(-)

lib/std/zig/cross_target.zig deleted-903
......@@ -1,903 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const Target = std.Target;
5const mem = std.mem;
6
7/// Contains all the same data as `Target`, additionally introducing the concept of "the native target".
8/// The purpose of this abstraction is to provide meaningful and unsurprising defaults.
9/// This struct does reference any resources and it is copyable.
10pub const CrossTarget = struct {
11 /// `null` means native.
12 cpu_arch: ?Target.Cpu.Arch = null,
13
14 cpu_model: CpuModel = CpuModel.determined_by_cpu_arch,
15
16 /// Sparse set of CPU features to add to the set from `cpu_model`.
17 cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
18
19 /// Sparse set of CPU features to remove from the set from `cpu_model`.
20 cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
21
22 /// `null` means native.
23 os_tag: ?Target.Os.Tag = null,
24
25 /// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native)
26 /// then `null` for this field means native.
27 os_version_min: ?OsVersion = null,
28
29 /// When cross compiling, `null` means default (latest known OS version).
30 /// When `os_tag` is native, `null` means equal to the native OS version.
31 os_version_max: ?OsVersion = null,
32
33 /// `null` means default when cross compiling, or native when os_tag is native.
34 /// If `isGnuLibC()` is `false`, this must be `null` and is ignored.
35 glibc_version: ?SemVer = null,
36
37 /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
38 abi: ?Target.Abi = null,
39
40 /// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
41 /// based on the `os_tag`.
42 dynamic_linker: DynamicLinker = DynamicLinker{},
43
44 pub const CpuModel = union(enum) {
45 /// Always native
46 native,
47
48 /// Always baseline
49 baseline,
50
51 /// If CPU Architecture is native, then the CPU model will be native. Otherwise,
52 /// it will be baseline.
53 determined_by_cpu_arch,
54
55 explicit: *const Target.Cpu.Model,
56 };
57
58 pub const OsVersion = union(enum) {
59 none: void,
60 semver: SemVer,
61 windows: Target.Os.WindowsVersion,
62 };
63
64 pub const SemVer = std.builtin.Version;
65
66 pub const DynamicLinker = Target.DynamicLinker;
67
68 pub fn fromTarget(target: Target) CrossTarget {
69 var result: CrossTarget = .{
70 .cpu_arch = target.cpu.arch,
71 .cpu_model = .{ .explicit = target.cpu.model },
72 .os_tag = target.os.tag,
73 .os_version_min = undefined,
74 .os_version_max = undefined,
75 .abi = target.abi,
76 .glibc_version = if (target.isGnuLibC())
77 target.os.version_range.linux.glibc
78 else
79 null,
80 };
81 result.updateOsVersionRange(target.os);
82
83 const all_features = target.cpu.arch.allFeaturesList();
84 var cpu_model_set = target.cpu.model.features;
85 cpu_model_set.populateDependencies(all_features);
86 {
87 // The "add" set is the full set with the CPU Model set removed.
88 const add_set = &result.cpu_features_add;
89 add_set.* = target.cpu.features;
90 add_set.removeFeatureSet(cpu_model_set);
91 }
92 {
93 // The "sub" set is the features that are on in CPU Model set and off in the full set.
94 const sub_set = &result.cpu_features_sub;
95 sub_set.* = cpu_model_set;
96 sub_set.removeFeatureSet(target.cpu.features);
97 }
98 return result;
99 }
100
101 fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void {
102 switch (os.tag) {
103 .freestanding,
104 .ananas,
105 .cloudabi,
106 .fuchsia,
107 .kfreebsd,
108 .lv2,
109 .solaris,
110 .zos,
111 .haiku,
112 .minix,
113 .rtems,
114 .nacl,
115 .aix,
116 .cuda,
117 .nvcl,
118 .amdhsa,
119 .ps4,
120 .elfiamcu,
121 .mesa3d,
122 .contiki,
123 .amdpal,
124 .hermit,
125 .hurd,
126 .wasi,
127 .emscripten,
128 .uefi,
129 .opencl,
130 .glsl450,
131 .vulkan,
132 .plan9,
133 .other,
134 => {
135 self.os_version_min = .{ .none = {} };
136 self.os_version_max = .{ .none = {} };
137 },
138
139 .freebsd,
140 .macos,
141 .ios,
142 .tvos,
143 .watchos,
144 .netbsd,
145 .openbsd,
146 .dragonfly,
147 => {
148 self.os_version_min = .{ .semver = os.version_range.semver.min };
149 self.os_version_max = .{ .semver = os.version_range.semver.max };
150 },
151
152 .linux => {
153 self.os_version_min = .{ .semver = os.version_range.linux.range.min };
154 self.os_version_max = .{ .semver = os.version_range.linux.range.max };
155 },
156
157 .windows => {
158 self.os_version_min = .{ .windows = os.version_range.windows.min };
159 self.os_version_max = .{ .windows = os.version_range.windows.max };
160 },
161 }
162 }
163
164 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
165 pub fn toTarget(self: CrossTarget) Target {
166 return .{
167 .cpu = self.getCpu(),
168 .os = self.getOs(),
169 .abi = self.getAbi(),
170 };
171 }
172
173 pub const ParseOptions = struct {
174 /// This is sometimes called a "triple". It looks roughly like this:
175 /// riscv64-linux-musl
176 /// The fields are, respectively:
177 /// * CPU Architecture
178 /// * Operating System (and optional version range)
179 /// * C ABI (optional, with optional glibc version)
180 /// The string "native" can be used for CPU architecture as well as Operating System.
181 /// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted.
182 arch_os_abi: []const u8 = "native",
183
184 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
185 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
186 /// to remove from the set.
187 /// The following special strings are recognized for CPU Model name:
188 /// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set
189 /// of features that is expected to be supported on most available hardware.
190 /// * "native" - The native CPU model is to be detected when compiling.
191 /// If this field is not provided (`null`), then the value will depend on the
192 /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline".
193 cpu_features: ?[]const u8 = null,
194
195 /// Absolute path to dynamic linker, to override the default, which is either a natively
196 /// detected path, or a standard path.
197 dynamic_linker: ?[]const u8 = null,
198
199 /// If this is provided, the function will populate some information about parsing failures,
200 /// so that user-friendly error messages can be delivered.
201 diagnostics: ?*Diagnostics = null,
202
203 pub const Diagnostics = struct {
204 /// If the architecture was determined, this will be populated.
205 arch: ?Target.Cpu.Arch = null,
206
207 /// If the OS name was determined, this will be populated.
208 os_name: ?[]const u8 = null,
209
210 /// If the OS tag was determined, this will be populated.
211 os_tag: ?Target.Os.Tag = null,
212
213 /// If the ABI was determined, this will be populated.
214 abi: ?Target.Abi = null,
215
216 /// If the CPU name was determined, this will be populated.
217 cpu_name: ?[]const u8 = null,
218
219 /// If error.UnknownCpuFeature is returned, this will be populated.
220 unknown_feature_name: ?[]const u8 = null,
221 };
222 };
223
224 pub fn parse(args: ParseOptions) !CrossTarget {
225 var dummy_diags: ParseOptions.Diagnostics = undefined;
226 const diags = args.diagnostics orelse &dummy_diags;
227
228 var result: CrossTarget = .{
229 .dynamic_linker = DynamicLinker.init(args.dynamic_linker),
230 };
231
232 var it = mem.split(u8, args.arch_os_abi, "-");
233 const arch_name = it.next().?;
234 const arch_is_native = mem.eql(u8, arch_name, "native");
235 if (!arch_is_native) {
236 result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse
237 return error.UnknownArchitecture;
238 }
239 const arch = result.getCpuArch();
240 diags.arch = arch;
241
242 if (it.next()) |os_text| {
243 try parseOs(&result, diags, os_text);
244 } else if (!arch_is_native) {
245 return error.MissingOperatingSystem;
246 }
247
248 const opt_abi_text = it.next();
249 if (opt_abi_text) |abi_text| {
250 var abi_it = mem.split(u8, abi_text, ".");
251 const abi = std.meta.stringToEnum(Target.Abi, abi_it.next().?) orelse
252 return error.UnknownApplicationBinaryInterface;
253 result.abi = abi;
254 diags.abi = abi;
255
256 const abi_ver_text = abi_it.rest();
257 if (abi_it.next() != null) {
258 if (result.isGnuLibC()) {
259 result.glibc_version = SemVer.parse(abi_ver_text) catch |err| switch (err) {
260 error.Overflow => return error.InvalidAbiVersion,
261 error.InvalidCharacter => return error.InvalidAbiVersion,
262 error.InvalidVersion => return error.InvalidAbiVersion,
263 };
264 } else {
265 return error.InvalidAbiVersion;
266 }
267 }
268 }
269
270 if (it.next() != null) return error.UnexpectedExtraField;
271
272 if (args.cpu_features) |cpu_features| {
273 const all_features = arch.allFeaturesList();
274 var index: usize = 0;
275 while (index < cpu_features.len and
276 cpu_features[index] != '+' and
277 cpu_features[index] != '-')
278 {
279 index += 1;
280 }
281 const cpu_name = cpu_features[0..index];
282 diags.cpu_name = cpu_name;
283
284 const add_set = &result.cpu_features_add;
285 const sub_set = &result.cpu_features_sub;
286 if (mem.eql(u8, cpu_name, "native")) {
287 result.cpu_model = .native;
288 } else if (mem.eql(u8, cpu_name, "baseline")) {
289 result.cpu_model = .baseline;
290 } else {
291 result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) };
292 }
293
294 while (index < cpu_features.len) {
295 const op = cpu_features[index];
296 const set = switch (op) {
297 '+' => add_set,
298 '-' => sub_set,
299 else => unreachable,
300 };
301 index += 1;
302 const start = index;
303 while (index < cpu_features.len and
304 cpu_features[index] != '+' and
305 cpu_features[index] != '-')
306 {
307 index += 1;
308 }
309 const feature_name = cpu_features[start..index];
310 for (all_features) |feature, feat_index_usize| {
311 const feat_index = @intCast(Target.Cpu.Feature.Set.Index, feat_index_usize);
312 if (mem.eql(u8, feature_name, feature.name)) {
313 set.addFeature(feat_index);
314 break;
315 }
316 } else {
317 diags.unknown_feature_name = feature_name;
318 return error.UnknownCpuFeature;
319 }
320 }
321 }
322
323 return result;
324 }
325
326 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
327 pub fn getCpu(self: CrossTarget) Target.Cpu {
328 switch (self.cpu_model) {
329 .native => {
330 // This works when doing `zig build` because Zig generates a build executable using
331 // native CPU model & features. However this will not be accurate otherwise, and
332 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
333 return builtin.cpu;
334 },
335 .baseline => {
336 var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
337 self.updateCpuFeatures(&adjusted_baseline.features);
338 return adjusted_baseline;
339 },
340 .determined_by_cpu_arch => if (self.cpu_arch == null) {
341 // This works when doing `zig build` because Zig generates a build executable using
342 // native CPU model & features. However this will not be accurate otherwise, and
343 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
344 return builtin.cpu;
345 } else {
346 var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
347 self.updateCpuFeatures(&adjusted_baseline.features);
348 return adjusted_baseline;
349 },
350 .explicit => |model| {
351 var adjusted_model = model.toCpu(self.getCpuArch());
352 self.updateCpuFeatures(&adjusted_model.features);
353 return adjusted_model;
354 },
355 }
356 }
357
358 pub fn getCpuArch(self: CrossTarget) Target.Cpu.Arch {
359 return self.cpu_arch orelse builtin.cpu.arch;
360 }
361
362 pub fn getCpuModel(self: CrossTarget) *const Target.Cpu.Model {
363 return switch (self.cpu_model) {
364 .explicit => |cpu_model| cpu_model,
365 else => self.getCpu().model,
366 };
367 }
368
369 pub fn getCpuFeatures(self: CrossTarget) Target.Cpu.Feature.Set {
370 return self.getCpu().features;
371 }
372
373 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
374 pub fn getOs(self: CrossTarget) Target.Os {
375 // `builtin.os` works when doing `zig build` because Zig generates a build executable using
376 // native OS version range. However this will not be accurate otherwise, and
377 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
378 var adjusted_os = if (self.os_tag) |os_tag| os_tag.defaultVersionRange() else builtin.os;
379
380 if (self.os_version_min) |min| switch (min) {
381 .none => {},
382 .semver => |semver| switch (self.getOsTag()) {
383 .linux => adjusted_os.version_range.linux.range.min = semver,
384 else => adjusted_os.version_range.semver.min = semver,
385 },
386 .windows => |win_ver| adjusted_os.version_range.windows.min = win_ver,
387 };
388
389 if (self.os_version_max) |max| switch (max) {
390 .none => {},
391 .semver => |semver| switch (self.getOsTag()) {
392 .linux => adjusted_os.version_range.linux.range.max = semver,
393 else => adjusted_os.version_range.semver.max = semver,
394 },
395 .windows => |win_ver| adjusted_os.version_range.windows.max = win_ver,
396 };
397
398 if (self.glibc_version) |glibc| {
399 assert(self.isGnuLibC());
400 adjusted_os.version_range.linux.glibc = glibc;
401 }
402
403 return adjusted_os;
404 }
405
406 pub fn getOsTag(self: CrossTarget) Target.Os.Tag {
407 return self.os_tag orelse builtin.os.tag;
408 }
409
410 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
411 pub fn getOsVersionMin(self: CrossTarget) OsVersion {
412 if (self.os_version_min) |version_min| return version_min;
413 var tmp: CrossTarget = undefined;
414 tmp.updateOsVersionRange(self.getOs());
415 return tmp.os_version_min.?;
416 }
417
418 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
419 pub fn getOsVersionMax(self: CrossTarget) OsVersion {
420 if (self.os_version_max) |version_max| return version_max;
421 var tmp: CrossTarget = undefined;
422 tmp.updateOsVersionRange(self.getOs());
423 return tmp.os_version_max.?;
424 }
425
426 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
427 pub fn getAbi(self: CrossTarget) Target.Abi {
428 if (self.abi) |abi| return abi;
429
430 if (self.os_tag == null) {
431 // This works when doing `zig build` because Zig generates a build executable using
432 // native CPU model & features. However this will not be accurate otherwise, and
433 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
434 return builtin.abi;
435 }
436
437 return Target.Abi.default(self.getCpuArch(), self.getOs());
438 }
439
440 pub fn isFreeBSD(self: CrossTarget) bool {
441 return self.getOsTag() == .freebsd;
442 }
443
444 pub fn isDarwin(self: CrossTarget) bool {
445 return self.getOsTag().isDarwin();
446 }
447
448 pub fn isNetBSD(self: CrossTarget) bool {
449 return self.getOsTag() == .netbsd;
450 }
451
452 pub fn isOpenBSD(self: CrossTarget) bool {
453 return self.getOsTag() == .openbsd;
454 }
455
456 pub fn isUefi(self: CrossTarget) bool {
457 return self.getOsTag() == .uefi;
458 }
459
460 pub fn isDragonFlyBSD(self: CrossTarget) bool {
461 return self.getOsTag() == .dragonfly;
462 }
463
464 pub fn isLinux(self: CrossTarget) bool {
465 return self.getOsTag() == .linux;
466 }
467
468 pub fn isWindows(self: CrossTarget) bool {
469 return self.getOsTag() == .windows;
470 }
471
472 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
473 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
474 }
475
476 pub fn staticLibSuffix(self: CrossTarget) [:0]const u8 {
477 return Target.staticLibSuffix_os_abi(self.getOsTag(), self.getAbi());
478 }
479
480 pub fn dynamicLibSuffix(self: CrossTarget) [:0]const u8 {
481 return self.getOsTag().dynamicLibSuffix();
482 }
483
484 pub fn libPrefix(self: CrossTarget) [:0]const u8 {
485 return Target.libPrefix_os_abi(self.getOsTag(), self.getAbi());
486 }
487
488 pub fn isNativeCpu(self: CrossTarget) bool {
489 return self.cpu_arch == null and
490 (self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and
491 self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty();
492 }
493
494 pub fn isNativeOs(self: CrossTarget) bool {
495 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
496 self.dynamic_linker.get() == null and self.glibc_version == null;
497 }
498
499 pub fn isNativeAbi(self: CrossTarget) bool {
500 return self.os_tag == null and self.abi == null;
501 }
502
503 pub fn isNative(self: CrossTarget) bool {
504 return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
505 }
506
507 pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![]u8 {
508 if (self.isNative()) {
509 return allocator.dupe(u8, "native");
510 }
511
512 const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native";
513 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
514
515 var result = std.ArrayList(u8).init(allocator);
516 defer result.deinit();
517
518 try result.writer().print("{s}-{s}", .{ arch_name, os_name });
519
520 // The zig target syntax does not allow specifying a max os version with no min, so
521 // if either are present, we need the min.
522 if (self.os_version_min != null or self.os_version_max != null) {
523 switch (self.getOsVersionMin()) {
524 .none => {},
525 .semver => |v| try result.writer().print(".{}", .{v}),
526 .windows => |v| try result.writer().print("{s}", .{v}),
527 }
528 }
529 if (self.os_version_max) |max| {
530 switch (max) {
531 .none => {},
532 .semver => |v| try result.writer().print("...{}", .{v}),
533 .windows => |v| try result.writer().print("..{s}", .{v}),
534 }
535 }
536
537 if (self.glibc_version) |v| {
538 try result.writer().print("-{s}.{}", .{ @tagName(self.getAbi()), v });
539 } else if (self.abi) |abi| {
540 try result.writer().print("-{s}", .{@tagName(abi)});
541 }
542
543 return result.toOwnedSlice();
544 }
545
546 pub fn allocDescription(self: CrossTarget, allocator: *mem.Allocator) ![]u8 {
547 // TODO is there anything else worthy of the description that is not
548 // already captured in the triple?
549 return self.zigTriple(allocator);
550 }
551
552 pub fn linuxTriple(self: CrossTarget, allocator: *mem.Allocator) ![]u8 {
553 return Target.linuxTripleSimple(allocator, self.getCpuArch(), self.getOsTag(), self.getAbi());
554 }
555
556 pub fn wantSharedLibSymLinks(self: CrossTarget) bool {
557 return self.getOsTag() != .windows;
558 }
559
560 pub const VcpkgLinkage = std.builtin.LinkMode;
561
562 /// Returned slice must be freed by the caller.
563 pub fn vcpkgTriplet(self: CrossTarget, allocator: *mem.Allocator, linkage: VcpkgLinkage) ![]u8 {
564 const arch = switch (self.getCpuArch()) {
565 .i386 => "x86",
566 .x86_64 => "x64",
567
568 .arm,
569 .armeb,
570 .thumb,
571 .thumbeb,
572 .aarch64_32,
573 => "arm",
574
575 .aarch64,
576 .aarch64_be,
577 => "arm64",
578
579 else => return error.UnsupportedVcpkgArchitecture,
580 };
581
582 const os = switch (self.getOsTag()) {
583 .windows => "windows",
584 .linux => "linux",
585 .macos => "macos",
586 else => return error.UnsupportedVcpkgOperatingSystem,
587 };
588
589 const static_suffix = switch (linkage) {
590 .Static => "-static",
591 .Dynamic => "",
592 };
593
594 return std.fmt.allocPrint(allocator, "{s}-{s}{s}", .{ arch, os, static_suffix });
595 }
596
597 pub const Executor = union(enum) {
598 native,
599 rosetta,
600 qemu: []const u8,
601 wine: []const u8,
602 wasmtime: []const u8,
603 darling: []const u8,
604 unavailable,
605 };
606
607 /// Note that even a `CrossTarget` which returns `false` for `isNative` could still be natively executed.
608 /// For example `-target arm-native` running on an aarch64 host.
609 pub fn getExternalExecutor(self: CrossTarget) Executor {
610 const cpu_arch = self.getCpuArch();
611 const os_tag = self.getOsTag();
612 const os_match = os_tag == builtin.os.tag;
613
614 // If the OS and CPU arch match, the binary can be considered native.
615 // TODO additionally match the CPU features. This `getExternalExecutor` function should
616 // be moved to std.Target and match any chosen target against the native target.
617 if (os_match and cpu_arch == builtin.cpu.arch) {
618 // However, we also need to verify that the dynamic linker path is valid.
619 if (self.os_tag == null) {
620 return .native;
621 }
622 // TODO here we call toTarget, a deprecated function, because of the above TODO about moving
623 // this code to std.Target.
624 const opt_dl = self.dynamic_linker.get() orelse self.toTarget().standardDynamicLinkerPath().get();
625 if (opt_dl) |dl| blk: {
626 std.fs.cwd().access(dl, .{}) catch break :blk;
627 return .native;
628 }
629 }
630 // If the OS match and OS is macOS and CPU is arm64, we can use Rosetta 2
631 // to emulate the foreign architecture.
632 if (os_match and os_tag == .macos and builtin.cpu.arch == .aarch64) {
633 return switch (cpu_arch) {
634 .x86_64 => .rosetta,
635 else => .unavailable,
636 };
637 }
638
639 // If the OS matches, we can use QEMU to emulate a foreign architecture.
640 if (os_match) {
641 return switch (cpu_arch) {
642 .aarch64 => Executor{ .qemu = "qemu-aarch64" },
643 .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
644 .arm => Executor{ .qemu = "qemu-arm" },
645 .armeb => Executor{ .qemu = "qemu-armeb" },
646 .i386 => Executor{ .qemu = "qemu-i386" },
647 .mips => Executor{ .qemu = "qemu-mips" },
648 .mipsel => Executor{ .qemu = "qemu-mipsel" },
649 .mips64 => Executor{ .qemu = "qemu-mips64" },
650 .mips64el => Executor{ .qemu = "qemu-mips64el" },
651 .powerpc => Executor{ .qemu = "qemu-ppc" },
652 .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
653 .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
654 .riscv32 => Executor{ .qemu = "qemu-riscv32" },
655 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
656 .s390x => Executor{ .qemu = "qemu-s390x" },
657 .sparc => Executor{ .qemu = "qemu-sparc" },
658 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
659 else => return .unavailable,
660 };
661 }
662
663 switch (os_tag) {
664 .windows => switch (cpu_arch.ptrBitWidth()) {
665 32 => return Executor{ .wine = "wine" },
666 64 => return Executor{ .wine = "wine64" },
667 else => return .unavailable,
668 },
669 .wasi => switch (cpu_arch.ptrBitWidth()) {
670 32 => return Executor{ .wasmtime = "wasmtime" },
671 else => return .unavailable,
672 },
673 .macos => {
674 // TODO loosen this check once upstream adds QEMU-based emulation
675 // layer for non-host architectures:
676 // https://github.com/darlinghq/darling/issues/863
677 if (cpu_arch != builtin.cpu.arch) {
678 return .unavailable;
679 }
680 return Executor{ .darling = "darling" };
681 },
682 else => return .unavailable,
683 }
684 }
685
686 pub fn isGnuLibC(self: CrossTarget) bool {
687 return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi());
688 }
689
690 pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) void {
691 assert(self.isGnuLibC());
692 self.glibc_version = SemVer{ .major = major, .minor = minor, .patch = patch };
693 }
694
695 pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat {
696 return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());
697 }
698
699 pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
700 set.removeFeatureSet(self.cpu_features_sub);
701 set.addFeatureSet(self.cpu_features_add);
702 set.populateDependencies(self.getCpuArch().allFeaturesList());
703 set.removeFeatureSet(self.cpu_features_sub);
704 }
705
706 fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
707 var it = mem.split(u8, text, ".");
708 const os_name = it.next().?;
709 diags.os_name = os_name;
710 const os_is_native = mem.eql(u8, os_name, "native");
711 if (!os_is_native) {
712 result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse
713 return error.UnknownOperatingSystem;
714 }
715 const tag = result.getOsTag();
716 diags.os_tag = tag;
717
718 const version_text = it.rest();
719 if (it.next() == null) return;
720
721 switch (tag) {
722 .freestanding,
723 .ananas,
724 .cloudabi,
725 .fuchsia,
726 .kfreebsd,
727 .lv2,
728 .solaris,
729 .zos,
730 .haiku,
731 .minix,
732 .rtems,
733 .nacl,
734 .aix,
735 .cuda,
736 .nvcl,
737 .amdhsa,
738 .ps4,
739 .elfiamcu,
740 .mesa3d,
741 .contiki,
742 .amdpal,
743 .hermit,
744 .hurd,
745 .wasi,
746 .emscripten,
747 .uefi,
748 .opencl,
749 .glsl450,
750 .vulkan,
751 .plan9,
752 .other,
753 => return error.InvalidOperatingSystemVersion,
754
755 .freebsd,
756 .macos,
757 .ios,
758 .tvos,
759 .watchos,
760 .netbsd,
761 .openbsd,
762 .linux,
763 .dragonfly,
764 => {
765 var range_it = mem.split(u8, version_text, "...");
766
767 const min_text = range_it.next().?;
768 const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
769 error.Overflow => return error.InvalidOperatingSystemVersion,
770 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
771 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
772 };
773 result.os_version_min = .{ .semver = min_ver };
774
775 const max_text = range_it.next() orelse return;
776 const max_ver = SemVer.parse(max_text) catch |err| switch (err) {
777 error.Overflow => return error.InvalidOperatingSystemVersion,
778 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
779 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
780 };
781 result.os_version_max = .{ .semver = max_ver };
782 },
783
784 .windows => {
785 var range_it = mem.split(u8, version_text, "...");
786
787 const min_text = range_it.next().?;
788 const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
789 return error.InvalidOperatingSystemVersion;
790 result.os_version_min = .{ .windows = min_ver };
791
792 const max_text = range_it.next() orelse return;
793 const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
794 return error.InvalidOperatingSystemVersion;
795 result.os_version_max = .{ .windows = max_ver };
796 },
797 }
798 }
799};
800
801test "CrossTarget.parse" {
802 if (builtin.target.isGnuLibC()) {
803 var cross_target = try CrossTarget.parse(.{});
804 cross_target.setGnuLibCVersion(2, 1, 1);
805
806 const text = try cross_target.zigTriple(std.testing.allocator);
807 defer std.testing.allocator.free(text);
808
809 var buf: [256]u8 = undefined;
810 const triple = std.fmt.bufPrint(
811 buf[0..],
812 "native-native-{s}.2.1.1",
813 .{@tagName(builtin.abi)},
814 ) catch unreachable;
815
816 try std.testing.expectEqualSlices(u8, triple, text);
817 }
818 {
819 const cross_target = try CrossTarget.parse(.{
820 .arch_os_abi = "aarch64-linux",
821 .cpu_features = "native",
822 });
823
824 try std.testing.expect(cross_target.cpu_arch.? == .aarch64);
825 try std.testing.expect(cross_target.cpu_model == .native);
826 }
827 {
828 const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
829
830 try std.testing.expect(cross_target.cpu_arch == null);
831 try std.testing.expect(cross_target.isNative());
832
833 const text = try cross_target.zigTriple(std.testing.allocator);
834 defer std.testing.allocator.free(text);
835 try std.testing.expectEqualSlices(u8, "native", text);
836 }
837 {
838 const cross_target = try CrossTarget.parse(.{
839 .arch_os_abi = "x86_64-linux-gnu",
840 .cpu_features = "x86_64-sse-sse2-avx-cx8",
841 });
842 const target = cross_target.toTarget();
843
844 try std.testing.expect(target.os.tag == .linux);
845 try std.testing.expect(target.abi == .gnu);
846 try std.testing.expect(target.cpu.arch == .x86_64);
847 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
848 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
849 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
850 try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
851 try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
852
853 try std.testing.expect(Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx, .cmov }));
854 try std.testing.expect(!Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx }));
855 try std.testing.expect(Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87 }));
856 try std.testing.expect(!Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87, .sse }));
857
858 const text = try cross_target.zigTriple(std.testing.allocator);
859 defer std.testing.allocator.free(text);
860 try std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text);
861 }
862 {
863 const cross_target = try CrossTarget.parse(.{
864 .arch_os_abi = "arm-linux-musleabihf",
865 .cpu_features = "generic+v8a",
866 });
867 const target = cross_target.toTarget();
868
869 try std.testing.expect(target.os.tag == .linux);
870 try std.testing.expect(target.abi == .musleabihf);
871 try std.testing.expect(target.cpu.arch == .arm);
872 try std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
873 try std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
874
875 const text = try cross_target.zigTriple(std.testing.allocator);
876 defer std.testing.allocator.free(text);
877 try std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text);
878 }
879 {
880 const cross_target = try CrossTarget.parse(.{
881 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
882 .cpu_features = "generic+v8a",
883 });
884 const target = cross_target.toTarget();
885
886 try std.testing.expect(target.cpu.arch == .aarch64);
887 try std.testing.expect(target.os.tag == .linux);
888 try std.testing.expect(target.os.version_range.linux.range.min.major == 3);
889 try std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
890 try std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
891 try std.testing.expect(target.os.version_range.linux.range.max.major == 4);
892 try std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
893 try std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
894 try std.testing.expect(target.os.version_range.linux.glibc.major == 2);
895 try std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
896 try std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
897 try std.testing.expect(target.abi == .gnu);
898
899 const text = try cross_target.zigTriple(std.testing.allocator);
900 defer std.testing.allocator.free(text);
901 try std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text);
902 }
903}
test/tests.zig+8-2
......@@ -270,8 +270,14 @@ const test_targets = blk: {
270270 .os_tag = .macos,
271271 .abi = .gnu,
272272 },
273 // https://github.com/ziglang/zig/issues/3295
274 .disable_native = true,
273 },
274
275 TestTarget{
276 .target = .{
277 .cpu_arch = .aarch64,
278 .os_tag = .macos,
279 .abi = .gnu,
280 },
275281 },
276282
277283 TestTarget{