master
1//! All the details about the machine that will be executing code.
2//! Unlike `Query` which might leave some things as "default" or "host", this
3//! data is fully resolved into a concrete set of OS versions, CPU features,
4//! etc.
5
6cpu: Cpu,
7os: Os,
8abi: Abi,
9ofmt: ObjectFormat,
10dynamic_linker: DynamicLinker = DynamicLinker.none,
11
12pub const Query = @import("Target/Query.zig");
13
14pub const Os = struct {
15 tag: Tag,
16 version_range: VersionRange,
17
18 pub const Tag = enum {
19 freestanding,
20 other,
21
22 contiki,
23 fuchsia,
24 hermit,
25 managarm,
26
27 haiku,
28 hurd,
29 illumos,
30 linux,
31 plan9,
32 rtems,
33 serenity,
34
35 dragonfly,
36 freebsd,
37 netbsd,
38 openbsd,
39
40 driverkit,
41 ios,
42 maccatalyst,
43 macos,
44 tvos,
45 visionos,
46 watchos,
47
48 windows,
49 uefi,
50
51 @"3ds",
52
53 ps3,
54 ps4,
55 ps5,
56 vita,
57
58 emscripten,
59 wasi,
60
61 amdhsa,
62 amdpal,
63 cuda,
64 mesa3d,
65 nvcl,
66 opencl,
67 opengl,
68 vulkan,
69
70 // LLVM tags deliberately omitted:
71 // - bridgeos
72 // - cheriotrtos
73 // - darwin
74 // - kfreebsd
75 // - nacl
76 // - shadermodel
77
78 pub inline fn isDarwin(tag: Tag) bool {
79 return switch (tag) {
80 .driverkit,
81 .ios,
82 .maccatalyst,
83 .macos,
84 .tvos,
85 .visionos,
86 .watchos,
87 => true,
88 else => false,
89 };
90 }
91
92 pub inline fn isBSD(tag: Tag) bool {
93 return tag.isDarwin() or switch (tag) {
94 .freebsd, .openbsd, .netbsd, .dragonfly => true,
95 else => false,
96 };
97 }
98
99 pub fn exeFileExt(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
100 return switch (tag) {
101 .windows => ".exe",
102 .uefi => ".efi",
103 .plan9 => arch.plan9Ext(),
104 else => switch (arch) {
105 .wasm32, .wasm64 => ".wasm",
106 else => "",
107 },
108 };
109 }
110
111 pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
112 return switch (abi) {
113 .msvc, .itanium => ".lib",
114 else => switch (tag) {
115 .windows, .uefi => ".lib",
116 else => ".a",
117 },
118 };
119 }
120
121 pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
122 return switch (tag) {
123 .windows, .uefi => ".dll",
124 .driverkit,
125 .ios,
126 .maccatalyst,
127 .macos,
128 .tvos,
129 .visionos,
130 .watchos,
131 => ".dylib",
132 else => ".so",
133 };
134 }
135
136 pub fn libPrefix(tag: Os.Tag, abi: Abi) [:0]const u8 {
137 return switch (abi) {
138 .msvc, .itanium => "",
139 else => switch (tag) {
140 .windows, .uefi => "",
141 else => "lib",
142 },
143 };
144 }
145
146 pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch, abi: Abi) Os {
147 return .{
148 .tag = tag,
149 .version_range = .default(arch, tag, abi),
150 };
151 }
152
153 pub inline fn versionRangeTag(tag: Tag) @typeInfo(TaggedVersionRange).@"union".tag_type.? {
154 return switch (tag) {
155 .freestanding,
156 .other,
157
158 .managarm,
159
160 .haiku,
161 .illumos,
162 .plan9,
163 .serenity,
164
165 .ps3,
166 .ps4,
167 .ps5,
168
169 .emscripten,
170
171 .mesa3d,
172 => .none,
173
174 .contiki,
175 .fuchsia,
176 .hermit,
177
178 .rtems,
179
180 .dragonfly,
181 .freebsd,
182 .netbsd,
183 .openbsd,
184
185 .driverkit,
186 .ios,
187 .maccatalyst,
188 .macos,
189 .tvos,
190 .visionos,
191 .watchos,
192
193 .uefi,
194
195 .@"3ds",
196
197 .vita,
198
199 .wasi,
200
201 .amdhsa,
202 .amdpal,
203 .cuda,
204 .nvcl,
205 .opencl,
206 .opengl,
207 .vulkan,
208 => .semver,
209
210 .hurd => .hurd,
211 .linux => .linux,
212
213 .windows => .windows,
214 };
215 }
216 };
217
218 /// Based on NTDDI version constants from
219 /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
220 pub const WindowsVersion = enum(u32) {
221 nt4 = 0x04000000,
222 win2k = 0x05000000,
223 xp = 0x05010000,
224 ws2003 = 0x05020000,
225 vista = 0x06000000,
226 win7 = 0x06010000,
227 win8 = 0x06020000,
228 win8_1 = 0x06030000,
229 win10 = 0x0A000000, //aka win10_th1
230 win10_th2 = 0x0A000001,
231 win10_rs1 = 0x0A000002,
232 win10_rs2 = 0x0A000003,
233 win10_rs3 = 0x0A000004,
234 win10_rs4 = 0x0A000005,
235 win10_rs5 = 0x0A000006,
236 win10_19h1 = 0x0A000007,
237 win10_vb = 0x0A000008, //aka win10_19h2
238 win10_mn = 0x0A000009, //aka win10_20h1
239 win10_fe = 0x0A00000A, //aka win10_20h2
240 win10_co = 0x0A00000B, //aka win10_21h1
241 win10_ni = 0x0A00000C, //aka win10_21h2
242 win10_cu = 0x0A00000D, //aka win10_22h2
243 win11_zn = 0x0A00000E, //aka win11_21h2
244 win11_ga = 0x0A00000F, //aka win11_22h2
245 win11_ge = 0x0A000010, //aka win11_23h2
246 win11_dt = 0x0A000011, //aka win11_24h2
247 _,
248
249 /// Latest Windows version that the Zig Standard Library is aware of
250 pub const latest = WindowsVersion.win11_dt;
251
252 /// Compared against build numbers reported by the runtime to distinguish win10 versions,
253 /// where 0x0A000000 + index corresponds to the WindowsVersion u32 value.
254 pub const known_win10_build_numbers = [_]u32{
255 10240, //win10 aka win10_th1
256 10586, //win10_th2
257 14393, //win10_rs1
258 15063, //win10_rs2
259 16299, //win10_rs3
260 17134, //win10_rs4
261 17763, //win10_rs5
262 18362, //win10_19h1
263 18363, //win10_vb aka win10_19h2
264 19041, //win10_mn aka win10_20h1
265 19042, //win10_fe aka win10_20h2
266 19043, //win10_co aka win10_21h1
267 19044, //win10_ni aka win10_21h2
268 19045, //win10_cu aka win10_22h2
269 22000, //win11_zn aka win11_21h2
270 22621, //win11_ga aka win11_22h2
271 22631, //win11_ge aka win11_23h2
272 26100, //win11_dt aka win11_24h2
273 };
274
275 /// Returns whether the first version `ver` is newer (greater) than or equal to the second version `ver`.
276 pub inline fn isAtLeast(ver: WindowsVersion, min_ver: WindowsVersion) bool {
277 return @intFromEnum(ver) >= @intFromEnum(min_ver);
278 }
279
280 pub const Range = struct {
281 min: WindowsVersion,
282 max: WindowsVersion,
283
284 pub inline fn includesVersion(range: Range, ver: WindowsVersion) bool {
285 return @intFromEnum(ver) >= @intFromEnum(range.min) and
286 @intFromEnum(ver) <= @intFromEnum(range.max);
287 }
288
289 /// Checks if system is guaranteed to be at least `version` or older than `version`.
290 /// Returns `null` if a runtime check is required.
291 pub inline fn isAtLeast(range: Range, min_ver: WindowsVersion) ?bool {
292 if (@intFromEnum(range.min) >= @intFromEnum(min_ver)) return true;
293 if (@intFromEnum(range.max) < @intFromEnum(min_ver)) return false;
294 return null;
295 }
296 };
297
298 pub fn parse(str: []const u8) !WindowsVersion {
299 return std.meta.stringToEnum(WindowsVersion, str) orelse
300 @enumFromInt(std.fmt.parseInt(u32, str, 0) catch
301 return error.InvalidOperatingSystemVersion);
302 }
303
304 /// This function is defined to serialize a Zig source code representation of this
305 /// type, that, when parsed, will deserialize into the same data.
306 pub fn format(wv: WindowsVersion, w: *std.Io.Writer) std.Io.Writer.Error!void {
307 if (std.enums.tagName(WindowsVersion, wv)) |name| {
308 var vecs: [2][]const u8 = .{ ".", name };
309 return w.writeVecAll(&vecs);
310 } else {
311 return w.print("@enumFromInt(0x{X:0>8})", .{wv});
312 }
313 }
314 };
315
316 pub const HurdVersionRange = struct {
317 range: std.SemanticVersion.Range,
318 glibc: std.SemanticVersion,
319
320 pub inline fn includesVersion(range: HurdVersionRange, ver: std.SemanticVersion) bool {
321 return range.range.includesVersion(ver);
322 }
323
324 /// Checks if system is guaranteed to be at least `version` or older than `version`.
325 /// Returns `null` if a runtime check is required.
326 pub inline fn isAtLeast(range: HurdVersionRange, ver: std.SemanticVersion) ?bool {
327 return range.range.isAtLeast(ver);
328 }
329 };
330
331 pub const LinuxVersionRange = struct {
332 range: std.SemanticVersion.Range,
333 glibc: std.SemanticVersion,
334 /// Android API level.
335 android: u32,
336
337 pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
338 return range.range.includesVersion(ver);
339 }
340
341 /// Checks if system is guaranteed to be at least `version` or older than `version`.
342 /// Returns `null` if a runtime check is required.
343 pub inline fn isAtLeast(range: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
344 return range.range.isAtLeast(ver);
345 }
346 };
347
348 /// The version ranges here represent the minimum OS version to be supported
349 /// and the maximum OS version to be supported. The default values represent
350 /// the range that the Zig Standard Library bases its abstractions on.
351 ///
352 /// The minimum version of the range is the main setting to tweak for a target.
353 /// Usually, the maximum target OS version will remain the default, which is
354 /// the latest released version of the OS.
355 ///
356 /// To test at compile time if the target is guaranteed to support a given OS feature,
357 /// one should check that the minimum version of the range is greater than or equal to
358 /// the version the feature was introduced in.
359 ///
360 /// To test at compile time if the target certainly will not support a given OS feature,
361 /// one should check that the maximum version of the range is less than the version the
362 /// feature was introduced in.
363 ///
364 /// If neither of these cases apply, a runtime check should be used to determine if the
365 /// target supports a given OS feature.
366 ///
367 /// Binaries built with a given maximum version will continue to function on newer
368 /// operating system versions. However, such a binary may not take full advantage of the
369 /// newer operating system APIs.
370 ///
371 /// See `Os.isAtLeast`.
372 pub const VersionRange = union {
373 none: void,
374 semver: std.SemanticVersion.Range,
375 hurd: HurdVersionRange,
376 linux: LinuxVersionRange,
377 windows: WindowsVersion.Range,
378
379 /// The default `VersionRange` represents the range that the Zig Standard Library
380 /// bases its abstractions on.
381 pub fn default(arch: Cpu.Arch, tag: Tag, abi: Abi) VersionRange {
382 return switch (tag) {
383 .freestanding,
384 .other,
385
386 .managarm,
387
388 .haiku,
389 .illumos,
390 .plan9,
391 .serenity,
392
393 .ps3,
394 .ps4,
395 .ps5,
396
397 .emscripten,
398
399 .mesa3d,
400 => .{ .none = {} },
401
402 .contiki => .{
403 .semver = .{
404 .min = .{ .major = 4, .minor = 0, .patch = 0 },
405 .max = .{ .major = 5, .minor = 1, .patch = 0 },
406 },
407 },
408 .fuchsia => .{
409 .semver = .{
410 .min = .{ .major = 1, .minor = 0, .patch = 0 },
411 .max = .{ .major = 28, .minor = 0, .patch = 0 },
412 },
413 },
414 .hermit => .{
415 .semver = .{
416 .min = .{ .major = 0, .minor = 5, .patch = 0 },
417 .max = .{ .major = 0, .minor = 11, .patch = 0 },
418 },
419 },
420
421 .hurd => .{
422 .hurd = .{
423 .range = .{
424 .min = .{ .major = 0, .minor = 9, .patch = 0 },
425 .max = .{ .major = 0, .minor = 9, .patch = 0 },
426 },
427 .glibc = .{ .major = 2, .minor = 28, .patch = 0 },
428 },
429 },
430 .linux => .{
431 .linux = .{
432 .range = .{
433 .min = blk: {
434 const default_min: std.SemanticVersion = .{ .major = 5, .minor = 10, .patch = 0 };
435
436 for (std.zig.target.available_libcs) |libc| {
437 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
438
439 if (libc.os_ver) |min| {
440 if (min.order(default_min) == .gt) break :blk min;
441 }
442 }
443
444 break :blk default_min;
445 },
446 .max = .{ .major = 6, .minor = 17, .patch = 0 },
447 },
448 .glibc = blk: {
449 // For 32-bit targets that traditionally used 32-bit time, we require
450 // glibc 2.34 for full 64-bit time support. For everything else, we only
451 // require glibc 2.31.
452 const default_min: std.SemanticVersion = switch (arch) {
453 .arm,
454 .armeb,
455 .csky,
456 .m68k,
457 .mips,
458 .mipsel,
459 .powerpc,
460 .sparc,
461 .x86,
462 => .{ .major = 2, .minor = 34, .patch = 0 },
463 .mips64,
464 .mips64el,
465 => if (abi == .gnuabin32)
466 .{ .major = 2, .minor = 34, .patch = 0 }
467 else
468 .{ .major = 2, .minor = 31, .patch = 0 },
469 else => .{ .major = 2, .minor = 31, .patch = 0 },
470 };
471
472 for (std.zig.target.available_libcs) |libc| {
473 if (libc.os != tag or libc.arch != arch or libc.abi != abi) continue;
474
475 if (libc.glibc_min) |min| {
476 if (min.order(default_min) == .gt) break :blk min;
477 }
478 }
479
480 break :blk default_min;
481 },
482 .android = 29,
483 },
484 },
485 .rtems => .{
486 .semver = .{
487 .min = .{ .major = 5, .minor = 1, .patch = 0 },
488 .max = .{ .major = 6, .minor = 1, .patch = 0 },
489 },
490 },
491
492 .dragonfly => .{
493 .semver = .{
494 .min = .{ .major = 6, .minor = 0, .patch = 0 },
495 .max = .{ .major = 6, .minor = 4, .patch = 2 },
496 },
497 },
498 .freebsd => .{
499 .semver = .{
500 .min = blk: {
501 const default_min: std.SemanticVersion = .{ .major = 14, .minor = 0, .patch = 0 };
502
503 for (std.zig.target.available_libcs) |libc| {
504 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
505
506 if (libc.os_ver) |min| {
507 if (min.order(default_min) == .gt) break :blk min;
508 }
509 }
510
511 break :blk default_min;
512 },
513 .max = .{ .major = 14, .minor = 3, .patch = 0 },
514 },
515 },
516 .netbsd => .{
517 .semver = .{
518 .min = blk: {
519 const default_min: std.SemanticVersion = .{ .major = 10, .minor = 1, .patch = 0 };
520
521 for (std.zig.target.available_libcs) |libc| {
522 if (libc.arch != arch or libc.os != tag or libc.abi != abi) continue;
523
524 if (libc.os_ver) |min| {
525 if (min.order(default_min) == .gt) break :blk min;
526 }
527 }
528
529 break :blk default_min;
530 },
531 .max = .{ .major = 10, .minor = 1, .patch = 0 },
532 },
533 },
534 .openbsd => .{
535 .semver = .{
536 .min = .{ .major = 7, .minor = 7, .patch = 0 },
537 .max = .{ .major = 7, .minor = 8, .patch = 0 },
538 },
539 },
540
541 .driverkit => .{
542 .semver = .{
543 .min = .{ .major = 20, .minor = 0, .patch = 0 },
544 .max = .{ .major = 25, .minor = 0, .patch = 0 },
545 },
546 },
547 .macos => .{
548 .semver = .{
549 .min = .{ .major = 13, .minor = 0, .patch = 0 },
550 .max = .{ .major = 15, .minor = 6, .patch = 0 },
551 },
552 },
553 .ios, .maccatalyst => .{
554 .semver = .{
555 .min = .{ .major = 15, .minor = 0, .patch = 0 },
556 .max = .{ .major = 18, .minor = 6, .patch = 0 },
557 },
558 },
559 .tvos => .{
560 .semver = .{
561 .min = .{ .major = 15, .minor = 0, .patch = 0 },
562 .max = .{ .major = 18, .minor = 5, .patch = 0 },
563 },
564 },
565 .visionos => .{
566 .semver = .{
567 .min = .{ .major = 1, .minor = 0, .patch = 0 },
568 .max = .{ .major = 2, .minor = 5, .patch = 0 },
569 },
570 },
571 .watchos => .{
572 .semver = .{
573 .min = .{ .major = 8, .minor = 0, .patch = 0 },
574 .max = .{ .major = 11, .minor = 6, .patch = 0 },
575 },
576 },
577
578 .windows => .{
579 .windows = .{
580 .min = .win10,
581 .max = WindowsVersion.latest,
582 },
583 },
584 .uefi => .{
585 .semver = .{
586 .min = .{ .major = 2, .minor = 0, .patch = 0 },
587 .max = .{ .major = 2, .minor = 11, .patch = 0 },
588 },
589 },
590
591 .@"3ds" => .{
592 .semver = .{
593 // These signify release versions (https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM11_Kernel_Capabilities)
594 // which are different from user-facing system versions (https://www.3dbrew.org/wiki/Home_Menu#System_Versions_List).
595 //
596 // Multiple system versions could refer to the same release version.
597 // The comment indicates the system version that release version was introduced (for minimum) and the latest (for maximum).
598 .min = .{ .major = 2, .minor = 27, .patch = 0 }, // 1.0.0-0
599 .max = .{ .major = 2, .minor = 58, .patch = 0 }, // 11.17.0-50
600 },
601 },
602
603 .vita => .{
604 .semver = .{
605 // 1.3 is the first public release
606 .min = .{ .major = 1, .minor = 3, .patch = 0 },
607 .max = .{ .major = 3, .minor = 60, .patch = 0 },
608 },
609 },
610
611 .wasi => .{
612 .semver = .{
613 .min = .{ .major = 0, .minor = 1, .patch = 0 },
614 .max = .{ .major = 0, .minor = 3, .patch = 0 },
615 },
616 },
617
618 .amdhsa => .{
619 .semver = .{
620 .min = .{ .major = 5, .minor = 0, .patch = 0 },
621 .max = .{ .major = 7, .minor = 1, .patch = 0 },
622 },
623 },
624 .amdpal => .{
625 .semver = .{
626 .min = .{ .major = 1, .minor = 1, .patch = 0 },
627 .max = .{ .major = 3, .minor = 5, .patch = 0 },
628 },
629 },
630 .cuda => .{
631 .semver = .{
632 .min = .{ .major = 11, .minor = 0, .patch = 1 },
633 .max = .{ .major = 13, .minor = 0, .patch = 2 },
634 },
635 },
636 .nvcl,
637 .opencl,
638 => .{
639 .semver = .{
640 .min = .{ .major = 2, .minor = 2, .patch = 0 },
641 .max = .{ .major = 3, .minor = 0, .patch = 19 },
642 },
643 },
644 .opengl => .{
645 .semver = .{
646 .min = .{ .major = 4, .minor = 5, .patch = 0 },
647 .max = .{ .major = 4, .minor = 6, .patch = 0 },
648 },
649 },
650 .vulkan => .{
651 .semver = .{
652 .min = .{ .major = 1, .minor = 2, .patch = 0 },
653 .max = .{ .major = 1, .minor = 4, .patch = 331 },
654 },
655 },
656 };
657 }
658 };
659
660 pub const TaggedVersionRange = union(enum) {
661 none: void,
662 semver: std.SemanticVersion.Range,
663 hurd: HurdVersionRange,
664 linux: LinuxVersionRange,
665 windows: WindowsVersion.Range,
666
667 pub fn gnuLibCVersion(range: TaggedVersionRange) ?std.SemanticVersion {
668 return switch (range) {
669 .none, .semver, .windows => null,
670 .hurd => |h| h.glibc,
671 .linux => |l| l.glibc,
672 };
673 }
674 };
675
676 /// Provides a tagged union. `Target` does not store the tag because it is
677 /// redundant with the OS tag; this function abstracts that part away.
678 pub inline fn versionRange(os: Os) TaggedVersionRange {
679 return switch (os.tag.versionRangeTag()) {
680 .none => .{ .none = {} },
681 .semver => .{ .semver = os.version_range.semver },
682 .hurd => .{ .hurd = os.version_range.hurd },
683 .linux => .{ .linux = os.version_range.linux },
684 .windows => .{ .windows = os.version_range.windows },
685 };
686 }
687
688 /// Checks if system is guaranteed to be at least `version` or older than `version`.
689 /// Returns `null` if a runtime check is required.
690 pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.versionRangeTag()) {
691 .none => void,
692 .semver, .hurd, .linux => std.SemanticVersion,
693 .windows => WindowsVersion,
694 }) ?bool {
695 return if (os.tag != tag) false else switch (tag.versionRangeTag()) {
696 .none => true,
697 inline .semver,
698 .hurd,
699 .linux,
700 .windows,
701 => |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
702 };
703 }
704};
705
706pub const aarch64 = @import("Target/aarch64.zig");
707pub const alpha = @import("Target/alpha.zig");
708pub const amdgcn = @import("Target/amdgcn.zig");
709pub const arc = @import("Target/arc.zig");
710pub const arm = @import("Target/arm.zig");
711pub const avr = @import("Target/avr.zig");
712pub const bpf = @import("Target/bpf.zig");
713pub const csky = @import("Target/csky.zig");
714pub const hexagon = @import("Target/hexagon.zig");
715pub const hppa = @import("Target/hppa.zig");
716pub const kalimba = @import("Target/generic.zig");
717pub const kvx = @import("Target/kvx.zig");
718pub const lanai = @import("Target/lanai.zig");
719pub const loongarch = @import("Target/loongarch.zig");
720pub const m68k = @import("Target/m68k.zig");
721pub const microblaze = @import("Target/generic.zig");
722pub const mips = @import("Target/mips.zig");
723pub const msp430 = @import("Target/msp430.zig");
724pub const nvptx = @import("Target/nvptx.zig");
725pub const or1k = @import("Target/generic.zig");
726pub const powerpc = @import("Target/powerpc.zig");
727pub const propeller = @import("Target/propeller.zig");
728pub const riscv = @import("Target/riscv.zig");
729pub const s390x = @import("Target/s390x.zig");
730pub const sh = @import("Target/generic.zig");
731pub const sparc = @import("Target/sparc.zig");
732pub const spirv = @import("Target/spirv.zig");
733pub const ve = @import("Target/ve.zig");
734pub const wasm = @import("Target/wasm.zig");
735pub const x86 = @import("Target/x86.zig");
736pub const xcore = @import("Target/xcore.zig");
737pub const xtensa = @import("Target/xtensa.zig");
738
739pub const Abi = enum {
740 none,
741 gnu,
742 gnuabin32,
743 gnuabi64,
744 gnueabi,
745 gnueabihf,
746 gnuf32,
747 gnusf,
748 gnux32,
749 eabi,
750 eabihf,
751 ilp32,
752 android,
753 androideabi,
754 musl,
755 muslabin32,
756 muslabi64,
757 musleabi,
758 musleabihf,
759 muslf32,
760 muslsf,
761 muslx32,
762 msvc,
763 itanium,
764 simulator,
765 ohos,
766 ohoseabi,
767
768 // LLVM tags deliberately omitted:
769 // - amplification
770 // - anyhit
771 // - callable
772 // - closesthit
773 // - compute
774 // - coreclr
775 // - domain
776 // - geometry
777 // - gnueabit64
778 // - gnueabihft64
779 // - gnuf64
780 // - gnut64
781 // - hull
782 // - intersection
783 // - library
784 // - llvm
785 // - mesh
786 // - miss
787 // - mlibc
788 // - mtia
789 // - pauthtest
790 // - pixel
791 // - raygeneration
792 // - rootsignature
793 // - vertex
794
795 pub fn default(arch: Cpu.Arch, os_tag: Os.Tag) Abi {
796 return switch (os_tag) {
797 .freestanding, .other => switch (arch) {
798 // Soft float is usually a sane default for freestanding.
799 .arm,
800 .armeb,
801 .csky,
802 .hppa,
803 .mips,
804 .mipsel,
805 .powerpc,
806 .powerpcle,
807 .sh,
808 .sheb,
809 .thumb,
810 .thumbeb,
811 => .eabi,
812 else => .none,
813 },
814 .haiku => switch (arch) {
815 .arm,
816 .powerpc,
817 => .eabihf,
818 else => .none,
819 },
820 .hurd => .gnu,
821 .linux => switch (arch) {
822 .arm,
823 .armeb,
824 .powerpc,
825 .powerpcle,
826 .thumb,
827 .thumbeb,
828 => .musleabihf,
829 .mips,
830 .mipsel,
831 => .musleabi,
832 .mips64,
833 .mips64el,
834 => .muslabi64,
835
836 // No musl support.
837 .arc,
838 .arceb,
839 => .gnu,
840 .csky,
841 => .gnueabi,
842 .hppa,
843 .sh,
844 .sheb,
845 => .gnueabihf,
846
847 // No glibc or musl support.
848 .xtensa,
849 .xtensaeb,
850 => .none,
851
852 else => .musl,
853 },
854 .rtems => switch (arch) {
855 .arm,
856 .armeb,
857 .thumb,
858 .thumbeb,
859 .mips,
860 .mipsel,
861 => .eabi,
862 .powerpc,
863 => .eabihf,
864 else => .none,
865 },
866 .freebsd => switch (arch) {
867 .arm,
868 .powerpc,
869 => .eabihf,
870 else => .none,
871 },
872 .netbsd => switch (arch) {
873 .arm,
874 .armeb,
875 .powerpc,
876 => .eabihf,
877 // Soft float tends to be more common for MIPS.
878 .mips,
879 .mipsel,
880 => .eabi,
881 else => .none,
882 },
883 .openbsd => switch (arch) {
884 .arm,
885 => .eabi,
886 .powerpc,
887 => .eabihf,
888 else => .none,
889 },
890 .windows => .gnu,
891 .uefi => .msvc,
892 .@"3ds" => .eabihf,
893 .vita => .eabihf,
894 .wasi, .emscripten => .musl,
895
896 .contiki,
897 .fuchsia,
898 .hermit,
899 .illumos,
900 .managarm,
901 .plan9,
902 .serenity,
903 .dragonfly,
904 .driverkit,
905 .ios,
906 .maccatalyst,
907 .macos,
908 .tvos,
909 .visionos,
910 .watchos,
911 .ps3,
912 .ps4,
913 .ps5,
914 .amdhsa,
915 .amdpal,
916 .cuda,
917 .mesa3d,
918 .nvcl,
919 .opencl,
920 .opengl,
921 .vulkan,
922 => .none,
923 };
924 }
925
926 pub inline fn isGnu(abi: Abi) bool {
927 return switch (abi) {
928 .gnu,
929 .gnuabin32,
930 .gnuabi64,
931 .gnueabi,
932 .gnueabihf,
933 .gnuf32,
934 .gnusf,
935 .gnux32,
936 => true,
937 else => false,
938 };
939 }
940
941 pub inline fn isMusl(abi: Abi) bool {
942 return switch (abi) {
943 .musl,
944 .muslabin32,
945 .muslabi64,
946 .musleabi,
947 .musleabihf,
948 .muslf32,
949 .muslsf,
950 .muslx32,
951 => true,
952 else => abi.isOpenHarmony(),
953 };
954 }
955
956 pub inline fn isOpenHarmony(abi: Abi) bool {
957 return switch (abi) {
958 .ohos, .ohoseabi => true,
959 else => false,
960 };
961 }
962
963 pub inline fn isAndroid(abi: Abi) bool {
964 return switch (abi) {
965 .android, .androideabi => true,
966 else => false,
967 };
968 }
969
970 pub const Float = enum {
971 hard,
972 soft,
973 };
974
975 pub inline fn float(abi: Abi) Float {
976 return switch (abi) {
977 .androideabi,
978 .eabi,
979 .gnueabi,
980 .musleabi,
981 .gnusf,
982 .ohoseabi,
983 => .soft,
984 else => .hard,
985 };
986 }
987};
988
989pub const ObjectFormat = enum {
990 /// C source code.
991 c,
992 /// The Common Object File Format used by Windows and UEFI.
993 coff,
994 /// The Executable and Linkable Format used by many Unixes.
995 elf,
996 /// The Intel HEX format for storing binary code in ASCII text.
997 hex,
998 /// The Mach object format used by macOS and other Apple platforms.
999 macho,
1000 /// The a.out format used by Plan 9 from Bell Labs.
1001 plan9,
1002 /// Machine code with no metadata.
1003 raw,
1004 /// The Khronos Group's Standard Portable Intermediate Representation V.
1005 spirv,
1006 /// The WebAssembly binary format.
1007 wasm,
1008
1009 // LLVM tags deliberately omitted:
1010 // - dxcontainer
1011
1012 pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 {
1013 return switch (of) {
1014 .c => ".c",
1015 .coff => ".obj",
1016 .elf, .macho, .wasm => ".o",
1017 .hex => ".ihex",
1018 .plan9 => arch.plan9Ext(),
1019 .raw => ".bin",
1020 .spirv => ".spv",
1021 };
1022 }
1023
1024 pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
1025 return switch (os_tag) {
1026 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => .macho,
1027 .plan9 => .plan9,
1028 .uefi, .windows => .coff,
1029 else => switch (arch) {
1030 .spirv32, .spirv64 => .spirv,
1031 .wasm32, .wasm64 => .wasm,
1032 else => .elf,
1033 },
1034 };
1035 }
1036};
1037
1038pub fn toElfMachine(target: *const Target) std.elf.EM {
1039 return switch (target.cpu.arch) {
1040 .aarch64, .aarch64_be => .AARCH64,
1041 .alpha => .ALPHA,
1042 .amdgcn => .AMDGPU,
1043 .arc, .arceb => .ARC_COMPACT2,
1044 .arm, .armeb, .thumb, .thumbeb => .ARM,
1045 .avr => .AVR,
1046 .bpfeb, .bpfel => .BPF,
1047 .csky => .CSKY,
1048 .hexagon => .QDSP6,
1049 .hppa, .hppa64 => .PARISC,
1050 .kalimba => .CSR_KALIMBA,
1051 .kvx => .KVX,
1052 .lanai => .LANAI,
1053 .loongarch32, .loongarch64 => .LOONGARCH,
1054 .m68k => .@"68K",
1055 .microblaze, .microblazeel => .MICROBLAZE,
1056 .mips, .mips64, .mipsel, .mips64el => .MIPS,
1057 .msp430 => .MSP430,
1058 .or1k => .OR1K,
1059 .powerpc, .powerpcle => .PPC,
1060 .powerpc64, .powerpc64le => .PPC64,
1061 .propeller => .PROPELLER,
1062 .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV,
1063 .s390x => .S390,
1064 .sh, .sheb => .SH,
1065 .sparc => if (target.cpu.has(.sparc, .v9)) .SPARC32PLUS else .SPARC,
1066 .sparc64 => .SPARCV9,
1067 .ve => .VE,
1068 .x86_16, .x86 => .@"386",
1069 .x86_64 => .X86_64,
1070 .xcore => .XCORE,
1071 .xtensa, .xtensaeb => .XTENSA,
1072
1073 .nvptx,
1074 .nvptx64,
1075 .spirv32,
1076 .spirv64,
1077 .wasm32,
1078 .wasm64,
1079 => .NONE,
1080 };
1081}
1082
1083pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
1084 return switch (target.cpu.arch) {
1085 .alpha => .ALPHA64,
1086 .arm => .ARM,
1087 .thumb => .ARMNT,
1088 .aarch64 => .ARM64,
1089 .loongarch32 => .LOONGARCH32,
1090 .loongarch64 => .LOONGARCH64,
1091 .mips => .R3000BE,
1092 .mipsel => .R3000,
1093 .mips64el => .R4000,
1094 .powerpcle => .POWERPC,
1095 .riscv32 => .RISCV32,
1096 .riscv64 => .RISCV64,
1097 .sh => .SH3,
1098 .x86 => .I386,
1099 .x86_64 => .AMD64,
1100
1101 .aarch64_be,
1102 .amdgcn,
1103 .arc,
1104 .arceb,
1105 .armeb,
1106 .avr,
1107 .bpfeb,
1108 .bpfel,
1109 .csky,
1110 .hexagon,
1111 .hppa,
1112 .hppa64,
1113 .kalimba,
1114 .kvx,
1115 .lanai,
1116 .m68k,
1117 .microblaze,
1118 .microblazeel,
1119 .mips64,
1120 .msp430,
1121 .nvptx,
1122 .nvptx64,
1123 .or1k,
1124 .powerpc,
1125 .powerpc64,
1126 .powerpc64le,
1127 .propeller,
1128 .riscv32be,
1129 .riscv64be,
1130 .s390x,
1131 .sheb,
1132 .sparc,
1133 .sparc64,
1134 .spirv32,
1135 .spirv64,
1136 .thumbeb,
1137 .ve,
1138 .wasm32,
1139 .wasm64,
1140 .x86_16,
1141 .xcore,
1142 .xtensa,
1143 .xtensaeb,
1144 => .UNKNOWN,
1145 };
1146}
1147
1148/// Deprecated; use 'std.zig.Subsystem' instead. To be removed after 0.16.0 is tagged.
1149pub const SubSystem = std.zig.Subsystem;
1150
1151pub const Cpu = struct {
1152 /// Architecture
1153 arch: Arch,
1154
1155 /// The CPU model to target. It has a set of features
1156 /// which are overridden with the `features` field.
1157 model: *const Model,
1158
1159 /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features.
1160 features: Feature.Set,
1161
1162 pub const Feature = struct {
1163 /// The bit index into `Set`. Has a default value of `undefined` because the canonical
1164 /// structures are populated via comptime logic.
1165 index: Set.Index = undefined,
1166
1167 /// Has a default value of `undefined` because the canonical
1168 /// structures are populated via comptime logic.
1169 name: []const u8 = undefined,
1170
1171 /// If this corresponds to an LLVM-recognized feature, this will be populated;
1172 /// otherwise null.
1173 llvm_name: ?[:0]const u8,
1174
1175 /// Human-friendly UTF-8 text.
1176 description: []const u8,
1177
1178 /// Sparse `Set` of features this depends on.
1179 dependencies: Set,
1180
1181 /// A bit set of all the features.
1182 pub const Set = struct {
1183 ints: [usize_count]usize,
1184
1185 pub const needed_bit_count = 317;
1186 pub const byte_count = (needed_bit_count + 7) / 8;
1187 pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize);
1188 pub const Index = std.math.Log2Int(std.meta.Int(.unsigned, usize_count * @bitSizeOf(usize)));
1189 pub const ShiftInt = std.math.Log2Int(usize);
1190
1191 pub const empty: Set = .{ .ints = @splat(0) };
1192
1193 pub fn isEmpty(set: Set) bool {
1194 return for (set.ints) |x| {
1195 if (x != 0) break false;
1196 } else true;
1197 }
1198
1199 pub fn count(set: Set) std.math.IntFittingRange(0, needed_bit_count) {
1200 var sum: usize = 0;
1201 for (set.ints) |x| sum += @popCount(x);
1202 return @intCast(sum);
1203 }
1204
1205 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
1206 const usize_index = arch_feature_index / @bitSizeOf(usize);
1207 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1208 return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
1209 }
1210
1211 /// Adds the specified feature but not its dependencies.
1212 pub fn addFeature(set: *Set, arch_feature_index: Index) void {
1213 const usize_index = arch_feature_index / @bitSizeOf(usize);
1214 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1215 set.ints[usize_index] |= @as(usize, 1) << bit_index;
1216 }
1217
1218 /// Adds the specified feature set but not its dependencies.
1219 pub fn addFeatureSet(set: *Set, other_set: Set) void {
1220 set.ints = @as(@Vector(usize_count, usize), set.ints) | @as(@Vector(usize_count, usize), other_set.ints);
1221 }
1222
1223 /// Removes the specified feature but not its dependents.
1224 pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
1225 const usize_index = arch_feature_index / @bitSizeOf(usize);
1226 const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
1227 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
1228 }
1229
1230 /// Removes the specified feature but not its dependents.
1231 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
1232 set.ints = @as(@Vector(usize_count, usize), set.ints) & ~@as(@Vector(usize_count, usize), other_set.ints);
1233 }
1234
1235 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
1236 @setEvalBranchQuota(1000000);
1237
1238 var old = set.ints;
1239 while (true) {
1240 for (all_features_list, 0..) |feature, index_usize| {
1241 const index: Index = @intCast(index_usize);
1242 if (set.isEnabled(index)) {
1243 set.addFeatureSet(feature.dependencies);
1244 }
1245 }
1246 const nothing_changed = std.mem.eql(usize, &old, &set.ints);
1247 if (nothing_changed) return;
1248 old = set.ints;
1249 }
1250 }
1251
1252 pub fn asBytes(set: *const Set) *const [byte_count]u8 {
1253 return std.mem.sliceAsBytes(&set.ints)[0..byte_count];
1254 }
1255
1256 pub fn eql(set: Set, other_set: Set) bool {
1257 return std.mem.eql(usize, &set.ints, &other_set.ints);
1258 }
1259
1260 pub fn isSuperSetOf(set: Set, other_set: Set) bool {
1261 const V = @Vector(usize_count, usize);
1262 const set_v: V = set.ints;
1263 const other_v: V = other_set.ints;
1264 return @reduce(.And, (set_v & other_v) == other_v);
1265 }
1266 };
1267
1268 pub fn FeatureSetFns(comptime F: type) type {
1269 return struct {
1270 /// Populates only the feature bits specified.
1271 pub fn featureSet(features: []const F) Set {
1272 var x = Set.empty;
1273 for (features) |feature| {
1274 x.addFeature(@intFromEnum(feature));
1275 }
1276 return x;
1277 }
1278
1279 /// Returns true if the specified feature is enabled.
1280 pub fn featureSetHas(set: Set, feature: F) bool {
1281 return set.isEnabled(@intFromEnum(feature));
1282 }
1283
1284 /// Returns true if any specified feature is enabled.
1285 pub fn featureSetHasAny(set: Set, features: anytype) bool {
1286 inline for (features) |feature| {
1287 if (set.isEnabled(@intFromEnum(@as(F, feature)))) return true;
1288 }
1289 return false;
1290 }
1291
1292 /// Returns true if every specified feature is enabled.
1293 pub fn featureSetHasAll(set: Set, features: anytype) bool {
1294 inline for (features) |feature| {
1295 if (!set.isEnabled(@intFromEnum(@as(F, feature)))) return false;
1296 }
1297 return true;
1298 }
1299 };
1300 }
1301 };
1302
1303 pub const Arch = enum {
1304 aarch64,
1305 aarch64_be,
1306 alpha,
1307 amdgcn,
1308 arc,
1309 arceb,
1310 arm,
1311 armeb,
1312 avr,
1313 bpfeb,
1314 bpfel,
1315 csky,
1316 hexagon,
1317 hppa,
1318 hppa64,
1319 kalimba,
1320 kvx,
1321 lanai,
1322 loongarch32,
1323 loongarch64,
1324 m68k,
1325 microblaze,
1326 microblazeel,
1327 mips,
1328 mipsel,
1329 mips64,
1330 mips64el,
1331 msp430,
1332 nvptx,
1333 nvptx64,
1334 or1k,
1335 powerpc,
1336 powerpcle,
1337 powerpc64,
1338 powerpc64le,
1339 propeller,
1340 riscv32,
1341 riscv32be,
1342 riscv64,
1343 riscv64be,
1344 s390x,
1345 sh,
1346 sheb,
1347 sparc,
1348 sparc64,
1349 spirv32,
1350 spirv64,
1351 thumb,
1352 thumbeb,
1353 ve,
1354 wasm32,
1355 wasm64,
1356 x86_16,
1357 x86,
1358 x86_64,
1359 xcore,
1360 xtensa,
1361 xtensaeb,
1362
1363 // LLVM tags deliberately omitted:
1364 // - aarch64_32
1365 // - amdil
1366 // - amdil64
1367 // - dxil
1368 // - r600
1369 // - hsail
1370 // - hsail64
1371 // - renderscript32
1372 // - renderscript64
1373 // - shave
1374 // - sparcel
1375 // - spir
1376 // - spir64
1377 // - spirv
1378 // - tce
1379 // - tcele
1380
1381 /// An architecture family can encompass multiple architectures as represented by `Arch`.
1382 /// For a given family tag, it is guaranteed that an `std.Target.<tag>` namespace exists
1383 /// containing CPU model and feature data.
1384 pub const Family = enum {
1385 aarch64,
1386 alpha,
1387 amdgcn,
1388 arc,
1389 arm,
1390 avr,
1391 bpf,
1392 csky,
1393 hexagon,
1394 hppa,
1395 kalimba,
1396 kvx,
1397 lanai,
1398 loongarch,
1399 m68k,
1400 microblaze,
1401 mips,
1402 msp430,
1403 nvptx,
1404 or1k,
1405 powerpc,
1406 propeller,
1407 riscv,
1408 s390x,
1409 sh,
1410 sparc,
1411 spirv,
1412 ve,
1413 wasm,
1414 x86,
1415 xcore,
1416 xtensa,
1417 };
1418
1419 pub inline fn family(arch: Arch) Family {
1420 return switch (arch) {
1421 .aarch64, .aarch64_be => .aarch64,
1422 .alpha => .alpha,
1423 .amdgcn => .amdgcn,
1424 .arc, .arceb => .arc,
1425 .arm, .armeb, .thumb, .thumbeb => .arm,
1426 .avr => .avr,
1427 .bpfeb, .bpfel => .bpf,
1428 .csky => .csky,
1429 .hexagon => .hexagon,
1430 .hppa, .hppa64 => .hppa,
1431 .kalimba => .kalimba,
1432 .kvx => .kvx,
1433 .lanai => .lanai,
1434 .loongarch32, .loongarch64 => .loongarch,
1435 .m68k => .m68k,
1436 .microblaze, .microblazeel => .microblaze,
1437 .mips, .mipsel, .mips64, .mips64el => .mips,
1438 .msp430 => .msp430,
1439 .or1k => .or1k,
1440 .nvptx, .nvptx64 => .nvptx,
1441 .powerpc, .powerpcle, .powerpc64, .powerpc64le => .powerpc,
1442 .propeller => .propeller,
1443 .riscv32, .riscv32be, .riscv64, .riscv64be => .riscv,
1444 .s390x => .s390x,
1445 .sh, .sheb => .sh,
1446 .sparc, .sparc64 => .sparc,
1447 .spirv32, .spirv64 => .spirv,
1448 .ve => .ve,
1449 .wasm32, .wasm64 => .wasm,
1450 .x86_16, .x86, .x86_64 => .x86,
1451 .xcore => .xcore,
1452 .xtensa, .xtensaeb => .xtensa,
1453 };
1454 }
1455
1456 pub inline fn isX86(arch: Arch) bool {
1457 return switch (arch) {
1458 .x86_16, .x86, .x86_64 => true,
1459 else => false,
1460 };
1461 }
1462
1463 /// Note that this includes Thumb.
1464 pub inline fn isArm(arch: Arch) bool {
1465 return switch (arch) {
1466 .arm, .armeb => true,
1467 else => arch.isThumb(),
1468 };
1469 }
1470
1471 pub inline fn isThumb(arch: Arch) bool {
1472 return switch (arch) {
1473 .thumb, .thumbeb => true,
1474 else => false,
1475 };
1476 }
1477
1478 pub inline fn isAARCH64(arch: Arch) bool {
1479 return switch (arch) {
1480 .aarch64, .aarch64_be => true,
1481 else => false,
1482 };
1483 }
1484
1485 pub inline fn isArc(arch: Arch) bool {
1486 return switch (arch) {
1487 .arc, .arceb => true,
1488 else => false,
1489 };
1490 }
1491
1492 pub inline fn isHppa(arch: Arch) bool {
1493 return switch (arch) {
1494 .hppa, .hppa64 => true,
1495 else => false,
1496 };
1497 }
1498
1499 pub inline fn isWasm(arch: Arch) bool {
1500 return switch (arch) {
1501 .wasm32, .wasm64 => true,
1502 else => false,
1503 };
1504 }
1505
1506 pub inline fn isLoongArch(arch: Arch) bool {
1507 return switch (arch) {
1508 .loongarch32, .loongarch64 => true,
1509 else => false,
1510 };
1511 }
1512
1513 pub inline fn isRISCV(arch: Arch) bool {
1514 return arch.isRiscv32() or arch.isRiscv64();
1515 }
1516
1517 pub inline fn isRiscv32(arch: Arch) bool {
1518 return switch (arch) {
1519 .riscv32, .riscv32be => true,
1520 else => false,
1521 };
1522 }
1523
1524 pub inline fn isRiscv64(arch: Arch) bool {
1525 return switch (arch) {
1526 .riscv64, .riscv64be => true,
1527 else => false,
1528 };
1529 }
1530
1531 pub inline fn isMicroblaze(arch: Arch) bool {
1532 return switch (arch) {
1533 .microblaze, .microblazeel => true,
1534 else => false,
1535 };
1536 }
1537
1538 pub inline fn isMIPS(arch: Arch) bool {
1539 return arch.isMIPS32() or arch.isMIPS64();
1540 }
1541
1542 pub inline fn isMIPS32(arch: Arch) bool {
1543 return switch (arch) {
1544 .mips, .mipsel => true,
1545 else => false,
1546 };
1547 }
1548
1549 pub inline fn isMIPS64(arch: Arch) bool {
1550 return switch (arch) {
1551 .mips64, .mips64el => true,
1552 else => false,
1553 };
1554 }
1555
1556 pub inline fn isPowerPC(arch: Arch) bool {
1557 return arch.isPowerPC32() or arch.isPowerPC64();
1558 }
1559
1560 pub inline fn isPowerPC32(arch: Arch) bool {
1561 return switch (arch) {
1562 .powerpc, .powerpcle => true,
1563 else => false,
1564 };
1565 }
1566
1567 pub inline fn isPowerPC64(arch: Arch) bool {
1568 return switch (arch) {
1569 .powerpc64, .powerpc64le => true,
1570 else => false,
1571 };
1572 }
1573
1574 pub inline fn isSPARC(arch: Arch) bool {
1575 return switch (arch) {
1576 .sparc, .sparc64 => true,
1577 else => false,
1578 };
1579 }
1580
1581 pub inline fn isSpirV(arch: Arch) bool {
1582 return switch (arch) {
1583 .spirv32, .spirv64 => true,
1584 else => false,
1585 };
1586 }
1587
1588 pub inline fn isSh(arch: Arch) bool {
1589 return switch (arch) {
1590 .sh, .sheb => true,
1591 else => false,
1592 };
1593 }
1594
1595 pub inline fn isBpf(arch: Arch) bool {
1596 return switch (arch) {
1597 .bpfel, .bpfeb => true,
1598 else => false,
1599 };
1600 }
1601
1602 pub inline fn isNvptx(arch: Arch) bool {
1603 return switch (arch) {
1604 .nvptx, .nvptx64 => true,
1605 else => false,
1606 };
1607 }
1608
1609 pub inline fn isXtensa(arch: Arch) bool {
1610 return switch (arch) {
1611 .xtensa, .xtensaeb => true,
1612 else => false,
1613 };
1614 }
1615
1616 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
1617 for (arch.allCpuModels()) |cpu| {
1618 if (std.mem.eql(u8, cpu_name, cpu.name)) {
1619 return cpu;
1620 }
1621 }
1622 return error.UnknownCpuModel;
1623 }
1624
1625 pub fn endian(arch: Arch) std.builtin.Endian {
1626 return switch (arch) {
1627 .aarch64,
1628 .alpha,
1629 .arm,
1630 .arc,
1631 .avr,
1632 .bpfel,
1633 .csky,
1634 .hexagon,
1635 .kalimba,
1636 .kvx,
1637 .loongarch32,
1638 .loongarch64,
1639 .microblazeel,
1640 .mipsel,
1641 .mips64el,
1642 .msp430,
1643 .powerpcle,
1644 .powerpc64le,
1645 .propeller,
1646 .riscv32,
1647 .riscv64,
1648 .sh,
1649 .thumb,
1650 .ve,
1651 .wasm32,
1652 .wasm64,
1653 .x86_16,
1654 .x86,
1655 .x86_64,
1656 .xcore,
1657 .xtensa,
1658 => .little,
1659
1660 .aarch64_be,
1661 .arceb,
1662 .armeb,
1663 .bpfeb,
1664 .hppa,
1665 .hppa64,
1666 .lanai,
1667 .m68k,
1668 .microblaze,
1669 .mips,
1670 .mips64,
1671 .or1k,
1672 .powerpc,
1673 .powerpc64,
1674 .riscv32be,
1675 .riscv64be,
1676 .s390x,
1677 .sheb,
1678 .thumbeb,
1679 .sparc,
1680 .sparc64,
1681 .xtensaeb,
1682 => .big,
1683
1684 // GPU endianness is opaque. For now, assume little endian.
1685 .amdgcn,
1686 .nvptx,
1687 .nvptx64,
1688 .spirv32,
1689 .spirv64,
1690 => .little,
1691 };
1692 }
1693
1694 /// All CPU features Zig is aware of, sorted lexicographically by name.
1695 pub fn allFeaturesList(arch: Arch) []const Cpu.Feature {
1696 return switch (arch.family()) {
1697 inline else => |f| &@field(Target, @tagName(f)).all_features,
1698 };
1699 }
1700
1701 /// All processors Zig is aware of, sorted lexicographically by name.
1702 pub fn allCpuModels(arch: Arch) []const *const Cpu.Model {
1703 return switch (arch.family()) {
1704 inline else => |f| comptime allCpusFromDecls(@field(Target, @tagName(f)).cpu),
1705 };
1706 }
1707
1708 fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
1709 @setEvalBranchQuota(2000);
1710 const decls = @typeInfo(cpus).@"struct".decls;
1711 var array: [decls.len]*const Cpu.Model = undefined;
1712 for (decls, 0..) |decl, i| {
1713 array[i] = &@field(cpus, decl.name);
1714 }
1715 const finalized = array;
1716 return &finalized;
1717 }
1718
1719 /// 0c spim little-endian MIPS 3000 family
1720 /// 1c 68000 Motorola MC68000
1721 /// 2c 68020 Motorola MC68020
1722 /// 5c arm little-endian ARM
1723 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
1724 /// 7c arm64 ARM64 (ARMv8)
1725 /// 8c 386 Intel x86, i486, Pentium, etc.
1726 /// kc sparc Sun SPARC
1727 /// qc power Power PC
1728 /// vc mips big-endian MIPS 3000 family
1729 pub fn plan9Ext(arch: Cpu.Arch) [:0]const u8 {
1730 return switch (arch) {
1731 .arm => ".5",
1732 .x86_64 => ".6",
1733 .aarch64 => ".7",
1734 .x86 => ".8",
1735 .sparc => ".k",
1736 .powerpc, .powerpcle => ".q",
1737 .mips, .mipsel => ".v",
1738 // ISAs without designated characters get 'X' for lack of a better option.
1739 else => ".X",
1740 };
1741 }
1742
1743 /// Returns the array of `Arch` to which a specific `std.builtin.CallingConvention` applies.
1744 /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`.
1745 pub fn fromCallingConvention(cc: std.builtin.CallingConvention.Tag) []const Arch {
1746 return switch (cc) {
1747 .auto,
1748 .async,
1749 .naked,
1750 .@"inline",
1751 => unreachable,
1752
1753 .x86_64_sysv,
1754 .x86_64_x32,
1755 .x86_64_win,
1756 .x86_64_regcall_v3_sysv,
1757 .x86_64_regcall_v4_win,
1758 .x86_64_vectorcall,
1759 .x86_64_interrupt,
1760 => &.{.x86_64},
1761
1762 .x86_sysv,
1763 .x86_win,
1764 .x86_stdcall,
1765 .x86_fastcall,
1766 .x86_thiscall,
1767 .x86_thiscall_mingw,
1768 .x86_regcall_v3,
1769 .x86_regcall_v4_win,
1770 .x86_vectorcall,
1771 .x86_interrupt,
1772 => &.{.x86},
1773
1774 .x86_16_cdecl,
1775 .x86_16_stdcall,
1776 .x86_16_regparmcall,
1777 .x86_16_interrupt,
1778 => &.{.x86_16},
1779
1780 .aarch64_aapcs,
1781 .aarch64_aapcs_darwin,
1782 .aarch64_aapcs_win,
1783 .aarch64_vfabi,
1784 .aarch64_vfabi_sve,
1785 => &.{ .aarch64, .aarch64_be },
1786
1787 .alpha_osf,
1788 => &.{.alpha},
1789
1790 .arm_aapcs,
1791 .arm_aapcs_vfp,
1792 .arm_interrupt,
1793 => &.{ .arm, .armeb, .thumb, .thumbeb },
1794
1795 .mips64_n64,
1796 .mips64_n32,
1797 .mips64_interrupt,
1798 => &.{ .mips64, .mips64el },
1799
1800 .mips_o32,
1801 .mips_interrupt,
1802 => &.{ .mips, .mipsel },
1803
1804 .riscv64_lp64,
1805 .riscv64_lp64_v,
1806 .riscv64_interrupt,
1807 => &.{ .riscv64, .riscv64be },
1808
1809 .riscv32_ilp32,
1810 .riscv32_ilp32_v,
1811 .riscv32_interrupt,
1812 => &.{ .riscv32, .riscv32be },
1813
1814 .sparc64_sysv,
1815 => &.{.sparc64},
1816
1817 .sparc_sysv,
1818 => &.{.sparc},
1819
1820 .powerpc64_elf,
1821 .powerpc64_elf_altivec,
1822 .powerpc64_elf_v2,
1823 => &.{ .powerpc64, .powerpc64le },
1824
1825 .powerpc_sysv,
1826 .powerpc_sysv_altivec,
1827 .powerpc_aix,
1828 .powerpc_aix_altivec,
1829 => &.{ .powerpc, .powerpcle },
1830
1831 .wasm_mvp,
1832 => &.{ .wasm64, .wasm32 },
1833
1834 .arc_sysv,
1835 .arc_interrupt,
1836 => &.{ .arc, .arceb },
1837
1838 .avr_gnu,
1839 .avr_builtin,
1840 .avr_signal,
1841 .avr_interrupt,
1842 => &.{.avr},
1843
1844 .bpf_std,
1845 => &.{ .bpfel, .bpfeb },
1846
1847 .csky_sysv,
1848 .csky_interrupt,
1849 => &.{.csky},
1850
1851 .hexagon_sysv,
1852 .hexagon_sysv_hvx,
1853 => &.{.hexagon},
1854
1855 .hppa_elf,
1856 => &.{.hppa},
1857
1858 .hppa64_elf,
1859 => &.{.hppa64},
1860
1861 .kvx_lp64,
1862 .kvx_ilp32,
1863 => &.{.kvx},
1864
1865 .lanai_sysv,
1866 => &.{.lanai},
1867
1868 .loongarch64_lp64,
1869 => &.{.loongarch64},
1870
1871 .loongarch32_ilp32,
1872 => &.{.loongarch32},
1873
1874 .m68k_sysv,
1875 .m68k_gnu,
1876 .m68k_rtd,
1877 .m68k_interrupt,
1878 => &.{.m68k},
1879
1880 .microblaze_std,
1881 .microblaze_interrupt,
1882 => &.{ .microblaze, .microblazeel },
1883
1884 .msp430_eabi,
1885 .msp430_interrupt,
1886 => &.{.msp430},
1887
1888 .or1k_sysv,
1889 => &.{.or1k},
1890
1891 .propeller_sysv,
1892 => &.{.propeller},
1893
1894 .s390x_sysv,
1895 .s390x_sysv_vx,
1896 => &.{.s390x},
1897
1898 .sh_gnu,
1899 .sh_renesas,
1900 .sh_interrupt,
1901 => &.{ .sh, .sheb },
1902
1903 .ve_sysv,
1904 => &.{.ve},
1905
1906 .xcore_xs1,
1907 .xcore_xs2,
1908 => &.{.xcore},
1909
1910 .xtensa_call0,
1911 .xtensa_windowed,
1912 => &.{ .xtensa, .xtensaeb },
1913
1914 .amdgcn_device,
1915 .amdgcn_kernel,
1916 .amdgcn_cs,
1917 => &.{.amdgcn},
1918
1919 .nvptx_device,
1920 .nvptx_kernel,
1921 => &.{ .nvptx, .nvptx64 },
1922
1923 .spirv_device,
1924 .spirv_kernel,
1925 .spirv_fragment,
1926 .spirv_vertex,
1927 => &.{ .spirv32, .spirv64 },
1928 };
1929 }
1930 };
1931
1932 pub const Model = struct {
1933 name: []const u8,
1934 llvm_name: ?[:0]const u8,
1935 features: Feature.Set,
1936
1937 pub fn toCpu(model: *const Model, arch: Arch) Cpu {
1938 var features = model.features;
1939 features.populateDependencies(arch.allFeaturesList());
1940 return .{
1941 .arch = arch,
1942 .model = model,
1943 .features = features,
1944 };
1945 }
1946
1947 /// Returns the most bare-bones CPU model that is valid for `arch`. Note that this function
1948 /// can return CPU models that are understood by LLVM, but *not* understood by Clang. If
1949 /// Clang compatibility is important, consider using `baseline` instead.
1950 pub fn generic(arch: Arch) *const Model {
1951 return switch (arch) {
1952 .alpha => &alpha.cpu.ev4,
1953 .amdgcn => &amdgcn.cpu.gfx600,
1954 .avr => &avr.cpu.avr1,
1955 .hppa => &hppa.cpu.ts_1,
1956 .hppa64 => &hppa.cpu.pa_8000,
1957 .kvx => &kvx.cpu.coolidge_v1,
1958 .loongarch32 => &loongarch.cpu.generic_la32,
1959 .loongarch64 => &loongarch.cpu.generic_la64,
1960 .mips, .mipsel => &mips.cpu.mips32,
1961 .mips64, .mips64el => &mips.cpu.mips64,
1962 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
1963 .powerpc, .powerpcle => &powerpc.cpu.ppc,
1964 .powerpc64, .powerpc64le => &powerpc.cpu.ppc64,
1965 .propeller => &propeller.cpu.p1,
1966 .riscv32, .riscv32be => &riscv.cpu.generic_rv32,
1967 .riscv64, .riscv64be => &riscv.cpu.generic_rv64,
1968 .sparc64 => &sparc.cpu.v9, // SPARC can only be 64-bit from v9 and up.
1969 .wasm32, .wasm64 => &wasm.cpu.mvp,
1970 .x86_16 => &x86.cpu.i86,
1971 .x86 => &x86.cpu.i386,
1972 .x86_64 => &x86.cpu.x86_64,
1973 inline else => |a| &@field(Target, @tagName(a.family())).cpu.generic,
1974 };
1975 }
1976
1977 /// Returns a conservative CPU model for `arch` that is expected to be compatible with the
1978 /// vast majority of hardware available. This function is guaranteed to return CPU models
1979 /// that are understood by both LLVM and Clang, unlike `generic`.
1980 ///
1981 /// For certain `os` values, this function will additionally bump the baseline higher than
1982 /// the baseline would be for `arch` in isolation; for example, for `aarch64-macos`, the
1983 /// baseline is considered to be `apple_m1`. To avoid this behavior entirely, pass
1984 /// `Os.Tag.freestanding`.
1985 pub fn baseline(arch: Arch, os: Os) *const Model {
1986 return switch (arch) {
1987 .alpha => &alpha.cpu.ev6,
1988 .amdgcn => &amdgcn.cpu.gfx906,
1989 .arm => switch (os.tag) {
1990 .@"3ds" => &arm.cpu.mpcore,
1991 .vita => &arm.cpu.cortex_a9,
1992 else => &arm.cpu.baseline,
1993 },
1994 .thumb => switch (os.tag) {
1995 .vita => &arm.cpu.cortex_a9,
1996 else => &arm.cpu.baseline,
1997 },
1998 .armeb, .thumbeb => &arm.cpu.baseline,
1999 .aarch64 => switch (os.tag) {
2000 .driverkit, .maccatalyst, .macos => &aarch64.cpu.apple_m1,
2001 .ios, .tvos => &aarch64.cpu.apple_a7,
2002 .visionos => &aarch64.cpu.apple_m2,
2003 .watchos => &aarch64.cpu.apple_s4,
2004 else => generic(arch),
2005 },
2006 .avr => &avr.cpu.avr2,
2007 .bpfel, .bpfeb => &bpf.cpu.v3,
2008 .csky => &csky.cpu.ck810, // gcc/clang do not have a generic csky model.
2009 .hexagon => &hexagon.cpu.hexagonv68, // gcc/clang do not have a generic hexagon model.
2010 .hppa => &hppa.cpu.pa_7300lc,
2011 .kvx => &kvx.cpu.coolidge_v2,
2012 .lanai => &lanai.cpu.v11, // clang does not have a generic lanai model.
2013 .loongarch64 => &loongarch.cpu.la64v1_0,
2014 .m68k => &m68k.cpu.M68000,
2015 .mips, .mipsel => &mips.cpu.mips32r2,
2016 .mips64, .mips64el => &mips.cpu.mips64r2,
2017 .msp430 => &msp430.cpu.msp430,
2018 .nvptx, .nvptx64 => &nvptx.cpu.sm_52,
2019 .powerpc64le => &powerpc.cpu.ppc64le,
2020 .riscv32, .riscv32be => &riscv.cpu.baseline_rv32,
2021 .riscv64, .riscv64be => &riscv.cpu.baseline_rv64,
2022 // gcc/clang do not have a generic s390x model.
2023 .s390x => &s390x.cpu.arch8,
2024 .sparc => &sparc.cpu.v9, // glibc does not work with 'plain' v8.
2025 .x86 => &x86.cpu.pentium4,
2026 .x86_64 => switch (os.tag) {
2027 .driverkit, .maccatalyst => &x86.cpu.nehalem,
2028 .macos => &x86.cpu.core2,
2029 .ps4 => &x86.cpu.btver2,
2030 .ps5 => &x86.cpu.znver2,
2031 else => generic(arch),
2032 },
2033 .xcore => &xcore.cpu.xs1b_generic,
2034 .wasm32, .wasm64 => &wasm.cpu.lime1,
2035
2036 else => generic(arch),
2037 };
2038 }
2039 };
2040
2041 /// The "default" set of CPU features for cross-compiling. A conservative set
2042 /// of features that is expected to be supported on most available hardware.
2043 pub fn baseline(arch: Arch, os: Os) Cpu {
2044 return Model.baseline(arch, os).toCpu(arch);
2045 }
2046
2047 /// Returns true if `feature` is enabled.
2048 pub fn has(cpu: Cpu, comptime family: Arch.Family, feature: @field(Target, @tagName(family)).Feature) bool {
2049 if (family != cpu.arch.family()) return false;
2050 return cpu.features.isEnabled(@intFromEnum(feature));
2051 }
2052
2053 /// Returns true if any feature in `features` is enabled.
2054 pub fn hasAny(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2055 if (family != cpu.arch.family()) return false;
2056 for (features) |feature| {
2057 if (cpu.features.isEnabled(@intFromEnum(feature))) return true;
2058 }
2059 return false;
2060 }
2061
2062 /// Returns true if all features in `features` are enabled.
2063 pub fn hasAll(cpu: Cpu, comptime family: Arch.Family, features: []const @field(Target, @tagName(family)).Feature) bool {
2064 if (family != cpu.arch.family()) return false;
2065 for (features) |feature| {
2066 if (!cpu.features.isEnabled(@intFromEnum(feature))) return false;
2067 }
2068 return true;
2069 }
2070};
2071
2072pub fn zigTriple(target: *const Target, allocator: Allocator) Allocator.Error![]u8 {
2073 return Query.fromTarget(target).zigTriple(allocator);
2074}
2075
2076pub fn hurdTupleSimple(allocator: Allocator, arch: Cpu.Arch, abi: Abi) ![]u8 {
2077 return std.fmt.allocPrint(allocator, "{s}-{s}", .{ @tagName(arch), @tagName(abi) });
2078}
2079
2080pub fn hurdTuple(target: *const Target, allocator: Allocator) ![]u8 {
2081 return hurdTupleSimple(allocator, target.cpu.arch, target.abi);
2082}
2083
2084pub fn linuxTripleSimple(allocator: Allocator, arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
2085 return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(arch), @tagName(os_tag), @tagName(abi) });
2086}
2087
2088pub fn linuxTriple(target: *const Target, allocator: Allocator) ![]u8 {
2089 return linuxTripleSimple(allocator, target.cpu.arch, target.os.tag, target.abi);
2090}
2091
2092pub fn exeFileExt(target: *const Target) [:0]const u8 {
2093 return target.os.tag.exeFileExt(target.cpu.arch);
2094}
2095
2096pub fn staticLibSuffix(target: *const Target) [:0]const u8 {
2097 return target.os.tag.staticLibSuffix(target.abi);
2098}
2099
2100pub fn dynamicLibSuffix(target: *const Target) [:0]const u8 {
2101 return target.os.tag.dynamicLibSuffix();
2102}
2103
2104pub fn libPrefix(target: *const Target) [:0]const u8 {
2105 return target.os.tag.libPrefix(target.abi);
2106}
2107
2108pub inline fn isMinGW(target: *const Target) bool {
2109 return target.os.tag == .windows and target.abi.isGnu();
2110}
2111
2112pub inline fn isGnuLibC(target: *const Target) bool {
2113 return switch (target.os.tag) {
2114 .hurd, .linux => target.abi.isGnu(),
2115 else => false,
2116 };
2117}
2118
2119pub inline fn isMuslLibC(target: *const Target) bool {
2120 return target.os.tag == .linux and target.abi.isMusl();
2121}
2122
2123pub inline fn isDarwinLibC(target: *const Target) bool {
2124 return switch (target.abi) {
2125 .none, .simulator => target.os.tag.isDarwin(),
2126 else => false,
2127 };
2128}
2129
2130pub inline fn isFreeBSDLibC(target: *const Target) bool {
2131 return switch (target.abi) {
2132 .none, .eabihf => target.os.tag == .freebsd,
2133 else => false,
2134 };
2135}
2136
2137pub inline fn isNetBSDLibC(target: *const Target) bool {
2138 return switch (target.abi) {
2139 .none, .eabi, .eabihf => target.os.tag == .netbsd,
2140 else => false,
2141 };
2142}
2143
2144pub inline fn isWasiLibC(target: *const Target) bool {
2145 return target.os.tag == .wasi and target.abi.isMusl();
2146}
2147
2148/// Does this target require linking libc? This may be the case if the target has an unstable
2149/// syscall interface, for example.
2150pub fn requiresLibC(target: *const Target) bool {
2151 return switch (target.os.tag) {
2152 .illumos,
2153 .driverkit,
2154 .ios,
2155 .maccatalyst,
2156 .macos,
2157 .tvos,
2158 .watchos,
2159 .visionos,
2160 .dragonfly,
2161 .openbsd,
2162 .haiku,
2163 .serenity,
2164 => true,
2165
2166 // Android API levels prior to 29 did not have native TLS support. For these API levels, TLS
2167 // is implemented through calls to `__emutls_get_address`. We provide this function in
2168 // compiler-rt, but it's implemented by way of `pthread_key_create` et al, so linking libc
2169 // is required.
2170 .linux => target.abi.isAndroid() and target.os.version_range.linux.android < 29,
2171
2172 .windows,
2173 .freebsd,
2174 .netbsd,
2175 .freestanding,
2176 .fuchsia,
2177 .managarm,
2178 .ps3,
2179 .rtems,
2180 .cuda,
2181 .nvcl,
2182 .amdhsa,
2183 .ps4,
2184 .ps5,
2185 .vita,
2186 .mesa3d,
2187 .contiki,
2188 .amdpal,
2189 .hermit,
2190 .hurd,
2191 .wasi,
2192 .emscripten,
2193 .uefi,
2194 .opencl,
2195 .opengl,
2196 .vulkan,
2197 .plan9,
2198 .other,
2199 .@"3ds",
2200 => false,
2201 };
2202}
2203
2204/// The places where a user can specify an address space attribute
2205pub const AddressSpaceContext = enum {
2206 /// A function is specified to be placed in a certain address space.
2207 function,
2208 /// A (global) variable is specified to be placed in a certain address space. In contrast to
2209 /// `.constant`, these values (and thus the address space they will be placed in) are required
2210 /// to be mutable.
2211 variable,
2212 /// A (global) constant value is specified to be placed in a certain address space. In contrast
2213 /// to `.variable`, values placed in this address space are not required to be mutable.
2214 constant,
2215 /// A pointer is ascripted to point into a certain address space.
2216 pointer,
2217};
2218
2219/// Returns whether this target supports `address_space`. If `context` is `null`, this
2220/// function simply answers the general question of whether the target has any concept
2221/// of `address_space`; if non-`null`, the function additionally checks whether
2222/// `address_space` is valid in that context.
2223pub fn supportsAddressSpace(
2224 target: Target,
2225 address_space: std.builtin.AddressSpace,
2226 context: ?AddressSpaceContext,
2227) bool {
2228 const arch = target.cpu.arch;
2229
2230 const is_nvptx = arch.isNvptx();
2231 const is_spirv = arch.isSpirV();
2232 const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
2233
2234 return switch (address_space) {
2235 .generic => true,
2236 .fs, .gs, .ss => (arch == .x86_64 or arch == .x86 or arch == .x86_16) and (context == null or context == .pointer),
2237 // Technically x86 can use segmentation...
2238 .far => (arch == .x86_16),
2239
2240 .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, // TODO this should also check how many flash banks the cpu has
2241 .cog, .hub => arch == .propeller,
2242 .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
2243
2244 .global, .local, .shared => is_gpu,
2245 .constant => is_gpu and (context == null or context == .constant),
2246 .param => is_nvptx,
2247 .input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv,
2248 };
2249}
2250
2251pub const DynamicLinker = struct {
2252 /// Contains the memory used to store the dynamic linker path. This field
2253 /// should not be used directly. See `get` and `set`. This field exists so
2254 /// that this API requires no allocator.
2255 buffer: [255]u8,
2256
2257 /// Used to construct the dynamic linker path. This field should not be used
2258 /// directly. See `get` and `set`.
2259 len: u8,
2260
2261 pub const none: DynamicLinker = .{ .buffer = undefined, .len = 0 };
2262
2263 /// Asserts that the length is less than or equal to 255 bytes.
2264 pub fn init(maybe_path: ?[]const u8) DynamicLinker {
2265 var dl: DynamicLinker = undefined;
2266 dl.set(maybe_path);
2267 return dl;
2268 }
2269
2270 pub fn initFmt(comptime fmt_str: []const u8, args: anytype) !DynamicLinker {
2271 var dl: DynamicLinker = undefined;
2272 try dl.setFmt(fmt_str, args);
2273 return dl;
2274 }
2275
2276 /// The returned memory has the same lifetime as the `DynamicLinker`.
2277 pub fn get(dl: *const DynamicLinker) ?[]const u8 {
2278 return if (dl.len > 0) dl.buffer[0..dl.len] else null;
2279 }
2280
2281 /// Asserts that the length is less than or equal to 255 bytes.
2282 pub fn set(dl: *DynamicLinker, maybe_path: ?[]const u8) void {
2283 const path = maybe_path orelse "";
2284 @memcpy(dl.buffer[0..path.len], path);
2285 dl.len = @intCast(path.len);
2286 }
2287
2288 /// Asserts that the length is less than or equal to 255 bytes.
2289 pub fn setFmt(dl: *DynamicLinker, comptime fmt_str: []const u8, args: anytype) !void {
2290 dl.len = @intCast((try std.fmt.bufPrint(&dl.buffer, fmt_str, args)).len);
2291 }
2292
2293 pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool {
2294 return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
2295 }
2296
2297 pub const Kind = enum {
2298 /// No dynamic linker.
2299 none,
2300 /// Dynamic linker path is determined by the arch/OS components.
2301 arch_os,
2302 /// Dynamic linker path is determined by the arch/OS/ABI components.
2303 arch_os_abi,
2304 };
2305
2306 pub fn kind(os: Os.Tag) Kind {
2307 return switch (os) {
2308 .fuchsia,
2309
2310 .haiku,
2311 .illumos,
2312 .serenity,
2313
2314 .dragonfly,
2315 .freebsd,
2316 .netbsd,
2317 .openbsd,
2318
2319 .driverkit,
2320 .ios,
2321 .maccatalyst,
2322 .macos,
2323 .tvos,
2324 .visionos,
2325 .watchos,
2326 => .arch_os,
2327 .hurd,
2328 .linux,
2329 => .arch_os_abi,
2330 .freestanding,
2331 .other,
2332
2333 .contiki,
2334 .hermit,
2335 .managarm, // Needs to be double-checked.
2336
2337 .plan9,
2338 .rtems,
2339
2340 .uefi,
2341 .windows,
2342
2343 .@"3ds",
2344
2345 .emscripten,
2346 .wasi,
2347
2348 .amdhsa,
2349 .amdpal,
2350 .cuda,
2351 .mesa3d,
2352 .nvcl,
2353 .opencl,
2354 .opengl,
2355 .vulkan,
2356
2357 .ps3,
2358 .ps4,
2359 .ps5,
2360 .vita,
2361 => .none,
2362 };
2363 }
2364
2365 /// The strictness of this function depends on the value of `kind(os.tag)`:
2366 ///
2367 /// * `.none`: Ignores all arguments and just returns `none`.
2368 /// * `.arch_os`: Ignores `abi` and returns the dynamic linker matching `cpu` and `os`.
2369 /// * `.arch_os_abi`: Returns the dynamic linker matching `cpu`, `os`, and `abi`.
2370 ///
2371 /// In the case of `.arch_os` in particular, callers should be aware that a valid dynamic linker
2372 /// being returned only means that the `cpu` + `os` combination represents a platform that
2373 /// actually exists and which has an established dynamic linker path that does not change with
2374 /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform.
2375 /// The responsibility for determining whether `abi` is valid in this case rests with the
2376 /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms.
2377 pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
2378 return switch (os.tag) {
2379 .fuchsia => switch (cpu.arch) {
2380 .aarch64,
2381 .riscv64,
2382 .x86_64,
2383 => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
2384 else => none,
2385 },
2386
2387 .haiku => switch (cpu.arch) {
2388 .arm,
2389 .aarch64,
2390 .m68k,
2391 .powerpc,
2392 .riscv64,
2393 .sparc64,
2394 .x86,
2395 .x86_64,
2396 => init("/system/runtime_loader"),
2397 else => none,
2398 },
2399
2400 .hurd => switch (cpu.arch) {
2401 .aarch64,
2402 .aarch64_be,
2403 => |arch| if (abi == .gnu) initFmt("/lib/ld-{s}.so.1", .{@tagName(arch)}) else none,
2404
2405 .x86 => if (abi == .gnu) init("/lib/ld.so.1") else none,
2406 .x86_64 => initFmt("/lib/ld-{s}.so.1", .{switch (abi) {
2407 .gnu => "x86-64",
2408 .gnux32 => "x32",
2409 else => return none,
2410 }}),
2411
2412 else => none,
2413 },
2414
2415 .illumos,
2416 => switch (cpu.arch) {
2417 .x86,
2418 .x86_64,
2419 => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}),
2420 else => none,
2421 },
2422
2423 .linux => if (abi.isAndroid())
2424 switch (cpu.arch) {
2425 .arm => if (abi == .androideabi) init("/system/bin/linker") else none,
2426
2427 .aarch64,
2428 .riscv64,
2429 .x86,
2430 .x86_64,
2431 => if (abi == .android) initFmt("/system/bin/linker{s}", .{
2432 if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
2433 }) else none,
2434
2435 else => none,
2436 }
2437 else if (abi.isMusl())
2438 switch (cpu.arch) {
2439 .arm,
2440 .armeb,
2441 .thumb,
2442 .thumbeb,
2443 => |arch| initFmt("/lib/ld-musl-arm{s}{s}.so.1", .{
2444 if (arch == .armeb or arch == .thumbeb) "eb" else "",
2445 switch (abi) {
2446 .musleabi => "",
2447 .musleabihf => "hf",
2448 else => return none,
2449 },
2450 }),
2451
2452 .loongarch32,
2453 .loongarch64,
2454 => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2455 @tagName(arch),
2456 switch (abi) {
2457 .musl => "",
2458 .muslf32 => "-sp",
2459 .muslsf => "-sf",
2460 else => return none,
2461 },
2462 }),
2463
2464 .aarch64,
2465 .aarch64_be,
2466 .hexagon,
2467 .kvx,
2468 .m68k,
2469 .microblaze,
2470 .microblazeel,
2471 .powerpc64,
2472 .powerpc64le,
2473 .s390x,
2474 => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none,
2475
2476 .mips,
2477 .mipsel,
2478 => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2479 if (cpu.has(.mips, .mips32r6)) "r6" else "",
2480 if (arch == .mipsel) "el" else "",
2481 switch (abi) {
2482 .musleabi => "-sf",
2483 .musleabihf => "",
2484 else => return none,
2485 },
2486 }),
2487
2488 .mips64,
2489 .mips64el,
2490 => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
2491 switch (abi) {
2492 .muslabi64 => "64",
2493 .muslabin32 => "n32",
2494 else => return none,
2495 },
2496 if (cpu.has(.mips, .mips64r6)) "r6" else "",
2497 if (arch == .mips64el) "el" else "",
2498 }),
2499
2500 .powerpc => initFmt("/lib/ld-musl-powerpc{s}.so.1", .{switch (abi) {
2501 .musleabi => "-sf",
2502 .musleabihf => "",
2503 else => return none,
2504 }}),
2505
2506 .sh,
2507 .sheb,
2508 => |arch| initFmt("/lib/ld-musl-{t}{s}.so.1", .{
2509 arch,
2510 switch (abi) {
2511 .musleabi => "-nofpu",
2512 .musleabihf => "",
2513 else => return none,
2514 },
2515 }),
2516
2517 .riscv32,
2518 .riscv64,
2519 => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{
2520 @tagName(arch),
2521 if (cpu.has(.riscv, .d))
2522 ""
2523 else if (cpu.has(.riscv, .f))
2524 "-sp"
2525 else
2526 "-sf",
2527 }) else none,
2528
2529 .x86 => if (abi == .musl) init("/lib/ld-musl-i386.so.1") else none,
2530
2531 .x86_64 => initFmt("/lib/ld-musl-{s}.so.1", .{switch (abi) {
2532 .musl => "x86_64",
2533 .muslx32 => "x32",
2534 else => return none,
2535 }}),
2536
2537 else => none,
2538 }
2539 else if (abi.isGnu())
2540 switch (cpu.arch) {
2541 // TODO: `700` ABI support.
2542 .arc,
2543 .arceb,
2544 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{t}.so.2", .{arch}) else none,
2545
2546 .arm,
2547 .armeb,
2548 .thumb,
2549 .thumbeb,
2550 => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) {
2551 .gnueabi => "",
2552 .gnueabihf => "-armhf",
2553 else => return none,
2554 }}),
2555
2556 .aarch64,
2557 .aarch64_be,
2558 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}.so.1", .{@tagName(arch)}) else none,
2559
2560 // TODO: `-be` architecture support.
2561 .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{switch (abi) {
2562 .gnueabi => "",
2563 .gnueabihf => "-hf",
2564 else => return none,
2565 }}),
2566
2567 .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) {
2568 .gnu => "lp64d",
2569 .gnuf32 => "lp64f",
2570 .gnusf => "lp64s",
2571 else => return none,
2572 }}),
2573
2574 .hppa,
2575 .m68k,
2576 .microblaze,
2577 .microblazeel,
2578 .xtensa,
2579 .xtensaeb,
2580 => if (abi == .gnu) init("/lib/ld.so.1") else none,
2581
2582 .mips,
2583 .mipsel,
2584 => switch (abi) {
2585 .gnueabi,
2586 .gnueabihf,
2587 => initFmt("/lib/ld{s}.so.1", .{
2588 if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2589 }),
2590 else => none,
2591 },
2592
2593 .mips64,
2594 .mips64el,
2595 => initFmt("/lib{s}/ld{s}.so.1", .{
2596 switch (abi) {
2597 .gnuabi64 => "64",
2598 .gnuabin32 => "32",
2599 else => return none,
2600 },
2601 if (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
2602 }),
2603
2604 .powerpc => switch (abi) {
2605 .gnueabi,
2606 .gnueabihf,
2607 => init("/lib/ld.so.1"),
2608 else => none,
2609 },
2610
2611 .powerpc64,
2612 .powerpc64le,
2613 => if (abi == .gnu) init("/lib64/ld64.so.2") else none,
2614
2615 .riscv32,
2616 .riscv64,
2617 => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{
2618 switch (arch) {
2619 .riscv32 => "riscv32-ilp32",
2620 .riscv64 => "riscv64-lp64",
2621 else => unreachable,
2622 },
2623 if (cpu.has(.riscv, .d))
2624 "d"
2625 else if (cpu.has(.riscv, .f))
2626 "f"
2627 else
2628 "",
2629 }) else none,
2630
2631 .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,
2632
2633 .sh,
2634 .sheb,
2635 => switch (abi) {
2636 .gnueabi,
2637 .gnueabihf,
2638 => init("/lib/ld-linux.so.2"),
2639 else => none,
2640 },
2641
2642 .alpha,
2643 .sparc,
2644 .x86,
2645 => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,
2646
2647 .sparc64 => if (abi == .gnu) init("/lib64/ld-linux.so.2") else none,
2648
2649 .x86_64 => switch (abi) {
2650 .gnu => init("/lib64/ld-linux-x86-64.so.2"),
2651 .gnux32 => init("/libx32/ld-linux-x32.so.2"),
2652 else => none,
2653 },
2654
2655 else => none,
2656 }
2657 else
2658 none, // Not a known Linux libc.
2659
2660 .serenity => switch (cpu.arch) {
2661 .aarch64,
2662 .riscv64,
2663 .x86_64,
2664 => init("/usr/lib/Loader.so"),
2665 else => none,
2666 },
2667
2668 .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{
2669 if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
2670 ""
2671 else
2672 "/usr",
2673 }) else none,
2674
2675 .freebsd => switch (cpu.arch) {
2676 .arm,
2677 .aarch64,
2678 .powerpc,
2679 .powerpc64,
2680 .powerpc64le,
2681 .riscv64,
2682 .x86,
2683 .x86_64,
2684 => initFmt("{s}/libexec/ld-elf.so.1", .{
2685 if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
2686 ""
2687 else
2688 "/usr",
2689 }),
2690 else => none,
2691 },
2692
2693 .netbsd => switch (cpu.arch) {
2694 .alpha,
2695 .arm,
2696 .armeb,
2697 .aarch64,
2698 .aarch64_be,
2699 .hppa,
2700 .m68k,
2701 .mips,
2702 .mipsel,
2703 .mips64,
2704 .mips64el,
2705 .powerpc,
2706 .sh,
2707 .sheb,
2708 .sparc,
2709 .sparc64,
2710 .x86,
2711 .x86_64,
2712 => init("/libexec/ld.elf_so"),
2713 else => none,
2714 },
2715
2716 .openbsd => switch (cpu.arch) {
2717 .alpha,
2718 .arm,
2719 .aarch64,
2720 .hppa,
2721 .mips64,
2722 .mips64el,
2723 .powerpc,
2724 .powerpc64,
2725 .riscv64,
2726 .sh,
2727 .sheb,
2728 .sparc64,
2729 .x86,
2730 .x86_64,
2731 => init("/usr/libexec/ld.so"),
2732 else => none,
2733 },
2734
2735 .driverkit,
2736 .ios,
2737 .maccatalyst,
2738 .macos,
2739 .tvos,
2740 .visionos,
2741 .watchos,
2742 => switch (cpu.arch) {
2743 .aarch64,
2744 .x86_64,
2745 => init("/usr/lib/dyld"),
2746 else => none,
2747 },
2748
2749 // Operating systems in this list have been verified as not having a standard
2750 // dynamic linker path.
2751 .freestanding,
2752 .other,
2753
2754 .contiki,
2755 .hermit,
2756
2757 .plan9,
2758 .rtems,
2759
2760 .uefi,
2761 .windows,
2762
2763 .@"3ds",
2764
2765 .vita,
2766
2767 .emscripten,
2768 .wasi,
2769
2770 .amdhsa,
2771 .amdpal,
2772 .cuda,
2773 .mesa3d,
2774 .nvcl,
2775 .opencl,
2776 .opengl,
2777 .vulkan,
2778 => none,
2779
2780 // TODO go over each item in this list and either move it to the above list, or
2781 // implement the standard dynamic linker path code for it.
2782 .managarm,
2783
2784 .ps3,
2785 .ps4,
2786 .ps5,
2787 => none,
2788 } catch unreachable;
2789 }
2790};
2791
2792pub fn standardDynamicLinkerPath(target: *const Target) DynamicLinker {
2793 return DynamicLinker.standard(target.cpu, target.os, target.abi);
2794}
2795
2796pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
2797 return ptrBitWidth_arch_abi(cpu.arch, abi);
2798}
2799
2800pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
2801 switch (abi) {
2802 .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
2803 .gnuabi64, .muslabi64 => return 64,
2804 else => {},
2805 }
2806 return switch (cpu_arch) {
2807 .avr,
2808 .msp430,
2809 .x86_16,
2810 => 16,
2811
2812 .arc,
2813 .arceb,
2814 .arm,
2815 .armeb,
2816 .csky,
2817 .hexagon,
2818 .hppa,
2819 .kalimba,
2820 .lanai,
2821 .loongarch32,
2822 .m68k,
2823 .microblaze,
2824 .microblazeel,
2825 .mips,
2826 .mipsel,
2827 .nvptx,
2828 .or1k,
2829 .powerpc,
2830 .powerpcle,
2831 .propeller,
2832 .riscv32,
2833 .riscv32be,
2834 .sh,
2835 .sheb,
2836 .sparc,
2837 .spirv32,
2838 .thumb,
2839 .thumbeb,
2840 .wasm32,
2841 .x86,
2842 .xcore,
2843 .xtensa,
2844 .xtensaeb,
2845 => 32,
2846
2847 .aarch64,
2848 .aarch64_be,
2849 .alpha,
2850 .amdgcn,
2851 .bpfeb,
2852 .bpfel,
2853 .hppa64,
2854 .kvx,
2855 .loongarch64,
2856 .mips64,
2857 .mips64el,
2858 .nvptx64,
2859 .powerpc64,
2860 .powerpc64le,
2861 .riscv64,
2862 .riscv64be,
2863 .s390x,
2864 .sparc64,
2865 .spirv64,
2866 .ve,
2867 .wasm64,
2868 .x86_64,
2869 => 64,
2870 };
2871}
2872
2873pub fn ptrBitWidth(target: *const Target) u16 {
2874 return ptrBitWidth_cpu_abi(target.cpu, target.abi);
2875}
2876
2877pub fn stackAlignment(target: *const Target) u16 {
2878 // Overrides for when the stack alignment is not equal to the pointer width.
2879 switch (target.cpu.arch) {
2880 .m68k,
2881 => return 2,
2882 .amdgcn,
2883 => return 4,
2884 .arm,
2885 .armeb,
2886 .hppa,
2887 .lanai,
2888 .mips,
2889 .mipsel,
2890 .sparc,
2891 .thumb,
2892 .thumbeb,
2893 => return 8,
2894 .aarch64,
2895 .aarch64_be,
2896 .alpha,
2897 .bpfeb,
2898 .bpfel,
2899 .hppa64,
2900 .loongarch32,
2901 .loongarch64,
2902 .mips64,
2903 .mips64el,
2904 .sparc64,
2905 .ve,
2906 .wasm32,
2907 .wasm64,
2908 .x86_64,
2909 => return 16,
2910 // Some of the following prongs should really be testing the ABI, but our current `Abi` enum
2911 // can't handle that level of nuance yet.
2912 .powerpc64,
2913 .powerpc64le,
2914 => if (target.os.tag == .linux) return 16,
2915 .riscv32,
2916 .riscv32be,
2917 .riscv64,
2918 .riscv64be,
2919 => if (!target.cpu.has(.riscv, .e)) return 16,
2920 .x86 => if (target.os.tag != .windows and target.os.tag != .uefi) return 16,
2921 .kvx => return 32,
2922 else => {},
2923 }
2924
2925 return @divExact(target.ptrBitWidth(), 8);
2926}
2927
2928pub const StackGrowth = enum {
2929 down,
2930 up,
2931};
2932
2933pub fn stackGrowth(target: *const Target) StackGrowth {
2934 // Strictly speaking, most architectures don't inherently define the stack growth direction; you
2935 // could quite easily argue that it is in fact a property of the ABI. However, that's just not
2936 // really how it plays out in the real world. And besides, we have no mechanism for indicating
2937 // a different stack growth ABI, nor a compelling use case for creating such a mechanism.
2938 return switch (target.cpu.arch) {
2939 .hppa,
2940 .hppa64,
2941 => .up,
2942 else => .down,
2943 };
2944}
2945
2946/// Default signedness of `char` for the native C compiler for this target
2947/// Note that char signedness is implementation-defined and many compilers provide
2948/// an option to override the default signedness e.g. GCC's -funsigned-char / -fsigned-char
2949pub fn cCharSignedness(target: *const Target) std.builtin.Signedness {
2950 if (target.os.tag.isDarwin() or target.os.tag == .windows or target.os.tag == .uefi) return .signed;
2951
2952 return switch (target.cpu.arch) {
2953 .aarch64,
2954 .aarch64_be,
2955 .arm,
2956 .armeb,
2957 .arc,
2958 .arceb,
2959 .csky,
2960 .hexagon,
2961 .msp430,
2962 .powerpc,
2963 .powerpcle,
2964 .powerpc64,
2965 .powerpc64le,
2966 .s390x,
2967 .riscv32,
2968 .riscv32be,
2969 .riscv64,
2970 .riscv64be,
2971 .thumb,
2972 .thumbeb,
2973 .xcore,
2974 .xtensa,
2975 .xtensaeb,
2976 => .unsigned,
2977 else => .signed,
2978 };
2979}
2980
2981pub const CType = enum {
2982 char,
2983 short,
2984 ushort,
2985 int,
2986 uint,
2987 long,
2988 ulong,
2989 longlong,
2990 ulonglong,
2991 float,
2992 double,
2993 longdouble,
2994};
2995
2996pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
2997 return switch (c_type) {
2998 .char,
2999 .short,
3000 .ushort,
3001 .int,
3002 .uint,
3003 .long,
3004 .ulong,
3005 .longlong,
3006 .ulonglong,
3007 .float,
3008 .double,
3009 => @divExact(cTypeBitSize(t, c_type), 8),
3010
3011 .longdouble => switch (cTypeBitSize(t, c_type)) {
3012 16 => 2,
3013 32 => 4,
3014 64 => 8,
3015 80 => @intCast(std.mem.alignForward(usize, 10, cTypeAlignment(t, .longdouble))),
3016 128 => 16,
3017 else => unreachable,
3018 },
3019 };
3020}
3021
3022pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
3023 switch (target.os.tag) {
3024 .freestanding, .other => switch (target.cpu.arch) {
3025 .msp430, .x86_16 => switch (c_type) {
3026 .char => return 8,
3027 .short, .ushort, .int, .uint => return 16,
3028 .float, .long, .ulong => return 32,
3029 .longlong, .ulonglong, .double, .longdouble => return 64,
3030 },
3031 .avr => switch (c_type) {
3032 .char => return 8,
3033 .short, .ushort, .int, .uint => return 16,
3034 .long, .ulong, .float, .double, .longdouble => return 32,
3035 .longlong, .ulonglong => return 64,
3036 },
3037 .mips64, .mips64el => switch (c_type) {
3038 .char => return 8,
3039 .short, .ushort => return 16,
3040 .int, .uint, .float => return 32,
3041 .long, .ulong => switch (target.abi) {
3042 .gnuabin32, .muslabin32 => return 32,
3043 else => return 64,
3044 },
3045 .longlong, .ulonglong, .double => return 64,
3046 .longdouble => return 128,
3047 },
3048 .x86_64 => switch (c_type) {
3049 .char => return 8,
3050 .short, .ushort => return 16,
3051 .int, .uint, .float => return 32,
3052 .long, .ulong => switch (target.abi) {
3053 .gnux32, .muslx32 => return 32,
3054 else => return 64,
3055 },
3056 .longlong, .ulonglong, .double => return 64,
3057 .longdouble => return 80,
3058 },
3059 else => switch (c_type) {
3060 .char => return 8,
3061 .short, .ushort => return 16,
3062 .int, .uint, .float => return 32,
3063 .long, .ulong => return target.ptrBitWidth(),
3064 .longlong, .ulonglong, .double => return 64,
3065 .longdouble => switch (target.cpu.arch) {
3066 .x86 => switch (target.abi) {
3067 .android => return 64,
3068 else => return 80,
3069 },
3070
3071 .powerpc,
3072 .powerpcle,
3073 .powerpc64,
3074 .powerpc64le,
3075 => switch (target.abi) {
3076 .musl,
3077 .muslabin32,
3078 .muslabi64,
3079 .musleabi,
3080 .musleabihf,
3081 .muslx32,
3082 => return 64,
3083 else => return 128,
3084 },
3085
3086 .alpha,
3087 .riscv32,
3088 .riscv32be,
3089 .riscv64,
3090 .riscv64be,
3091 .aarch64,
3092 .aarch64_be,
3093 .s390x,
3094 .sparc64,
3095 .wasm32,
3096 .wasm64,
3097 .loongarch32,
3098 .loongarch64,
3099 .ve,
3100 => return 128,
3101
3102 else => return 64,
3103 },
3104 },
3105 },
3106
3107 .fuchsia,
3108 .hermit,
3109
3110 .haiku,
3111 .hurd,
3112 .illumos,
3113 .linux,
3114 .plan9,
3115 .rtems,
3116 .serenity,
3117
3118 .freebsd,
3119 .dragonfly,
3120 .netbsd,
3121 .openbsd,
3122
3123 .wasi,
3124 .emscripten,
3125 => switch (target.cpu.arch) {
3126 .mips64, .mips64el => switch (c_type) {
3127 .char => return 8,
3128 .short, .ushort => return 16,
3129 .int, .uint, .float => return 32,
3130 .long, .ulong => switch (target.abi) {
3131 .gnuabin32, .muslabin32 => return 32,
3132 else => return 64,
3133 },
3134 .longlong, .ulonglong, .double => return 64,
3135 .longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
3136 },
3137 .x86_64 => switch (c_type) {
3138 .char => return 8,
3139 .short, .ushort => return 16,
3140 .int, .uint, .float => return 32,
3141 .long, .ulong => switch (target.abi) {
3142 .gnux32, .muslx32 => return 32,
3143 else => return 64,
3144 },
3145 .longlong, .ulonglong, .double => return 64,
3146 .longdouble => return 80,
3147 },
3148 else => switch (c_type) {
3149 .char => return 8,
3150 .short, .ushort => return 16,
3151 .int, .uint, .float => return 32,
3152 .long, .ulong => return target.ptrBitWidth(),
3153 .longlong, .ulonglong, .double => return 64,
3154 .longdouble => switch (target.cpu.arch) {
3155 .x86 => switch (target.abi) {
3156 .android => return 64,
3157 else => return 80,
3158 },
3159
3160 .powerpc,
3161 .powerpcle,
3162 => switch (target.abi) {
3163 .musl,
3164 .muslabin32,
3165 .muslabi64,
3166 .musleabi,
3167 .musleabihf,
3168 .muslx32,
3169 => return 64,
3170 else => switch (target.os.tag) {
3171 .freebsd, .netbsd, .openbsd => return 64,
3172 else => return 128,
3173 },
3174 },
3175
3176 .powerpc64,
3177 .powerpc64le,
3178 => switch (target.abi) {
3179 .musl,
3180 .muslabin32,
3181 .muslabi64,
3182 .musleabi,
3183 .musleabihf,
3184 .muslx32,
3185 => return 64,
3186 else => switch (target.os.tag) {
3187 .freebsd, .openbsd => return 64,
3188 else => return 128,
3189 },
3190 },
3191
3192 .alpha,
3193 .riscv32,
3194 .riscv32be,
3195 .riscv64,
3196 .riscv64be,
3197 .aarch64,
3198 .aarch64_be,
3199 .s390x,
3200 .mips64,
3201 .mips64el,
3202 .sparc64,
3203 .wasm32,
3204 .wasm64,
3205 .loongarch32,
3206 .loongarch64,
3207 .ve,
3208 => return 128,
3209
3210 else => return 64,
3211 },
3212 },
3213 },
3214
3215 .windows, .uefi => switch (target.cpu.arch) {
3216 .x86 => switch (c_type) {
3217 .char => return 8,
3218 .short, .ushort => return 16,
3219 .int, .uint, .float => return 32,
3220 .long, .ulong => return 32,
3221 .longlong, .ulonglong, .double => return 64,
3222 .longdouble => switch (target.abi) {
3223 .gnu, .ilp32 => return 80,
3224 else => return 64,
3225 },
3226 },
3227 .x86_64 => switch (c_type) {
3228 .char => return 8,
3229 .short, .ushort => return 16,
3230 .int, .uint, .float => return 32,
3231 .long, .ulong => return 32,
3232 .longlong, .ulonglong, .double => return 64,
3233 .longdouble => switch (target.abi) {
3234 .gnu, .ilp32 => return 80,
3235 else => return 64,
3236 },
3237 },
3238 else => switch (c_type) {
3239 .char => return 8,
3240 .short, .ushort => return 16,
3241 .int, .uint, .float => return 32,
3242 .long, .ulong => return 32,
3243 .longlong, .ulonglong, .double => return 64,
3244 .longdouble => return 64,
3245 },
3246 },
3247
3248 .driverkit,
3249 .ios,
3250 .maccatalyst,
3251 .macos,
3252 .tvos,
3253 .visionos,
3254 .watchos,
3255 => switch (c_type) {
3256 .char => return 8,
3257 .short, .ushort => return 16,
3258 .int, .uint, .float => return 32,
3259 .long, .ulong => switch (target.cpu.arch) {
3260 .x86_64 => return 64,
3261 else => switch (target.abi) {
3262 .ilp32 => return 32,
3263 else => return 64,
3264 },
3265 },
3266 .longlong, .ulonglong, .double => return 64,
3267 .longdouble => switch (target.cpu.arch) {
3268 .x86_64 => return 80,
3269 else => return 64,
3270 },
3271 },
3272
3273 .nvcl, .cuda => switch (c_type) {
3274 .char => return 8,
3275 .short, .ushort => return 16,
3276 .int, .uint, .float => return 32,
3277 .long, .ulong => switch (target.cpu.arch) {
3278 .nvptx => return 32,
3279 .nvptx64 => return 64,
3280 else => return 64,
3281 },
3282 .longlong, .ulonglong, .double => return 64,
3283 .longdouble => return 64,
3284 },
3285
3286 .amdhsa, .amdpal, .mesa3d => switch (c_type) {
3287 .char => return 8,
3288 .short, .ushort => return 16,
3289 .int, .uint, .float => return 32,
3290 .long, .ulong, .longlong, .ulonglong, .double => return 64,
3291 .longdouble => return 128,
3292 },
3293
3294 .opencl, .vulkan => switch (c_type) {
3295 .char => return 8,
3296 .short, .ushort => return 16,
3297 .int, .uint, .float => return 32,
3298 .long, .ulong, .double => return 64,
3299 .longlong, .ulonglong => return 128,
3300 // Note: The OpenCL specification does not guarantee a particular size for long double,
3301 // but clang uses 128 bits.
3302 .longdouble => return 128,
3303 },
3304
3305 .@"3ds" => switch (c_type) {
3306 .char => return 8,
3307 .short, .ushort => return 16,
3308 .int, .uint, .float, .long, .ulong => return 32,
3309 .longlong, .ulonglong, .double, .longdouble => return 64,
3310 },
3311
3312 .ps4, .ps5 => switch (c_type) {
3313 .char => return 8,
3314 .short, .ushort => return 16,
3315 .int, .uint, .float => return 32,
3316 .long, .ulong => return 64,
3317 .longlong, .ulonglong, .double => return 64,
3318 .longdouble => return 80,
3319 },
3320 .vita => switch (c_type) {
3321 .char => return 8,
3322 .short, .ushort => return 16,
3323 .int, .uint, .float => return 32,
3324 .long, .ulong => return 64,
3325 .longlong, .ulonglong, .double, .longdouble => return 64,
3326 },
3327
3328 .ps3,
3329 .contiki,
3330 .managarm,
3331 .opengl,
3332 => @panic("specify the C integer and float type sizes for this OS"),
3333 }
3334}
3335
3336pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
3337 // Overrides for unusual alignments
3338 switch (target.cpu.arch) {
3339 .avr => return 1,
3340 .x86 => switch (target.os.tag) {
3341 .windows, .uefi => switch (c_type) {
3342 .longlong, .ulonglong, .double => return 8,
3343 .longdouble => switch (target.abi) {
3344 .gnu, .ilp32 => return 4,
3345 else => return 8,
3346 },
3347 else => {},
3348 },
3349 else => {},
3350 },
3351 .m68k => switch (c_type) {
3352 .int, .uint, .long, .ulong => return 2,
3353 else => {},
3354 },
3355 .wasm32, .wasm64 => switch (target.os.tag) {
3356 .emscripten => switch (c_type) {
3357 .longdouble => return 8,
3358 else => {},
3359 },
3360 else => {},
3361 },
3362 else => {},
3363 }
3364
3365 // Next-power-of-two-aligned, up to a maximum.
3366 return @min(
3367 std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
3368 @as(u16, switch (target.cpu.arch) {
3369 .msp430,
3370 .x86_16,
3371 => 2,
3372
3373 .arc,
3374 .arceb,
3375 .csky,
3376 .kalimba,
3377 .microblaze,
3378 .microblazeel,
3379 .or1k,
3380 .propeller,
3381 .sh,
3382 .sheb,
3383 .x86,
3384 .xcore,
3385 .xtensa,
3386 .xtensaeb,
3387 => 4,
3388
3389 .amdgcn,
3390 .arm,
3391 .armeb,
3392 .bpfeb,
3393 .bpfel,
3394 .hexagon,
3395 .hppa,
3396 .lanai,
3397 .m68k,
3398 .mips,
3399 .mipsel,
3400 .nvptx,
3401 .nvptx64,
3402 .s390x,
3403 .sparc,
3404 .thumb,
3405 .thumbeb,
3406 => 8,
3407
3408 .aarch64,
3409 .aarch64_be,
3410 .alpha,
3411 .hppa64,
3412 .kvx,
3413 .loongarch32,
3414 .loongarch64,
3415 .mips64,
3416 .mips64el,
3417 .powerpc,
3418 .powerpcle,
3419 .powerpc64,
3420 .powerpc64le,
3421 .riscv32,
3422 .riscv32be,
3423 .riscv64,
3424 .riscv64be,
3425 .sparc64,
3426 .spirv32,
3427 .spirv64,
3428 .ve,
3429 .wasm32,
3430 .wasm64,
3431 .x86_64,
3432 => 16,
3433
3434 .avr,
3435 => unreachable, // Handled above.
3436 }),
3437 );
3438}
3439
3440pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 {
3441 // Overrides for unusual alignments
3442 switch (target.cpu.arch) {
3443 .arc, .arceb => switch (c_type) {
3444 .longdouble => return 4,
3445 else => {},
3446 },
3447 .avr => return 1,
3448 .x86 => switch (target.os.tag) {
3449 .windows, .uefi => switch (c_type) {
3450 .longdouble => switch (target.abi) {
3451 .gnu, .ilp32 => return 4,
3452 else => return 8,
3453 },
3454 else => {},
3455 },
3456 else => switch (c_type) {
3457 .longdouble => return 4,
3458 else => {},
3459 },
3460 },
3461 .m68k => switch (c_type) {
3462 .int, .uint, .long, .ulong => return 2,
3463 else => {},
3464 },
3465 .wasm32, .wasm64 => switch (target.os.tag) {
3466 .emscripten => switch (c_type) {
3467 .longdouble => return 8,
3468 else => {},
3469 },
3470 else => {},
3471 },
3472 else => {},
3473 }
3474
3475 // Next-power-of-two-aligned, up to a maximum.
3476 return @min(
3477 std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
3478 @as(u16, switch (target.cpu.arch) {
3479 .x86_16, .msp430 => 2,
3480
3481 .arc,
3482 .arceb,
3483 .csky,
3484 .kalimba,
3485 .microblaze,
3486 .microblazeel,
3487 .or1k,
3488 .propeller,
3489 .sh,
3490 .sheb,
3491 .xcore,
3492 .xtensa,
3493 .xtensaeb,
3494 => 4,
3495
3496 .amdgcn,
3497 .arm,
3498 .armeb,
3499 .bpfeb,
3500 .bpfel,
3501 .hexagon,
3502 .hppa,
3503 .lanai,
3504 .m68k,
3505 .mips,
3506 .mipsel,
3507 .nvptx,
3508 .nvptx64,
3509 .s390x,
3510 .sparc,
3511 .thumb,
3512 .thumbeb,
3513 .x86,
3514 => 8,
3515
3516 .aarch64,
3517 .aarch64_be,
3518 .alpha,
3519 .hppa64,
3520 .kvx,
3521 .loongarch32,
3522 .loongarch64,
3523 .mips64,
3524 .mips64el,
3525 .powerpc,
3526 .powerpcle,
3527 .powerpc64,
3528 .powerpc64le,
3529 .riscv32,
3530 .riscv32be,
3531 .riscv64,
3532 .riscv64be,
3533 .sparc64,
3534 .spirv32,
3535 .spirv64,
3536 .ve,
3537 .wasm32,
3538 .wasm64,
3539 .x86_64,
3540 => 16,
3541
3542 .avr,
3543 => unreachable, // Handled above.
3544 }),
3545 );
3546}
3547
3548pub fn cMaxIntAlignment(target: *const Target) u16 {
3549 return switch (target.cpu.arch) {
3550 .avr => 1,
3551
3552 .msp430, .x86_16 => 2,
3553
3554 .arc,
3555 .arceb,
3556 .csky,
3557 .kalimba,
3558 .microblaze,
3559 .microblazeel,
3560 .or1k,
3561 .propeller,
3562 .sh,
3563 .sheb,
3564 .xcore,
3565 => 4,
3566
3567 .arm,
3568 .armeb,
3569 .hexagon,
3570 .hppa,
3571 .lanai,
3572 .loongarch32,
3573 .m68k,
3574 .mips,
3575 .mipsel,
3576 .powerpc,
3577 .powerpcle,
3578 .riscv32,
3579 .riscv32be,
3580 .s390x,
3581 .sparc,
3582 .thumb,
3583 .thumbeb,
3584 .x86,
3585 .xtensa,
3586 .xtensaeb,
3587 => 8,
3588
3589 .aarch64,
3590 .aarch64_be,
3591 .alpha,
3592 .amdgcn,
3593 .bpfel,
3594 .bpfeb,
3595 .hppa64,
3596 .kvx,
3597 .loongarch64,
3598 .mips64,
3599 .mips64el,
3600 .nvptx,
3601 .nvptx64,
3602 .powerpc64,
3603 .powerpc64le,
3604 .riscv64,
3605 .riscv64be,
3606 .sparc64,
3607 .spirv32,
3608 .spirv64,
3609 .ve,
3610 .wasm32,
3611 .wasm64,
3612 .x86_64,
3613 => 16,
3614 };
3615}
3616
3617pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention {
3618 return switch (target.cpu.arch) {
3619 .x86_64 => switch (target.os.tag) {
3620 .windows, .uefi => .{ .x86_64_win = .{} },
3621 else => switch (target.abi) {
3622 .gnuabin32, .muslabin32 => .{ .x86_64_x32 = .{} },
3623 else => .{ .x86_64_sysv = .{} },
3624 },
3625 },
3626 .x86 => switch (target.os.tag) {
3627 .windows, .uefi => .{ .x86_win = .{} },
3628 else => .{ .x86_sysv = .{} },
3629 },
3630 .x86_16 => .{ .x86_16_cdecl = .{} },
3631 .aarch64, .aarch64_be => if (target.os.tag.isDarwin())
3632 .{ .aarch64_aapcs_darwin = .{} }
3633 else switch (target.os.tag) {
3634 .windows => .{ .aarch64_aapcs_win = .{} },
3635 else => .{ .aarch64_aapcs = .{} },
3636 },
3637 .alpha => .{ .alpha_osf = .{} },
3638 .arm, .armeb, .thumb, .thumbeb => switch (target.abi.float()) {
3639 .soft => .{ .arm_aapcs = .{} },
3640 .hard => .{ .arm_aapcs_vfp = .{} },
3641 },
3642 .mips64, .mips64el => switch (target.abi) {
3643 .gnuabin32, .muslabin32 => .{ .mips64_n32 = .{} },
3644 else => .{ .mips64_n64 = .{} },
3645 },
3646 .mips, .mipsel => .{ .mips_o32 = .{} },
3647 .riscv64, .riscv64be => .{ .riscv64_lp64 = .{} },
3648 .riscv32, .riscv32be => .{ .riscv32_ilp32 = .{} },
3649 .sparc64 => .{ .sparc64_sysv = .{} },
3650 .sparc => .{ .sparc_sysv = .{} },
3651 .powerpc64 => if (target.abi.isMusl())
3652 .{ .powerpc64_elf_v2 = .{} }
3653 else
3654 .{ .powerpc64_elf = .{} },
3655 .powerpc64le => .{ .powerpc64_elf_v2 = .{} },
3656 .powerpc, .powerpcle => .{ .powerpc_sysv = .{} },
3657 .wasm32, .wasm64 => .{ .wasm_mvp = .{} },
3658 .arc, .arceb => .{ .arc_sysv = .{} },
3659 .avr => .avr_gnu,
3660 .bpfel, .bpfeb => .{ .bpf_std = .{} },
3661 .csky => .{ .csky_sysv = .{} },
3662 .hexagon => .{ .hexagon_sysv = .{} },
3663 .hppa => .{ .hppa_elf = .{} },
3664 .hppa64 => .{ .hppa64_elf = .{} },
3665 .kalimba => null,
3666 .kvx => switch (target.abi) {
3667 .ilp32 => .{ .kvx_ilp32 = .{} },
3668 else => .{ .kvx_lp64 = .{} },
3669 },
3670 .lanai => .{ .lanai_sysv = .{} },
3671 .loongarch64 => .{ .loongarch64_lp64 = .{} },
3672 .loongarch32 => .{ .loongarch32_ilp32 = .{} },
3673 .m68k => if (target.abi.isGnu() or target.abi.isMusl())
3674 .{ .m68k_gnu = .{} }
3675 else
3676 .{ .m68k_sysv = .{} },
3677 .microblaze, .microblazeel => .{ .microblaze_std = .{} },
3678 .msp430 => .{ .msp430_eabi = .{} },
3679 .or1k => .{ .or1k_sysv = .{} },
3680 .propeller => .{ .propeller_sysv = .{} },
3681 .s390x => .{ .s390x_sysv = .{} },
3682 .sh, .sheb => .{ .sh_gnu = .{} },
3683 .ve => .{ .ve_sysv = .{} },
3684 .xcore => .{ .xcore_xs1 = .{} },
3685 .xtensa, .xtensaeb => .{ .xtensa_call0 = .{} },
3686 .amdgcn => .{ .amdgcn_device = .{} },
3687 .nvptx, .nvptx64 => .nvptx_device,
3688 .spirv32, .spirv64 => .spirv_device,
3689 };
3690}
3691
3692const Target = @This();
3693const std = @import("std.zig");
3694const builtin = @import("builtin");
3695const Allocator = std.mem.Allocator;
3696const assert = std.debug.assert;
3697
3698test {
3699 std.testing.refAllDecls(Cpu.Arch);
3700}