authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-29 01:57:06-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-29 01:57:06-05:00
log76176104001420ea04840f9b31e706289e4ebf11
tree4ba46044adc883630a3452b33f9d70541581d7ae
parent1b41f2d77ea14de27b0655a35a727d664cfc4ca4
parent3cba603eae1a1c8b0338f5584041c73d55682c0a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4550 from ziglang/os-version-ranges

introduce operating system version ranges as part of the target; self-host native dynamic linker detection and native glibc version detection

104 files changed, 3338 insertions(+), 2123 deletions(-)

build.zig+1-1
......@@ -298,7 +298,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
298298 }
299299 dependOnLib(b, exe, ctx.llvm);
300300
301 if (exe.target.getOs() == .linux) {
301 if (exe.target.getOsTag() == .linux) {
302302 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
303303 \\Unable to determine path to libstdc++.a
304304 \\On Fedora, install libstdc++-static and try again.
doc/docgen.zig+42-41
......@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
21const std = @import("std");
2const builtin = std.builtin;
33const io = std.io;
44const fs = std.fs;
55const process = std.process;
......@@ -10,8 +10,8 @@ const testing = std.testing;
1010
1111const max_doc_file_size = 10 * 1024 * 1024;
1212
13const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt();
14const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt();
13const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
14const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
1515const tmp_dir_name = "docgen_tmp";
1616const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1717
......@@ -521,7 +521,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
521521 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", .{code_kind_str});
522522 }
523523
524 var mode = builtin.Mode.Debug;
524 var mode: builtin.Mode = .Debug;
525525 var link_objects = std.ArrayList([]const u8).init(allocator);
526526 defer link_objects.deinit();
527527 var target_str: ?[]const u8 = null;
......@@ -533,9 +533,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
533533 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);
534534 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];
535535 if (mem.eql(u8, end_tag_name, "code_release_fast")) {
536 mode = builtin.Mode.ReleaseFast;
536 mode = .ReleaseFast;
537537 } else if (mem.eql(u8, end_tag_name, "code_release_safe")) {
538 mode = builtin.Mode.ReleaseSafe;
538 mode = .ReleaseSafe;
539539 } else if (mem.eql(u8, end_tag_name, "code_link_object")) {
540540 _ = try eatToken(tokenizer, Token.Id.Separator);
541541 const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
......@@ -1001,30 +1001,30 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
10011001
10021002 for (toc.nodes) |node| {
10031003 switch (node) {
1004 Node.Content => |data| {
1004 .Content => |data| {
10051005 try out.write(data);
10061006 },
1007 Node.Link => |info| {
1007 .Link => |info| {
10081008 if (!toc.urls.contains(info.url)) {
10091009 return parseError(tokenizer, info.token, "url not found: {}", .{info.url});
10101010 }
10111011 try out.print("<a href=\"#{}\">{}</a>", .{ info.url, info.name });
10121012 },
1013 Node.Nav => {
1013 .Nav => {
10141014 try out.write(toc.toc);
10151015 },
1016 Node.Builtin => |tok| {
1016 .Builtin => |tok| {
10171017 try out.write("<pre>");
10181018 try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
10191019 try out.write("</pre>");
10201020 },
1021 Node.HeaderOpen => |info| {
1021 .HeaderOpen => |info| {
10221022 try out.print(
10231023 "<h{} id=\"{}\"><a href=\"#toc-{}\">{}</a> <a class=\"hdr\" href=\"#{}\">§</a></h{}>\n",
10241024 .{ info.n, info.url, info.url, info.name, info.url, info.n },
10251025 );
10261026 },
1027 Node.SeeAlso => |items| {
1027 .SeeAlso => |items| {
10281028 try out.write("<p>See also:</p><ul>\n");
10291029 for (items) |item| {
10301030 const url = try urlize(allocator, item.name);
......@@ -1035,10 +1035,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
10351035 }
10361036 try out.write("</ul>\n");
10371037 },
1038 Node.Syntax => |content_tok| {
1038 .Syntax => |content_tok| {
10391039 try tokenizeAndPrint(tokenizer, out, content_tok);
10401040 },
1041 Node.Code => |code| {
1041 .Code => |code| {
10421042 code_progress_index += 1;
10431043 warn("docgen example code {}/{}...", .{ code_progress_index, tokenizer.code_node_count });
10441044
......@@ -1075,16 +1075,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
10751075 });
10761076 try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", .{code.name});
10771077 switch (code.mode) {
1078 builtin.Mode.Debug => {},
1079 builtin.Mode.ReleaseSafe => {
1078 .Debug => {},
1079 .ReleaseSafe => {
10801080 try build_args.append("--release-safe");
10811081 try out.print(" --release-safe", .{});
10821082 },
1083 builtin.Mode.ReleaseFast => {
1083 .ReleaseFast => {
10841084 try build_args.append("--release-fast");
10851085 try out.print(" --release-fast", .{});
10861086 },
1087 builtin.Mode.ReleaseSmall => {
1087 .ReleaseSmall => {
10881088 try build_args.append("--release-small");
10891089 try out.print(" --release-small", .{});
10901090 },
......@@ -1142,13 +1142,14 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
11421142 try out.print("\n{}</code></pre>\n", .{colored_stderr});
11431143 break :code_block;
11441144 }
1145 const exec_result = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{});
1145 const exec_result = exec(allocator, &env_map, build_args.toSliceConst()) catch
1146 return parseError(tokenizer, code.source_token, "example failed to compile", .{});
11461147
11471148 if (code.target_str) |triple| {
11481149 if (mem.startsWith(u8, triple, "wasm32") or
11491150 mem.startsWith(u8, triple, "riscv64-linux") or
1150 mem.startsWith(u8, triple, "x86_64-linux") and
1151 (builtin.os != .linux or builtin.arch != .x86_64))
1151 (mem.startsWith(u8, triple, "x86_64-linux") and
1152 std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64))
11521153 {
11531154 // skip execution
11541155 try out.print("</code></pre>\n", .{});
......@@ -1207,16 +1208,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
12071208 });
12081209 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
12091210 switch (code.mode) {
1210 builtin.Mode.Debug => {},
1211 builtin.Mode.ReleaseSafe => {
1211 .Debug => {},
1212 .ReleaseSafe => {
12121213 try test_args.append("--release-safe");
12131214 try out.print(" --release-safe", .{});
12141215 },
1215 builtin.Mode.ReleaseFast => {
1216 .ReleaseFast => {
12161217 try test_args.append("--release-fast");
12171218 try out.print(" --release-fast", .{});
12181219 },
1219 builtin.Mode.ReleaseSmall => {
1220 .ReleaseSmall => {
12201221 try test_args.append("--release-small");
12211222 try out.print(" --release-small", .{});
12221223 },
......@@ -1249,16 +1250,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
12491250 });
12501251 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
12511252 switch (code.mode) {
1252 builtin.Mode.Debug => {},
1253 builtin.Mode.ReleaseSafe => {
1253 .Debug => {},
1254 .ReleaseSafe => {
12541255 try test_args.append("--release-safe");
12551256 try out.print(" --release-safe", .{});
12561257 },
1257 builtin.Mode.ReleaseFast => {
1258 .ReleaseFast => {
12581259 try test_args.append("--release-fast");
12591260 try out.print(" --release-fast", .{});
12601261 },
1261 builtin.Mode.ReleaseSmall => {
1262 .ReleaseSmall => {
12621263 try test_args.append("--release-small");
12631264 try out.print(" --release-small", .{});
12641265 },
......@@ -1306,16 +1307,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
13061307 });
13071308 var mode_arg: []const u8 = "";
13081309 switch (code.mode) {
1309 builtin.Mode.Debug => {},
1310 builtin.Mode.ReleaseSafe => {
1310 .Debug => {},
1311 .ReleaseSafe => {
13111312 try test_args.append("--release-safe");
13121313 mode_arg = " --release-safe";
13131314 },
1314 builtin.Mode.ReleaseFast => {
1315 .ReleaseFast => {
13151316 try test_args.append("--release-fast");
13161317 mode_arg = " --release-fast";
13171318 },
1318 builtin.Mode.ReleaseSmall => {
1319 .ReleaseSmall => {
13191320 try test_args.append("--release-small");
13201321 mode_arg = " --release-small";
13211322 },
......@@ -1386,20 +1387,20 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
13861387 }
13871388
13881389 switch (code.mode) {
1389 builtin.Mode.Debug => {},
1390 builtin.Mode.ReleaseSafe => {
1390 .Debug => {},
1391 .ReleaseSafe => {
13911392 try build_args.append("--release-safe");
13921393 if (!code.is_inline) {
13931394 try out.print(" --release-safe", .{});
13941395 }
13951396 },
1396 builtin.Mode.ReleaseFast => {
1397 .ReleaseFast => {
13971398 try build_args.append("--release-fast");
13981399 if (!code.is_inline) {
13991400 try out.print(" --release-fast", .{});
14001401 }
14011402 },
1402 builtin.Mode.ReleaseSmall => {
1403 .ReleaseSmall => {
14031404 try build_args.append("--release-small");
14041405 if (!code.is_inline) {
14051406 try out.print(" --release-small", .{});
......@@ -1461,16 +1462,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
14611462 });
14621463 try out.print("<pre><code class=\"shell\">$ zig build-lib {}.zig", .{code.name});
14631464 switch (code.mode) {
1464 builtin.Mode.Debug => {},
1465 builtin.Mode.ReleaseSafe => {
1465 .Debug => {},
1466 .ReleaseSafe => {
14661467 try test_args.append("--release-safe");
14671468 try out.print(" --release-safe", .{});
14681469 },
1469 builtin.Mode.ReleaseFast => {
1470 .ReleaseFast => {
14701471 try test_args.append("--release-fast");
14711472 try out.print(" --release-fast", .{});
14721473 },
1473 builtin.Mode.ReleaseSmall => {
1474 .ReleaseSmall => {
14741475 try test_args.append("--release-small");
14751476 try out.print(" --release-small", .{});
14761477 },
doc/langref.html.in+15-15
......@@ -965,7 +965,8 @@ const nan = std.math.nan(f128);
965965 but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:</p>
966966 {#code_begin|obj|foo#}
967967 {#code_release_fast#}
968const builtin = @import("builtin");
968const std = @import("std");
969const builtin = std.builtin;
969970const big = @as(f64, 1 << 40);
970971
971972export fn foo_strict(x: f64) f64 {
......@@ -2063,15 +2064,15 @@ test "pointer child type" {
20632064 alignment of the underlying type, it can be omitted from the type:
20642065 </p>
20652066 {#code_begin|test#}
2066const assert = @import("std").debug.assert;
2067const builtin = @import("builtin");
2067const std = @import("std");
2068const assert = std.debug.assert;
20682069
20692070test "variable alignment" {
20702071 var x: i32 = 1234;
20712072 const align_of_i32 = @alignOf(@TypeOf(x));
20722073 assert(@TypeOf(&x) == *i32);
20732074 assert(*i32 == *align(align_of_i32) i32);
2074 if (builtin.arch == builtin.Arch.x86_64) {
2075 if (std.Target.current.cpu.arch == .x86_64) {
20752076 assert((*i32).alignment == 4);
20762077 }
20772078}
......@@ -2474,7 +2475,7 @@ test "default struct initialization fields" {
24742475 </p>
24752476 {#code_begin|test#}
24762477const std = @import("std");
2477const builtin = @import("builtin");
2478const builtin = std.builtin;
24782479const assert = std.debug.assert;
24792480
24802481const Full = packed struct {
......@@ -3204,8 +3205,8 @@ test "separate scopes" {
32043205
32053206 {#header_open|switch#}
32063207 {#code_begin|test|switch#}
3207const assert = @import("std").debug.assert;
3208const builtin = @import("builtin");
3208const std = @import("std");
3209const assert = std.debug.assert;
32093210
32103211test "switch simple" {
32113212 const a: u64 = 10;
......@@ -3249,16 +3250,16 @@ test "switch simple" {
32493250}
32503251
32513252// Switch expressions can be used outside a function:
3252const os_msg = switch (builtin.os) {
3253 builtin.Os.linux => "we found a linux user",
3253const os_msg = switch (std.Target.current.os.tag) {
3254 .linux => "we found a linux user",
32543255 else => "not a linux user",
32553256};
32563257
32573258// Inside a function, switch statements implicitly are compile-time
32583259// evaluated if the target expression is compile-time known.
32593260test "switch inside function" {
3260 switch (builtin.os) {
3261 builtin.Os.fuchsia => {
3261 switch (std.Target.current.os.tag) {
3262 .fuchsia => {
32623263 // On an OS other than fuchsia, block is not even analyzed,
32633264 // so this compile error is not triggered.
32643265 // On fuchsia this compile error would be triggered.
......@@ -7364,8 +7365,6 @@ test "main" {
73647365 the {#syntax#}export{#endsyntax#} keyword used on a function:
73657366 </p>
73667367 {#code_begin|obj#}
7367const builtin = @import("builtin");
7368
73697368comptime {
73707369 @export(internalName, .{ .name = "foo", .linkage = .Strong });
73717370}
......@@ -9397,7 +9396,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
93979396 </p>
93989397 {#code_begin|test|detect_test#}
93999398const std = @import("std");
9400const builtin = @import("builtin");
9399const builtin = std.builtin;
94019400const assert = std.debug.assert;
94029401
94039402test "builtin.is_test" {
......@@ -9715,7 +9714,8 @@ WebAssembly.instantiate(typedArray, {
97159714 <pre><code>$ node test.js
97169715The result is 3</code></pre>
97179716 {#header_open|WASI#}
9718 <p>Zig's support for WebAssembly System Interface (WASI) is under active development. Example of using the standard library and reading command line arguments:</p>
9717 <p>Zig's support for WebAssembly System Interface (WASI) is under active development.
9718 Example of using the standard library and reading command line arguments:</p>
97199719 {#code_begin|exe|wasi#}
97209720 {#target_wasi#}
97219721const std = @import("std");
lib/std/build.zig+133-106
......@@ -1,5 +1,5 @@
11const std = @import("std.zig");
2const builtin = @import("builtin");
2const builtin = std.builtin;
33const io = std.io;
44const fs = std.fs;
55const mem = std.mem;
......@@ -15,6 +15,7 @@ const BufSet = std.BufSet;
1515const BufMap = std.BufMap;
1616const fmt_lib = std.fmt;
1717const File = std.fs.File;
18const CrossTarget = std.zig.CrossTarget;
1819
1920pub const FmtStep = @import("build/fmt.zig").FmtStep;
2021pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
......@@ -521,24 +522,91 @@ pub const Builder = struct {
521522 return mode;
522523 }
523524
524 /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.
525 pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {
526 if (supported_targets) |target_list| {
527 // TODO detect multiple args and emit an error message
528 // there's probably a better way to collect the target
529 for (target_list) |targ| {
530 const targ_str = targ.zigTriple(self.allocator) catch unreachable;
531 const targ_desc = targ.allocDescription(self.allocator) catch unreachable;
532 const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;
533 if (this_targ_opt) {
534 return targ;
525 pub const StandardTargetOptionsArgs = struct {
526 whitelist: ?[]const CrossTarget = null,
527
528 default_target: CrossTarget = CrossTarget{},
529 };
530
531 /// Exposes standard `zig build` options for choosing a target.
532 pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
533 const triple = self.option(
534 []const u8,
535 "target",
536 "The CPU architecture, OS, and ABI to build for.",
537 ) orelse return args.default_target;
538
539 // TODO add cpu and features as part of the target triple
540
541 var diags: CrossTarget.ParseOptions.Diagnostics = .{};
542 const selected_target = CrossTarget.parse(.{
543 .arch_os_abi = triple,
544 .diagnostics = &diags,
545 }) catch |err| switch (err) {
546 error.UnknownCpuModel => {
547 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
548 diags.cpu_name.?,
549 @tagName(diags.arch.?),
550 });
551 for (diags.arch.?.allCpuModels()) |cpu| {
552 std.debug.warn(" {}\n", .{cpu.name});
553 }
554 process.exit(1);
555 },
556 error.UnknownCpuFeature => {
557 std.debug.warn(
558 \\Unknown CPU feature: '{}'
559 \\Available CPU features for architecture '{}':
560 \\
561 , .{
562 diags.unknown_feature_name,
563 @tagName(diags.arch.?),
564 });
565 for (diags.arch.?.allFeaturesList()) |feature| {
566 std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
567 }
568 process.exit(1);
569 },
570 error.UnknownOperatingSystem => {
571 std.debug.warn(
572 \\Unknown OS: '{}'
573 \\Available operating systems:
574 \\
575 , .{diags.os_name});
576 inline for (std.meta.fields(std.Target.Os.Tag)) |field| {
577 std.debug.warn(" {}\n", .{field.name});
578 }
579 process.exit(1);
580 },
581 else => |e| {
582 std.debug.warn("Unable to parse target '{}': {}\n", .{ triple, @errorName(e) });
583 process.exit(1);
584 },
585 };
586
587 const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable;
588
589 if (args.whitelist) |list| whitelist_check: {
590 // Make sure it's a match of one of the list.
591 for (list) |t| {
592 const t_triple = t.zigTriple(self.allocator) catch unreachable;
593 if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
594 break :whitelist_check;
535595 }
536596 }
537 return Target.Native;
538 } else {
539 const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;
540 return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target
597 std.debug.warn("Chosen target '{}' does not match one of the supported targets:\n", .{
598 selected_canonicalized_triple,
599 });
600 for (list) |t| {
601 const t_triple = t.zigTriple(self.allocator) catch unreachable;
602 std.debug.warn(" {}\n", .{t_triple});
603 }
604 // TODO instead of process exit, return error and have a zig build flag implemented by
605 // the build runner that turns process exits into error return traces
606 process.exit(1);
541607 }
608
609 return selected_target;
542610 }
543611
544612 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
......@@ -796,7 +864,7 @@ pub const Builder = struct {
796864
797865 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
798866 // TODO report error for ambiguous situations
799 const exe_extension = (Target{ .Native = {} }).exeFileExt();
867 const exe_extension = @as(CrossTarget, .{}).exeFileExt();
800868 for (self.search_prefixes.toSliceConst()) |search_prefix| {
801869 for (names) |name| {
802870 if (fs.path.isAbsolute(name)) {
......@@ -971,21 +1039,19 @@ pub const Builder = struct {
9711039};
9721040
9731041test "builder.findProgram compiles" {
974 // TODO: uncomment and fix the leak
975 // const builder = try Builder.create(std.testing.allocator, "zig", "zig-cache", "zig-cache");
976 const builder = try Builder.create(std.heap.page_allocator, "zig", "zig-cache", "zig-cache");
1042 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1043 defer arena.deinit();
1044
1045 const builder = try Builder.create(&arena.allocator, "zig", "zig-cache", "zig-cache");
9771046 defer builder.destroy();
9781047 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
9791048}
9801049
981/// Deprecated. Use `builtin.Version`.
1050/// Deprecated. Use `std.builtin.Version`.
9821051pub const Version = builtin.Version;
9831052
984/// Deprecated. Use `std.Target.Cross`.
985pub const CrossTarget = std.Target.Cross;
986
987/// Deprecated. Use `std.Target`.
988pub const Target = std.Target;
1053/// Deprecated. Use `std.zig.CrossTarget`.
1054pub const Target = std.zig.CrossTarget;
9891055
9901056pub const Pkg = struct {
9911057 name: []const u8,
......@@ -1038,7 +1104,7 @@ pub const LibExeObjStep = struct {
10381104 step: Step,
10391105 builder: *Builder,
10401106 name: []const u8,
1041 target: Target,
1107 target: CrossTarget = CrossTarget{},
10421108 linker_script: ?[]const u8 = null,
10431109 version_script: ?[]const u8 = null,
10441110 out_filename: []const u8,
......@@ -1076,7 +1142,7 @@ pub const LibExeObjStep = struct {
10761142 out_pdb_filename: []const u8,
10771143 packages: ArrayList(Pkg),
10781144 build_options_contents: std.Buffer,
1079 system_linker_hack: bool,
1145 system_linker_hack: bool = false,
10801146
10811147 object_src: []const u8,
10821148
......@@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct {
10911157 install_step: ?*InstallArtifactStep,
10921158
10931159 libc_file: ?[]const u8 = null,
1094 target_glibc: ?Version = null,
10951160
10961161 valgrind_support: ?bool = null,
10971162
......@@ -1112,8 +1177,6 @@ pub const LibExeObjStep = struct {
11121177 /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
11131178 glibc_multi_install_dir: ?[]const u8 = null,
11141179
1115 dynamic_linker: ?[]const u8 = null,
1116
11171180 /// Position Independent Code
11181181 force_pic: ?bool = null,
11191182
......@@ -1191,7 +1254,6 @@ pub const LibExeObjStep = struct {
11911254 .kind = kind,
11921255 .root_src = root_src,
11931256 .name = name,
1194 .target = Target.Native,
11951257 .frameworks = BufSet.init(builder.allocator),
11961258 .step = Step.init(name, builder.allocator, make),
11971259 .version = ver,
......@@ -1210,7 +1272,6 @@ pub const LibExeObjStep = struct {
12101272 .object_src = undefined,
12111273 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
12121274 .c_std = Builder.CStd.C99,
1213 .system_linker_hack = false,
12141275 .override_lib_dir = null,
12151276 .main_pkg_path = null,
12161277 .exec_cmd_args = null,
......@@ -1282,36 +1343,11 @@ pub const LibExeObjStep = struct {
12821343 }
12831344 }
12841345
1285 /// Deprecated. Use `setTheTarget`.
1286 pub fn setTarget(
1287 self: *LibExeObjStep,
1288 target_arch: builtin.Arch,
1289 target_os: builtin.Os,
1290 target_abi: builtin.Abi,
1291 ) void {
1292 return self.setTheTarget(Target{
1293 .Cross = CrossTarget{
1294 .arch = target_arch,
1295 .os = target_os,
1296 .abi = target_abi,
1297 .cpu_features = target_arch.getBaselineCpuFeatures(),
1298 },
1299 });
1300 }
1301
1302 pub fn setTheTarget(self: *LibExeObjStep, target: Target) void {
1346 pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void {
13031347 self.target = target;
13041348 self.computeOutFileNames();
13051349 }
13061350
1307 pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
1308 self.target_glibc = Version{
1309 .major = major,
1310 .minor = minor,
1311 .patch = patch,
1312 };
1313 }
1314
13151351 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
13161352 self.output_dir = self.builder.dupePath(dir);
13171353 }
......@@ -1692,7 +1728,7 @@ pub const LibExeObjStep = struct {
16921728 .NotFound => return error.VcpkgNotFound,
16931729 .Found => |root| {
16941730 const allocator = self.builder.allocator;
1695 const triplet = try Target.vcpkgTriplet(allocator, self.target, linkage);
1731 const triplet = try self.target.vcpkgTriplet(allocator, linkage);
16961732 defer self.builder.allocator.free(triplet);
16971733
16981734 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });
......@@ -1905,47 +1941,46 @@ pub const LibExeObjStep = struct {
19051941 try zig_args.append(@tagName(self.code_model));
19061942 }
19071943
1908 switch (self.target) {
1909 .Native => {},
1910 .Cross => |cross| {
1911 try zig_args.append("-target");
1912 try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
1944 if (!self.target.isNative()) {
1945 try zig_args.append("-target");
1946 try zig_args.append(try self.target.zigTriple(builder.allocator));
19131947
1914 const all_features = self.target.getArch().allFeaturesList();
1915 var populated_cpu_features = cross.cpu.model.features;
1916 populated_cpu_features.populateDependencies(all_features);
1948 // TODO this logic can disappear if cpu model + features becomes part of the target triple
1949 const cross = self.target.toTarget();
1950 const all_features = cross.cpu.arch.allFeaturesList();
1951 var populated_cpu_features = cross.cpu.model.features;
1952 populated_cpu_features.populateDependencies(all_features);
19171953
1918 if (populated_cpu_features.eql(cross.cpu.features)) {
1919 // The CPU name alone is sufficient.
1920 // If it is the baseline CPU, no command line args are required.
1921 if (cross.cpu.model != Target.Cpu.baseline(self.target.getArch()).model) {
1922 try zig_args.append("-mcpu");
1923 try zig_args.append(cross.cpu.model.name);
1924 }
1925 } else {
1926 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
1927 try mcpu_buffer.append(cross.cpu.model.name);
1928
1929 for (all_features) |feature, i_usize| {
1930 const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
1931 const in_cpu_set = populated_cpu_features.isEnabled(i);
1932 const in_actual_set = cross.cpu.features.isEnabled(i);
1933 if (in_cpu_set and !in_actual_set) {
1934 try mcpu_buffer.appendByte('-');
1935 try mcpu_buffer.append(feature.name);
1936 } else if (!in_cpu_set and in_actual_set) {
1937 try mcpu_buffer.appendByte('+');
1938 try mcpu_buffer.append(feature.name);
1939 }
1954 if (populated_cpu_features.eql(cross.cpu.features)) {
1955 // The CPU name alone is sufficient.
1956 // If it is the baseline CPU, no command line args are required.
1957 if (cross.cpu.model != std.Target.Cpu.baseline(cross.cpu.arch).model) {
1958 try zig_args.append("-mcpu");
1959 try zig_args.append(cross.cpu.model.name);
1960 }
1961 } else {
1962 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
1963 try mcpu_buffer.append(cross.cpu.model.name);
1964
1965 for (all_features) |feature, i_usize| {
1966 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
1967 const in_cpu_set = populated_cpu_features.isEnabled(i);
1968 const in_actual_set = cross.cpu.features.isEnabled(i);
1969 if (in_cpu_set and !in_actual_set) {
1970 try mcpu_buffer.appendByte('-');
1971 try mcpu_buffer.append(feature.name);
1972 } else if (!in_cpu_set and in_actual_set) {
1973 try mcpu_buffer.appendByte('+');
1974 try mcpu_buffer.append(feature.name);
19401975 }
1941 try zig_args.append(mcpu_buffer.toSliceConst());
19421976 }
1943 },
1944 }
1977 try zig_args.append(mcpu_buffer.toSliceConst());
1978 }
19451979
1946 if (self.target_glibc) |ver| {
1947 try zig_args.append("-target-glibc");
1948 try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));
1980 if (self.target.dynamic_linker.get()) |dynamic_linker| {
1981 try zig_args.append("--dynamic-linker");
1982 try zig_args.append(dynamic_linker);
1983 }
19491984 }
19501985
19511986 if (self.linker_script) |linker_script| {
......@@ -1953,11 +1988,6 @@ pub const LibExeObjStep = struct {
19531988 zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
19541989 }
19551990
1956 if (self.dynamic_linker) |dynamic_linker| {
1957 try zig_args.append("--dynamic-linker");
1958 try zig_args.append(dynamic_linker);
1959 }
1960
19611991 if (self.version_script) |version_script| {
19621992 try zig_args.append("--version-script");
19631993 try zig_args.append(builder.pathFromRoot(version_script));
......@@ -1975,7 +2005,7 @@ pub const LibExeObjStep = struct {
19752005 } else switch (self.target.getExternalExecutor()) {
19762006 .native, .unavailable => {},
19772007 .qemu => |bin_name| if (self.enable_qemu) qemu: {
1978 const need_cross_glibc = self.target.isGnu() and self.target.isLinux() and self.is_linking_libc;
2008 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
19792009 const glibc_dir_arg = if (need_cross_glibc)
19802010 self.glibc_multi_install_dir orelse break :qemu
19812011 else
......@@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum {
24202450 Found,
24212451};
24222452
2423pub const VcpkgLinkage = enum {
2424 Static,
2425 Dynamic,
2426};
2453pub const VcpkgLinkage = std.builtin.LinkMode;
24272454
24282455pub const InstallDir = enum {
24292456 Prefix,
lib/std/build/run.zig+1-1
......@@ -82,7 +82,7 @@ pub const RunStep = struct {
8282
8383 var key: []const u8 = undefined;
8484 var prev_path: ?[]const u8 = undefined;
85 if (builtin.os == .windows) {
85 if (builtin.os.tag == .windows) {
8686 key = "Path";
8787 prev_path = env_map.get(key);
8888 if (prev_path == null) {
lib/std/build/translate_c.zig+6-8
......@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;
77const CheckFileStep = build.CheckFileStep;
88const fs = std.fs;
99const mem = std.mem;
10const CrossTarget = std.zig.CrossTarget;
1011
1112pub const TranslateCStep = struct {
1213 step: Step,
......@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {
1415 source: build.FileSource,
1516 output_dir: ?[]const u8,
1617 out_basename: []const u8,
17 target: std.Target = .Native,
18 target: CrossTarget = CrossTarget{},
1819
1920 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
2021 const self = builder.allocator.create(TranslateCStep) catch unreachable;
......@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {
3940 ) catch unreachable;
4041 }
4142
42 pub fn setTarget(self: *TranslateCStep, target: std.Target) void {
43 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
4344 self.target = target;
4445 }
4546
......@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {
6364 try argv_list.append("--cache");
6465 try argv_list.append("on");
6566
66 switch (self.target) {
67 .Native => {},
68 .Cross => {
69 try argv_list.append("-target");
70 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
71 },
67 if (!self.target.isNative()) {
68 try argv_list.append("-target");
69 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
7270 }
7371
7472 try argv_list.append(self.source.getPath(self.builder));
lib/std/builtin.zig+55-2
......@@ -398,7 +398,60 @@ pub const LinkMode = enum {
398398pub const Version = struct {
399399 major: u32,
400400 minor: u32,
401 patch: u32,
401 patch: u32 = 0,
402
403 pub const Range = struct {
404 min: Version,
405 max: Version,
406
407 pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
408 if (self.min.compare(ver) == .gt) return false;
409 if (self.max.compare(ver) == .lt) return false;
410 return true;
411 }
412 };
413
414 pub fn order(lhs: Version, rhs: Version) std.math.Order {
415 if (lhs.major < rhs.major) return .lt;
416 if (lhs.major > rhs.major) return .gt;
417 if (lhs.minor < rhs.minor) return .lt;
418 if (lhs.minor > rhs.minor) return .gt;
419 if (lhs.patch < rhs.patch) return .lt;
420 if (lhs.patch > rhs.patch) return .gt;
421 return .eq;
422 }
423
424 pub fn parse(text: []const u8) !Version {
425 var it = std.mem.separate(text, ".");
426 return Version{
427 .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
428 .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
429 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
430 };
431 }
432
433 pub fn format(
434 self: Version,
435 comptime fmt: []const u8,
436 options: std.fmt.FormatOptions,
437 context: var,
438 comptime Error: type,
439 comptime output: fn (@TypeOf(context), []const u8) Error!void,
440 ) Error!void {
441 if (fmt.len == 0) {
442 if (self.patch == 0) {
443 if (self.minor == 0) {
444 return std.fmt.format(context, Error, output, "{}", .{self.major});
445 } else {
446 return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
447 }
448 } else {
449 return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
450 }
451 } else {
452 @compileError("Unknown format string: '" ++ fmt ++ "'");
453 }
454 }
402455};
403456
404457/// This data structure is used by the Zig language code generation and
......@@ -474,7 +527,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
474527 root.os.panic(msg, error_return_trace);
475528 unreachable;
476529 }
477 switch (os) {
530 switch (os.tag) {
478531 .freestanding => {
479532 while (true) {
480533 @breakpoint();
lib/std/c.zig+14-13
......@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
21const std = @import("std");
2const builtin = std.builtin;
33const page_size = std.mem.page_size;
44
55pub const tokenizer = @import("c/tokenizer.zig");
......@@ -10,7 +10,7 @@ pub const ast = @import("c/ast.zig");
1010
1111pub usingnamespace @import("os/bits.zig");
1212
13pub usingnamespace switch (builtin.os) {
13pub usingnamespace switch (std.Target.current.os.tag) {
1414 .linux => @import("c/linux.zig"),
1515 .windows => @import("c/windows.zig"),
1616 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
......@@ -46,17 +46,16 @@ pub fn versionCheck(glibc_version: builtin.Version) type {
4646 return struct {
4747 pub const ok = blk: {
4848 if (!builtin.link_libc) break :blk false;
49 switch (builtin.abi) {
50 .musl, .musleabi, .musleabihf => break :blk true,
51 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => {
52 const ver = builtin.glibc_version orelse break :blk false;
53 if (ver.major < glibc_version.major) break :blk false;
54 if (ver.major > glibc_version.major) break :blk true;
55 if (ver.minor < glibc_version.minor) break :blk false;
56 if (ver.minor > glibc_version.minor) break :blk true;
57 break :blk ver.patch >= glibc_version.patch;
58 },
59 else => break :blk false,
49 if (std.Target.current.abi.isMusl()) break :blk true;
50 if (std.Target.current.isGnuLibC()) {
51 const ver = std.Target.current.os.version_range.linux.glibc;
52 const order = ver.order(glibc_version);
53 break :blk switch (order) {
54 .gt, .eq => true,
55 .lt => false,
56 };
57 } else {
58 break :blk false;
6059 }
6160 };
6261 };
......@@ -109,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8
109108pub extern "c" fn dup(fd: fd_t) c_int;
110109pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
111110pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
111pub extern "c" fn readlinkat(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
112112pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
113113pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
114114pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
......@@ -125,6 +125,7 @@ pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*u
125125pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;
126126pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;
127127pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;
128pub extern "c" fn uname(buf: *utsname) c_int;
128129
129130pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
130131pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;
lib/std/c/linux.zig+1-1
......@@ -94,7 +94,7 @@ pub const pthread_cond_t = extern struct {
9494 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
9595};
9696const __SIZEOF_PTHREAD_COND_T = 48;
97const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) {
97const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) {
9898 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
9999 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
100100 .aarch64 => 48,
lib/std/child_process.zig+13-13
......@@ -17,9 +17,9 @@ const TailQueue = std.TailQueue;
1717const maxInt = std.math.maxInt;
1818
1919pub const ChildProcess = struct {
20 pid: if (builtin.os == .windows) void else i32,
21 handle: if (builtin.os == .windows) windows.HANDLE else void,
22 thread_handle: if (builtin.os == .windows) windows.HANDLE else void,
20 pid: if (builtin.os.tag == .windows) void else i32,
21 handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
22 thread_handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
2323
2424 allocator: *mem.Allocator,
2525
......@@ -39,15 +39,15 @@ pub const ChildProcess = struct {
3939 stderr_behavior: StdIo,
4040
4141 /// Set to change the user id when spawning the child process.
42 uid: if (builtin.os == .windows) void else ?u32,
42 uid: if (builtin.os.tag == .windows) void else ?u32,
4343
4444 /// Set to change the group id when spawning the child process.
45 gid: if (builtin.os == .windows) void else ?u32,
45 gid: if (builtin.os.tag == .windows) void else ?u32,
4646
4747 /// Set to change the current working directory when spawning the child process.
4848 cwd: ?[]const u8,
4949
50 err_pipe: if (builtin.os == .windows) void else [2]os.fd_t,
50 err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t,
5151
5252 expand_arg0: Arg0Expand,
5353
......@@ -96,8 +96,8 @@ pub const ChildProcess = struct {
9696 .term = null,
9797 .env_map = null,
9898 .cwd = null,
99 .uid = if (builtin.os == .windows) {} else null,
100 .gid = if (builtin.os == .windows) {} else null,
99 .uid = if (builtin.os.tag == .windows) {} else null,
100 .gid = if (builtin.os.tag == .windows) {} else null,
101101 .stdin = null,
102102 .stdout = null,
103103 .stderr = null,
......@@ -118,7 +118,7 @@ pub const ChildProcess = struct {
118118
119119 /// On success must call `kill` or `wait`.
120120 pub fn spawn(self: *ChildProcess) SpawnError!void {
121 if (builtin.os == .windows) {
121 if (builtin.os.tag == .windows) {
122122 return self.spawnWindows();
123123 } else {
124124 return self.spawnPosix();
......@@ -132,7 +132,7 @@ pub const ChildProcess = struct {
132132
133133 /// Forcibly terminates child process and then cleans up all resources.
134134 pub fn kill(self: *ChildProcess) !Term {
135 if (builtin.os == .windows) {
135 if (builtin.os.tag == .windows) {
136136 return self.killWindows(1);
137137 } else {
138138 return self.killPosix();
......@@ -162,7 +162,7 @@ pub const ChildProcess = struct {
162162
163163 /// Blocks until child process terminates and then cleans up all resources.
164164 pub fn wait(self: *ChildProcess) !Term {
165 if (builtin.os == .windows) {
165 if (builtin.os.tag == .windows) {
166166 return self.waitWindows();
167167 } else {
168168 return self.waitPosix();
......@@ -307,7 +307,7 @@ pub const ChildProcess = struct {
307307 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
308308 defer destroyPipe(self.err_pipe);
309309
310 if (builtin.os == .linux) {
310 if (builtin.os.tag == .linux) {
311311 var fd = [1]std.os.pollfd{std.os.pollfd{
312312 .fd = self.err_pipe[0],
313313 .events = std.os.POLLIN,
......@@ -402,7 +402,7 @@ pub const ChildProcess = struct {
402402 // This pipe is used to communicate errors between the time of fork
403403 // and execve from the child process to the parent process.
404404 const err_pipe = blk: {
405 if (builtin.os == .linux) {
405 if (builtin.os.tag == .linux) {
406406 const fd = try os.eventfd(0, 0);
407407 // There's no distinction between the readable and the writeable
408408 // end with eventfd
lib/std/cstr.zig+2-2
......@@ -4,8 +4,8 @@ const debug = std.debug;
44const mem = std.mem;
55const testing = std.testing;
66
7pub const line_sep = switch (builtin.os) {
8 builtin.Os.windows => "\r\n",
7pub const line_sep = switch (builtin.os.tag) {
8 .windows => "\r\n",
99 else => "\n",
1010};
1111
lib/std/debug.zig+12-12
......@@ -1,4 +1,5 @@
11const std = @import("std.zig");
2const builtin = std.builtin;
23const math = std.math;
34const mem = std.mem;
45const io = std.io;
......@@ -11,7 +12,6 @@ const macho = std.macho;
1112const coff = std.coff;
1213const pdb = std.pdb;
1314const ArrayList = std.ArrayList;
14const builtin = @import("builtin");
1515const root = @import("root");
1616const maxInt = std.math.maxInt;
1717const File = std.fs.File;
......@@ -101,7 +101,7 @@ pub fn detectTTYConfig() TTY.Config {
101101 } else |_| {
102102 if (stderr_file.supportsAnsiEscapeCodes()) {
103103 return .escape_codes;
104 } else if (builtin.os == .windows and stderr_file.isTty()) {
104 } else if (builtin.os.tag == .windows and stderr_file.isTty()) {
105105 return .windows_api;
106106 } else {
107107 return .no_color;
......@@ -155,7 +155,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
155155/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
156156/// equals the passed in addresses pointer.
157157pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
158 if (builtin.os == .windows) {
158 if (builtin.os.tag == .windows) {
159159 const addrs = stack_trace.instruction_addresses;
160160 const u32_addrs_len = @intCast(u32, addrs.len);
161161 const first_addr = first_address orelse {
......@@ -231,7 +231,7 @@ pub fn assert(ok: bool) void {
231231pub fn panic(comptime format: []const u8, args: var) noreturn {
232232 @setCold(true);
233233 // TODO: remove conditional once wasi / LLVM defines __builtin_return_address
234 const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress();
234 const first_trace_addr = if (builtin.os.tag == .wasi) null else @returnAddress();
235235 panicExtra(null, first_trace_addr, format, args);
236236}
237237
......@@ -361,7 +361,7 @@ pub fn writeCurrentStackTrace(
361361 tty_config: TTY.Config,
362362 start_addr: ?usize,
363363) !void {
364 if (builtin.os == .windows) {
364 if (builtin.os.tag == .windows) {
365365 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
366366 }
367367 var it = StackIterator.init(start_addr, null);
......@@ -418,7 +418,7 @@ pub const TTY = struct {
418418 .Dim => noasync out_stream.write(DIM) catch return,
419419 .Reset => noasync out_stream.write(RESET) catch return,
420420 },
421 .windows_api => if (builtin.os == .windows) {
421 .windows_api => if (builtin.os.tag == .windows) {
422422 const S = struct {
423423 var attrs: windows.WORD = undefined;
424424 var init_attrs = false;
......@@ -617,7 +617,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
617617 if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
618618 return noasync root.os.debug.openSelfDebugInfo(allocator);
619619 }
620 switch (builtin.os) {
620 switch (builtin.os.tag) {
621621 .linux,
622622 .freebsd,
623623 .macosx,
......@@ -1019,7 +1019,7 @@ pub const DebugInfo = struct {
10191019 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
10201020 if (comptime std.Target.current.isDarwin())
10211021 return self.lookupModuleDyld(address)
1022 else if (builtin.os == .windows)
1022 else if (builtin.os.tag == .windows)
10231023 return self.lookupModuleWin32(address)
10241024 else
10251025 return self.lookupModuleDl(address);
......@@ -1242,7 +1242,7 @@ const SymbolInfo = struct {
12421242 }
12431243};
12441244
1245pub const ModuleDebugInfo = switch (builtin.os) {
1245pub const ModuleDebugInfo = switch (builtin.os.tag) {
12461246 .macosx, .ios, .watchos, .tvos => struct {
12471247 base_address: usize,
12481248 mapped_memory: []const u8,
......@@ -1602,7 +1602,7 @@ fn getDebugInfoAllocator() *mem.Allocator {
16021602}
16031603
16041604/// Whether or not the current target can print useful debug information when a segfault occurs.
1605pub const have_segfault_handling_support = builtin.os == .linux or builtin.os == .windows;
1605pub const have_segfault_handling_support = builtin.os.tag == .linux or builtin.os.tag == .windows;
16061606pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
16071607 root.enable_segfault_handler
16081608else
......@@ -1621,7 +1621,7 @@ pub fn attachSegfaultHandler() void {
16211621 if (!have_segfault_handling_support) {
16221622 @compileError("segfault handler not supported for this target");
16231623 }
1624 if (builtin.os == .windows) {
1624 if (builtin.os.tag == .windows) {
16251625 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
16261626 return;
16271627 }
......@@ -1637,7 +1637,7 @@ pub fn attachSegfaultHandler() void {
16371637}
16381638
16391639fn resetSegfaultHandler() void {
1640 if (builtin.os == .windows) {
1640 if (builtin.os.tag == .windows) {
16411641 if (windows_segfault_handle) |handle| {
16421642 assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
16431643 windows_segfault_handle = null;
lib/std/dynamic_library.zig+4-4
......@@ -11,7 +11,7 @@ const system = std.os.system;
1111const maxInt = std.math.maxInt;
1212const max = std.math.max;
1313
14pub const DynLib = switch (builtin.os) {
14pub const DynLib = switch (builtin.os.tag) {
1515 .linux => if (builtin.link_libc) DlDynlib else ElfDynLib,
1616 .windows => WindowsDynLib,
1717 .macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib,
......@@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
8282 for (dyn_table) |*dyn| {
8383 switch (dyn.d_tag) {
8484 elf.DT_DEBUG => {
85 const r_debug = @intToPtr(*RDebug, dyn.d_un.d_ptr);
85 const r_debug = @intToPtr(*RDebug, dyn.d_val);
8686 if (r_debug.r_version != 1) return error.InvalidExe;
8787 break :init r_debug.r_map;
8888 },
8989 elf.DT_PLTGOT => {
90 const got_table = @intToPtr([*]usize, dyn.d_un.d_ptr);
90 const got_table = @intToPtr([*]usize, dyn.d_val);
9191 // The address to the link_map structure is stored in the
9292 // second slot
9393 break :init @intToPtr(?*LinkMap, got_table[1]);
......@@ -390,7 +390,7 @@ pub const DlDynlib = struct {
390390};
391391
392392test "dynamic_library" {
393 const libname = switch (builtin.os) {
393 const libname = switch (builtin.os.tag) {
394394 .linux, .freebsd => "invalid_so.so",
395395 .windows => "invalid_dll.dll",
396396 .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib",
lib/std/elf.zig+17-18
......@@ -349,16 +349,6 @@ pub const Elf = struct {
349349 program_headers: []ProgramHeader,
350350 allocator: *mem.Allocator,
351351
352 /// Call close when done.
353 pub fn openPath(allocator: *mem.Allocator, path: []const u8) !Elf {
354 @compileError("TODO implement");
355 }
356
357 /// Call close when done.
358 pub fn openFile(allocator: *mem.Allocator, file: File) !Elf {
359 @compileError("TODO implement");
360 }
361
362352 pub fn openStream(
363353 allocator: *mem.Allocator,
364354 seekable_stream: *io.SeekableStream(anyerror, anyerror),
......@@ -554,6 +544,21 @@ pub const Elf = struct {
554544};
555545
556546pub const EI_NIDENT = 16;
547
548pub const EI_CLASS = 4;
549pub const ELFCLASSNONE = 0;
550pub const ELFCLASS32 = 1;
551pub const ELFCLASS64 = 2;
552pub const ELFCLASSNUM = 3;
553
554pub const EI_DATA = 5;
555pub const ELFDATANONE = 0;
556pub const ELFDATA2LSB = 1;
557pub const ELFDATA2MSB = 2;
558pub const ELFDATANUM = 3;
559
560pub const EI_VERSION = 6;
561
557562pub const Elf32_Half = u16;
558563pub const Elf64_Half = u16;
559564pub const Elf32_Word = u32;
......@@ -703,17 +708,11 @@ pub const Elf64_Rela = extern struct {
703708};
704709pub const Elf32_Dyn = extern struct {
705710 d_tag: Elf32_Sword,
706 d_un: extern union {
707 d_val: Elf32_Word,
708 d_ptr: Elf32_Addr,
709 },
711 d_val: Elf32_Addr,
710712};
711713pub const Elf64_Dyn = extern struct {
712714 d_tag: Elf64_Sxword,
713 d_un: extern union {
714 d_val: Elf64_Xword,
715 d_ptr: Elf64_Addr,
716 },
715 d_val: Elf64_Addr,
717716};
718717pub const Elf32_Verdef = extern struct {
719718 vd_version: Elf32_Half,
lib/std/event/channel.zig+1-1
......@@ -273,7 +273,7 @@ test "std.event.Channel" {
273273 if (builtin.single_threaded) return error.SkipZigTest;
274274
275275 // https://github.com/ziglang/zig/issues/3251
276 if (builtin.os == .freebsd) return error.SkipZigTest;
276 if (builtin.os.tag == .freebsd) return error.SkipZigTest;
277277
278278 var channel: Channel(i32) = undefined;
279279 channel.init(&[0]i32{});
lib/std/event/future.zig+1-1
......@@ -86,7 +86,7 @@ test "std.event.Future" {
8686 // https://github.com/ziglang/zig/issues/1908
8787 if (builtin.single_threaded) return error.SkipZigTest;
8888 // https://github.com/ziglang/zig/issues/3251
89 if (builtin.os == .freebsd) return error.SkipZigTest;
89 if (builtin.os.tag == .freebsd) return error.SkipZigTest;
9090 // TODO provide a way to run tests in evented I/O mode
9191 if (!std.io.is_async) return error.SkipZigTest;
9292
lib/std/event/lock.zig+1-1
......@@ -123,7 +123,7 @@ test "std.event.Lock" {
123123 if (builtin.single_threaded) return error.SkipZigTest;
124124
125125 // TODO https://github.com/ziglang/zig/issues/3251
126 if (builtin.os == .freebsd) return error.SkipZigTest;
126 if (builtin.os.tag == .freebsd) return error.SkipZigTest;
127127
128128 var lock = Lock.init();
129129 defer lock.deinit();
lib/std/event/loop.zig+13-13
......@@ -34,7 +34,7 @@ pub const Loop = struct {
3434 handle: anyframe,
3535 overlapped: Overlapped,
3636
37 pub const overlapped_init = switch (builtin.os) {
37 pub const overlapped_init = switch (builtin.os.tag) {
3838 .windows => windows.OVERLAPPED{
3939 .Internal = 0,
4040 .InternalHigh = 0,
......@@ -52,7 +52,7 @@ pub const Loop = struct {
5252 EventFd,
5353 };
5454
55 pub const EventFd = switch (builtin.os) {
55 pub const EventFd = switch (builtin.os.tag) {
5656 .macosx, .freebsd, .netbsd, .dragonfly => KEventFd,
5757 .linux => struct {
5858 base: ResumeNode,
......@@ -71,7 +71,7 @@ pub const Loop = struct {
7171 kevent: os.Kevent,
7272 };
7373
74 pub const Basic = switch (builtin.os) {
74 pub const Basic = switch (builtin.os.tag) {
7575 .macosx, .freebsd, .netbsd, .dragonfly => KEventBasic,
7676 .linux => struct {
7777 base: ResumeNode,
......@@ -173,7 +173,7 @@ pub const Loop = struct {
173173 const wakeup_bytes = [_]u8{0x1} ** 8;
174174
175175 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
176 switch (builtin.os) {
176 switch (builtin.os.tag) {
177177 .linux => {
178178 self.os_data.fs_queue = std.atomic.Queue(Request).init();
179179 self.os_data.fs_queue_item = 0;
......@@ -404,7 +404,7 @@ pub const Loop = struct {
404404 }
405405
406406 fn deinitOsData(self: *Loop) void {
407 switch (builtin.os) {
407 switch (builtin.os.tag) {
408408 .linux => {
409409 noasync os.close(self.os_data.final_eventfd);
410410 while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);
......@@ -568,7 +568,7 @@ pub const Loop = struct {
568568 };
569569 const eventfd_node = &resume_stack_node.data;
570570 eventfd_node.base.handle = next_tick_node.data;
571 switch (builtin.os) {
571 switch (builtin.os.tag) {
572572 .macosx, .freebsd, .netbsd, .dragonfly => {
573573 const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent);
574574 const empty_kevs = &[0]os.Kevent{};
......@@ -628,7 +628,7 @@ pub const Loop = struct {
628628
629629 self.workerRun();
630630
631 switch (builtin.os) {
631 switch (builtin.os.tag) {
632632 .linux,
633633 .macosx,
634634 .freebsd,
......@@ -678,7 +678,7 @@ pub const Loop = struct {
678678 const prev = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
679679 if (prev == 1) {
680680 // cause all the threads to stop
681 switch (builtin.os) {
681 switch (builtin.os.tag) {
682682 .linux => {
683683 self.posixFsRequest(&self.os_data.fs_end_request);
684684 // writing 8 bytes to an eventfd cannot fail
......@@ -902,7 +902,7 @@ pub const Loop = struct {
902902 self.finishOneEvent();
903903 }
904904
905 switch (builtin.os) {
905 switch (builtin.os.tag) {
906906 .linux => {
907907 // only process 1 event so we don't steal from other threads
908908 var events: [1]os.linux.epoll_event = undefined;
......@@ -989,7 +989,7 @@ pub const Loop = struct {
989989 fn posixFsRequest(self: *Loop, request_node: *Request.Node) void {
990990 self.beginOneEvent(); // finished in posixFsRun after processing the msg
991991 self.os_data.fs_queue.put(request_node);
992 switch (builtin.os) {
992 switch (builtin.os.tag) {
993993 .macosx, .freebsd, .netbsd, .dragonfly => {
994994 const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wake);
995995 const empty_kevs = &[0]os.Kevent{};
......@@ -1018,7 +1018,7 @@ pub const Loop = struct {
10181018 // https://github.com/ziglang/zig/issues/3157
10191019 fn posixFsRun(self: *Loop) void {
10201020 while (true) {
1021 if (builtin.os == .linux) {
1021 if (builtin.os.tag == .linux) {
10221022 @atomicStore(i32, &self.os_data.fs_queue_item, 0, .SeqCst);
10231023 }
10241024 while (self.os_data.fs_queue.get()) |node| {
......@@ -1053,7 +1053,7 @@ pub const Loop = struct {
10531053 }
10541054 self.finishOneEvent();
10551055 }
1056 switch (builtin.os) {
1056 switch (builtin.os.tag) {
10571057 .linux => {
10581058 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
10591059 switch (os.linux.getErrno(rc)) {
......@@ -1071,7 +1071,7 @@ pub const Loop = struct {
10711071 }
10721072 }
10731073
1074 const OsData = switch (builtin.os) {
1074 const OsData = switch (builtin.os.tag) {
10751075 .linux => LinuxOsData,
10761076 .macosx, .freebsd, .netbsd, .dragonfly => KEventData,
10771077 .windows => struct {
lib/std/fmt/parse_float.zig+1-1
......@@ -382,7 +382,7 @@ pub fn parseFloat(comptime T: type, s: []const u8) !T {
382382}
383383
384384test "fmt.parseFloat" {
385 if (std.Target.current.isWindows()) {
385 if (std.Target.current.os.tag == .windows) {
386386 // TODO https://github.com/ziglang/zig/issues/508
387387 return error.SkipZigTest;
388388 }
lib/std/fs.zig+23-23
......@@ -29,7 +29,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
2929/// All file system operations which return a path are guaranteed to
3030/// fit into a UTF-8 encoded array of this length.
3131/// The byte count includes room for a null sentinel byte.
32pub const MAX_PATH_BYTES = switch (builtin.os) {
32pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
3333 .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX,
3434 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
3535 // If it would require 4 UTF-8 bytes, then there would be a surrogate
......@@ -47,7 +47,7 @@ pub const base64_encoder = base64.Base64Encoder.init(
4747
4848/// Whether or not async file system syscalls need a dedicated thread because the operating
4949/// system does not support non-blocking I/O on the file system.
50pub const need_async_thread = std.io.is_async and switch (builtin.os) {
50pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) {
5151 .windows, .other => false,
5252 else => true,
5353};
......@@ -270,7 +270,7 @@ pub const AtomicFile = struct {
270270 assert(!self.finished);
271271 self.file.close();
272272 self.finished = true;
273 if (builtin.os == .windows) {
273 if (builtin.os.tag == .windows) {
274274 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
275275 const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));
276276 return os.renameW(&tmp_path_w, &dest_path_w);
......@@ -394,7 +394,7 @@ pub const Dir = struct {
394394
395395 const IteratorError = error{AccessDenied} || os.UnexpectedError;
396396
397 pub const Iterator = switch (builtin.os) {
397 pub const Iterator = switch (builtin.os.tag) {
398398 .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct {
399399 dir: Dir,
400400 seek: i64,
......@@ -409,7 +409,7 @@ pub const Dir = struct {
409409 /// Memory such as file names referenced in this returned entry becomes invalid
410410 /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
411411 pub fn next(self: *Self) Error!?Entry {
412 switch (builtin.os) {
412 switch (builtin.os.tag) {
413413 .macosx, .ios => return self.nextDarwin(),
414414 .freebsd, .netbsd, .dragonfly => return self.nextBsd(),
415415 else => @compileError("unimplemented"),
......@@ -644,7 +644,7 @@ pub const Dir = struct {
644644 };
645645
646646 pub fn iterate(self: Dir) Iterator {
647 switch (builtin.os) {
647 switch (builtin.os.tag) {
648648 .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{
649649 .dir = self,
650650 .seek = 0,
......@@ -710,7 +710,7 @@ pub const Dir = struct {
710710 /// Asserts that the path parameter has no null bytes.
711711 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
712712 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
713 if (builtin.os == .windows) {
713 if (builtin.os.tag == .windows) {
714714 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
715715 return self.openFileW(&path_w, flags);
716716 }
......@@ -720,7 +720,7 @@ pub const Dir = struct {
720720
721721 /// Same as `openFile` but the path parameter is null-terminated.
722722 pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
723 if (builtin.os == .windows) {
723 if (builtin.os.tag == .windows) {
724724 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
725725 return self.openFileW(&path_w, flags);
726726 }
......@@ -760,7 +760,7 @@ pub const Dir = struct {
760760 /// Asserts that the path parameter has no null bytes.
761761 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
762762 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
763 if (builtin.os == .windows) {
763 if (builtin.os.tag == .windows) {
764764 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
765765 return self.createFileW(&path_w, flags);
766766 }
......@@ -770,7 +770,7 @@ pub const Dir = struct {
770770
771771 /// Same as `createFile` but the path parameter is null-terminated.
772772 pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
773 if (builtin.os == .windows) {
773 if (builtin.os.tag == .windows) {
774774 const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
775775 return self.createFileW(&path_w, flags);
776776 }
......@@ -901,7 +901,7 @@ pub const Dir = struct {
901901 /// Asserts that the path parameter has no null bytes.
902902 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
903903 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
904 if (builtin.os == .windows) {
904 if (builtin.os.tag == .windows) {
905905 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
906906 return self.openDirTraverseW(&sub_path_w);
907907 }
......@@ -919,7 +919,7 @@ pub const Dir = struct {
919919 /// Asserts that the path parameter has no null bytes.
920920 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {
921921 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
922 if (builtin.os == .windows) {
922 if (builtin.os.tag == .windows) {
923923 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
924924 return self.openDirListW(&sub_path_w);
925925 }
......@@ -930,7 +930,7 @@ pub const Dir = struct {
930930
931931 /// Same as `openDirTraverse` except the parameter is null-terminated.
932932 pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
933 if (builtin.os == .windows) {
933 if (builtin.os.tag == .windows) {
934934 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
935935 return self.openDirTraverseW(&sub_path_w);
936936 } else {
......@@ -941,7 +941,7 @@ pub const Dir = struct {
941941
942942 /// Same as `openDirList` except the parameter is null-terminated.
943943 pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
944 if (builtin.os == .windows) {
944 if (builtin.os.tag == .windows) {
945945 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
946946 return self.openDirListW(&sub_path_w);
947947 } else {
......@@ -1083,7 +1083,7 @@ pub const Dir = struct {
10831083 /// Asserts that the path parameter has no null bytes.
10841084 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
10851085 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
1086 if (builtin.os == .windows) {
1086 if (builtin.os.tag == .windows) {
10871087 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
10881088 return self.deleteDirW(&sub_path_w);
10891089 }
......@@ -1340,7 +1340,7 @@ pub const Dir = struct {
13401340 /// For example, instead of testing if a file exists and then opening it, just
13411341 /// open it and handle the error for file not found.
13421342 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
1343 if (builtin.os == .windows) {
1343 if (builtin.os.tag == .windows) {
13441344 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
13451345 return self.accessW(&sub_path_w, flags);
13461346 }
......@@ -1350,7 +1350,7 @@ pub const Dir = struct {
13501350
13511351 /// Same as `access` except the path parameter is null-terminated.
13521352 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
1353 if (builtin.os == .windows) {
1353 if (builtin.os.tag == .windows) {
13541354 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
13551355 return self.accessW(&sub_path_w, flags);
13561356 }
......@@ -1381,7 +1381,7 @@ pub const Dir = struct {
13811381/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
13821382/// On POSIX targets, this function is comptime-callable.
13831383pub fn cwd() Dir {
1384 if (builtin.os == .windows) {
1384 if (builtin.os.tag == .windows) {
13851385 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
13861386 } else {
13871387 return Dir{ .fd = os.AT_FDCWD };
......@@ -1560,10 +1560,10 @@ pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
15601560pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;
15611561
15621562pub fn openSelfExe() OpenSelfExeError!File {
1563 if (builtin.os == .linux) {
1563 if (builtin.os.tag == .linux) {
15641564 return openFileAbsoluteC("/proc/self/exe", .{});
15651565 }
1566 if (builtin.os == .windows) {
1566 if (builtin.os.tag == .windows) {
15671567 const wide_slice = selfExePathW();
15681568 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
15691569 return cwd().openReadW(&prefixed_path_w);
......@@ -1575,7 +1575,7 @@ pub fn openSelfExe() OpenSelfExeError!File {
15751575}
15761576
15771577test "openSelfExe" {
1578 switch (builtin.os) {
1578 switch (builtin.os.tag) {
15791579 .linux, .macosx, .ios, .windows, .freebsd, .dragonfly => (try openSelfExe()).close(),
15801580 else => return error.SkipZigTest, // Unsupported OS.
15811581 }
......@@ -1600,7 +1600,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
16001600 if (rc != 0) return error.NameTooLong;
16011601 return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer));
16021602 }
1603 switch (builtin.os) {
1603 switch (builtin.os.tag) {
16041604 .linux => return os.readlinkC("/proc/self/exe", out_buffer),
16051605 .freebsd, .dragonfly => {
16061606 var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };
......@@ -1642,7 +1642,7 @@ pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
16421642/// Get the directory path that contains the current executable.
16431643/// Returned value is a slice of out_buffer.
16441644pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {
1645 if (builtin.os == .linux) {
1645 if (builtin.os.tag == .linux) {
16461646 // If the currently executing binary has been deleted,
16471647 // the file path looks something like `/a/b/c/exe (deleted)`
16481648 // This path cannot be opened, but it's valid for determining the directory
lib/std/fs/file.zig+6-6
......@@ -29,7 +29,7 @@ pub const File = struct {
2929
3030 pub const Mode = os.mode_t;
3131
32 pub const default_mode = switch (builtin.os) {
32 pub const default_mode = switch (builtin.os.tag) {
3333 .windows => 0,
3434 else => 0o666,
3535 };
......@@ -83,7 +83,7 @@ pub const File = struct {
8383
8484 /// Test whether ANSI escape codes will be treated as such.
8585 pub fn supportsAnsiEscapeCodes(self: File) bool {
86 if (builtin.os == .windows) {
86 if (builtin.os.tag == .windows) {
8787 return os.isCygwinPty(self.handle);
8888 }
8989 if (self.isTty()) {
......@@ -128,7 +128,7 @@ pub const File = struct {
128128
129129 /// TODO: integrate with async I/O
130130 pub fn getEndPos(self: File) GetPosError!u64 {
131 if (builtin.os == .windows) {
131 if (builtin.os.tag == .windows) {
132132 return windows.GetFileSizeEx(self.handle);
133133 }
134134 return (try self.stat()).size;
......@@ -138,7 +138,7 @@ pub const File = struct {
138138
139139 /// TODO: integrate with async I/O
140140 pub fn mode(self: File) ModeError!Mode {
141 if (builtin.os == .windows) {
141 if (builtin.os.tag == .windows) {
142142 return {};
143143 }
144144 return (try self.stat()).mode;
......@@ -162,7 +162,7 @@ pub const File = struct {
162162
163163 /// TODO: integrate with async I/O
164164 pub fn stat(self: File) StatError!Stat {
165 if (builtin.os == .windows) {
165 if (builtin.os.tag == .windows) {
166166 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
167167 var info: windows.FILE_ALL_INFORMATION = undefined;
168168 const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
......@@ -209,7 +209,7 @@ pub const File = struct {
209209 /// last modification timestamp in nanoseconds
210210 mtime: i64,
211211 ) UpdateTimesError!void {
212 if (builtin.os == .windows) {
212 if (builtin.os.tag == .windows) {
213213 const atime_ft = windows.nanoSecondsToFileTime(atime);
214214 const mtime_ft = windows.nanoSecondsToFileTime(mtime);
215215 return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);
lib/std/fs/get_app_data_dir.zig+1-1
......@@ -13,7 +13,7 @@ pub const GetAppDataDirError = error{
1313/// Caller owns returned memory.
1414/// TODO determine if we can remove the allocator requirement
1515pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
16 switch (builtin.os) {
16 switch (builtin.os.tag) {
1717 .windows => {
1818 var dir_path_ptr: [*:0]u16 = undefined;
1919 switch (os.windows.shell32.SHGetKnownFolderPath(
lib/std/fs/path.zig+19-19
......@@ -13,18 +13,18 @@ const process = std.process;
1313
1414pub const sep_windows = '\\';
1515pub const sep_posix = '/';
16pub const sep = if (builtin.os == .windows) sep_windows else sep_posix;
16pub const sep = if (builtin.os.tag == .windows) sep_windows else sep_posix;
1717
1818pub const sep_str_windows = "\\";
1919pub const sep_str_posix = "/";
20pub const sep_str = if (builtin.os == .windows) sep_str_windows else sep_str_posix;
20pub const sep_str = if (builtin.os.tag == .windows) sep_str_windows else sep_str_posix;
2121
2222pub const delimiter_windows = ';';
2323pub const delimiter_posix = ':';
24pub const delimiter = if (builtin.os == .windows) delimiter_windows else delimiter_posix;
24pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix;
2525
2626pub fn isSep(byte: u8) bool {
27 if (builtin.os == .windows) {
27 if (builtin.os.tag == .windows) {
2828 return byte == '/' or byte == '\\';
2929 } else {
3030 return byte == '/';
......@@ -74,7 +74,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u
7474 return buf;
7575}
7676
77pub const join = if (builtin.os == .windows) joinWindows else joinPosix;
77pub const join = if (builtin.os.tag == .windows) joinWindows else joinPosix;
7878
7979/// Naively combines a series of paths with the native path seperator.
8080/// Allocates memory for the result, which must be freed by the caller.
......@@ -129,7 +129,7 @@ test "join" {
129129}
130130
131131pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
132 if (builtin.os == .windows) {
132 if (builtin.os.tag == .windows) {
133133 return isAbsoluteWindowsC(path_c);
134134 } else {
135135 return isAbsolutePosixC(path_c);
......@@ -137,7 +137,7 @@ pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
137137}
138138
139139pub fn isAbsolute(path: []const u8) bool {
140 if (builtin.os == .windows) {
140 if (builtin.os.tag == .windows) {
141141 return isAbsoluteWindows(path);
142142 } else {
143143 return isAbsolutePosix(path);
......@@ -318,7 +318,7 @@ test "windowsParsePath" {
318318}
319319
320320pub fn diskDesignator(path: []const u8) []const u8 {
321 if (builtin.os == .windows) {
321 if (builtin.os.tag == .windows) {
322322 return diskDesignatorWindows(path);
323323 } else {
324324 return "";
......@@ -383,7 +383,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
383383
384384/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
385385pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
386 if (builtin.os == .windows) {
386 if (builtin.os.tag == .windows) {
387387 return resolveWindows(allocator, paths);
388388 } else {
389389 return resolvePosix(allocator, paths);
......@@ -400,7 +400,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
400400/// Without performing actual syscalls, resolving `..` could be incorrect.
401401pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
402402 if (paths.len == 0) {
403 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
403 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
404404 return process.getCwdAlloc(allocator);
405405 }
406406
......@@ -495,7 +495,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
495495 result_disk_designator = result[0..result_index];
496496 },
497497 WindowsPath.Kind.None => {
498 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
498 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
499499 const cwd = try process.getCwdAlloc(allocator);
500500 defer allocator.free(cwd);
501501 const parsed_cwd = windowsParsePath(cwd);
......@@ -510,7 +510,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
510510 },
511511 }
512512 } else {
513 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
513 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
514514 // TODO call get cwd for the result_disk_designator instead of the global one
515515 const cwd = try process.getCwdAlloc(allocator);
516516 defer allocator.free(cwd);
......@@ -581,7 +581,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
581581/// Without performing actual syscalls, resolving `..` could be incorrect.
582582pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
583583 if (paths.len == 0) {
584 assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd
584 assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
585585 return process.getCwdAlloc(allocator);
586586 }
587587
......@@ -603,7 +603,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
603603 if (have_abs) {
604604 result = try allocator.alloc(u8, max_size);
605605 } else {
606 assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd
606 assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
607607 const cwd = try process.getCwdAlloc(allocator);
608608 defer allocator.free(cwd);
609609 result = try allocator.alloc(u8, max_size + cwd.len + 1);
......@@ -645,7 +645,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
645645test "resolve" {
646646 const cwd = try process.getCwdAlloc(testing.allocator);
647647 defer testing.allocator.free(cwd);
648 if (builtin.os == .windows) {
648 if (builtin.os.tag == .windows) {
649649 if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
650650 cwd[0] = asciiUpper(cwd[0]);
651651 }
......@@ -661,7 +661,7 @@ test "resolveWindows" {
661661 // TODO https://github.com/ziglang/zig/issues/3288
662662 return error.SkipZigTest;
663663 }
664 if (builtin.os == .windows) {
664 if (builtin.os.tag == .windows) {
665665 const cwd = try process.getCwdAlloc(testing.allocator);
666666 defer testing.allocator.free(cwd);
667667 const parsed_cwd = windowsParsePath(cwd);
......@@ -732,7 +732,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {
732732/// If the path is a file in the current directory (no directory component)
733733/// then returns null
734734pub fn dirname(path: []const u8) ?[]const u8 {
735 if (builtin.os == .windows) {
735 if (builtin.os.tag == .windows) {
736736 return dirnameWindows(path);
737737 } else {
738738 return dirnamePosix(path);
......@@ -864,7 +864,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
864864}
865865
866866pub fn basename(path: []const u8) []const u8 {
867 if (builtin.os == .windows) {
867 if (builtin.os.tag == .windows) {
868868 return basenameWindows(path);
869869 } else {
870870 return basenamePosix(path);
......@@ -980,7 +980,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
980980/// string is returned.
981981/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
982982pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
983 if (builtin.os == .windows) {
983 if (builtin.os.tag == .windows) {
984984 return relativeWindows(allocator, from, to);
985985 } else {
986986 return relativePosix(allocator, from, to);
lib/std/fs/watch.zig+4-4
......@@ -42,7 +42,7 @@ pub fn Watch(comptime V: type) type {
4242 os_data: OsData,
4343 allocator: *Allocator,
4444
45 const OsData = switch (builtin.os) {
45 const OsData = switch (builtin.os.tag) {
4646 // TODO https://github.com/ziglang/zig/issues/3778
4747 .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
4848 .linux => LinuxOsData,
......@@ -121,7 +121,7 @@ pub fn Watch(comptime V: type) type {
121121 const self = try allocator.create(Self);
122122 errdefer allocator.destroy(self);
123123
124 switch (builtin.os) {
124 switch (builtin.os.tag) {
125125 .linux => {
126126 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
127127 errdefer os.close(inotify_fd);
......@@ -172,7 +172,7 @@ pub fn Watch(comptime V: type) type {
172172
173173 /// All addFile calls and removeFile calls must have completed.
174174 pub fn deinit(self: *Self) void {
175 switch (builtin.os) {
175 switch (builtin.os.tag) {
176176 .macosx, .freebsd, .netbsd, .dragonfly => {
177177 // TODO we need to cancel the frames before destroying the lock
178178 self.os_data.table_lock.deinit();
......@@ -223,7 +223,7 @@ pub fn Watch(comptime V: type) type {
223223 }
224224
225225 pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
226 switch (builtin.os) {
226 switch (builtin.os.tag) {
227227 .macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value),
228228 .linux => return addFileLinux(self, file_path, value),
229229 .windows => return addFileWindows(self, file_path, value),
lib/std/heap.zig+7-7
......@@ -36,7 +36,7 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new
3636/// Thread-safe and lock-free.
3737pub const page_allocator = if (std.Target.current.isWasm())
3838 &wasm_page_allocator_state
39else if (std.Target.current.getOs() == .freestanding)
39else if (std.Target.current.os.tag == .freestanding)
4040 root.os.heap.page_allocator
4141else
4242 &page_allocator_state;
......@@ -57,7 +57,7 @@ const PageAllocator = struct {
5757 fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
5858 if (n == 0) return &[0]u8{};
5959
60 if (builtin.os == .windows) {
60 if (builtin.os.tag == .windows) {
6161 const w = os.windows;
6262
6363 // Although officially it's at least aligned to page boundary,
......@@ -143,7 +143,7 @@ const PageAllocator = struct {
143143
144144 fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
145145 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
146 if (builtin.os == .windows) {
146 if (builtin.os.tag == .windows) {
147147 const w = os.windows;
148148 if (new_size == 0) {
149149 // From the docs:
......@@ -183,7 +183,7 @@ const PageAllocator = struct {
183183
184184 fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
185185 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
186 if (builtin.os == .windows) {
186 if (builtin.os.tag == .windows) {
187187 if (old_mem.len == 0) {
188188 return alloc(allocator, new_size, new_align);
189189 }
......@@ -412,7 +412,7 @@ const WasmPageAllocator = struct {
412412 }
413413};
414414
415pub const HeapAllocator = switch (builtin.os) {
415pub const HeapAllocator = switch (builtin.os.tag) {
416416 .windows => struct {
417417 allocator: Allocator,
418418 heap_handle: ?HeapHandle,
......@@ -855,7 +855,7 @@ test "PageAllocator" {
855855 try testAllocatorAlignedShrink(allocator);
856856 }
857857
858 if (builtin.os == .windows) {
858 if (builtin.os.tag == .windows) {
859859 // Trying really large alignment. As mentionned in the implementation,
860860 // VirtualAlloc returns 64K aligned addresses. We want to make sure
861861 // PageAllocator works beyond that, as it's not tested by
......@@ -868,7 +868,7 @@ test "PageAllocator" {
868868}
869869
870870test "HeapAllocator" {
871 if (builtin.os == .windows) {
871 if (builtin.os.tag == .windows) {
872872 var heap_allocator = HeapAllocator.init();
873873 defer heap_allocator.deinit();
874874
lib/std/io.zig+3-3
......@@ -35,7 +35,7 @@ else
3535pub const is_async = mode != .blocking;
3636
3737fn getStdOutHandle() os.fd_t {
38 if (builtin.os == .windows) {
38 if (builtin.os.tag == .windows) {
3939 return os.windows.peb().ProcessParameters.hStdOutput;
4040 }
4141
......@@ -54,7 +54,7 @@ pub fn getStdOut() File {
5454}
5555
5656fn getStdErrHandle() os.fd_t {
57 if (builtin.os == .windows) {
57 if (builtin.os.tag == .windows) {
5858 return os.windows.peb().ProcessParameters.hStdError;
5959 }
6060
......@@ -74,7 +74,7 @@ pub fn getStdErr() File {
7474}
7575
7676fn getStdInHandle() os.fd_t {
77 if (builtin.os == .windows) {
77 if (builtin.os.tag == .windows) {
7878 return os.windows.peb().ProcessParameters.hStdInput;
7979 }
8080
lib/std/io/test.zig+1-1
......@@ -544,7 +544,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing:
544544}
545545
546546test "Serializer/Deserializer generic" {
547 if (std.Target.current.isWindows()) {
547 if (std.Target.current.os.tag == .windows) {
548548 // TODO https://github.com/ziglang/zig/issues/508
549549 return error.SkipZigTest;
550550 }
lib/std/math/fabs.zig+1-1
......@@ -95,7 +95,7 @@ test "math.fabs64.special" {
9595}
9696
9797test "math.fabs128.special" {
98 if (std.Target.current.isWindows()) {
98 if (std.Target.current.os.tag == .windows) {
9999 // TODO https://github.com/ziglang/zig/issues/508
100100 return error.SkipZigTest;
101101 }
lib/std/math/isinf.zig+3-3
......@@ -74,7 +74,7 @@ pub fn isNegativeInf(x: var) bool {
7474}
7575
7676test "math.isInf" {
77 if (std.Target.current.isWindows()) {
77 if (std.Target.current.os.tag == .windows) {
7878 // TODO https://github.com/ziglang/zig/issues/508
7979 return error.SkipZigTest;
8080 }
......@@ -97,7 +97,7 @@ test "math.isInf" {
9797}
9898
9999test "math.isPositiveInf" {
100 if (std.Target.current.isWindows()) {
100 if (std.Target.current.os.tag == .windows) {
101101 // TODO https://github.com/ziglang/zig/issues/508
102102 return error.SkipZigTest;
103103 }
......@@ -120,7 +120,7 @@ test "math.isPositiveInf" {
120120}
121121
122122test "math.isNegativeInf" {
123 if (std.Target.current.isWindows()) {
123 if (std.Target.current.os.tag == .windows) {
124124 // TODO https://github.com/ziglang/zig/issues/508
125125 return error.SkipZigTest;
126126 }
lib/std/math/isnan.zig+1-1
......@@ -16,7 +16,7 @@ pub fn isSignalNan(x: var) bool {
1616}
1717
1818test "math.isNan" {
19 if (std.Target.current.isWindows()) {
19 if (std.Target.current.os.tag == .windows) {
2020 // TODO https://github.com/ziglang/zig/issues/508
2121 return error.SkipZigTest;
2222 }
lib/std/mutex.zig+2-2
......@@ -73,7 +73,7 @@ pub const Mutex = if (builtin.single_threaded)
7373 return self.tryAcquire() orelse @panic("deadlock detected");
7474 }
7575 }
76else if (builtin.os == .windows)
76else if (builtin.os.tag == .windows)
7777// https://locklessinc.com/articles/keyed_events/
7878 extern union {
7979 locked: u8,
......@@ -161,7 +161,7 @@ else if (builtin.os == .windows)
161161 }
162162 };
163163 }
164else if (builtin.link_libc or builtin.os == .linux)
164else if (builtin.link_libc or builtin.os.tag == .linux)
165165// stack-based version of https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs
166166 struct {
167167 state: usize,
lib/std/net.zig+1-1
......@@ -501,7 +501,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
501501
502502 return result;
503503 }
504 if (builtin.os == .linux) {
504 if (builtin.os.tag == .linux) {
505505 const flags = std.c.AI_NUMERICSERV;
506506 const family = os.AF_UNSPEC;
507507 var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
lib/std/net/test.zig+2-2
......@@ -63,7 +63,7 @@ test "parse and render IPv4 addresses" {
6363}
6464
6565test "resolve DNS" {
66 if (std.builtin.os == .windows) {
66 if (std.builtin.os.tag == .windows) {
6767 // DNS resolution not implemented on Windows yet.
6868 return error.SkipZigTest;
6969 }
......@@ -81,7 +81,7 @@ test "resolve DNS" {
8181test "listen on a port, send bytes, receive bytes" {
8282 if (!std.io.is_async) return error.SkipZigTest;
8383
84 if (std.builtin.os != .linux) {
84 if (std.builtin.os.tag != .linux) {
8585 // TODO build abstractions for other operating systems
8686 return error.SkipZigTest;
8787 }
lib/std/os.zig+83-81
......@@ -56,7 +56,7 @@ pub const system = if (@hasDecl(root, "os") and root.os != @This())
5656 root.os.system
5757else if (builtin.link_libc)
5858 std.c
59else switch (builtin.os) {
59else switch (builtin.os.tag) {
6060 .macosx, .ios, .watchos, .tvos => darwin,
6161 .freebsd => freebsd,
6262 .linux => linux,
......@@ -93,10 +93,10 @@ pub const errno = system.getErrno;
9393/// must call `fsync` before `close`.
9494/// Note: The Zig standard library does not support POSIX thread cancellation.
9595pub fn close(fd: fd_t) void {
96 if (builtin.os == .windows) {
96 if (builtin.os.tag == .windows) {
9797 return windows.CloseHandle(fd);
9898 }
99 if (builtin.os == .wasi) {
99 if (builtin.os.tag == .wasi) {
100100 _ = wasi.fd_close(fd);
101101 }
102102 if (comptime std.Target.current.isDarwin()) {
......@@ -121,12 +121,12 @@ pub const GetRandomError = OpenError;
121121/// appropriate OS-specific library call. Otherwise it uses the zig standard
122122/// library implementation.
123123pub fn getrandom(buffer: []u8) GetRandomError!void {
124 if (builtin.os == .windows) {
124 if (builtin.os.tag == .windows) {
125125 return windows.RtlGenRandom(buffer);
126126 }
127 if (builtin.os == .linux or builtin.os == .freebsd) {
127 if (builtin.os.tag == .linux or builtin.os.tag == .freebsd) {
128128 var buf = buffer;
129 const use_c = builtin.os != .linux or
129 const use_c = builtin.os.tag != .linux or
130130 std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok;
131131
132132 while (buf.len != 0) {
......@@ -153,7 +153,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
153153 }
154154 return;
155155 }
156 if (builtin.os == .wasi) {
156 if (builtin.os.tag == .wasi) {
157157 switch (wasi.random_get(buffer.ptr, buffer.len)) {
158158 0 => return,
159159 else => |err| return unexpectedErrno(err),
......@@ -188,13 +188,13 @@ pub fn abort() noreturn {
188188 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
189189 // even when linking libc on Windows we use our own abort implementation.
190190 // See https://github.com/ziglang/zig/issues/2071 for more details.
191 if (builtin.os == .windows) {
191 if (builtin.os.tag == .windows) {
192192 if (builtin.mode == .Debug) {
193193 @breakpoint();
194194 }
195195 windows.kernel32.ExitProcess(3);
196196 }
197 if (!builtin.link_libc and builtin.os == .linux) {
197 if (!builtin.link_libc and builtin.os.tag == .linux) {
198198 raise(SIGABRT) catch {};
199199
200200 // TODO the rest of the implementation of abort() from musl libc here
......@@ -202,10 +202,10 @@ pub fn abort() noreturn {
202202 raise(SIGKILL) catch {};
203203 exit(127);
204204 }
205 if (builtin.os == .uefi) {
205 if (builtin.os.tag == .uefi) {
206206 exit(0); // TODO choose appropriate exit code
207207 }
208 if (builtin.os == .wasi) {
208 if (builtin.os.tag == .wasi) {
209209 @breakpoint();
210210 exit(1);
211211 }
......@@ -223,7 +223,7 @@ pub fn raise(sig: u8) RaiseError!void {
223223 }
224224 }
225225
226 if (builtin.os == .linux) {
226 if (builtin.os.tag == .linux) {
227227 var set: linux.sigset_t = undefined;
228228 // block application signals
229229 _ = linux.sigprocmask(SIG_BLOCK, &linux.app_mask, &set);
......@@ -260,16 +260,16 @@ pub fn exit(status: u8) noreturn {
260260 if (builtin.link_libc) {
261261 system.exit(status);
262262 }
263 if (builtin.os == .windows) {
263 if (builtin.os.tag == .windows) {
264264 windows.kernel32.ExitProcess(status);
265265 }
266 if (builtin.os == .wasi) {
266 if (builtin.os.tag == .wasi) {
267267 wasi.proc_exit(status);
268268 }
269 if (builtin.os == .linux and !builtin.single_threaded) {
269 if (builtin.os.tag == .linux and !builtin.single_threaded) {
270270 linux.exit_group(status);
271271 }
272 if (builtin.os == .uefi) {
272 if (builtin.os.tag == .uefi) {
273273 // exit() is only avaliable if exitBootServices() has not been called yet.
274274 // This call to exit should not fail, so we don't care about its return value.
275275 if (uefi.system_table.boot_services) |bs| {
......@@ -299,11 +299,11 @@ pub const ReadError = error{
299299/// If the application has a global event loop enabled, EAGAIN is handled
300300/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
301301pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
302 if (builtin.os == .windows) {
302 if (builtin.os.tag == .windows) {
303303 return windows.ReadFile(fd, buf, null);
304304 }
305305
306 if (builtin.os == .wasi and !builtin.link_libc) {
306 if (builtin.os.tag == .wasi and !builtin.link_libc) {
307307 const iovs = [1]iovec{iovec{
308308 .iov_base = buf.ptr,
309309 .iov_len = buf.len,
......@@ -352,7 +352,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
352352/// * Windows
353353/// On these systems, the read races with concurrent writes to the same file descriptor.
354354pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
355 if (builtin.os == .windows) {
355 if (builtin.os.tag == .windows) {
356356 // TODO batch these into parallel requests
357357 var off: usize = 0;
358358 var iov_i: usize = 0;
......@@ -406,7 +406,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
406406/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
407407/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
408408pub fn pread(fd: fd_t, buf: []u8, offset: u64) ReadError!usize {
409 if (builtin.os == .windows) {
409 if (builtin.os.tag == .windows) {
410410 return windows.ReadFile(fd, buf, offset);
411411 }
412412
......@@ -493,7 +493,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
493493 }
494494 }
495495
496 if (builtin.os == .windows) {
496 if (builtin.os.tag == .windows) {
497497 // TODO batch these into parallel requests
498498 var off: usize = 0;
499499 var iov_i: usize = 0;
......@@ -557,11 +557,11 @@ pub const WriteError = error{
557557/// If the application has a global event loop enabled, EAGAIN is handled
558558/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
559559pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
560 if (builtin.os == .windows) {
560 if (builtin.os.tag == .windows) {
561561 return windows.WriteFile(fd, bytes, null);
562562 }
563563
564 if (builtin.os == .wasi and !builtin.link_libc) {
564 if (builtin.os.tag == .wasi and !builtin.link_libc) {
565565 const ciovs = [1]iovec_const{iovec_const{
566566 .iov_base = bytes.ptr,
567567 .iov_len = bytes.len,
......@@ -650,7 +650,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
650650/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
651651/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
652652pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) WriteError!void {
653 if (comptime std.Target.current.isWindows()) {
653 if (std.Target.current.os.tag == .windows) {
654654 return windows.WriteFile(fd, bytes, offset);
655655 }
656656
......@@ -739,7 +739,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void
739739 }
740740 }
741741
742 if (comptime std.Target.current.isWindows()) {
742 if (std.Target.current.os.tag == .windows) {
743743 var off = offset;
744744 for (iov) |item| {
745745 try pwrite(fd, item.iov_base[0..item.iov_len], off);
......@@ -1129,7 +1129,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {
11291129 }
11301130 return null;
11311131 }
1132 if (builtin.os == .windows) {
1132 if (builtin.os.tag == .windows) {
11331133 @compileError("std.os.getenv is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API.");
11341134 }
11351135 // TODO see https://github.com/ziglang/zig/issues/4524
......@@ -1158,7 +1158,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
11581158 const value = system.getenv(key) orelse return null;
11591159 return mem.toSliceConst(u8, value);
11601160 }
1161 if (builtin.os == .windows) {
1161 if (builtin.os.tag == .windows) {
11621162 @compileError("std.os.getenvZ is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API.");
11631163 }
11641164 return getenv(mem.toSliceConst(u8, key));
......@@ -1167,7 +1167,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
11671167/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
11681168/// See also `getenv`.
11691169pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
1170 if (builtin.os != .windows) {
1170 if (builtin.os.tag != .windows) {
11711171 @compileError("std.os.getenvW is a Windows-only API");
11721172 }
11731173 const key_slice = mem.toSliceConst(u16, key);
......@@ -1199,7 +1199,7 @@ pub const GetCwdError = error{
11991199
12001200/// The result is a slice of out_buffer, indexed from 0.
12011201pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
1202 if (builtin.os == .windows) {
1202 if (builtin.os.tag == .windows) {
12031203 return windows.GetCurrentDirectory(out_buffer);
12041204 }
12051205
......@@ -1240,7 +1240,7 @@ pub const SymLinkError = error{
12401240/// If `sym_link_path` exists, it will not be overwritten.
12411241/// See also `symlinkC` and `symlinkW`.
12421242pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
1243 if (builtin.os == .windows) {
1243 if (builtin.os.tag == .windows) {
12441244 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
12451245 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
12461246 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
......@@ -1254,7 +1254,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
12541254/// This is the same as `symlink` except the parameters are null-terminated pointers.
12551255/// See also `symlink`.
12561256pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {
1257 if (builtin.os == .windows) {
1257 if (builtin.os.tag == .windows) {
12581258 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
12591259 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
12601260 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
......@@ -1329,7 +1329,7 @@ pub const UnlinkError = error{
13291329/// Delete a name and possibly the file it refers to.
13301330/// See also `unlinkC`.
13311331pub fn unlink(file_path: []const u8) UnlinkError!void {
1332 if (builtin.os == .windows) {
1332 if (builtin.os.tag == .windows) {
13331333 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
13341334 return windows.DeleteFileW(&file_path_w);
13351335 } else {
......@@ -1340,7 +1340,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
13401340
13411341/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
13421342pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void {
1343 if (builtin.os == .windows) {
1343 if (builtin.os.tag == .windows) {
13441344 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
13451345 return windows.DeleteFileW(&file_path_w);
13461346 }
......@@ -1372,7 +1372,7 @@ pub const UnlinkatError = UnlinkError || error{
13721372/// Asserts that the path parameter has no null bytes.
13731373pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
13741374 if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0);
1375 if (builtin.os == .windows) {
1375 if (builtin.os.tag == .windows) {
13761376 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
13771377 return unlinkatW(dirfd, &file_path_w, flags);
13781378 }
......@@ -1382,7 +1382,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
13821382
13831383/// Same as `unlinkat` but `file_path` is a null-terminated string.
13841384pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {
1385 if (builtin.os == .windows) {
1385 if (builtin.os.tag == .windows) {
13861386 const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);
13871387 return unlinkatW(dirfd, &file_path_w, flags);
13881388 }
......@@ -1493,7 +1493,7 @@ const RenameError = error{
14931493
14941494/// Change the name or location of a file.
14951495pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
1496 if (builtin.os == .windows) {
1496 if (builtin.os.tag == .windows) {
14971497 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
14981498 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
14991499 return renameW(&old_path_w, &new_path_w);
......@@ -1506,7 +1506,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
15061506
15071507/// Same as `rename` except the parameters are null-terminated byte arrays.
15081508pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {
1509 if (builtin.os == .windows) {
1509 if (builtin.os.tag == .windows) {
15101510 const old_path_w = try windows.cStrToPrefixedFileW(old_path);
15111511 const new_path_w = try windows.cStrToPrefixedFileW(new_path);
15121512 return renameW(&old_path_w, &new_path_w);
......@@ -1561,7 +1561,7 @@ pub const MakeDirError = error{
15611561/// Create a directory.
15621562/// `mode` is ignored on Windows.
15631563pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
1564 if (builtin.os == .windows) {
1564 if (builtin.os.tag == .windows) {
15651565 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
15661566 return windows.CreateDirectoryW(&dir_path_w, null);
15671567 } else {
......@@ -1572,7 +1572,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
15721572
15731573/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
15741574pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
1575 if (builtin.os == .windows) {
1575 if (builtin.os.tag == .windows) {
15761576 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
15771577 return windows.CreateDirectoryW(&dir_path_w, null);
15781578 }
......@@ -1611,7 +1611,7 @@ pub const DeleteDirError = error{
16111611
16121612/// Deletes an empty directory.
16131613pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
1614 if (builtin.os == .windows) {
1614 if (builtin.os.tag == .windows) {
16151615 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
16161616 return windows.RemoveDirectoryW(&dir_path_w);
16171617 } else {
......@@ -1622,7 +1622,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
16221622
16231623/// Same as `rmdir` except the parameter is null-terminated.
16241624pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void {
1625 if (builtin.os == .windows) {
1625 if (builtin.os.tag == .windows) {
16261626 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
16271627 return windows.RemoveDirectoryW(&dir_path_w);
16281628 }
......@@ -1658,7 +1658,7 @@ pub const ChangeCurDirError = error{
16581658/// Changes the current working directory of the calling process.
16591659/// `dir_path` is recommended to be a UTF-8 encoded string.
16601660pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
1661 if (builtin.os == .windows) {
1661 if (builtin.os.tag == .windows) {
16621662 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
16631663 @compileError("TODO implement chdir for Windows");
16641664 } else {
......@@ -1669,7 +1669,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
16691669
16701670/// Same as `chdir` except the parameter is null-terminated.
16711671pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void {
1672 if (builtin.os == .windows) {
1672 if (builtin.os.tag == .windows) {
16731673 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
16741674 @compileError("TODO implement chdir for Windows");
16751675 }
......@@ -1700,7 +1700,7 @@ pub const ReadLinkError = error{
17001700/// Read value of a symbolic link.
17011701/// The return value is a slice of `out_buffer` from index 0.
17021702pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
1703 if (builtin.os == .windows) {
1703 if (builtin.os.tag == .windows) {
17041704 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
17051705 @compileError("TODO implement readlink for Windows");
17061706 } else {
......@@ -1711,7 +1711,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
17111711
17121712/// Same as `readlink` except `file_path` is null-terminated.
17131713pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
1714 if (builtin.os == .windows) {
1714 if (builtin.os.tag == .windows) {
17151715 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
17161716 @compileError("TODO implement readlink for Windows");
17171717 }
......@@ -1732,7 +1732,7 @@ pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
17321732}
17331733
17341734pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
1735 if (builtin.os == .windows) {
1735 if (builtin.os.tag == .windows) {
17361736 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
17371737 @compileError("TODO implement readlink for Windows");
17381738 }
......@@ -1800,7 +1800,7 @@ pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
18001800
18011801/// Test whether a file descriptor refers to a terminal.
18021802pub fn isatty(handle: fd_t) bool {
1803 if (builtin.os == .windows) {
1803 if (builtin.os.tag == .windows) {
18041804 if (isCygwinPty(handle))
18051805 return true;
18061806
......@@ -1810,7 +1810,7 @@ pub fn isatty(handle: fd_t) bool {
18101810 if (builtin.link_libc) {
18111811 return system.isatty(handle) != 0;
18121812 }
1813 if (builtin.os == .wasi) {
1813 if (builtin.os.tag == .wasi) {
18141814 var statbuf: fdstat_t = undefined;
18151815 const err = system.fd_fdstat_get(handle, &statbuf);
18161816 if (err != 0) {
......@@ -1828,7 +1828,7 @@ pub fn isatty(handle: fd_t) bool {
18281828
18291829 return true;
18301830 }
1831 if (builtin.os == .linux) {
1831 if (builtin.os.tag == .linux) {
18321832 var wsz: linux.winsize = undefined;
18331833 return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, @as(isize, handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
18341834 }
......@@ -1836,7 +1836,7 @@ pub fn isatty(handle: fd_t) bool {
18361836}
18371837
18381838pub fn isCygwinPty(handle: fd_t) bool {
1839 if (builtin.os != .windows) return false;
1839 if (builtin.os.tag != .windows) return false;
18401840
18411841 const size = @sizeOf(windows.FILE_NAME_INFO);
18421842 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);
......@@ -2589,7 +2589,7 @@ pub const AccessError = error{
25892589/// check user's permissions for a file
25902590/// TODO currently this assumes `mode` is `F_OK` on Windows.
25912591pub fn access(path: []const u8, mode: u32) AccessError!void {
2592 if (builtin.os == .windows) {
2592 if (builtin.os.tag == .windows) {
25932593 const path_w = try windows.sliceToPrefixedFileW(path);
25942594 _ = try windows.GetFileAttributesW(&path_w);
25952595 return;
......@@ -2603,7 +2603,7 @@ pub const accessC = accessZ;
26032603
26042604/// Same as `access` except `path` is null-terminated.
26052605pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
2606 if (builtin.os == .windows) {
2606 if (builtin.os.tag == .windows) {
26072607 const path_w = try windows.cStrToPrefixedFileW(path);
26082608 _ = try windows.GetFileAttributesW(&path_w);
26092609 return;
......@@ -2644,7 +2644,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v
26442644/// Check user's permissions for a file, based on an open directory handle.
26452645/// TODO currently this ignores `mode` and `flags` on Windows.
26462646pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
2647 if (builtin.os == .windows) {
2647 if (builtin.os.tag == .windows) {
26482648 const path_w = try windows.sliceToPrefixedFileW(path);
26492649 return faccessatW(dirfd, &path_w, mode, flags);
26502650 }
......@@ -2654,7 +2654,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
26542654
26552655/// Same as `faccessat` except the path parameter is null-terminated.
26562656pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {
2657 if (builtin.os == .windows) {
2657 if (builtin.os.tag == .windows) {
26582658 const path_w = try windows.cStrToPrefixedFileW(path);
26592659 return faccessatW(dirfd, &path_w, mode, flags);
26602660 }
......@@ -2811,7 +2811,7 @@ pub const SeekError = error{Unseekable} || UnexpectedError;
28112811
28122812/// Repositions read/write file offset relative to the beginning.
28132813pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
2814 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2814 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
28152815 var result: u64 = undefined;
28162816 switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) {
28172817 0 => return,
......@@ -2823,7 +2823,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
28232823 else => |err| return unexpectedErrno(err),
28242824 }
28252825 }
2826 if (builtin.os == .windows) {
2826 if (builtin.os.tag == .windows) {
28272827 return windows.SetFilePointerEx_BEGIN(fd, offset);
28282828 }
28292829 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned
......@@ -2840,7 +2840,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
28402840
28412841/// Repositions read/write file offset relative to the current offset.
28422842pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
2843 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2843 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
28442844 var result: u64 = undefined;
28452845 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_CUR))) {
28462846 0 => return,
......@@ -2852,7 +2852,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
28522852 else => |err| return unexpectedErrno(err),
28532853 }
28542854 }
2855 if (builtin.os == .windows) {
2855 if (builtin.os.tag == .windows) {
28562856 return windows.SetFilePointerEx_CURRENT(fd, offset);
28572857 }
28582858 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
......@@ -2868,7 +2868,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
28682868
28692869/// Repositions read/write file offset relative to the end.
28702870pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
2871 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2871 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
28722872 var result: u64 = undefined;
28732873 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_END))) {
28742874 0 => return,
......@@ -2880,7 +2880,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
28802880 else => |err| return unexpectedErrno(err),
28812881 }
28822882 }
2883 if (builtin.os == .windows) {
2883 if (builtin.os.tag == .windows) {
28842884 return windows.SetFilePointerEx_END(fd, offset);
28852885 }
28862886 switch (errno(system.lseek(fd, offset, SEEK_END))) {
......@@ -2896,7 +2896,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
28962896
28972897/// Returns the read/write file offset relative to the beginning.
28982898pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
2899 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2899 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
29002900 var result: u64 = undefined;
29012901 switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {
29022902 0 => return result,
......@@ -2908,7 +2908,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
29082908 else => |err| return unexpectedErrno(err),
29092909 }
29102910 }
2911 if (builtin.os == .windows) {
2911 if (builtin.os.tag == .windows) {
29122912 return windows.SetFilePointerEx_CURRENT_get(fd);
29132913 }
29142914 const rc = system.lseek(fd, 0, SEEK_CUR);
......@@ -2957,7 +2957,7 @@ pub const RealPathError = error{
29572957/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
29582958/// See also `realpathC` and `realpathW`.
29592959pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2960 if (builtin.os == .windows) {
2960 if (builtin.os.tag == .windows) {
29612961 const pathname_w = try windows.sliceToPrefixedFileW(pathname);
29622962 return realpathW(&pathname_w, out_buffer);
29632963 }
......@@ -2967,11 +2967,11 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
29672967
29682968/// Same as `realpath` except `pathname` is null-terminated.
29692969pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2970 if (builtin.os == .windows) {
2970 if (builtin.os.tag == .windows) {
29712971 const pathname_w = try windows.cStrToPrefixedFileW(pathname);
29722972 return realpathW(&pathname_w, out_buffer);
29732973 }
2974 if (builtin.os == .linux and !builtin.link_libc) {
2974 if (builtin.os.tag == .linux and !builtin.link_libc) {
29752975 const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
29762976 defer close(fd);
29772977
......@@ -3121,7 +3121,7 @@ pub fn dl_iterate_phdr(
31213121pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
31223122
31233123pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
3124 if (comptime std.Target.current.getOs() == .wasi) {
3124 if (std.Target.current.os.tag == .wasi) {
31253125 var ts: timestamp_t = undefined;
31263126 switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {
31273127 0 => {
......@@ -3144,7 +3144,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
31443144}
31453145
31463146pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
3147 if (comptime std.Target.current.getOs() == .wasi) {
3147 if (std.Target.current.os.tag == .wasi) {
31483148 var ts: timestamp_t = undefined;
31493149 switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {
31503150 0 => res.* = .{
......@@ -3222,7 +3222,7 @@ pub const SigaltstackError = error{
32223222} || UnexpectedError;
32233223
32243224pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
3225 if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi)
3225 if (builtin.os.tag == .windows or builtin.os.tag == .uefi or builtin.os.tag == .wasi)
32263226 @compileError("std.os.sigaltstack not available for this target");
32273227
32283228 switch (errno(system.sigaltstack(ss, old_ss))) {
......@@ -3294,23 +3294,25 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
32943294 else => |err| return unexpectedErrno(err),
32953295 }
32963296 }
3297 if (builtin.os == .linux) {
3298 var uts: utsname = undefined;
3299 switch (errno(system.uname(&uts))) {
3300 0 => {
3301 const hostname = mem.toSlice(u8, @ptrCast([*:0]u8, &uts.nodename));
3302 mem.copy(u8, name_buffer, hostname);
3303 return name_buffer[0..hostname.len];
3304 },
3305 EFAULT => unreachable,
3306 EPERM => return error.PermissionDenied,
3307 else => |err| return unexpectedErrno(err),
3308 }
3297 if (builtin.os.tag == .linux) {
3298 const uts = uname();
3299 const hostname = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.nodename));
3300 mem.copy(u8, name_buffer, hostname);
3301 return name_buffer[0..hostname.len];
33093302 }
33103303
33113304 @compileError("TODO implement gethostname for this OS");
33123305}
33133306
3307pub fn uname() utsname {
3308 var uts: utsname = undefined;
3309 switch (errno(system.uname(&uts))) {
3310 0 => return uts,
3311 EFAULT => unreachable,
3312 else => unreachable,
3313 }
3314}
3315
33143316pub fn res_mkquery(
33153317 op: u4,
33163318 dname: []const u8,
......@@ -3611,7 +3613,7 @@ pub const SchedYieldError = error{
36113613};
36123614
36133615pub fn sched_yield() SchedYieldError!void {
3614 if (builtin.os == .windows) {
3616 if (builtin.os.tag == .windows) {
36153617 // The return value has to do with how many other threads there are; it is not
36163618 // an error condition on Windows.
36173619 _ = windows.kernel32.SwitchToThread();
lib/std/os/bits.zig+2-2
......@@ -3,10 +3,10 @@
33//! Root source files can define `os.bits` and these will additionally be added
44//! to the namespace.
55
6const builtin = @import("builtin");
6const std = @import("std");
77const root = @import("root");
88
9pub usingnamespace switch (builtin.os) {
9pub usingnamespace switch (std.Target.current.os.tag) {
1010 .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),
1111 .dragonfly => @import("bits/dragonfly.zig"),
1212 .freebsd => @import("bits/freebsd.zig"),
lib/std/os/linux.zig+1-1
......@@ -1070,7 +1070,7 @@ pub fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) usi
10701070}
10711071
10721072test "" {
1073 if (builtin.os == .linux) {
1073 if (builtin.os.tag == .linux) {
10741074 _ = @import("linux/test.zig");
10751075 }
10761076}
lib/std/os/test.zig+8-8
......@@ -53,7 +53,7 @@ test "std.Thread.getCurrentId" {
5353 thread.wait();
5454 if (Thread.use_pthreads) {
5555 expect(thread_current_id == thread_id);
56 } else if (builtin.os == .windows) {
56 } else if (builtin.os.tag == .windows) {
5757 expect(Thread.getCurrentId() != thread_current_id);
5858 } else {
5959 // If the thread completes very quickly, then thread_id can be 0. See the
......@@ -151,7 +151,7 @@ test "realpath" {
151151}
152152
153153test "sigaltstack" {
154 if (builtin.os == .windows or builtin.os == .wasi) return error.SkipZigTest;
154 if (builtin.os.tag == .windows or builtin.os.tag == .wasi) return error.SkipZigTest;
155155
156156 var st: os.stack_t = undefined;
157157 try os.sigaltstack(null, &st);
......@@ -204,7 +204,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
204204}
205205
206206test "dl_iterate_phdr" {
207 if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
207 if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macosx)
208208 return error.SkipZigTest;
209209
210210 var counter: usize = 0;
......@@ -213,7 +213,7 @@ test "dl_iterate_phdr" {
213213}
214214
215215test "gethostname" {
216 if (builtin.os == .windows)
216 if (builtin.os.tag == .windows)
217217 return error.SkipZigTest;
218218
219219 var buf: [os.HOST_NAME_MAX]u8 = undefined;
......@@ -222,7 +222,7 @@ test "gethostname" {
222222}
223223
224224test "pipe" {
225 if (builtin.os == .windows)
225 if (builtin.os.tag == .windows)
226226 return error.SkipZigTest;
227227
228228 var fds = try os.pipe();
......@@ -241,7 +241,7 @@ test "argsAlloc" {
241241
242242test "memfd_create" {
243243 // memfd_create is linux specific.
244 if (builtin.os != .linux) return error.SkipZigTest;
244 if (builtin.os.tag != .linux) return error.SkipZigTest;
245245 const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
246246 // Related: https://github.com/ziglang/zig/issues/4019
247247 error.SystemOutdated => return error.SkipZigTest,
......@@ -258,7 +258,7 @@ test "memfd_create" {
258258}
259259
260260test "mmap" {
261 if (builtin.os == .windows)
261 if (builtin.os.tag == .windows)
262262 return error.SkipZigTest;
263263
264264 // Simple mmap() call with non page-aligned size
......@@ -353,7 +353,7 @@ test "mmap" {
353353}
354354
355355test "getenv" {
356 if (builtin.os == .windows) {
356 if (builtin.os.tag == .windows) {
357357 expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
358358 } else {
359359 expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
lib/std/packed_int_array.zig+2-2
......@@ -593,7 +593,7 @@ test "PackedInt(Array/Slice)Endian" {
593593// after this one is not mapped and will cause a segfault if we
594594// don't account for the bounds.
595595test "PackedIntArray at end of available memory" {
596 switch (builtin.os) {
596 switch (builtin.os.tag) {
597597 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
598598 else => return,
599599 }
......@@ -612,7 +612,7 @@ test "PackedIntArray at end of available memory" {
612612}
613613
614614test "PackedIntSlice at end of available memory" {
615 switch (builtin.os) {
615 switch (builtin.os.tag) {
616616 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
617617 else => return,
618618 }
lib/std/process.zig+15-11
......@@ -36,7 +36,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
3636 var result = BufMap.init(allocator);
3737 errdefer result.deinit();
3838
39 if (builtin.os == .windows) {
39 if (builtin.os.tag == .windows) {
4040 const ptr = os.windows.peb().ProcessParameters.Environment;
4141
4242 var i: usize = 0;
......@@ -61,7 +61,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
6161 try result.setMove(key, value);
6262 }
6363 return result;
64 } else if (builtin.os == .wasi) {
64 } else if (builtin.os.tag == .wasi) {
6565 var environ_count: usize = undefined;
6666 var environ_buf_size: usize = undefined;
6767
......@@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{
137137
138138/// Caller must free returned memory.
139139pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
140 if (builtin.os == .windows) {
140 if (builtin.os.tag == .windows) {
141141 const result_w = blk: {
142142 const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
143143 defer allocator.free(key_w);
......@@ -338,12 +338,12 @@ pub const ArgIteratorWindows = struct {
338338};
339339
340340pub const ArgIterator = struct {
341 const InnerType = if (builtin.os == .windows) ArgIteratorWindows else ArgIteratorPosix;
341 const InnerType = if (builtin.os.tag == .windows) ArgIteratorWindows else ArgIteratorPosix;
342342
343343 inner: InnerType,
344344
345345 pub fn init() ArgIterator {
346 if (builtin.os == .wasi) {
346 if (builtin.os.tag == .wasi) {
347347 // TODO: Figure out a compatible interface accomodating WASI
348348 @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
349349 }
......@@ -355,7 +355,7 @@ pub const ArgIterator = struct {
355355
356356 /// You must free the returned memory when done.
357357 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
358 if (builtin.os == .windows) {
358 if (builtin.os.tag == .windows) {
359359 return self.inner.next(allocator);
360360 } else {
361361 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
......@@ -380,7 +380,7 @@ pub fn args() ArgIterator {
380380
381381/// Caller must call argsFree on result.
382382pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
383 if (builtin.os == .wasi) {
383 if (builtin.os.tag == .wasi) {
384384 var count: usize = undefined;
385385 var buf_size: usize = undefined;
386386
......@@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
445445}
446446
447447pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
448 if (builtin.os == .wasi) {
448 if (builtin.os.tag == .wasi) {
449449 const last_item = args_alloc[args_alloc.len - 1];
450450 const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
451451 const first_item_ptr = args_alloc[0].ptr;
......@@ -498,7 +498,7 @@ pub const UserInfo = struct {
498498
499499/// POSIX function which gets a uid from username.
500500pub fn getUserInfo(name: []const u8) !UserInfo {
501 return switch (builtin.os) {
501 return switch (builtin.os.tag) {
502502 .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),
503503 else => @compileError("Unsupported OS"),
504504 };
......@@ -591,7 +591,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
591591}
592592
593593pub fn getBaseAddress() usize {
594 switch (builtin.os) {
594 switch (builtin.os.tag) {
595595 .linux => {
596596 const base = os.system.getauxval(std.elf.AT_BASE);
597597 if (base != 0) {
......@@ -609,13 +609,17 @@ pub fn getBaseAddress() usize {
609609}
610610
611611/// Caller owns the result value and each inner slice.
612/// TODO Remove the `Allocator` requirement from this API, which will remove the `Allocator`
613/// requirement from `std.zig.system.NativeTargetInfo.detect`. Most likely this will require
614/// introducing a new, lower-level function which takes a callback function, and then this
615/// function which takes an allocator can exist on top of it.
612616pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
613617 switch (builtin.link_mode) {
614618 .Static => return &[_][:0]u8{},
615619 .Dynamic => {},
616620 }
617621 const List = std.ArrayList([:0]u8);
618 switch (builtin.os) {
622 switch (builtin.os.tag) {
619623 .linux,
620624 .freebsd,
621625 .netbsd,
lib/std/reset_event.zig+3-3
......@@ -16,7 +16,7 @@ pub const ResetEvent = struct {
1616
1717 pub const OsEvent = if (builtin.single_threaded)
1818 DebugEvent
19 else if (builtin.link_libc and builtin.os != .windows and builtin.os != .linux)
19 else if (builtin.link_libc and builtin.os.tag != .windows and builtin.os.tag != .linux)
2020 PosixEvent
2121 else
2222 AtomicEvent;
......@@ -106,7 +106,7 @@ const PosixEvent = struct {
106106 fn deinit(self: *PosixEvent) void {
107107 // on dragonfly, *destroy() functions can return EINVAL
108108 // for statically initialized pthread structures
109 const err = if (builtin.os == .dragonfly) os.EINVAL else 0;
109 const err = if (builtin.os.tag == .dragonfly) os.EINVAL else 0;
110110
111111 const retm = c.pthread_mutex_destroy(&self.mutex);
112112 assert(retm == 0 or retm == err);
......@@ -215,7 +215,7 @@ const AtomicEvent = struct {
215215 }
216216 }
217217
218 pub const Futex = switch (builtin.os) {
218 pub const Futex = switch (builtin.os.tag) {
219219 .windows => WindowsFutex,
220220 .linux => LinuxFutex,
221221 else => SpinFutex,
lib/std/special/c.zig+4-4
......@@ -17,7 +17,7 @@ const is_msvc = switch (builtin.abi) {
1717 .msvc => true,
1818 else => false,
1919};
20const is_freestanding = switch (builtin.os) {
20const is_freestanding = switch (builtin.os.tag) {
2121 .freestanding => true,
2222 else => false,
2323};
......@@ -81,7 +81,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
8181 @setCold(true);
8282 std.debug.panic("{}", .{msg});
8383 }
84 if (builtin.os != .freestanding and builtin.os != .other) {
84 if (builtin.os.tag != .freestanding and builtin.os.tag != .other) {
8585 std.os.abort();
8686 }
8787 while (true) {}
......@@ -178,11 +178,11 @@ test "test_bcmp" {
178178comptime {
179179 if (builtin.mode != builtin.Mode.ReleaseFast and
180180 builtin.mode != builtin.Mode.ReleaseSmall and
181 builtin.os != builtin.Os.windows)
181 builtin.os.tag != .windows)
182182 {
183183 @export(__stack_chk_fail, .{ .name = "__stack_chk_fail" });
184184 }
185 if (builtin.os == builtin.Os.linux) {
185 if (builtin.os.tag == .linux) {
186186 @export(clone, .{ .name = "clone" });
187187 }
188188}
lib/std/special/compiler_rt.zig+8-10
......@@ -1,11 +1,9 @@
1const builtin = @import("builtin");
1const std = @import("std");
2const builtin = std.builtin;
23const is_test = builtin.is_test;
34
4const is_gnu = switch (builtin.abi) {
5 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
6 else => false,
7};
8const is_mingw = builtin.os == .windows and is_gnu;
5const is_gnu = std.Target.current.abi.isGnu();
6const is_mingw = builtin.os.tag == .windows and is_gnu;
97
108comptime {
119 const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
......@@ -180,7 +178,7 @@ comptime {
180178 @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
181179 @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
182180
183 if (builtin.os == .linux) {
181 if (builtin.os.tag == .linux) {
184182 @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
185183 }
186184
......@@ -250,7 +248,7 @@ comptime {
250248 @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
251249 }
252250
253 if (builtin.os == .windows) {
251 if (builtin.os.tag == .windows) {
254252 // Default stack-probe functions emitted by LLVM
255253 if (is_mingw) {
256254 @export(@import("compiler_rt/stack_probe.zig")._chkstk, .{ .name = "_alloca", .linkage = strong_linkage });
......@@ -288,7 +286,7 @@ comptime {
288286 else => {},
289287 }
290288 } else {
291 if (builtin.glibc_version != null) {
289 if (std.Target.current.isGnuLibC() and builtin.link_libc) {
292290 @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });
293291 }
294292 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
......@@ -307,7 +305,7 @@ comptime {
307305pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
308306 @setCold(true);
309307 if (is_test) {
310 @import("std").debug.panic("{}", .{msg});
308 std.debug.panic("{}", .{msg});
311309 } else {
312310 unreachable;
313311 }
lib/std/special/compiler_rt/addXf3_test.zig+2-2
......@@ -31,7 +31,7 @@ fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
3131}
3232
3333test "addtf3" {
34 if (@import("std").Target.current.isWindows()) {
34 if (@import("std").Target.current.os.tag == .windows) {
3535 // TODO https://github.com/ziglang/zig/issues/508
3636 return error.SkipZigTest;
3737 }
......@@ -75,7 +75,7 @@ fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
7575}
7676
7777test "subtf3" {
78 if (@import("std").Target.current.isWindows()) {
78 if (@import("std").Target.current.os.tag == .windows) {
7979 // TODO https://github.com/ziglang/zig/issues/508
8080 return error.SkipZigTest;
8181 }
lib/std/special/compiler_rt/extendXfYf2_test.zig+1-1
......@@ -90,7 +90,7 @@ test "extendhfsf2" {
9090 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
9191 // On x86 the NaN becomes quiet because the return is pushed on the x87
9292 // stack due to ABI requirements
93 if (builtin.arch != .i386 and builtin.os == .windows)
93 if (builtin.arch != .i386 and builtin.os.tag == .windows)
9494 test__extendhfsf2(0x7c01, 0x7f802000); // sNaN
9595
9696 test__extendhfsf2(0, 0); // 0
lib/std/special/compiler_rt/fixtfdi_test.zig+1-1
......@@ -11,7 +11,7 @@ fn test__fixtfdi(a: f128, expected: i64) void {
1111}
1212
1313test "fixtfdi" {
14 if (@import("std").Target.current.isWindows()) {
14 if (@import("std").Target.current.os.tag == .windows) {
1515 // TODO https://github.com/ziglang/zig/issues/508
1616 return error.SkipZigTest;
1717 }
lib/std/special/compiler_rt/fixtfsi_test.zig+1-1
......@@ -11,7 +11,7 @@ fn test__fixtfsi(a: f128, expected: i32) void {
1111}
1212
1313test "fixtfsi" {
14 if (@import("std").Target.current.isWindows()) {
14 if (@import("std").Target.current.os.tag == .windows) {
1515 // TODO https://github.com/ziglang/zig/issues/508
1616 return error.SkipZigTest;
1717 }
lib/std/special/compiler_rt/fixtfti_test.zig+1-1
......@@ -11,7 +11,7 @@ fn test__fixtfti(a: f128, expected: i128) void {
1111}
1212
1313test "fixtfti" {
14 if (@import("std").Target.current.isWindows()) {
14 if (@import("std").Target.current.os.tag == .windows) {
1515 // TODO https://github.com/ziglang/zig/issues/508
1616 return error.SkipZigTest;
1717 }
lib/std/special/compiler_rt/fixunstfdi_test.zig+1-1
......@@ -7,7 +7,7 @@ fn test__fixunstfdi(a: f128, expected: u64) void {
77}
88
99test "fixunstfdi" {
10 if (@import("std").Target.current.isWindows()) {
10 if (@import("std").Target.current.os.tag == .windows) {
1111 // TODO https://github.com/ziglang/zig/issues/508
1212 return error.SkipZigTest;
1313 }
lib/std/special/compiler_rt/fixunstfsi_test.zig+1-1
......@@ -9,7 +9,7 @@ fn test__fixunstfsi(a: f128, expected: u32) void {
99const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
1010
1111test "fixunstfsi" {
12 if (@import("std").Target.current.isWindows()) {
12 if (@import("std").Target.current.os.tag == .windows) {
1313 // TODO https://github.com/ziglang/zig/issues/508
1414 return error.SkipZigTest;
1515 }
lib/std/special/compiler_rt/fixunstfti_test.zig+1-1
......@@ -9,7 +9,7 @@ fn test__fixunstfti(a: f128, expected: u128) void {
99const inf128 = @bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000));
1010
1111test "fixunstfti" {
12 if (@import("std").Target.current.isWindows()) {
12 if (@import("std").Target.current.os.tag == .windows) {
1313 // TODO https://github.com/ziglang/zig/issues/508
1414 return error.SkipZigTest;
1515 }
lib/std/special/compiler_rt/floattitf_test.zig+1-1
......@@ -7,7 +7,7 @@ fn test__floattitf(a: i128, expected: f128) void {
77}
88
99test "floattitf" {
10 if (@import("std").Target.current.isWindows()) {
10 if (@import("std").Target.current.os.tag == .windows) {
1111 // TODO https://github.com/ziglang/zig/issues/508
1212 return error.SkipZigTest;
1313 }
lib/std/special/compiler_rt/floatuntitf_test.zig+1-1
......@@ -7,7 +7,7 @@ fn test__floatuntitf(a: u128, expected: f128) void {
77}
88
99test "floatuntitf" {
10 if (@import("std").Target.current.isWindows()) {
10 if (@import("std").Target.current.os.tag == .windows) {
1111 // TODO https://github.com/ziglang/zig/issues/508
1212 return error.SkipZigTest;
1313 }
lib/std/special/compiler_rt/mulXf3_test.zig+1-1
......@@ -44,7 +44,7 @@ fn makeNaN128(rand: u64) f128 {
4444 return float_result;
4545}
4646test "multf3" {
47 if (@import("std").Target.current.isWindows()) {
47 if (@import("std").Target.current.os.tag == .windows) {
4848 // TODO https://github.com/ziglang/zig/issues/508
4949 return error.SkipZigTest;
5050 }
lib/std/special/compiler_rt/truncXfYf2.zig+6-6
......@@ -1,23 +1,23 @@
11const std = @import("std");
22
33pub fn __truncsfhf2(a: f32) callconv(.C) u16 {
4 return @bitCast(u16, truncXfYf2(f16, f32, a));
4 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));
55}
66
77pub fn __truncdfhf2(a: f64) callconv(.C) u16 {
8 return @bitCast(u16, truncXfYf2(f16, f64, a));
8 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
99}
1010
1111pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
12 return truncXfYf2(f32, f128, a);
12 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a });
1313}
1414
1515pub fn __trunctfdf2(a: f128) callconv(.C) f64 {
16 return truncXfYf2(f64, f128, a);
16 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f64, f128, a });
1717}
1818
1919pub fn __truncdfsf2(a: f64) callconv(.C) f32 {
20 return truncXfYf2(f32, f64, a);
20 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f64, a });
2121}
2222
2323pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 {
......@@ -35,7 +35,7 @@ pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
3535 return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a});
3636}
3737
38inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
38fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
3939 const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits);
4040 const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits);
4141 const srcSigBits = std.math.floatMantissaBits(src_t);
lib/std/special/compiler_rt/truncXfYf2_test.zig+2-2
......@@ -151,7 +151,7 @@ fn test__trunctfsf2(a: f128, expected: u32) void {
151151}
152152
153153test "trunctfsf2" {
154 if (@import("std").Target.current.isWindows()) {
154 if (@import("std").Target.current.os.tag == .windows) {
155155 // TODO https://github.com/ziglang/zig/issues/508
156156 return error.SkipZigTest;
157157 }
......@@ -190,7 +190,7 @@ fn test__trunctfdf2(a: f128, expected: u64) void {
190190}
191191
192192test "trunctfdf2" {
193 if (@import("std").Target.current.isWindows()) {
193 if (@import("std").Target.current.os.tag == .windows) {
194194 // TODO https://github.com/ziglang/zig/issues/508
195195 return error.SkipZigTest;
196196 }
lib/std/special/init-exe/build.zig+10
......@@ -1,8 +1,18 @@
11const Builder = @import("std").build.Builder;
22
33pub fn build(b: *Builder) void {
4 // Standard target options allows the person running `zig build` to choose
5 // what target to build for. Here we do not override the defaults, which
6 // means any target is allowed, and the default is native. Other options
7 // for restricting supported target set are available.
8 const target = b.standardTargetOptions(.{});
9
10 // Standard release options allow the person running `zig build` to select
11 // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
412 const mode = b.standardReleaseOptions();
13
514 const exe = b.addExecutable("$", "src/main.zig");
15 exe.setTarget(target);
616 exe.setBuildMode(mode);
717 exe.install();
818
lib/std/special/init-exe/src/main.zig+1-1
......@@ -1,5 +1,5 @@
11const std = @import("std");
22
33pub fn main() anyerror!void {
4 std.debug.warn("All your base are belong to us.\n", .{});
4 std.debug.warn("All your codebase are belong to us.\n", .{});
55}
lib/std/spinlock.zig+1-1
......@@ -46,7 +46,7 @@ pub const SpinLock = struct {
4646 // and yielding for 380-410 iterations was found to be
4747 // a nice sweet spot. Posix systems on the other hand,
4848 // especially linux, perform better by yielding the thread.
49 switch (builtin.os) {
49 switch (builtin.os.tag) {
5050 .windows => loopHint(400),
5151 else => std.os.sched_yield() catch loopHint(1),
5252 }
lib/std/start.zig+8-8
......@@ -12,7 +12,7 @@ const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1212
1313comptime {
1414 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
15 if (builtin.os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
15 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
1616 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
1717 }
1818 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
......@@ -20,17 +20,17 @@ comptime {
2020 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
2121 @export(main, .{ .name = "main", .linkage = .Weak });
2222 }
23 } else if (builtin.os == .windows) {
23 } else if (builtin.os.tag == .windows) {
2424 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
2525 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
2626 {
2727 @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" });
2828 }
29 } else if (builtin.os == .uefi) {
29 } else if (builtin.os.tag == .uefi) {
3030 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
31 } else if (builtin.arch.isWasm() and builtin.os == .freestanding) {
31 } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
3232 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
33 } else if (builtin.os != .other and builtin.os != .freestanding) {
33 } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
3434 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
3535 }
3636 }
......@@ -78,7 +78,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
7878}
7979
8080fn _start() callconv(.Naked) noreturn {
81 if (builtin.os == builtin.Os.wasi) {
81 if (builtin.os.tag == .wasi) {
8282 // This is marked inline because for some reason LLVM in release mode fails to inline it,
8383 // and we want fewer call frames in stack traces.
8484 std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{}));
......@@ -133,7 +133,7 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
133133
134134// TODO https://github.com/ziglang/zig/issues/265
135135fn posixCallMainAndExit() noreturn {
136 if (builtin.os == builtin.Os.freebsd) {
136 if (builtin.os.tag == .freebsd) {
137137 @setAlignStack(16);
138138 }
139139 const argc = starting_stack_ptr[0];
......@@ -144,7 +144,7 @@ fn posixCallMainAndExit() noreturn {
144144 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
145145 const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count];
146146
147 if (builtin.os == .linux) {
147 if (builtin.os.tag == .linux) {
148148 // Find the beginning of the auxiliary vector
149149 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
150150 std.os.linux.elf_aux_maybe = auxv;
lib/std/target.zig+602-621
......@@ -1,61 +1,291 @@
11const std = @import("std.zig");
22const mem = std.mem;
33const builtin = std.builtin;
4const Version = std.builtin.Version;
45
56/// TODO Nearly all the functions in this namespace would be
67/// better off if https://github.com/ziglang/zig/issues/425
78/// was solved.
8pub const Target = union(enum) {
9 Native: void,
10 Cross: Cross,
11
12 pub const Os = enum {
13 freestanding,
14 ananas,
15 cloudabi,
16 dragonfly,
17 freebsd,
18 fuchsia,
19 ios,
20 kfreebsd,
21 linux,
22 lv2,
23 macosx,
24 netbsd,
25 openbsd,
26 solaris,
27 windows,
28 haiku,
29 minix,
30 rtems,
31 nacl,
32 cnk,
33 aix,
34 cuda,
35 nvcl,
36 amdhsa,
37 ps4,
38 elfiamcu,
39 tvos,
40 watchos,
41 mesa3d,
42 contiki,
43 amdpal,
44 hermit,
45 hurd,
46 wasi,
47 emscripten,
48 uefi,
49 other,
50
51 pub fn parse(text: []const u8) !Os {
52 const info = @typeInfo(Os);
53 inline for (info.Enum.fields) |field| {
54 if (mem.eql(u8, text, field.name)) {
55 return @field(Os, field.name);
9pub const Target = struct {
10 cpu: Cpu,
11 os: Os,
12 abi: Abi,
13
14 pub const Os = struct {
15 tag: Tag,
16 version_range: VersionRange,
17
18 pub const Tag = enum {
19 freestanding,
20 ananas,
21 cloudabi,
22 dragonfly,
23 freebsd,
24 fuchsia,
25 ios,
26 kfreebsd,
27 linux,
28 lv2,
29 macosx,
30 netbsd,
31 openbsd,
32 solaris,
33 windows,
34 haiku,
35 minix,
36 rtems,
37 nacl,
38 cnk,
39 aix,
40 cuda,
41 nvcl,
42 amdhsa,
43 ps4,
44 elfiamcu,
45 tvos,
46 watchos,
47 mesa3d,
48 contiki,
49 amdpal,
50 hermit,
51 hurd,
52 wasi,
53 emscripten,
54 uefi,
55 other,
56
57 pub fn isDarwin(tag: Tag) bool {
58 return switch (tag) {
59 .ios, .macosx, .watchos, .tvos => true,
60 else => false,
61 };
62 }
63
64 pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
65 if (tag.isDarwin()) {
66 return ".dylib";
67 }
68 switch (tag) {
69 .windows => return ".dll",
70 else => return ".so",
71 }
72 }
73 };
74
75 /// Based on NTDDI version constants from
76 /// https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt
77 pub const WindowsVersion = enum(u32) {
78 nt4 = 0x04000000,
79 win2k = 0x05000000,
80 xp = 0x05010000,
81 ws2003 = 0x05020000,
82 vista = 0x06000000,
83 win7 = 0x06010000,
84 win8 = 0x06020000,
85 win8_1 = 0x06030000,
86 win10 = 0x0A000000,
87 win10_th2 = 0x0A000001,
88 win10_rs1 = 0x0A000002,
89 win10_rs2 = 0x0A000003,
90 win10_rs3 = 0x0A000004,
91 win10_rs4 = 0x0A000005,
92 win10_rs5 = 0x0A000006,
93 win10_19h1 = 0x0A000007,
94 _,
95
96 pub const Range = struct {
97 min: WindowsVersion,
98 max: WindowsVersion,
99
100 pub fn includesVersion(self: Range, ver: WindowsVersion) bool {
101 return @enumToInt(ver) >= @enumToInt(self.min) and @enumToInt(ver) <= @enumToInt(self.max);
56102 }
103 };
104 };
105
106 pub const LinuxVersionRange = struct {
107 range: Version.Range,
108 glibc: Version,
109
110 pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
111 return self.range.includesVersion(ver);
57112 }
58 return error.UnknownOperatingSystem;
113 };
114
115 /// The version ranges here represent the minimum OS version to be supported
116 /// and the maximum OS version to be supported. The default values represent
117 /// the range that the Zig Standard Library bases its abstractions on.
118 ///
119 /// The minimum version of the range is the main setting to tweak for a target.
120 /// Usually, the maximum target OS version will remain the default, which is
121 /// the latest released version of the OS.
122 ///
123 /// To test at compile time if the target is guaranteed to support a given OS feature,
124 /// one should check that the minimum version of the range is greater than or equal to
125 /// the version the feature was introduced in.
126 ///
127 /// To test at compile time if the target certainly will not support a given OS feature,
128 /// one should check that the maximum version of the range is less than the version the
129 /// feature was introduced in.
130 ///
131 /// If neither of these cases apply, a runtime check should be used to determine if the
132 /// target supports a given OS feature.
133 ///
134 /// Binaries built with a given maximum version will continue to function on newer operating system
135 /// versions. However, such a binary may not take full advantage of the newer operating system APIs.
136 pub const VersionRange = union {
137 none: void,
138 semver: Version.Range,
139 linux: LinuxVersionRange,
140 windows: WindowsVersion.Range,
141
142 /// The default `VersionRange` represents the range that the Zig Standard Library
143 /// bases its abstractions on.
144 pub fn default(tag: Tag) VersionRange {
145 switch (tag) {
146 .freestanding,
147 .ananas,
148 .cloudabi,
149 .dragonfly,
150 .fuchsia,
151 .kfreebsd,
152 .lv2,
153 .solaris,
154 .haiku,
155 .minix,
156 .rtems,
157 .nacl,
158 .cnk,
159 .aix,
160 .cuda,
161 .nvcl,
162 .amdhsa,
163 .ps4,
164 .elfiamcu,
165 .mesa3d,
166 .contiki,
167 .amdpal,
168 .hermit,
169 .hurd,
170 .wasi,
171 .emscripten,
172 .uefi,
173 .other,
174 => return .{ .none = {} },
175
176 .freebsd => return .{
177 .semver = Version.Range{
178 .min = .{ .major = 12, .minor = 0 },
179 .max = .{ .major = 12, .minor = 1 },
180 },
181 },
182 .macosx => return .{
183 .semver = .{
184 .min = .{ .major = 10, .minor = 13 },
185 .max = .{ .major = 10, .minor = 15, .patch = 3 },
186 },
187 },
188 .ios => return .{
189 .semver = .{
190 .min = .{ .major = 12, .minor = 0 },
191 .max = .{ .major = 13, .minor = 4, .patch = 0 },
192 },
193 },
194 .watchos => return .{
195 .semver = .{
196 .min = .{ .major = 6, .minor = 0 },
197 .max = .{ .major = 6, .minor = 2, .patch = 0 },
198 },
199 },
200 .tvos => return .{
201 .semver = .{
202 .min = .{ .major = 13, .minor = 0 },
203 .max = .{ .major = 13, .minor = 4, .patch = 0 },
204 },
205 },
206 .netbsd => return .{
207 .semver = .{
208 .min = .{ .major = 8, .minor = 0 },
209 .max = .{ .major = 9, .minor = 0 },
210 },
211 },
212 .openbsd => return .{
213 .semver = .{
214 .min = .{ .major = 6, .minor = 6 },
215 .max = .{ .major = 6, .minor = 6 },
216 },
217 },
218
219 .linux => return .{
220 .linux = .{
221 .range = .{
222 .min = .{ .major = 3, .minor = 16 },
223 .max = .{ .major = 5, .minor = 5, .patch = 5 },
224 },
225 .glibc = .{ .major = 2, .minor = 17 },
226 },
227 },
228
229 .windows => return .{
230 .windows = .{
231 .min = .win8_1,
232 .max = .win10_19h1,
233 },
234 },
235 }
236 }
237 };
238
239 pub fn defaultVersionRange(tag: Tag) Os {
240 return .{
241 .tag = tag,
242 .version_range = VersionRange.default(tag),
243 };
244 }
245
246 pub fn requiresLibC(os: Os) bool {
247 return switch (os.tag) {
248 .freebsd,
249 .netbsd,
250 .macosx,
251 .ios,
252 .tvos,
253 .watchos,
254 .dragonfly,
255 .openbsd,
256 => true,
257
258 .linux,
259 .windows,
260 .freestanding,
261 .ananas,
262 .cloudabi,
263 .fuchsia,
264 .kfreebsd,
265 .lv2,
266 .solaris,
267 .haiku,
268 .minix,
269 .rtems,
270 .nacl,
271 .cnk,
272 .aix,
273 .cuda,
274 .nvcl,
275 .amdhsa,
276 .ps4,
277 .elfiamcu,
278 .mesa3d,
279 .contiki,
280 .amdpal,
281 .hermit,
282 .hurd,
283 .wasi,
284 .emscripten,
285 .uefi,
286 .other,
287 => false,
288 };
59289 }
60290 };
61291
......@@ -100,11 +330,10 @@ pub const Target = union(enum) {
100330 macabi,
101331
102332 pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
103 switch (arch) {
104 .wasm32, .wasm64 => return .musl,
105 else => {},
333 if (arch.isWasm()) {
334 return .musl;
106335 }
107 switch (target_os) {
336 switch (target_os.tag) {
108337 .freestanding,
109338 .ananas,
110339 .cloudabi,
......@@ -149,14 +378,25 @@ pub const Target = union(enum) {
149378 }
150379 }
151380
152 pub fn parse(text: []const u8) !Abi {
153 const info = @typeInfo(Abi);
154 inline for (info.Enum.fields) |field| {
155 if (mem.eql(u8, text, field.name)) {
156 return @field(Abi, field.name);
157 }
158 }
159 return error.UnknownApplicationBinaryInterface;
381 pub fn isGnu(abi: Abi) bool {
382 return switch (abi) {
383 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
384 else => false,
385 };
386 }
387
388 pub fn isMusl(abi: Abi) bool {
389 return switch (abi) {
390 .musl, .musleabi, .musleabihf => true,
391 else => false,
392 };
393 }
394
395 pub fn oFileExt(abi: Abi) [:0]const u8 {
396 return switch (abi) {
397 .msvc => ".obj",
398 else => ".o",
399 };
160400 }
161401 };
162402
......@@ -179,12 +419,6 @@ pub const Target = union(enum) {
179419 EfiRuntimeDriver,
180420 };
181421
182 pub const Cross = struct {
183 cpu: Cpu,
184 os: Os,
185 abi: Abi,
186 };
187
188422 pub const Cpu = struct {
189423 /// Architecture
190424 arch: Arch,
......@@ -230,6 +464,12 @@ pub const Target = union(enum) {
230464 return Set{ .ints = [1]usize{0} ** usize_count };
231465 }
232466
467 pub fn isEmpty(set: Set) bool {
468 return for (set.ints) |x| {
469 if (x != 0) break false;
470 } else true;
471 }
472
233473 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
234474 const usize_index = arch_feature_index / @bitSizeOf(usize);
235475 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
......@@ -256,6 +496,15 @@ pub const Target = union(enum) {
256496 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
257497 }
258498
499 /// Removes the specified feature but not its dependents.
500 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
501 // TODO should be able to use binary not on @Vector type.
502 // https://github.com/ziglang/zig/issues/903
503 for (set.ints) |*int, i| {
504 int.* &= ~other_set.ints[i];
505 }
506 }
507
259508 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
260509 @setEvalBranchQuota(1000000);
261510
......@@ -393,7 +642,7 @@ pub const Target = union(enum) {
393642 return cpu;
394643 }
395644 }
396 return error.UnknownCpu;
645 return error.UnknownCpuModel;
397646 }
398647
399648 pub fn toElfMachine(arch: Arch) std.elf.EM {
......@@ -509,6 +758,66 @@ pub const Target = union(enum) {
509758 };
510759 }
511760
761 pub fn ptrBitWidth(arch: Arch) u32 {
762 switch (arch) {
763 .avr,
764 .msp430,
765 => return 16,
766
767 .arc,
768 .arm,
769 .armeb,
770 .hexagon,
771 .le32,
772 .mips,
773 .mipsel,
774 .powerpc,
775 .r600,
776 .riscv32,
777 .sparc,
778 .sparcel,
779 .tce,
780 .tcele,
781 .thumb,
782 .thumbeb,
783 .i386,
784 .xcore,
785 .nvptx,
786 .amdil,
787 .hsail,
788 .spir,
789 .kalimba,
790 .shave,
791 .lanai,
792 .wasm32,
793 .renderscript32,
794 .aarch64_32,
795 => return 32,
796
797 .aarch64,
798 .aarch64_be,
799 .mips64,
800 .mips64el,
801 .powerpc64,
802 .powerpc64le,
803 .riscv64,
804 .x86_64,
805 .nvptx64,
806 .le64,
807 .amdil64,
808 .hsail64,
809 .spir64,
810 .wasm64,
811 .renderscript64,
812 .amdgcn,
813 .bpfel,
814 .bpfeb,
815 .sparcv9,
816 .s390x,
817 => return 64,
818 }
819 }
820
512821 /// Returns a name that matches the lib/std/target/* directory name.
513822 pub fn genericName(arch: Arch) []const u8 {
514823 return switch (arch) {
......@@ -576,16 +885,6 @@ pub const Target = union(enum) {
576885 else => &[0]*const Model{},
577886 };
578887 }
579
580 pub fn parse(text: []const u8) !Arch {
581 const info = @typeInfo(Arch);
582 inline for (info.Enum.fields) |field| {
583 if (mem.eql(u8, text, field.name)) {
584 return @as(Arch, @field(Arch, field.name));
585 }
586 }
587 return error.UnknownArchitecture;
588 }
589888 };
590889
591890 pub const Model = struct {
......@@ -602,524 +901,168 @@ pub const Target = union(enum) {
602901 .features = features,
603902 };
604903 }
904
905 pub fn baseline(arch: Arch) *const Model {
906 const S = struct {
907 const generic_model = Model{
908 .name = "generic",
909 .llvm_name = null,
910 .features = Cpu.Feature.Set.empty,
911 };
912 };
913 return switch (arch) {
914 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
915 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
916 .avr => &avr.cpu.avr1,
917 .bpfel, .bpfeb => &bpf.cpu.generic,
918 .hexagon => &hexagon.cpu.generic,
919 .mips, .mipsel => &mips.cpu.mips32,
920 .mips64, .mips64el => &mips.cpu.mips64,
921 .msp430 => &msp430.cpu.generic,
922 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
923 .amdgcn => &amdgpu.cpu.generic,
924 .riscv32 => &riscv.cpu.baseline_rv32,
925 .riscv64 => &riscv.cpu.baseline_rv64,
926 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
927 .s390x => &systemz.cpu.generic,
928 .i386 => &x86.cpu.pentium4,
929 .x86_64 => &x86.cpu.x86_64,
930 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
931 .wasm32, .wasm64 => &wasm.cpu.generic,
932
933 else => &S.generic_model,
934 };
935 }
605936 };
606937
607938 /// The "default" set of CPU features for cross-compiling. A conservative set
608939 /// of features that is expected to be supported on most available hardware.
609940 pub fn baseline(arch: Arch) Cpu {
610 const S = struct {
611 const generic_model = Model{
612 .name = "generic",
613 .llvm_name = null,
614 .features = Cpu.Feature.Set.empty,
615 };
616 };
617 const model = switch (arch) {
618 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
619 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
620 .avr => &avr.cpu.avr1,
621 .bpfel, .bpfeb => &bpf.cpu.generic,
622 .hexagon => &hexagon.cpu.generic,
623 .mips, .mipsel => &mips.cpu.mips32,
624 .mips64, .mips64el => &mips.cpu.mips64,
625 .msp430 => &msp430.cpu.generic,
626 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
627 .amdgcn => &amdgpu.cpu.generic,
628 .riscv32 => &riscv.cpu.baseline_rv32,
629 .riscv64 => &riscv.cpu.baseline_rv64,
630 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
631 .s390x => &systemz.cpu.generic,
632 .i386 => &x86.cpu.pentium4,
633 .x86_64 => &x86.cpu.x86_64,
634 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
635 .wasm32, .wasm64 => &wasm.cpu.generic,
636
637 else => &S.generic_model,
638 };
639 return model.toCpu(arch);
941 return Model.baseline(arch).toCpu(arch);
640942 }
641943 };
642944
643945 pub const current = Target{
644 .Cross = Cross{
645 .cpu = builtin.cpu,
646 .os = builtin.os,
647 .abi = builtin.abi,
648 },
946 .cpu = builtin.cpu,
947 .os = builtin.os,
948 .abi = builtin.abi,
649949 };
650950
651951 pub const stack_align = 16;
652952
653 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
654 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
655 @tagName(self.getArch()),
656 @tagName(self.getOs()),
657 @tagName(self.getAbi()),
658 });
659 }
660
661 /// Returned slice must be freed by the caller.
662 pub fn vcpkgTriplet(allocator: *mem.Allocator, target: Target, linkage: std.build.VcpkgLinkage) ![]const u8 {
663 const arch = switch (target.getArch()) {
664 .i386 => "x86",
665 .x86_64 => "x64",
666
667 .arm,
668 .armeb,
669 .thumb,
670 .thumbeb,
671 .aarch64_32,
672 => "arm",
673
674 .aarch64,
675 .aarch64_be,
676 => "arm64",
677
678 else => return error.VcpkgNoSuchArchitecture,
679 };
680
681 const os = switch (target.getOs()) {
682 .windows => "windows",
683 .linux => "linux",
684 .macosx => "macos",
685 else => return error.VcpkgNoSuchOs,
686 };
687
688 if (linkage == .Static) {
689 return try mem.join(allocator, "-", &[_][]const u8{ arch, os, "static" });
690 } else {
691 return try mem.join(allocator, "-", &[_][]const u8{ arch, os });
692 }
953 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
954 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
693955 }
694956
695 pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 {
696 // TODO is there anything else worthy of the description that is not
697 // already captured in the triple?
698 return self.zigTriple(allocator);
957 pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
958 return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
699959 }
700960
701 pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 {
702 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
703 @tagName(self.getArch()),
704 @tagName(self.getOs()),
705 @tagName(self.getAbi()),
706 });
961 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
962 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
707963 }
708964
709 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
710 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{
711 @tagName(self.getArch()),
712 @tagName(self.getOs()),
713 @tagName(self.getAbi()),
714 });
965 pub fn oFileExt(self: Target) [:0]const u8 {
966 return self.abi.oFileExt();
715967 }
716968
717 pub const ParseOptions = struct {
718 /// This is sometimes called a "triple". It looks roughly like this:
719 /// riscv64-linux-gnu
720 /// The fields are, respectively:
721 /// * CPU Architecture
722 /// * Operating System
723 /// * C ABI (optional)
724 arch_os_abi: []const u8,
725
726 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
727 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
728 /// to remove from the set.
729 cpu_features: []const u8 = "baseline",
730
731 /// If this is provided, the function will populate some information about parsing failures,
732 /// so that user-friendly error messages can be delivered.
733 diagnostics: ?*Diagnostics = null,
734
735 pub const Diagnostics = struct {
736 /// If the architecture was determined, this will be populated.
737 arch: ?Cpu.Arch = null,
738
739 /// If the OS was determined, this will be populated.
740 os: ?Os = null,
741
742 /// If the ABI was determined, this will be populated.
743 abi: ?Abi = null,
744
745 /// If the CPU name was determined, this will be populated.
746 cpu_name: ?[]const u8 = null,
747
748 /// If error.UnknownCpuFeature is returned, this will be populated.
749 unknown_feature_name: ?[]const u8 = null,
750 };
751 };
752
753 pub fn parse(args: ParseOptions) !Target {
754 var dummy_diags: ParseOptions.Diagnostics = undefined;
755 var diags = args.diagnostics orelse &dummy_diags;
756
757 var it = mem.separate(args.arch_os_abi, "-");
758 const arch_name = it.next() orelse return error.MissingArchitecture;
759 const arch = try Cpu.Arch.parse(arch_name);
760 diags.arch = arch;
761
762 const os_name = it.next() orelse return error.MissingOperatingSystem;
763 const os = try Os.parse(os_name);
764 diags.os = os;
765
766 const abi_name = it.next();
767 const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os);
768 diags.abi = abi;
769
770 if (it.next() != null) return error.UnexpectedExtraField;
771
772 const all_features = arch.allFeaturesList();
773 var index: usize = 0;
774 while (index < args.cpu_features.len and
775 args.cpu_features[index] != '+' and
776 args.cpu_features[index] != '-')
777 {
778 index += 1;
969 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
970 switch (os_tag) {
971 .windows => return ".exe",
972 .uefi => return ".efi",
973 else => if (cpu_arch.isWasm()) {
974 return ".wasm";
975 } else {
976 return "";
977 },
779978 }
780 const cpu_name = args.cpu_features[0..index];
781 diags.cpu_name = cpu_name;
782
783 const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
784 const cpu_model = try arch.parseCpuModel(cpu_name);
785
786 var set = cpu_model.features;
787 while (index < args.cpu_features.len) {
788 const op = args.cpu_features[index];
789 index += 1;
790 const start = index;
791 while (index < args.cpu_features.len and
792 args.cpu_features[index] != '+' and
793 args.cpu_features[index] != '-')
794 {
795 index += 1;
796 }
797 const feature_name = args.cpu_features[start..index];
798 for (all_features) |feature, feat_index_usize| {
799 const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize);
800 if (mem.eql(u8, feature_name, feature.name)) {
801 switch (op) {
802 '+' => set.addFeature(feat_index),
803 '-' => set.removeFeature(feat_index),
804 else => unreachable,
805 }
806 break;
807 }
808 } else {
809 diags.unknown_feature_name = feature_name;
810 return error.UnknownCpuFeature;
811 }
812 }
813 set.populateDependencies(all_features);
814 break :blk .{
815 .arch = arch,
816 .model = cpu_model,
817 .features = set,
818 };
819 };
820 var cross = Cross{
821 .cpu = cpu,
822 .os = os,
823 .abi = abi,
824 };
825 return Target{ .Cross = cross };
826979 }
827980
828 pub fn oFileExt(self: Target) []const u8 {
829 return switch (self.getAbi()) {
830 .msvc => ".obj",
831 else => ".o",
832 };
981 pub fn exeFileExt(self: Target) [:0]const u8 {
982 return exeFileExtSimple(self.cpu.arch, self.os.tag);
833983 }
834984
835 pub fn exeFileExt(self: Target) []const u8 {
836 if (self.isWindows()) {
837 return ".exe";
838 } else if (self.isUefi()) {
839 return ".efi";
840 } else if (self.isWasm()) {
985 pub fn staticLibSuffix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
986 if (cpu_arch.isWasm()) {
841987 return ".wasm";
842 } else {
843 return "";
844988 }
845 }
846
847 pub fn staticLibSuffix(self: Target) []const u8 {
848 if (self.isWasm()) {
849 return ".wasm";
850 }
851 switch (self.getAbi()) {
989 switch (abi) {
852990 .msvc => return ".lib",
853991 else => return ".a",
854992 }
855993 }
856994
857 pub fn dynamicLibSuffix(self: Target) []const u8 {
858 if (self.isDarwin()) {
859 return ".dylib";
860 }
861 switch (self.getOs()) {
862 .windows => return ".dll",
863 else => return ".so",
864 }
995 pub fn staticLibSuffix(self: Target) [:0]const u8 {
996 return staticLibSuffix_cpu_arch_abi(self.cpu.arch, self.abi);
997 }
998
999 pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
1000 return self.os.tag.dynamicLibSuffix();
8651001 }
8661002
867 pub fn libPrefix(self: Target) []const u8 {
868 if (self.isWasm()) {
1003 pub fn libPrefix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
1004 if (cpu_arch.isWasm()) {
8691005 return "";
8701006 }
871 switch (self.getAbi()) {
1007 switch (abi) {
8721008 .msvc => return "",
8731009 else => return "lib",
8741010 }
8751011 }
8761012
877 pub fn getOs(self: Target) Os {
878 return switch (self) {
879 .Native => builtin.os,
880 .Cross => |t| t.os,
881 };
882 }
883
884 pub fn getCpu(self: Target) Cpu {
885 return switch (self) {
886 .Native => builtin.cpu,
887 .Cross => |cross| cross.cpu,
888 };
889 }
890
891 pub fn getArch(self: Target) Cpu.Arch {
892 return self.getCpu().arch;
893 }
894
895 pub fn getAbi(self: Target) Abi {
896 switch (self) {
897 .Native => return builtin.abi,
898 .Cross => |t| return t.abi,
899 }
1013 pub fn libPrefix(self: Target) [:0]const u8 {
1014 return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
9001015 }
9011016
9021017 pub fn getObjectFormat(self: Target) ObjectFormat {
903 switch (self) {
904 .Native => return @import("builtin").object_format,
905 .Cross => blk: {
906 if (self.isWindows() or self.isUefi()) {
907 return .coff;
908 } else if (self.isDarwin()) {
909 return .macho;
910 }
911 if (self.isWasm()) {
912 return .wasm;
913 }
914 return .elf;
915 },
1018 if (self.os.tag == .windows or self.os.tag == .uefi) {
1019 return .coff;
1020 } else if (self.isDarwin()) {
1021 return .macho;
1022 }
1023 if (self.cpu.arch.isWasm()) {
1024 return .wasm;
9161025 }
1026 return .elf;
9171027 }
9181028
9191029 pub fn isMinGW(self: Target) bool {
920 return self.isWindows() and self.isGnu();
1030 return self.os.tag == .windows and self.isGnu();
9211031 }
9221032
9231033 pub fn isGnu(self: Target) bool {
924 return switch (self.getAbi()) {
925 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
926 else => false,
927 };
1034 return self.abi.isGnu();
9281035 }
9291036
9301037 pub fn isMusl(self: Target) bool {
931 return switch (self.getAbi()) {
932 .musl, .musleabi, .musleabihf => true,
933 else => false,
934 };
935 }
936
937 pub fn isDarwin(self: Target) bool {
938 return switch (self.getOs()) {
939 .ios, .macosx, .watchos, .tvos => true,
940 else => false,
941 };
942 }
943
944 pub fn isWindows(self: Target) bool {
945 return switch (self.getOs()) {
946 .windows => true,
947 else => false,
948 };
949 }
950
951 pub fn isLinux(self: Target) bool {
952 return switch (self.getOs()) {
953 .linux => true,
954 else => false,
955 };
1038 return self.abi.isMusl();
9561039 }
9571040
9581041 pub fn isAndroid(self: Target) bool {
959 return switch (self.getAbi()) {
1042 return switch (self.abi) {
9601043 .android => true,
9611044 else => false,
9621045 };
9631046 }
9641047
965 pub fn isDragonFlyBSD(self: Target) bool {
966 return switch (self.getOs()) {
967 .dragonfly => true,
968 else => false,
969 };
970 }
971
972 pub fn isUefi(self: Target) bool {
973 return switch (self.getOs()) {
974 .uefi => true,
975 else => false,
976 };
977 }
978
9791048 pub fn isWasm(self: Target) bool {
980 return switch (self.getArch()) {
981 .wasm32, .wasm64 => true,
982 else => false,
983 };
984 }
985
986 pub fn isFreeBSD(self: Target) bool {
987 return switch (self.getOs()) {
988 .freebsd => true,
989 else => false,
990 };
1049 return self.cpu.arch.isWasm();
9911050 }
9921051
993 pub fn isNetBSD(self: Target) bool {
994 return switch (self.getOs()) {
995 .netbsd => true,
996 else => false,
997 };
1052 pub fn isDarwin(self: Target) bool {
1053 return self.os.tag.isDarwin();
9981054 }
9991055
1000 pub fn wantSharedLibSymLinks(self: Target) bool {
1001 return !self.isWindows();
1056 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
1057 return os_tag == .linux and abi.isGnu();
10021058 }
10031059
1004 pub fn osRequiresLibC(self: Target) bool {
1005 return self.isDarwin() or self.isFreeBSD() or self.isNetBSD();
1006 }
1007
1008 pub fn getArchPtrBitWidth(self: Target) u32 {
1009 switch (self.getArch()) {
1010 .avr,
1011 .msp430,
1012 => return 16,
1013
1014 .arc,
1015 .arm,
1016 .armeb,
1017 .hexagon,
1018 .le32,
1019 .mips,
1020 .mipsel,
1021 .powerpc,
1022 .r600,
1023 .riscv32,
1024 .sparc,
1025 .sparcel,
1026 .tce,
1027 .tcele,
1028 .thumb,
1029 .thumbeb,
1030 .i386,
1031 .xcore,
1032 .nvptx,
1033 .amdil,
1034 .hsail,
1035 .spir,
1036 .kalimba,
1037 .shave,
1038 .lanai,
1039 .wasm32,
1040 .renderscript32,
1041 .aarch64_32,
1042 => return 32,
1043
1044 .aarch64,
1045 .aarch64_be,
1046 .mips64,
1047 .mips64el,
1048 .powerpc64,
1049 .powerpc64le,
1050 .riscv64,
1051 .x86_64,
1052 .nvptx64,
1053 .le64,
1054 .amdil64,
1055 .hsail64,
1056 .spir64,
1057 .wasm64,
1058 .renderscript64,
1059 .amdgcn,
1060 .bpfel,
1061 .bpfeb,
1062 .sparcv9,
1063 .s390x,
1064 => return 64,
1065 }
1060 pub fn isGnuLibC(self: Target) bool {
1061 return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
10661062 }
10671063
10681064 pub fn supportsNewStackCall(self: Target) bool {
1069 return !self.isWasm();
1070 }
1071
1072 pub const Executor = union(enum) {
1073 native,
1074 qemu: []const u8,
1075 wine: []const u8,
1076 wasmtime: []const u8,
1077 unavailable,
1078 };
1079
1080 pub fn getExternalExecutor(self: Target) Executor {
1081 if (@as(@TagType(Target), self) == .Native) return .native;
1082
1083 // If the target OS matches the host OS, we can use QEMU to emulate a foreign architecture.
1084 if (self.getOs() == builtin.os) {
1085 return switch (self.getArch()) {
1086 .aarch64 => Executor{ .qemu = "qemu-aarch64" },
1087 .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
1088 .arm => Executor{ .qemu = "qemu-arm" },
1089 .armeb => Executor{ .qemu = "qemu-armeb" },
1090 .i386 => Executor{ .qemu = "qemu-i386" },
1091 .mips => Executor{ .qemu = "qemu-mips" },
1092 .mipsel => Executor{ .qemu = "qemu-mipsel" },
1093 .mips64 => Executor{ .qemu = "qemu-mips64" },
1094 .mips64el => Executor{ .qemu = "qemu-mips64el" },
1095 .powerpc => Executor{ .qemu = "qemu-ppc" },
1096 .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
1097 .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
1098 .riscv32 => Executor{ .qemu = "qemu-riscv32" },
1099 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
1100 .s390x => Executor{ .qemu = "qemu-s390x" },
1101 .sparc => Executor{ .qemu = "qemu-sparc" },
1102 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
1103 else => return .unavailable,
1104 };
1105 }
1106
1107 if (self.isWindows()) {
1108 switch (self.getArchPtrBitWidth()) {
1109 32 => return Executor{ .wine = "wine" },
1110 64 => return Executor{ .wine = "wine64" },
1111 else => return .unavailable,
1112 }
1113 }
1114
1115 if (self.getOs() == .wasi) {
1116 switch (self.getArchPtrBitWidth()) {
1117 32 => return Executor{ .wasmtime = "wasmtime" },
1118 else => return .unavailable,
1119 }
1120 }
1121
1122 return .unavailable;
1065 return !self.cpu.arch.isWasm();
11231066 }
11241067
11251068 pub const FloatAbi = enum {
......@@ -1129,7 +1072,7 @@ pub const Target = union(enum) {
11291072 };
11301073
11311074 pub fn getFloatAbi(self: Target) FloatAbi {
1132 return switch (self.getAbi()) {
1075 return switch (self.abi) {
11331076 .gnueabihf,
11341077 .eabihf,
11351078 .musleabihf,
......@@ -1139,13 +1082,10 @@ pub const Target = union(enum) {
11391082 }
11401083
11411084 pub fn hasDynamicLinker(self: Target) bool {
1142 switch (self.getArch()) {
1143 .wasm32,
1144 .wasm64,
1145 => return false,
1146 else => {},
1085 if (self.cpu.arch.isWasm()) {
1086 return false;
11471087 }
1148 switch (self.getOs()) {
1088 switch (self.os.tag) {
11491089 .freestanding,
11501090 .ios,
11511091 .tvos,
......@@ -1160,65 +1100,95 @@ pub const Target = union(enum) {
11601100 }
11611101 }
11621102
1163 /// Caller owns returned memory.
1164 pub fn getStandardDynamicLinkerPath(
1165 self: Target,
1166 allocator: *mem.Allocator,
1167 ) error{
1168 OutOfMemory,
1169 UnknownDynamicLinkerPath,
1170 TargetHasNoDynamicLinker,
1171 }![:0]u8 {
1172 const a = allocator;
1173 if (self.isAndroid()) {
1174 return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
1175 "/system/bin/linker64"
1176 else
1177 "/system/bin/linker");
1103 pub const DynamicLinker = struct {
1104 /// Contains the memory used to store the dynamic linker path. This field should
1105 /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator.
1106 buffer: [255]u8 = undefined,
1107
1108 /// Used to construct the dynamic linker path. This field should not be used
1109 /// directly. See `get` and `set`.
1110 max_byte: ?u8 = null,
1111
1112 /// Asserts that the length is less than or equal to 255 bytes.
1113 pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
1114 var result: DynamicLinker = undefined;
1115 result.set(dl_or_null);
1116 return result;
11781117 }
11791118
1180 if (self.isMusl()) {
1181 var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
1182 defer result.deinit();
1183
1184 var is_arm = false;
1185 switch (self.getArch()) {
1186 .arm, .thumb => {
1187 try result.append("arm");
1188 is_arm = true;
1189 },
1190 .armeb, .thumbeb => {
1191 try result.append("armeb");
1192 is_arm = true;
1193 },
1194 else => |arch| try result.append(@tagName(arch)),
1119 /// The returned memory has the same lifetime as the `DynamicLinker`.
1120 pub fn get(self: *const DynamicLinker) ?[]const u8 {
1121 const m: usize = self.max_byte orelse return null;
1122 return self.buffer[0 .. m + 1];
1123 }
1124
1125 /// Asserts that the length is less than or equal to 255 bytes.
1126 pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
1127 if (dl_or_null) |dl| {
1128 mem.copy(u8, &self.buffer, dl);
1129 self.max_byte = @intCast(u8, dl.len - 1);
1130 } else {
1131 self.max_byte = null;
1132 }
1133 }
1134 };
1135
1136 /// The result will be a byte index *pointing at the final byte*. In other words, length minus one.
1137 /// A return value of `null` means the concept of a dynamic linker is not meaningful for that target.
1138 pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
1139 var result: DynamicLinker = .{};
1140 const S = struct {
1141 fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker {
1142 r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
1143 return r.*;
11951144 }
1196 if (is_arm and self.getFloatAbi() == .hard) {
1197 try result.append("hf");
1145 fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
1146 mem.copy(u8, &r.buffer, s);
1147 r.max_byte = @intCast(u8, s.len - 1);
1148 return r.*;
11981149 }
1199 try result.append(".so.1");
1200 return result.toOwnedSlice();
1150 };
1151 const print = S.print;
1152 const copy = S.copy;
1153
1154 if (self.isAndroid()) {
1155 const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
1156 return print(&result, "/system/bin/linker{}", .{suffix});
12011157 }
12021158
1203 switch (self.getOs()) {
1204 .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
1205 .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
1206 .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
1207 .linux => switch (self.getArch()) {
1159 if (self.isMusl()) {
1160 const is_arm = switch (self.cpu.arch) {
1161 .arm, .armeb, .thumb, .thumbeb => true,
1162 else => false,
1163 };
1164 const arch_part = switch (self.cpu.arch) {
1165 .arm, .thumb => "arm",
1166 .armeb, .thumbeb => "armeb",
1167 else => |arch| @tagName(arch),
1168 };
1169 const arch_suffix = if (is_arm and self.getFloatAbi() == .hard) "hf" else "";
1170 return print(&result, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
1171 }
1172
1173 switch (self.os.tag) {
1174 .freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
1175 .netbsd => return copy(&result, "/libexec/ld.elf_so"),
1176 .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
1177 .linux => switch (self.cpu.arch) {
12081178 .i386,
12091179 .sparc,
12101180 .sparcel,
1211 => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
1181 => return copy(&result, "/lib/ld-linux.so.2"),
12121182
1213 .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
1214 .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
1215 .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
1183 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
1184 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
1185 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
12161186
12171187 .arm,
12181188 .armeb,
12191189 .thumb,
12201190 .thumbeb,
1221 => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
1191 => return copy(&result, switch (self.getFloatAbi()) {
12221192 .hard => "/lib/ld-linux-armhf.so.3",
12231193 else => "/lib/ld-linux.so.3",
12241194 }),
......@@ -1227,28 +1197,43 @@ pub const Target = union(enum) {
12271197 .mipsel,
12281198 .mips64,
12291199 .mips64el,
1230 => return error.UnknownDynamicLinkerPath,
1200 => {
1201 const lib_suffix = switch (self.abi) {
1202 .gnuabin32, .gnux32 => "32",
1203 .gnuabi64 => "64",
1204 else => "",
1205 };
1206 const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
1207 const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
1208 return print(&result, "/lib{}/{}", .{ lib_suffix, loader });
1209 },
12311210
1232 .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
1233 .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
1234 .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
1235 .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
1236 .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
1211 .powerpc => return copy(&result, "/lib/ld.so.1"),
1212 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
1213 .s390x => return copy(&result, "/lib64/ld64.so.1"),
1214 .sparcv9 => return copy(&result, "/lib64/ld-linux.so.2"),
1215 .x86_64 => return copy(&result, switch (self.abi) {
12371216 .gnux32 => "/libx32/ld-linux-x32.so.2",
12381217 else => "/lib64/ld-linux-x86-64.so.2",
12391218 }),
12401219
1241 .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
1242 .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
1220 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
1221 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
12431222
1223 // Architectures in this list have been verified as not having a standard
1224 // dynamic linker path.
12441225 .wasm32,
12451226 .wasm64,
1246 => return error.TargetHasNoDynamicLinker,
1227 .bpfel,
1228 .bpfeb,
1229 .nvptx,
1230 .nvptx64,
1231 => return result,
12471232
1233 // TODO go over each item in this list and either move it to the above list, or
1234 // implement the standard dynamic linker path code for it.
12481235 .arc,
12491236 .avr,
1250 .bpfel,
1251 .bpfeb,
12521237 .hexagon,
12531238 .msp430,
12541239 .r600,
......@@ -1256,8 +1241,6 @@ pub const Target = union(enum) {
12561241 .tce,
12571242 .tcele,
12581243 .xcore,
1259 .nvptx,
1260 .nvptx64,
12611244 .le32,
12621245 .le64,
12631246 .amdil,
......@@ -1271,9 +1254,11 @@ pub const Target = union(enum) {
12711254 .lanai,
12721255 .renderscript32,
12731256 .renderscript64,
1274 => return error.UnknownDynamicLinkerPath,
1257 => return result,
12751258 },
12761259
1260 // Operating systems in this list have been verified as not having a standard
1261 // dynamic linker path.
12771262 .freestanding,
12781263 .ios,
12791264 .tvos,
......@@ -1282,40 +1267,36 @@ pub const Target = union(enum) {
12821267 .uefi,
12831268 .windows,
12841269 .emscripten,
1270 .wasi,
12851271 .other,
1286 => return error.TargetHasNoDynamicLinker,
1287
1288 else => return error.UnknownDynamicLinkerPath,
1272 => return result,
1273
1274 // TODO go over each item in this list and either move it to the above list, or
1275 // implement the standard dynamic linker path code for it.
1276 .ananas,
1277 .cloudabi,
1278 .fuchsia,
1279 .kfreebsd,
1280 .lv2,
1281 .openbsd,
1282 .solaris,
1283 .haiku,
1284 .minix,
1285 .rtems,
1286 .nacl,
1287 .cnk,
1288 .aix,
1289 .cuda,
1290 .nvcl,
1291 .amdhsa,
1292 .ps4,
1293 .elfiamcu,
1294 .mesa3d,
1295 .contiki,
1296 .amdpal,
1297 .hermit,
1298 .hurd,
1299 => return result,
12891300 }
12901301 }
12911302};
1292
1293test "Target.parse" {
1294 {
1295 const target = (try Target.parse(.{
1296 .arch_os_abi = "x86_64-linux-gnu",
1297 .cpu_features = "x86_64-sse-sse2-avx-cx8",
1298 })).Cross;
1299
1300 std.testing.expect(target.os == .linux);
1301 std.testing.expect(target.abi == .gnu);
1302 std.testing.expect(target.cpu.arch == .x86_64);
1303 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
1304 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
1305 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
1306 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
1307 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
1308 }
1309 {
1310 const target = (try Target.parse(.{
1311 .arch_os_abi = "arm-linux-musleabihf",
1312 .cpu_features = "generic+v8a",
1313 })).Cross;
1314
1315 std.testing.expect(target.os == .linux);
1316 std.testing.expect(target.abi == .musleabihf);
1317 std.testing.expect(target.cpu.arch == .arm);
1318 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
1319 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
1320 }
1321}
lib/std/testing.zig+4-6
......@@ -1,5 +1,3 @@
1const builtin = @import("builtin");
2const TypeId = builtin.TypeId;
31const std = @import("std.zig");
42
53pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
......@@ -65,16 +63,16 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
6563
6664 .Pointer => |pointer| {
6765 switch (pointer.size) {
68 builtin.TypeInfo.Pointer.Size.One,
69 builtin.TypeInfo.Pointer.Size.Many,
70 builtin.TypeInfo.Pointer.Size.C,
66 .One,
67 .Many,
68 .C,
7169 => {
7270 if (actual != expected) {
7371 std.debug.panic("expected {*}, found {*}", .{ expected, actual });
7472 }
7573 },
7674
77 builtin.TypeInfo.Pointer.Size.Slice => {
75 .Slice => {
7876 if (actual.ptr != expected.ptr) {
7977 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
8078 }
lib/std/thread.zig+10-10
......@@ -9,14 +9,14 @@ const assert = std.debug.assert;
99pub const Thread = struct {
1010 data: Data,
1111
12 pub const use_pthreads = builtin.os != .windows and builtin.link_libc;
12 pub const use_pthreads = builtin.os.tag != .windows and builtin.link_libc;
1313
1414 /// Represents a kernel thread handle.
1515 /// May be an integer or a pointer depending on the platform.
1616 /// On Linux and POSIX, this is the same as Id.
1717 pub const Handle = if (use_pthreads)
1818 c.pthread_t
19 else switch (builtin.os) {
19 else switch (builtin.os.tag) {
2020 .linux => i32,
2121 .windows => windows.HANDLE,
2222 else => void,
......@@ -25,7 +25,7 @@ pub const Thread = struct {
2525 /// Represents a unique ID per thread.
2626 /// May be an integer or pointer depending on the platform.
2727 /// On Linux and POSIX, this is the same as Handle.
28 pub const Id = switch (builtin.os) {
28 pub const Id = switch (builtin.os.tag) {
2929 .windows => windows.DWORD,
3030 else => Handle,
3131 };
......@@ -35,7 +35,7 @@ pub const Thread = struct {
3535 handle: Thread.Handle,
3636 memory: []align(mem.page_size) u8,
3737 }
38 else switch (builtin.os) {
38 else switch (builtin.os.tag) {
3939 .linux => struct {
4040 handle: Thread.Handle,
4141 memory: []align(mem.page_size) u8,
......@@ -55,7 +55,7 @@ pub const Thread = struct {
5555 if (use_pthreads) {
5656 return c.pthread_self();
5757 } else
58 return switch (builtin.os) {
58 return switch (builtin.os.tag) {
5959 .linux => os.linux.gettid(),
6060 .windows => windows.kernel32.GetCurrentThreadId(),
6161 else => @compileError("Unsupported OS"),
......@@ -83,7 +83,7 @@ pub const Thread = struct {
8383 else => unreachable,
8484 }
8585 os.munmap(self.data.memory);
86 } else switch (builtin.os) {
86 } else switch (builtin.os.tag) {
8787 .linux => {
8888 while (true) {
8989 const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
......@@ -150,7 +150,7 @@ pub const Thread = struct {
150150 const Context = @TypeOf(context);
151151 comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
152152
153 if (builtin.os == builtin.Os.windows) {
153 if (builtin.os.tag == .windows) {
154154 const WinThread = struct {
155155 const OuterContext = struct {
156156 thread: Thread,
......@@ -309,7 +309,7 @@ pub const Thread = struct {
309309 os.EINVAL => unreachable,
310310 else => return os.unexpectedErrno(@intCast(usize, err)),
311311 }
312 } else if (builtin.os == .linux) {
312 } else if (builtin.os.tag == .linux) {
313313 var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |
314314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
315315 os.CLONE_DETACHED;
......@@ -369,11 +369,11 @@ pub const Thread = struct {
369369 };
370370
371371 pub fn cpuCount() CpuCountError!usize {
372 if (builtin.os == .linux) {
372 if (builtin.os.tag == .linux) {
373373 const cpu_set = try os.sched_getaffinity(0);
374374 return @as(usize, os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast
375375 }
376 if (builtin.os == .windows) {
376 if (builtin.os.tag == .windows) {
377377 var system_info: windows.SYSTEM_INFO = undefined;
378378 windows.kernel32.GetSystemInfo(&system_info);
379379 return @intCast(usize, system_info.dwNumberOfProcessors);
lib/std/time.zig+10-8
......@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
21const std = @import("std.zig");
2const builtin = std.builtin;
33const assert = std.debug.assert;
44const testing = std.testing;
55const os = std.os;
......@@ -7,10 +7,12 @@ const math = std.math;
77
88pub const epoch = @import("time/epoch.zig");
99
10const is_windows = std.Target.current.os.tag == .windows;
11
1012/// Spurious wakeups are possible and no precision of timing is guaranteed.
1113/// TODO integrate with evented I/O
1214pub fn sleep(nanoseconds: u64) void {
13 if (builtin.os == .windows) {
15 if (is_windows) {
1416 const ns_per_ms = ns_per_s / ms_per_s;
1517 const big_ms_from_ns = nanoseconds / ns_per_ms;
1618 const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD);
......@@ -31,7 +33,7 @@ pub fn timestamp() u64 {
3133/// Get the posix timestamp, UTC, in milliseconds
3234/// TODO audit this function. is it possible to return an error?
3335pub fn milliTimestamp() u64 {
34 if (builtin.os == .windows) {
36 if (is_windows) {
3537 //FileTime has a granularity of 100 nanoseconds
3638 // and uses the NTFS/Windows epoch
3739 var ft: os.windows.FILETIME = undefined;
......@@ -42,7 +44,7 @@ pub fn milliTimestamp() u64 {
4244 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
4345 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
4446 }
45 if (builtin.os == .wasi and !builtin.link_libc) {
47 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4648 var ns: os.wasi.timestamp_t = undefined;
4749
4850 // TODO: Verify that precision is ignored
......@@ -102,7 +104,7 @@ pub const Timer = struct {
102104 ///if we used resolution's value when performing the
103105 /// performance counter calc on windows/darwin, it would
104106 /// be less precise
105 frequency: switch (builtin.os) {
107 frequency: switch (builtin.os.tag) {
106108 .windows => u64,
107109 .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,
108110 else => void,
......@@ -127,7 +129,7 @@ pub const Timer = struct {
127129 pub fn start() Error!Timer {
128130 var self: Timer = undefined;
129131
130 if (builtin.os == .windows) {
132 if (is_windows) {
131133 self.frequency = os.windows.QueryPerformanceFrequency();
132134 self.resolution = @divFloor(ns_per_s, self.frequency);
133135 self.start_time = os.windows.QueryPerformanceCounter();
......@@ -172,7 +174,7 @@ pub const Timer = struct {
172174 }
173175
174176 fn clockNative() u64 {
175 if (builtin.os == .windows) {
177 if (is_windows) {
176178 return os.windows.QueryPerformanceCounter();
177179 }
178180 if (comptime std.Target.current.isDarwin()) {
......@@ -184,7 +186,7 @@ pub const Timer = struct {
184186 }
185187
186188 fn nativeDurationToNanos(self: Timer, duration: u64) u64 {
187 if (builtin.os == .windows) {
189 if (is_windows) {
188190 return @divFloor(duration * ns_per_s, self.frequency);
189191 }
190192 if (comptime std.Target.current.isDarwin()) {
lib/std/zig.zig+3-6
......@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri
66pub const render = @import("zig/render.zig").render;
77pub const ast = @import("zig/ast.zig");
88pub const system = @import("zig/system.zig");
9pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
910
10test "std.zig tests" {
11 _ = @import("zig/ast.zig");
12 _ = @import("zig/parse.zig");
13 _ = @import("zig/render.zig");
14 _ = @import("zig/tokenizer.zig");
15 _ = @import("zig/parse_string_literal.zig");
11test "" {
12 @import("std").meta.refAllDecls(@This());
1613}
lib/std/zig/cross_target.zig created+835
......@@ -0,0 +1,835 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const Target = std.Target;
4const mem = std.mem;
5
6/// Contains all the same data as `Target`, additionally introducing the concept of "the native target".
7/// The purpose of this abstraction is to provide meaningful and unsurprising defaults.
8/// This struct does reference any resources and it is copyable.
9pub const CrossTarget = struct {
10 /// `null` means native.
11 cpu_arch: ?Target.Cpu.Arch = null,
12
13 cpu_model: CpuModel = CpuModel.determined_by_cpu_arch,
14
15 /// Sparse set of CPU features to add to the set from `cpu_model`.
16 cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
17
18 /// Sparse set of CPU features to remove from the set from `cpu_model`.
19 cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
20
21 /// `null` means native.
22 os_tag: ?Target.Os.Tag = null,
23
24 /// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native)
25 /// then `null` for this field means native.
26 os_version_min: ?OsVersion = null,
27
28 /// When cross compiling, `null` means default (latest known OS version).
29 /// When `os_tag` is native, `null` means equal to the native OS version.
30 os_version_max: ?OsVersion = null,
31
32 /// `null` means default when cross compiling, or native when os_tag is native.
33 /// If `isGnuLibC()` is `false`, this must be `null` and is ignored.
34 glibc_version: ?SemVer = null,
35
36 /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
37 abi: ?Target.Abi = null,
38
39 /// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
40 /// based on the `os_tag`.
41 dynamic_linker: DynamicLinker = DynamicLinker{},
42
43 pub const CpuModel = union(enum) {
44 /// Always native
45 native,
46
47 /// Always baseline
48 baseline,
49
50 /// If CPU Architecture is native, then the CPU model will be native. Otherwise,
51 /// it will be baseline.
52 determined_by_cpu_arch,
53
54 explicit: *const Target.Cpu.Model,
55 };
56
57 pub const OsVersion = union(enum) {
58 none: void,
59 semver: SemVer,
60 windows: Target.Os.WindowsVersion,
61 };
62
63 pub const SemVer = std.builtin.Version;
64
65 pub const DynamicLinker = Target.DynamicLinker;
66
67 pub fn fromTarget(target: Target) CrossTarget {
68 var result: CrossTarget = .{
69 .cpu_arch = target.cpu.arch,
70 .cpu_model = .{ .explicit = target.cpu.model },
71 .os_tag = target.os.tag,
72 .os_version_min = undefined,
73 .os_version_max = undefined,
74 .abi = target.abi,
75 .glibc_version = if (target.isGnuLibC())
76 target.os.version_range.linux.glibc
77 else
78 null,
79 };
80 result.updateOsVersionRange(target.os);
81
82 const all_features = target.cpu.arch.allFeaturesList();
83 var cpu_model_set = target.cpu.model.features;
84 cpu_model_set.populateDependencies(all_features);
85 {
86 // The "add" set is the full set with the CPU Model set removed.
87 const add_set = &result.cpu_features_add;
88 add_set.* = target.cpu.features;
89 add_set.removeFeatureSet(cpu_model_set);
90 }
91 {
92 // The "sub" set is the features that are on in CPU Model set and off in the full set.
93 const sub_set = &result.cpu_features_sub;
94 sub_set.* = cpu_model_set;
95 sub_set.removeFeatureSet(target.cpu.features);
96 }
97 return result;
98 }
99
100 fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void {
101 switch (os.tag) {
102 .freestanding,
103 .ananas,
104 .cloudabi,
105 .dragonfly,
106 .fuchsia,
107 .kfreebsd,
108 .lv2,
109 .solaris,
110 .haiku,
111 .minix,
112 .rtems,
113 .nacl,
114 .cnk,
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 .other,
130 => {
131 self.os_version_min = .{ .none = {} };
132 self.os_version_max = .{ .none = {} };
133 },
134
135 .freebsd,
136 .macosx,
137 .ios,
138 .netbsd,
139 .openbsd,
140 .tvos,
141 .watchos,
142 => {
143 self.os_version_min = .{ .semver = os.version_range.semver.min };
144 self.os_version_max = .{ .semver = os.version_range.semver.max };
145 },
146
147 .linux => {
148 self.os_version_min = .{ .semver = os.version_range.linux.range.min };
149 self.os_version_max = .{ .semver = os.version_range.linux.range.max };
150 },
151
152 .windows => {
153 self.os_version_min = .{ .windows = os.version_range.windows.min };
154 self.os_version_max = .{ .windows = os.version_range.windows.max };
155 },
156 }
157 }
158
159 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
160 pub fn toTarget(self: CrossTarget) Target {
161 return .{
162 .cpu = self.getCpu(),
163 .os = self.getOs(),
164 .abi = self.getAbi(),
165 };
166 }
167
168 pub const ParseOptions = struct {
169 /// This is sometimes called a "triple". It looks roughly like this:
170 /// riscv64-linux-musl
171 /// The fields are, respectively:
172 /// * CPU Architecture
173 /// * Operating System (and optional version range)
174 /// * C ABI (optional, with optional glibc version)
175 /// The string "native" can be used for CPU architecture as well as Operating System.
176 /// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted.
177 arch_os_abi: []const u8 = "native",
178
179 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
180 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
181 /// to remove from the set.
182 /// The following special strings are recognized for CPU Model name:
183 /// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set
184 /// of features that is expected to be supported on most available hardware.
185 /// * "native" - The native CPU model is to be detected when compiling.
186 /// If this field is not provided (`null`), then the value will depend on the
187 /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline".
188 cpu_features: ?[]const u8 = null,
189
190 /// Absolute path to dynamic linker, to override the default, which is either a natively
191 /// detected path, or a standard path.
192 dynamic_linker: ?[]const u8 = null,
193
194 /// If this is provided, the function will populate some information about parsing failures,
195 /// so that user-friendly error messages can be delivered.
196 diagnostics: ?*Diagnostics = null,
197
198 pub const Diagnostics = struct {
199 /// If the architecture was determined, this will be populated.
200 arch: ?Target.Cpu.Arch = null,
201
202 /// If the OS name was determined, this will be populated.
203 os_name: ?[]const u8 = null,
204
205 /// If the OS tag was determined, this will be populated.
206 os_tag: ?Target.Os.Tag = null,
207
208 /// If the ABI was determined, this will be populated.
209 abi: ?Target.Abi = null,
210
211 /// If the CPU name was determined, this will be populated.
212 cpu_name: ?[]const u8 = null,
213
214 /// If error.UnknownCpuFeature is returned, this will be populated.
215 unknown_feature_name: ?[]const u8 = null,
216 };
217 };
218
219 pub fn parse(args: ParseOptions) !CrossTarget {
220 var dummy_diags: ParseOptions.Diagnostics = undefined;
221 const diags = args.diagnostics orelse &dummy_diags;
222
223 var result: CrossTarget = .{
224 .dynamic_linker = DynamicLinker.init(args.dynamic_linker),
225 };
226
227 var it = mem.separate(args.arch_os_abi, "-");
228 const arch_name = it.next().?;
229 const arch_is_native = mem.eql(u8, arch_name, "native");
230 if (!arch_is_native) {
231 result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse
232 return error.UnknownArchitecture;
233 }
234 const arch = result.getCpuArch();
235 diags.arch = arch;
236
237 if (it.next()) |os_text| {
238 try parseOs(&result, diags, os_text);
239 } else if (!arch_is_native) {
240 return error.MissingOperatingSystem;
241 }
242
243 const opt_abi_text = it.next();
244 if (opt_abi_text) |abi_text| {
245 var abi_it = mem.separate(abi_text, ".");
246 const abi = std.meta.stringToEnum(Target.Abi, abi_it.next().?) orelse
247 return error.UnknownApplicationBinaryInterface;
248 result.abi = abi;
249 diags.abi = abi;
250
251 const abi_ver_text = abi_it.rest();
252 if (abi_it.next() != null) {
253 if (result.isGnuLibC()) {
254 result.glibc_version = SemVer.parse(abi_ver_text) catch |err| switch (err) {
255 error.Overflow => return error.InvalidAbiVersion,
256 error.InvalidCharacter => return error.InvalidAbiVersion,
257 error.InvalidVersion => return error.InvalidAbiVersion,
258 };
259 } else {
260 return error.InvalidAbiVersion;
261 }
262 }
263 }
264
265 if (it.next() != null) return error.UnexpectedExtraField;
266
267 if (args.cpu_features) |cpu_features| {
268 const all_features = arch.allFeaturesList();
269 var index: usize = 0;
270 while (index < cpu_features.len and
271 cpu_features[index] != '+' and
272 cpu_features[index] != '-')
273 {
274 index += 1;
275 }
276 const cpu_name = cpu_features[0..index];
277 diags.cpu_name = cpu_name;
278
279 const add_set = &result.cpu_features_add;
280 const sub_set = &result.cpu_features_sub;
281 if (mem.eql(u8, cpu_name, "native")) {
282 result.cpu_model = .native;
283 } else if (mem.eql(u8, cpu_name, "baseline")) {
284 result.cpu_model = .baseline;
285 } else {
286 result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) };
287 }
288
289 while (index < cpu_features.len) {
290 const op = cpu_features[index];
291 const set = switch (op) {
292 '+' => add_set,
293 '-' => sub_set,
294 else => unreachable,
295 };
296 index += 1;
297 const start = index;
298 while (index < cpu_features.len and
299 cpu_features[index] != '+' and
300 cpu_features[index] != '-')
301 {
302 index += 1;
303 }
304 const feature_name = cpu_features[start..index];
305 for (all_features) |feature, feat_index_usize| {
306 const feat_index = @intCast(Target.Cpu.Feature.Set.Index, feat_index_usize);
307 if (mem.eql(u8, feature_name, feature.name)) {
308 set.addFeature(feat_index);
309 break;
310 }
311 } else {
312 diags.unknown_feature_name = feature_name;
313 return error.UnknownCpuFeature;
314 }
315 }
316 }
317
318 return result;
319 }
320
321 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
322 pub fn getCpu(self: CrossTarget) Target.Cpu {
323 switch (self.cpu_model) {
324 .native => {
325 // This works when doing `zig build` because Zig generates a build executable using
326 // native CPU model & features. However this will not be accurate otherwise, and
327 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
328 return Target.current.cpu;
329 },
330 .baseline => {
331 var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
332 self.updateCpuFeatures(&adjusted_baseline.features);
333 return adjusted_baseline;
334 },
335 .determined_by_cpu_arch => if (self.cpu_arch == null) {
336 // This works when doing `zig build` because Zig generates a build executable using
337 // native CPU model & features. However this will not be accurate otherwise, and
338 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
339 return Target.current.cpu;
340 } else {
341 var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
342 self.updateCpuFeatures(&adjusted_baseline.features);
343 return adjusted_baseline;
344 },
345 .explicit => |model| {
346 var adjusted_model = model.toCpu(self.getCpuArch());
347 self.updateCpuFeatures(&adjusted_model.features);
348 return adjusted_model;
349 },
350 }
351 }
352
353 pub fn getCpuArch(self: CrossTarget) Target.Cpu.Arch {
354 return self.cpu_arch orelse Target.current.cpu.arch;
355 }
356
357 pub fn getCpuModel(self: CrossTarget) *const Target.Cpu.Model {
358 if (self.cpu_model) |cpu_model| return cpu_model;
359 return self.getCpu().model;
360 }
361
362 pub fn getCpuFeatures(self: CrossTarget) Target.Cpu.Feature.Set {
363 return self.getCpu().features;
364 }
365
366 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
367 pub fn getOs(self: CrossTarget) Target.Os {
368 // `Target.current.os` works when doing `zig build` because Zig generates a build executable using
369 // native OS version range. However this will not be accurate otherwise, and
370 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
371 var adjusted_os = if (self.os_tag) |os_tag| Target.Os.defaultVersionRange(os_tag) else Target.current.os;
372
373 if (self.os_version_min) |min| switch (min) {
374 .none => {},
375 .semver => |semver| switch (self.getOsTag()) {
376 .linux => adjusted_os.version_range.linux.range.min = semver,
377 else => adjusted_os.version_range.semver.min = semver,
378 },
379 .windows => |win_ver| adjusted_os.version_range.windows.min = win_ver,
380 };
381
382 if (self.os_version_max) |max| switch (max) {
383 .none => {},
384 .semver => |semver| switch (self.getOsTag()) {
385 .linux => adjusted_os.version_range.linux.range.max = semver,
386 else => adjusted_os.version_range.semver.max = semver,
387 },
388 .windows => |win_ver| adjusted_os.version_range.windows.max = win_ver,
389 };
390
391 if (self.glibc_version) |glibc| {
392 assert(self.isGnuLibC());
393 adjusted_os.version_range.linux.glibc = glibc;
394 }
395
396 return adjusted_os;
397 }
398
399 pub fn getOsTag(self: CrossTarget) Target.Os.Tag {
400 return self.os_tag orelse Target.current.os.tag;
401 }
402
403 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
404 pub fn getOsVersionMin(self: CrossTarget) OsVersion {
405 if (self.os_version_min) |version_min| return version_min;
406 var tmp: CrossTarget = undefined;
407 tmp.updateOsVersionRange(self.getOs());
408 return tmp.os_version_min.?;
409 }
410
411 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
412 pub fn getOsVersionMax(self: CrossTarget) OsVersion {
413 if (self.os_version_max) |version_max| return version_max;
414 var tmp: CrossTarget = undefined;
415 tmp.updateOsVersionRange(self.getOs());
416 return tmp.os_version_max.?;
417 }
418
419 /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
420 pub fn getAbi(self: CrossTarget) Target.Abi {
421 if (self.abi) |abi| return abi;
422
423 if (self.os_tag == null) {
424 // This works when doing `zig build` because Zig generates a build executable using
425 // native CPU model & features. However this will not be accurate otherwise, and
426 // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
427 return Target.current.abi;
428 }
429
430 return Target.Abi.default(self.getCpuArch(), self.getOs());
431 }
432
433 pub fn isFreeBSD(self: CrossTarget) bool {
434 return self.getOsTag() == .freebsd;
435 }
436
437 pub fn isDarwin(self: CrossTarget) bool {
438 return self.getOsTag().isDarwin();
439 }
440
441 pub fn isNetBSD(self: CrossTarget) bool {
442 return self.getOsTag() == .netbsd;
443 }
444
445 pub fn isUefi(self: CrossTarget) bool {
446 return self.getOsTag() == .uefi;
447 }
448
449 pub fn isDragonFlyBSD(self: CrossTarget) bool {
450 return self.getOsTag() == .dragonfly;
451 }
452
453 pub fn isLinux(self: CrossTarget) bool {
454 return self.getOsTag() == .linux;
455 }
456
457 pub fn isWindows(self: CrossTarget) bool {
458 return self.getOsTag() == .windows;
459 }
460
461 pub fn oFileExt(self: CrossTarget) [:0]const u8 {
462 return self.getAbi().oFileExt();
463 }
464
465 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
466 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
467 }
468
469 pub fn staticLibSuffix(self: CrossTarget) [:0]const u8 {
470 return Target.staticLibSuffix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
471 }
472
473 pub fn dynamicLibSuffix(self: CrossTarget) [:0]const u8 {
474 return self.getOsTag().dynamicLibSuffix();
475 }
476
477 pub fn libPrefix(self: CrossTarget) [:0]const u8 {
478 return Target.libPrefix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
479 }
480
481 pub fn isNative(self: CrossTarget) bool {
482 return self.cpu_arch == null and
483 (self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and
484 self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty() and
485 self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
486 self.abi == null and self.dynamic_linker.get() == null and self.glibc_version == null;
487 }
488
489 pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 {
490 if (self.isNative()) {
491 return mem.dupeZ(allocator, u8, "native");
492 }
493
494 const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native";
495 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
496
497 var result = try std.Buffer.allocPrint(allocator, "{}-{}", .{ arch_name, os_name });
498 defer result.deinit();
499
500 // The zig target syntax does not allow specifying a max os version with no min, so
501 // if either are present, we need the min.
502 if (self.os_version_min != null or self.os_version_max != null) {
503 switch (self.getOsVersionMin()) {
504 .none => {},
505 .semver => |v| try result.print(".{}", .{v}),
506 .windows => |v| try result.print(".{}", .{@tagName(v)}),
507 }
508 }
509 if (self.os_version_max) |max| {
510 switch (max) {
511 .none => {},
512 .semver => |v| try result.print("...{}", .{v}),
513 .windows => |v| try result.print("...{}", .{@tagName(v)}),
514 }
515 }
516
517 if (self.glibc_version) |v| {
518 try result.print("-{}.{}", .{ @tagName(self.getAbi()), v });
519 } else if (self.abi) |abi| {
520 try result.print("-{}", .{@tagName(abi)});
521 }
522
523 return result.toOwnedSlice();
524 }
525
526 pub fn allocDescription(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
527 // TODO is there anything else worthy of the description that is not
528 // already captured in the triple?
529 return self.zigTriple(allocator);
530 }
531
532 pub fn linuxTriple(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
533 return Target.linuxTripleSimple(allocator, self.getCpuArch(), self.getOsTag(), self.getAbi());
534 }
535
536 pub fn wantSharedLibSymLinks(self: CrossTarget) bool {
537 return self.getOsTag() != .windows;
538 }
539
540 pub const VcpkgLinkage = std.builtin.LinkMode;
541
542 /// Returned slice must be freed by the caller.
543 pub fn vcpkgTriplet(self: CrossTarget, allocator: *mem.Allocator, linkage: VcpkgLinkage) ![:0]u8 {
544 const arch = switch (self.getCpuArch()) {
545 .i386 => "x86",
546 .x86_64 => "x64",
547
548 .arm,
549 .armeb,
550 .thumb,
551 .thumbeb,
552 .aarch64_32,
553 => "arm",
554
555 .aarch64,
556 .aarch64_be,
557 => "arm64",
558
559 else => return error.UnsupportedVcpkgArchitecture,
560 };
561
562 const os = switch (self.getOsTag()) {
563 .windows => "windows",
564 .linux => "linux",
565 .macosx => "macos",
566 else => return error.UnsupportedVcpkgOperatingSystem,
567 };
568
569 const static_suffix = switch (linkage) {
570 .Static => "-static",
571 .Dynamic => "",
572 };
573
574 return std.fmt.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
575 }
576
577 pub const Executor = union(enum) {
578 native,
579 qemu: []const u8,
580 wine: []const u8,
581 wasmtime: []const u8,
582 unavailable,
583 };
584
585 /// Note that even a `CrossTarget` which returns `false` for `isNative` could still be natively executed.
586 /// For example `-target arm-native` running on an aarch64 host.
587 pub fn getExternalExecutor(self: CrossTarget) Executor {
588 const cpu_arch = self.getCpuArch();
589 const os_tag = self.getOsTag();
590 const os_match = os_tag == Target.current.os.tag;
591
592 // If the OS and CPU arch match, the binary can be considered native.
593 if (os_match and cpu_arch == Target.current.cpu.arch) {
594 // However, we also need to verify that the dynamic linker path is valid.
595 // TODO Until that is implemented, we prevent returning `.native` when the OS is non-native.
596 if (self.os_tag == null) {
597 return .native;
598 }
599 }
600
601 // If the OS matches, we can use QEMU to emulate a foreign architecture.
602 if (os_match) {
603 return switch (cpu_arch) {
604 .aarch64 => Executor{ .qemu = "qemu-aarch64" },
605 .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
606 .arm => Executor{ .qemu = "qemu-arm" },
607 .armeb => Executor{ .qemu = "qemu-armeb" },
608 .i386 => Executor{ .qemu = "qemu-i386" },
609 .mips => Executor{ .qemu = "qemu-mips" },
610 .mipsel => Executor{ .qemu = "qemu-mipsel" },
611 .mips64 => Executor{ .qemu = "qemu-mips64" },
612 .mips64el => Executor{ .qemu = "qemu-mips64el" },
613 .powerpc => Executor{ .qemu = "qemu-ppc" },
614 .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
615 .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
616 .riscv32 => Executor{ .qemu = "qemu-riscv32" },
617 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
618 .s390x => Executor{ .qemu = "qemu-s390x" },
619 .sparc => Executor{ .qemu = "qemu-sparc" },
620 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
621 else => return .unavailable,
622 };
623 }
624
625 switch (os_tag) {
626 .windows => switch (cpu_arch.ptrBitWidth()) {
627 32 => return Executor{ .wine = "wine" },
628 64 => return Executor{ .wine = "wine64" },
629 else => return .unavailable,
630 },
631 .wasi => switch (cpu_arch.ptrBitWidth()) {
632 32 => return Executor{ .wasmtime = "wasmtime" },
633 else => return .unavailable,
634 },
635 else => return .unavailable,
636 }
637 }
638
639 pub fn isGnuLibC(self: CrossTarget) bool {
640 return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi());
641 }
642
643 pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) void {
644 assert(self.isGnuLibC());
645 self.glibc_version = SemVer{ .major = major, .minor = minor, .patch = patch };
646 }
647
648 fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
649 set.removeFeatureSet(self.cpu_features_sub);
650 set.addFeatureSet(self.cpu_features_add);
651 set.populateDependencies(self.getCpuArch().allFeaturesList());
652 set.removeFeatureSet(self.cpu_features_sub);
653 }
654
655 fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
656 var it = mem.separate(text, ".");
657 const os_name = it.next().?;
658 diags.os_name = os_name;
659 const os_is_native = mem.eql(u8, os_name, "native");
660 if (!os_is_native) {
661 result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse
662 return error.UnknownOperatingSystem;
663 }
664 const tag = result.getOsTag();
665 diags.os_tag = tag;
666
667 const version_text = it.rest();
668 if (it.next() == null) return;
669
670 switch (tag) {
671 .freestanding,
672 .ananas,
673 .cloudabi,
674 .dragonfly,
675 .fuchsia,
676 .ios,
677 .kfreebsd,
678 .lv2,
679 .solaris,
680 .haiku,
681 .minix,
682 .rtems,
683 .nacl,
684 .cnk,
685 .aix,
686 .cuda,
687 .nvcl,
688 .amdhsa,
689 .ps4,
690 .elfiamcu,
691 .tvos,
692 .watchos,
693 .mesa3d,
694 .contiki,
695 .amdpal,
696 .hermit,
697 .hurd,
698 .wasi,
699 .emscripten,
700 .uefi,
701 .other,
702 => return error.InvalidOperatingSystemVersion,
703
704 .freebsd,
705 .macosx,
706 .netbsd,
707 .openbsd,
708 .linux,
709 => {
710 var range_it = mem.separate(version_text, "...");
711
712 const min_text = range_it.next().?;
713 const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
714 error.Overflow => return error.InvalidOperatingSystemVersion,
715 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
716 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
717 };
718 result.os_version_min = .{ .semver = min_ver };
719
720 const max_text = range_it.next() orelse return;
721 const max_ver = SemVer.parse(max_text) catch |err| switch (err) {
722 error.Overflow => return error.InvalidOperatingSystemVersion,
723 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
724 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
725 };
726 result.os_version_max = .{ .semver = max_ver };
727 },
728
729 .windows => {
730 var range_it = mem.separate(version_text, "...");
731
732 const min_text = range_it.next().?;
733 const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
734 return error.InvalidOperatingSystemVersion;
735 result.os_version_min = .{ .windows = min_ver };
736
737 const max_text = range_it.next() orelse return;
738 const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
739 return error.InvalidOperatingSystemVersion;
740 result.os_version_max = .{ .windows = max_ver };
741 },
742 }
743 }
744};
745
746test "CrossTarget.parse" {
747 if (Target.current.isGnuLibC()) {
748 var cross_target = try CrossTarget.parse(.{});
749 cross_target.setGnuLibCVersion(2, 1, 1);
750
751 const text = try cross_target.zigTriple(std.testing.allocator);
752 defer std.testing.allocator.free(text);
753 std.testing.expectEqualSlices(u8, "native-native-gnu.2.1.1", text);
754 }
755 {
756 const cross_target = try CrossTarget.parse(.{
757 .arch_os_abi = "aarch64-linux",
758 .cpu_features = "native",
759 });
760
761 std.testing.expect(cross_target.cpu_arch.? == .aarch64);
762 std.testing.expect(cross_target.cpu_model == .native);
763 }
764 {
765 const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
766
767 std.testing.expect(cross_target.cpu_arch == null);
768 std.testing.expect(cross_target.isNative());
769
770 const text = try cross_target.zigTriple(std.testing.allocator);
771 defer std.testing.allocator.free(text);
772 std.testing.expectEqualSlices(u8, "native", text);
773 }
774 {
775 const cross_target = try CrossTarget.parse(.{
776 .arch_os_abi = "x86_64-linux-gnu",
777 .cpu_features = "x86_64-sse-sse2-avx-cx8",
778 });
779 const target = cross_target.toTarget();
780
781 std.testing.expect(target.os.tag == .linux);
782 std.testing.expect(target.abi == .gnu);
783 std.testing.expect(target.cpu.arch == .x86_64);
784 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
785 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
786 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
787 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
788 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
789
790 const text = try cross_target.zigTriple(std.testing.allocator);
791 defer std.testing.allocator.free(text);
792 std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text);
793 }
794 {
795 const cross_target = try CrossTarget.parse(.{
796 .arch_os_abi = "arm-linux-musleabihf",
797 .cpu_features = "generic+v8a",
798 });
799 const target = cross_target.toTarget();
800
801 std.testing.expect(target.os.tag == .linux);
802 std.testing.expect(target.abi == .musleabihf);
803 std.testing.expect(target.cpu.arch == .arm);
804 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
805 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
806
807 const text = try cross_target.zigTriple(std.testing.allocator);
808 defer std.testing.allocator.free(text);
809 std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text);
810 }
811 {
812 const cross_target = try CrossTarget.parse(.{
813 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
814 .cpu_features = "generic+v8a",
815 });
816 const target = cross_target.toTarget();
817
818 std.testing.expect(target.cpu.arch == .aarch64);
819 std.testing.expect(target.os.tag == .linux);
820 std.testing.expect(target.os.version_range.linux.range.min.major == 3);
821 std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
822 std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
823 std.testing.expect(target.os.version_range.linux.range.max.major == 4);
824 std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
825 std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
826 std.testing.expect(target.os.version_range.linux.glibc.major == 2);
827 std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
828 std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
829 std.testing.expect(target.abi == .gnu);
830
831 const text = try cross_target.zigTriple(std.testing.allocator);
832 defer std.testing.allocator.free(text);
833 std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text);
834 }
835}
lib/std/zig/system.zig+612-2
......@@ -1,11 +1,15 @@
11const std = @import("../std.zig");
2const elf = std.elf;
23const mem = std.mem;
4const fs = std.fs;
35const Allocator = std.mem.Allocator;
46const ArrayList = std.ArrayList;
57const assert = std.debug.assert;
68const process = std.process;
9const Target = std.Target;
10const CrossTarget = std.zig.CrossTarget;
711
8const is_windows = std.Target.current.isWindows();
12const is_windows = Target.current.os.tag == .windows;
913
1014pub const NativePaths = struct {
1115 include_dirs: ArrayList([:0]u8),
......@@ -77,7 +81,7 @@ pub const NativePaths = struct {
7781 }
7882
7983 if (!is_windows) {
80 const triple = try std.Target.current.linuxTriple(allocator);
84 const triple = try Target.current.linuxTriple(allocator);
8185
8286 // TODO: $ ld --verbose | grep SEARCH_DIR
8387 // the output contains some paths that end with lib64, maybe include them too?
......@@ -161,3 +165,609 @@ pub const NativePaths = struct {
161165 try array.append(item);
162166 }
163167};
168
169pub const NativeTargetInfo = struct {
170 target: Target,
171
172 dynamic_linker: DynamicLinker = DynamicLinker{},
173
174 pub const DynamicLinker = Target.DynamicLinker;
175
176 pub const DetectError = error{
177 OutOfMemory,
178 FileSystem,
179 SystemResources,
180 SymLinkLoop,
181 ProcessFdQuotaExceeded,
182 SystemFdQuotaExceeded,
183 DeviceBusy,
184 };
185
186 /// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected
187 /// natively, which should be standard or default, and which are provided explicitly, this function
188 /// resolves the native components by detecting the native system, and then resolves standard/default parts
189 /// relative to that.
190 /// Any resources this function allocates are released before returning, and so there is no
191 /// deinitialization method.
192 /// TODO Remove the Allocator requirement from this function.
193 pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
194 const cpu = switch (cross_target.cpu_model) {
195 .native => detectNativeCpuAndFeatures(cross_target),
196 .baseline => baselineCpuAndFeatures(cross_target),
197 .determined_by_cpu_arch => if (cross_target.cpu_arch == null)
198 detectNativeCpuAndFeatures(cross_target)
199 else
200 baselineCpuAndFeatures(cross_target),
201 .explicit => |model| blk: {
202 var adjusted_model = model.toCpu(cross_target.getCpuArch());
203 cross_target.updateCpuFeatures(&adjusted_model.features);
204 break :blk adjusted_model;
205 },
206 };
207
208 var os = Target.Os.defaultVersionRange(cross_target.getOsTag());
209 if (cross_target.os_tag == null) {
210 switch (Target.current.os.tag) {
211 .linux => {
212 const uts = std.os.uname();
213 const release = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.release));
214 if (std.builtin.Version.parse(release)) |ver| {
215 os.version_range.linux.range.min = ver;
216 os.version_range.linux.range.max = ver;
217 } else |err| switch (err) {
218 error.Overflow => {},
219 error.InvalidCharacter => {},
220 error.InvalidVersion => {},
221 }
222 },
223 .windows => {
224 // TODO Detect native operating system version.
225 },
226 .macosx => {
227 // TODO Detect native operating system version.
228 },
229 .freebsd => {
230 // TODO Detect native operating system version.
231 },
232 else => {},
233 }
234 }
235
236 if (cross_target.os_version_min) |min| switch (min) {
237 .none => {},
238 .semver => |semver| switch (cross_target.getOsTag()) {
239 .linux => os.version_range.linux.range.min = semver,
240 else => os.version_range.semver.min = semver,
241 },
242 .windows => |win_ver| os.version_range.windows.min = win_ver,
243 };
244
245 if (cross_target.os_version_max) |max| switch (max) {
246 .none => {},
247 .semver => |semver| switch (cross_target.getOsTag()) {
248 .linux => os.version_range.linux.range.max = semver,
249 else => os.version_range.semver.max = semver,
250 },
251 .windows => |win_ver| os.version_range.windows.max = win_ver,
252 };
253
254 if (cross_target.glibc_version) |glibc| {
255 assert(cross_target.isGnuLibC());
256 os.version_range.linux.glibc = glibc;
257 }
258
259 return detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
260 }
261
262 /// First we attempt to use the executable's own binary. If it is dynamically
263 /// linked, then it should answer both the C ABI question and the dynamic linker question.
264 /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then
265 /// we fall back to the defaults.
266 /// TODO Remove the Allocator requirement from this function.
267 fn detectAbiAndDynamicLinker(
268 allocator: *Allocator,
269 cpu: Target.Cpu,
270 os: Target.Os,
271 cross_target: CrossTarget,
272 ) DetectError!NativeTargetInfo {
273 const native_target_has_ld = comptime Target.current.hasDynamicLinker();
274 const is_linux = Target.current.os.tag == .linux;
275 const have_all_info = cross_target.dynamic_linker.get() != null and
276 cross_target.abi != null and (!is_linux or cross_target.abi.?.isGnu());
277 const os_is_non_native = cross_target.os_tag != null;
278 if (!native_target_has_ld or have_all_info or os_is_non_native) {
279 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
280 }
281 // The current target's ABI cannot be relied on for this. For example, we may build the zig
282 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
283 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
284 // and supported by Zig. But that means that we must detect the system ABI here rather than
285 // relying on `Target.current`.
286 const all_abis = comptime blk: {
287 assert(@enumToInt(Target.Abi.none) == 0);
288 const fields = std.meta.fields(Target.Abi)[1..];
289 var array: [fields.len]Target.Abi = undefined;
290 inline for (fields) |field, i| {
291 array[i] = @field(Target.Abi, field.name);
292 }
293 break :blk array;
294 };
295 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
296 var ld_info_list_len: usize = 0;
297
298 for (all_abis) |abi| {
299 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
300 // skip adding it to `ld_info_list`.
301 const target: Target = .{
302 .cpu = cpu,
303 .os = os,
304 .abi = abi,
305 };
306 const ld = target.standardDynamicLinkerPath();
307 if (ld.get() == null) continue;
308
309 ld_info_list_buffer[ld_info_list_len] = .{
310 .ld = ld,
311 .abi = abi,
312 };
313 ld_info_list_len += 1;
314 }
315 const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
316
317 if (cross_target.dynamic_linker.get()) |explicit_ld| {
318 const explicit_ld_basename = fs.path.basename(explicit_ld);
319 for (ld_info_list) |ld_info| {
320 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
321 }
322 }
323
324 // Best case scenario: the executable is dynamically linked, and we can iterate
325 // over our own shared objects and find a dynamic linker.
326 self_exe: {
327 const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
328 defer allocator.free(lib_paths);
329
330 var found_ld_info: LdInfo = undefined;
331 var found_ld_path: [:0]const u8 = undefined;
332
333 // Look for dynamic linker.
334 // This is O(N^M) but typical case here is N=2 and M=10.
335 find_ld: for (lib_paths) |lib_path| {
336 for (ld_info_list) |ld_info| {
337 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
338 if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
339 found_ld_info = ld_info;
340 found_ld_path = lib_path;
341 break :find_ld;
342 }
343 }
344 } else break :self_exe;
345
346 // Look for glibc version.
347 var os_adjusted = os;
348 if (Target.current.os.tag == .linux and found_ld_info.abi.isGnu() and
349 cross_target.glibc_version == null)
350 {
351 for (lib_paths) |lib_path| {
352 if (std.mem.endsWith(u8, lib_path, glibc_so_basename)) {
353 os_adjusted.version_range.linux.glibc = glibcVerFromSO(lib_path) catch |err| switch (err) {
354 error.UnrecognizedGnuLibCFileName => continue,
355 error.InvalidGnuLibCVersion => continue,
356 error.GnuLibCVersionUnavailable => continue,
357 else => |e| return e,
358 };
359 break;
360 }
361 }
362 }
363
364 var result: NativeTargetInfo = .{
365 .target = .{
366 .cpu = cpu,
367 .os = os_adjusted,
368 .abi = cross_target.abi orelse found_ld_info.abi,
369 },
370 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
371 DynamicLinker.init(found_ld_path)
372 else
373 cross_target.dynamic_linker,
374 };
375 return result;
376 }
377
378 // If Zig is statically linked, such as via distributed binary static builds, the above
379 // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.
380 // Since that path is hard-coded into the shebang line of many portable scripts, it's a
381 // reasonably reliable path to check for.
382 return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
383 error.FileSystem,
384 error.SystemResources,
385 error.SymLinkLoop,
386 error.ProcessFdQuotaExceeded,
387 error.SystemFdQuotaExceeded,
388 error.DeviceBusy,
389 => |e| return e,
390
391 error.UnableToReadElfFile,
392 error.InvalidElfClass,
393 error.InvalidElfVersion,
394 error.InvalidElfEndian,
395 error.InvalidElfFile,
396 error.InvalidElfMagic,
397 error.UsrBinEnvNotAvailable,
398 error.Unexpected,
399 error.UnexpectedEndOfFile,
400 error.NameTooLong,
401 // Finally, we fall back on the standard path.
402 => defaultAbiAndDynamicLinker(cpu, os, cross_target),
403 };
404 }
405
406 const glibc_so_basename = "libc.so.6";
407
408 fn glibcVerFromSO(so_path: [:0]const u8) !std.builtin.Version {
409 var link_buf: [std.os.PATH_MAX]u8 = undefined;
410 const link_name = std.os.readlinkC(so_path.ptr, &link_buf) catch |err| switch (err) {
411 error.AccessDenied => return error.GnuLibCVersionUnavailable,
412 error.FileSystem => return error.FileSystem,
413 error.SymLinkLoop => return error.SymLinkLoop,
414 error.NameTooLong => unreachable,
415 error.FileNotFound => return error.GnuLibCVersionUnavailable,
416 error.SystemResources => return error.SystemResources,
417 error.NotDir => return error.GnuLibCVersionUnavailable,
418 error.Unexpected => return error.GnuLibCVersionUnavailable,
419 };
420 return glibcVerFromLinkName(link_name);
421 }
422
423 fn glibcVerFromLinkName(link_name: []const u8) !std.builtin.Version {
424 // example: "libc-2.3.4.so"
425 // example: "libc-2.27.so"
426 const prefix = "libc-";
427 const suffix = ".so";
428 if (!mem.startsWith(u8, link_name, prefix) or !mem.endsWith(u8, link_name, suffix)) {
429 return error.UnrecognizedGnuLibCFileName;
430 }
431 // chop off "libc-" and ".so"
432 const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
433 return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) {
434 error.Overflow => return error.InvalidGnuLibCVersion,
435 error.InvalidCharacter => return error.InvalidGnuLibCVersion,
436 error.InvalidVersion => return error.InvalidGnuLibCVersion,
437 };
438 }
439
440 fn abiAndDynamicLinkerFromUsrBinEnv(
441 cpu: Target.Cpu,
442 os: Target.Os,
443 ld_info_list: []const LdInfo,
444 cross_target: CrossTarget,
445 ) !NativeTargetInfo {
446 const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
447 error.NoSpaceLeft => unreachable,
448 error.NameTooLong => unreachable,
449 error.PathAlreadyExists => unreachable,
450 error.SharingViolation => unreachable,
451 error.InvalidUtf8 => unreachable,
452 error.BadPathName => unreachable,
453 error.PipeBusy => unreachable,
454
455 error.IsDir => return error.UsrBinEnvNotAvailable,
456 error.NotDir => return error.UsrBinEnvNotAvailable,
457 error.AccessDenied => return error.UsrBinEnvNotAvailable,
458 error.NoDevice => return error.UsrBinEnvNotAvailable,
459 error.FileNotFound => return error.UsrBinEnvNotAvailable,
460 error.FileTooBig => return error.UsrBinEnvNotAvailable,
461
462 else => |e| return e,
463 };
464 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
465 _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len);
466 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
467 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
468 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
469 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
470 elf.ELFDATA2LSB => .Little,
471 elf.ELFDATA2MSB => .Big,
472 else => return error.InvalidElfEndian,
473 };
474 const need_bswap = elf_endian != std.builtin.endian;
475 if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
476
477 const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) {
478 elf.ELFCLASS32 => false,
479 elf.ELFCLASS64 => true,
480 else => return error.InvalidElfClass,
481 };
482 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
483 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
484 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
485
486 var result: NativeTargetInfo = .{
487 .target = .{
488 .cpu = cpu,
489 .os = os,
490 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
491 },
492 .dynamic_linker = cross_target.dynamic_linker,
493 };
494 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
495 const look_for_ld = cross_target.dynamic_linker.get() == null;
496
497 var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;
498 if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
499
500 var ph_i: u16 = 0;
501 while (ph_i < phnum) {
502 // Reserve some bytes so that we can deref the 64-bit struct fields
503 // even when the ELF file is 32-bits.
504 const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
505 const ph_read_byte_len = try preadFull(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
506 var ph_buf_i: usize = 0;
507 while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
508 ph_i += 1;
509 phoff += phentsize;
510 ph_buf_i += phentsize;
511 }) {
512 const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[ph_buf_i]));
513 const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[ph_buf_i]));
514 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
515 switch (p_type) {
516 elf.PT_INTERP => if (look_for_ld) {
517 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
518 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
519 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
520 _ = try preadFull(env_file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
521 // PT_INTERP includes a null byte in p_filesz.
522 const len = p_filesz - 1;
523 // dynamic_linker.max_byte is "max", not "len".
524 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
525 result.dynamic_linker.max_byte = @intCast(u8, len - 1);
526
527 // Use it to determine ABI.
528 const full_ld_path = result.dynamic_linker.buffer[0..len];
529 for (ld_info_list) |ld_info| {
530 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
531 if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
532 result.target.abi = ld_info.abi;
533 break;
534 }
535 }
536 },
537 // We only need this for detecting glibc version.
538 elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC() and
539 cross_target.glibc_version == null)
540 {
541 var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
542 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
543 const dyn_size: u64 = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
544 const dyn_num = p_filesz / dyn_size;
545 var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
546 var dyn_i: usize = 0;
547 dyn: while (dyn_i < dyn_num) {
548 // Reserve some bytes so that we can deref the 64-bit struct fields
549 // even when the ELF file is 32-bits.
550 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
551 const dyn_read_byte_len = try preadFull(
552 env_file,
553 dyn_buf[0 .. dyn_buf.len - dyn_reserve],
554 dyn_off,
555 dyn_size,
556 );
557 var dyn_buf_i: usize = 0;
558 while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
559 dyn_i += 1;
560 dyn_off += dyn_size;
561 dyn_buf_i += dyn_size;
562 }) {
563 const dyn32 = @ptrCast(
564 *elf.Elf32_Dyn,
565 @alignCast(@alignOf(elf.Elf32_Dyn), &dyn_buf[dyn_buf_i]),
566 );
567 const dyn64 = @ptrCast(
568 *elf.Elf64_Dyn,
569 @alignCast(@alignOf(elf.Elf64_Dyn), &dyn_buf[dyn_buf_i]),
570 );
571 const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
572 const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
573 if (tag == elf.DT_RUNPATH) {
574 rpath_offset = val;
575 break :dyn;
576 }
577 }
578 }
579 },
580 else => continue,
581 }
582 }
583 }
584
585 if (Target.current.os.tag == .linux and result.target.isGnuLibC() and cross_target.glibc_version == null) {
586 if (rpath_offset) |rpoff| {
587 const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
588
589 var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff);
590 const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize);
591 const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx);
592
593 var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
594 if (sh_buf.len < shentsize) return error.InvalidElfFile;
595
596 _ = try preadFull(env_file, &sh_buf, str_section_off, shentsize);
597 const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
598 const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
599 const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
600 const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
601 var strtab_buf: [4096:0]u8 = undefined;
602 const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
603 const shstrtab_read_len = try preadFull(env_file, &strtab_buf, shstrtab_off, shstrtab_len);
604 const shstrtab = strtab_buf[0..shstrtab_read_len];
605
606 const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
607 var sh_i: u16 = 0;
608 const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) {
609 // Reserve some bytes so that we can deref the 64-bit struct fields
610 // even when the ELF file is 32-bits.
611 const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
612 const sh_read_byte_len = try preadFull(
613 env_file,
614 sh_buf[0 .. sh_buf.len - sh_reserve],
615 shoff,
616 shentsize,
617 );
618 var sh_buf_i: usize = 0;
619 while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({
620 sh_i += 1;
621 shoff += shentsize;
622 sh_buf_i += shentsize;
623 }) {
624 const sh32 = @ptrCast(
625 *elf.Elf32_Shdr,
626 @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf[sh_buf_i]),
627 );
628 const sh64 = @ptrCast(
629 *elf.Elf64_Shdr,
630 @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf[sh_buf_i]),
631 );
632 const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name);
633 // TODO this pointer cast should not be necessary
634 const sh_name = mem.toSliceConst(u8, @ptrCast([*:0]u8, shstrtab[sh_name_off..].ptr));
635 if (mem.eql(u8, sh_name, ".dynstr")) {
636 break :find_dyn_str .{
637 .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset),
638 .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size),
639 };
640 }
641 }
642 } else null;
643
644 if (dynstr) |ds| {
645 const strtab_len = std.math.min(ds.size, strtab_buf.len);
646 const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_len);
647 const strtab = strtab_buf[0..strtab_read_len];
648 // TODO this pointer cast should not be necessary
649 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
650 var it = mem.tokenize(rpath_list, ":");
651 while (it.next()) |rpath| {
652 var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) {
653 error.NameTooLong => unreachable,
654 error.InvalidUtf8 => unreachable,
655 error.BadPathName => unreachable,
656 error.DeviceBusy => unreachable,
657
658 error.FileNotFound,
659 error.NotDir,
660 error.AccessDenied,
661 error.NoDevice,
662 => continue,
663
664 error.ProcessFdQuotaExceeded,
665 error.SystemFdQuotaExceeded,
666 error.SystemResources,
667 error.SymLinkLoop,
668 error.Unexpected,
669 => |e| return e,
670 };
671 defer dir.close();
672
673 var link_buf: [std.os.PATH_MAX]u8 = undefined;
674 const link_name = std.os.readlinkatC(
675 dir.fd,
676 glibc_so_basename,
677 &link_buf,
678 ) catch |err| switch (err) {
679 error.NameTooLong => unreachable,
680
681 error.AccessDenied,
682 error.FileNotFound,
683 error.NotDir,
684 => continue,
685
686 error.SystemResources,
687 error.FileSystem,
688 error.SymLinkLoop,
689 error.Unexpected,
690 => |e| return e,
691 };
692 result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
693 link_name,
694 ) catch |err| switch (err) {
695 error.UnrecognizedGnuLibCFileName,
696 error.InvalidGnuLibCVersion,
697 => continue,
698 };
699 break;
700 }
701 }
702 }
703 }
704
705 return result;
706 }
707
708 fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
709 var i: u64 = 0;
710 while (i < min_read_len) {
711 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
712 error.OperationAborted => unreachable, // Windows-only
713 error.WouldBlock => unreachable, // Did not request blocking mode
714 error.SystemResources => return error.SystemResources,
715 error.IsDir => return error.UnableToReadElfFile,
716 error.BrokenPipe => return error.UnableToReadElfFile,
717 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
718 error.Unexpected => return error.Unexpected,
719 error.InputOutput => return error.FileSystem,
720 };
721 if (len == 0) return error.UnexpectedEndOfFile;
722 i += len;
723 }
724 return i;
725 }
726
727 fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: CrossTarget) !NativeTargetInfo {
728 const target: Target = .{
729 .cpu = cpu,
730 .os = os,
731 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
732 };
733 return NativeTargetInfo{
734 .target = target,
735 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
736 target.standardDynamicLinkerPath()
737 else
738 cross_target.dynamic_linker,
739 };
740 }
741
742 const LdInfo = struct {
743 ld: DynamicLinker,
744 abi: Target.Abi,
745 };
746
747 fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
748 if (is_64) {
749 if (need_bswap) {
750 return @byteSwap(@TypeOf(int_64), int_64);
751 } else {
752 return int_64;
753 }
754 } else {
755 if (need_bswap) {
756 return @byteSwap(@TypeOf(int_32), int_32);
757 } else {
758 return int_32;
759 }
760 }
761 }
762
763 fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
764 // TODO Detect native CPU model & features. Until that is implemented we use baseline.
765 return baselineCpuAndFeatures(cross_target);
766 }
767
768 fn baselineCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
769 var adjusted_baseline = Target.Cpu.baseline(cross_target.getCpuArch());
770 cross_target.updateCpuFeatures(&adjusted_baseline.features);
771 return adjusted_baseline;
772 }
773};
src-self-hosted/c_int.zig+1-1
......@@ -70,7 +70,7 @@ pub const CInt = struct {
7070
7171 pub fn sizeInBits(cint: CInt, self: Target) u32 {
7272 const arch = self.getArch();
73 switch (self.getOs()) {
73 switch (self.os.tag) {
7474 .freestanding, .other => switch (self.getArch()) {
7575 .msp430 => switch (cint.id) {
7676 .Short,
src-self-hosted/clang.zig+1-1
......@@ -1050,7 +1050,7 @@ pub const struct_ZigClangExprEvalResult = extern struct {
10501050
10511051pub const struct_ZigClangAPValue = extern struct {
10521052 Kind: ZigClangAPValueKind,
1053 Data: if (builtin.os == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,
1053 Data: if (builtin.os.tag == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,
10541054};
10551055pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType;
10561056
src-self-hosted/introspect.zig+1-9
......@@ -1,4 +1,4 @@
1// Introspection and determination of system libraries needed by zig.
1//! Introspection and determination of system libraries needed by zig.
22
33const std = @import("std");
44const mem = std.mem;
......@@ -6,14 +6,6 @@ const fs = std.fs;
66
77const warn = std.debug.warn;
88
9pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
10 if (target == .Native) {
11 return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
12 } else {
13 return target.getStandardDynamicLinkerPath(allocator);
14 }
15}
16
179/// Caller must free result
1810pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
1911 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
src-self-hosted/libc_installation.zig+12-114
......@@ -7,11 +7,7 @@ const Allocator = std.mem.Allocator;
77const Batch = std.event.Batch;
88
99const is_darwin = Target.current.isDarwin();
10const is_windows = Target.current.isWindows();
11const is_freebsd = Target.current.isFreeBSD();
12const is_netbsd = Target.current.isNetBSD();
13const is_linux = Target.current.isLinux();
14const is_dragonfly = Target.current.isDragonFlyBSD();
10const is_windows = Target.current.os.tag == .windows;
1511const is_gnu = Target.current.isGnu();
1612
1713usingnamespace @import("windows_sdk.zig");
......@@ -99,27 +95,27 @@ pub const LibCInstallation = struct {
9995 return error.ParseError;
10096 }
10197 if (self.crt_dir == null and !is_darwin) {
102 try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.getOs())});
98 try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.os.tag)});
10399 return error.ParseError;
104100 }
105101 if (self.static_crt_dir == null and is_windows and is_gnu) {
106102 try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{
107 @tagName(Target.current.getOs()),
108 @tagName(Target.current.getAbi()),
103 @tagName(Target.current.os.tag),
104 @tagName(Target.current.abi),
109105 });
110106 return error.ParseError;
111107 }
112108 if (self.msvc_lib_dir == null and is_windows and !is_gnu) {
113109 try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{
114 @tagName(Target.current.getOs()),
115 @tagName(Target.current.getAbi()),
110 @tagName(Target.current.os.tag),
111 @tagName(Target.current.abi),
116112 });
117113 return error.ParseError;
118114 }
119115 if (self.kernel32_lib_dir == null and is_windows and !is_gnu) {
120116 try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{
121 @tagName(Target.current.getOs()),
122 @tagName(Target.current.getAbi()),
117 @tagName(Target.current.os.tag),
118 @tagName(Target.current.abi),
123119 });
124120 return error.ParseError;
125121 }
......@@ -216,10 +212,10 @@ pub const LibCInstallation = struct {
216212 var batch = Batch(FindError!void, 2, .auto_async).init();
217213 errdefer batch.wait() catch {};
218214 batch.add(&async self.findNativeIncludeDirPosix(args));
219 if (is_freebsd or is_netbsd) {
220 self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib");
221 } else if (is_linux or is_dragonfly) {
222 batch.add(&async self.findNativeCrtDirPosix(args));
215 switch (Target.current.os.tag) {
216 .freebsd, .netbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"),
217 .linux, .dragonfly => batch.add(&async self.findNativeCrtDirPosix(args)),
218 else => {},
223219 }
224220 break :blk batch.wait();
225221 };
......@@ -616,104 +612,6 @@ fn printVerboseInvocation(
616612 }
617613}
618614
619/// Caller owns returned memory.
620pub fn detectNativeDynamicLinker(allocator: *Allocator) error{
621 OutOfMemory,
622 TargetHasNoDynamicLinker,
623 UnknownDynamicLinkerPath,
624}![:0]u8 {
625 if (!comptime Target.current.hasDynamicLinker()) {
626 return error.TargetHasNoDynamicLinker;
627 }
628
629 // The current target's ABI cannot be relied on for this. For example, we may build the zig
630 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
631 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
632 // and supported by Zig. But that means that we must detect the system ABI here rather than
633 // relying on `std.Target.current`.
634
635 const LdInfo = struct {
636 ld_path: []u8,
637 abi: Target.Abi,
638 };
639 var ld_info_list = std.ArrayList(LdInfo).init(allocator);
640 defer {
641 for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path);
642 ld_info_list.deinit();
643 }
644
645 const all_abis = comptime blk: {
646 const fields = std.meta.fields(Target.Abi);
647 var array: [fields.len]Target.Abi = undefined;
648 inline for (fields) |field, i| {
649 array[i] = @field(Target.Abi, field.name);
650 }
651 break :blk array;
652 };
653 for (all_abis) |abi| {
654 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
655 // skip adding it to `ld_info_list`.
656 const target: Target = .{
657 .Cross = .{
658 .cpu = Target.Cpu.baseline(Target.current.getArch()),
659 .os = Target.current.getOs(),
660 .abi = abi,
661 },
662 };
663 const standard_ld_path = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
664 error.OutOfMemory => return error.OutOfMemory,
665 error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => continue,
666 };
667 errdefer allocator.free(standard_ld_path);
668 try ld_info_list.append(.{
669 .ld_path = standard_ld_path,
670 .abi = abi,
671 });
672 }
673
674 // Best case scenario: the zig compiler is dynamically linked, and we can iterate
675 // over our own shared objects and find a dynamic linker.
676 {
677 const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
678 defer allocator.free(lib_paths);
679
680 // This is O(N^M) but typical case here is N=2 and M=10.
681 for (lib_paths) |lib_path| {
682 for (ld_info_list.toSlice()) |ld_info| {
683 const standard_ld_basename = fs.path.basename(ld_info.ld_path);
684 if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
685 return std.mem.dupeZ(allocator, u8, lib_path);
686 }
687 }
688 }
689 }
690
691 // If Zig is statically linked, such as via distributed binary static builds, the above
692 // trick won't work. What are we left with? Try to run the system C compiler and get
693 // it to tell us the dynamic linker path.
694 // TODO: instead of this, look at the shared libs of /usr/bin/env.
695 for (ld_info_list.toSlice()) |ld_info| {
696 const standard_ld_basename = fs.path.basename(ld_info.ld_path);
697
698 const full_ld_path = ccPrintFileName(.{
699 .allocator = allocator,
700 .search_basename = standard_ld_basename,
701 .want_dirname = .full_path,
702 }) catch |err| switch (err) {
703 error.OutOfMemory => return error.OutOfMemory,
704 error.LibCRuntimeNotFound,
705 error.CCompilerExitCode,
706 error.CCompilerCrashed,
707 error.UnableToSpawnCCompiler,
708 => continue,
709 };
710 return full_ld_path;
711 }
712
713 // Finally, we fall back on the standard path.
714 return Target.current.getStandardDynamicLinkerPath(allocator);
715}
716
717615const Search = struct {
718616 path: []const u8,
719617 version: []const u8,
src-self-hosted/link.zig+2-2
......@@ -515,7 +515,7 @@ const DarwinPlatform = struct {
515515 break :blk ver;
516516 },
517517 .None => blk: {
518 assert(comp.target.getOs() == .macosx);
518 assert(comp.target.os.tag == .macosx);
519519 result.kind = .MacOS;
520520 break :blk "10.14";
521521 },
......@@ -534,7 +534,7 @@ const DarwinPlatform = struct {
534534 }
535535
536536 if (result.kind == .IPhoneOS) {
537 switch (comp.target.getArch()) {
537 switch (comp.target.cpu.arch) {
538538 .i386,
539539 .x86_64,
540540 => result.kind = .IPhoneOSSimulator,
src-self-hosted/main.zig+3-3
......@@ -79,9 +79,9 @@ pub fn main() !void {
7979 } else if (mem.eql(u8, cmd, "libc")) {
8080 return cmdLibC(allocator, cmd_args);
8181 } else if (mem.eql(u8, cmd, "targets")) {
82 // TODO figure out the current target rather than using the target that was specified when
83 // compiling the compiler
84 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, Target.current);
82 const info = try std.zig.system.NativeTargetInfo.detect(allocator);
83 defer info.deinit(allocator);
84 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);
8585 } else if (mem.eql(u8, cmd, "version")) {
8686 return cmdVersion(allocator, cmd_args);
8787 } else if (mem.eql(u8, cmd, "zen")) {
src-self-hosted/print_targets.zig+6-6
......@@ -124,7 +124,7 @@ pub fn cmdTargets(
124124
125125 try jws.objectField("os");
126126 try jws.beginArray();
127 inline for (@typeInfo(Target.Os).Enum.fields) |field| {
127 inline for (@typeInfo(Target.Os.Tag).Enum.fields) |field| {
128128 try jws.arrayElem();
129129 try jws.emitString(field.name);
130130 }
......@@ -201,16 +201,16 @@ pub fn cmdTargets(
201201 try jws.objectField("cpu");
202202 try jws.beginObject();
203203 try jws.objectField("arch");
204 try jws.emitString(@tagName(native_target.getArch()));
204 try jws.emitString(@tagName(native_target.cpu.arch));
205205
206206 try jws.objectField("name");
207 const cpu = native_target.getCpu();
207 const cpu = native_target.cpu;
208208 try jws.emitString(cpu.model.name);
209209
210210 {
211211 try jws.objectField("features");
212212 try jws.beginArray();
213 for (native_target.getArch().allFeaturesList()) |feature, i_usize| {
213 for (native_target.cpu.arch.allFeaturesList()) |feature, i_usize| {
214214 const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
215215 if (cpu.features.isEnabled(index)) {
216216 try jws.arrayElem();
......@@ -222,9 +222,9 @@ pub fn cmdTargets(
222222 try jws.endObject();
223223 }
224224 try jws.objectField("os");
225 try jws.emitString(@tagName(native_target.getOs()));
225 try jws.emitString(@tagName(native_target.os.tag));
226226 try jws.objectField("abi");
227 try jws.emitString(@tagName(native_target.getAbi()));
227 try jws.emitString(@tagName(native_target.abi));
228228 // TODO implement native glibc version detection in self-hosted
229229 try jws.endObject();
230230
src-self-hosted/stage2.zig+279-124
......@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
1010const ArrayList = std.ArrayList;
1111const Buffer = std.Buffer;
1212const Target = std.Target;
13const CrossTarget = std.zig.CrossTarget;
1314const self_hosted_main = @import("main.zig");
1415const errmsg = @import("errmsg.zig");
1516const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
......@@ -87,7 +88,7 @@ const Error = extern enum {
8788 NotLazy,
8889 IsAsync,
8990 ImportOutsidePkgPath,
90 UnknownCpu,
91 UnknownCpuModel,
9192 UnknownCpuFeature,
9293 InvalidCpuFeatures,
9394 InvalidLlvmCpuFeaturesFormat,
......@@ -110,6 +111,8 @@ const Error = extern enum {
110111 WindowsSdkNotFound,
111112 UnknownDynamicLinkerPath,
112113 TargetHasNoDynamicLinker,
114 InvalidAbiVersion,
115 InvalidOperatingSystemVersion,
113116};
114117
115118const FILE = std.c.FILE;
......@@ -632,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
632635}
633636
634637fn cmdTargets(zig_triple: [*:0]const u8) !void {
635 var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
636 target.Cross.cpu = blk: {
637 const llvm = @import("llvm.zig");
638 const llvm_cpu_name = llvm.GetHostCPUName();
639 const llvm_cpu_features = llvm.GetNativeFeatures();
640 break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);
641 };
638 var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
639 var dynamic_linker: ?[*:0]u8 = null;
640 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
642641 return @import("print_targets.zig").cmdTargets(
643642 std.heap.c_allocator,
644643 &[0][]u8{},
......@@ -652,16 +651,24 @@ export fn stage2_target_parse(
652651 target: *Stage2Target,
653652 zig_triple: ?[*:0]const u8,
654653 mcpu: ?[*:0]const u8,
654 dynamic_linker: ?[*:0]const u8,
655655) Error {
656 stage2TargetParse(target, zig_triple, mcpu) catch |err| switch (err) {
656 stage2TargetParse(target, zig_triple, mcpu, dynamic_linker) catch |err| switch (err) {
657657 error.OutOfMemory => return .OutOfMemory,
658658 error.UnknownArchitecture => return .UnknownArchitecture,
659659 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
660660 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
661661 error.MissingOperatingSystem => return .MissingOperatingSystem,
662 error.MissingArchitecture => return .MissingArchitecture,
663662 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
664663 error.UnexpectedExtraField => return .SemanticAnalyzeFail,
664 error.InvalidAbiVersion => return .InvalidAbiVersion,
665 error.InvalidOperatingSystemVersion => return .InvalidOperatingSystemVersion,
666 error.FileSystem => return .FileSystem,
667 error.SymLinkLoop => return .SymLinkLoop,
668 error.SystemResources => return .SystemResources,
669 error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
670 error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
671 error.DeviceBusy => return .DeviceBusy,
665672 };
666673 return .None;
667674}
......@@ -670,17 +677,20 @@ fn stage2TargetParse(
670677 stage1_target: *Stage2Target,
671678 zig_triple_oz: ?[*:0]const u8,
672679 mcpu_oz: ?[*:0]const u8,
680 dynamic_linker_oz: ?[*:0]const u8,
673681) !void {
674 const target: Target = if (zig_triple_oz) |zig_triple_z| blk: {
682 const target: CrossTarget = if (zig_triple_oz) |zig_triple_z| blk: {
675683 const zig_triple = mem.toSliceConst(u8, zig_triple_z);
676 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";
677 var diags: std.Target.ParseOptions.Diagnostics = .{};
678 break :blk Target.parse(.{
684 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
685 const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
686 var diags: CrossTarget.ParseOptions.Diagnostics = .{};
687 break :blk CrossTarget.parse(.{
679688 .arch_os_abi = zig_triple,
680689 .cpu_features = mcpu,
690 .dynamic_linker = dynamic_linker,
681691 .diagnostics = &diags,
682692 }) catch |err| switch (err) {
683 error.UnknownCpu => {
693 error.UnknownCpuModel => {
684694 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
685695 diags.cpu_name.?,
686696 @tagName(diags.arch.?),
......@@ -706,73 +716,11 @@ fn stage2TargetParse(
706716 },
707717 else => |e| return e,
708718 };
709 } else Target.Native;
719 } else .{};
710720
711721 try stage1_target.fromTarget(target);
712722}
713723
714fn initStage1TargetCpuFeatures(stage1_target: *Stage2Target, cpu: Target.Cpu) !void {
715 const allocator = std.heap.c_allocator;
716 const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{
717 cpu.model.name,
718 cpu.features.asBytes(),
719 });
720 errdefer allocator.free(cache_hash);
721
722 const generic_arch_name = cpu.arch.genericName();
723 var builtin_str_buffer = try std.Buffer.allocPrint(allocator,
724 \\Cpu{{
725 \\ .arch = .{},
726 \\ .model = &Target.{}.cpu.{},
727 \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
728 \\
729 , .{
730 @tagName(cpu.arch),
731 generic_arch_name,
732 cpu.model.name,
733 generic_arch_name,
734 generic_arch_name,
735 });
736 defer builtin_str_buffer.deinit();
737
738 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
739 defer llvm_features_buffer.deinit();
740
741 for (cpu.arch.allFeaturesList()) |feature, index_usize| {
742 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
743 const is_enabled = cpu.features.isEnabled(index);
744
745 if (feature.llvm_name) |llvm_name| {
746 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
747 try llvm_features_buffer.appendByte(plus_or_minus);
748 try llvm_features_buffer.append(llvm_name);
749 try llvm_features_buffer.append(",");
750 }
751
752 if (is_enabled) {
753 // TODO some kind of "zig identifier escape" function rather than
754 // unconditionally using @"" syntax
755 try builtin_str_buffer.append(" .@\"");
756 try builtin_str_buffer.append(feature.name);
757 try builtin_str_buffer.append("\",\n");
758 }
759 }
760
761 try builtin_str_buffer.append(
762 \\ }),
763 \\};
764 \\
765 );
766
767 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
768 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
769
770 stage1_target.llvm_cpu_name = if (cpu.model.llvm_name) |s| s.ptr else null;
771 stage1_target.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr;
772 stage1_target.builtin_str = builtin_str_buffer.toOwnedSlice().ptr;
773 stage1_target.cache_hash = cache_hash.ptr;
774}
775
776724// ABI warning
777725const Stage2LibCInstallation = extern struct {
778726 include_dir: [*:0]const u8,
......@@ -948,15 +896,18 @@ const Stage2Target = extern struct {
948896
949897 is_native: bool,
950898
951 glibc_version: ?*Stage2GLibCVersion, // null means default
899 glibc_or_darwin_version: ?*Stage2SemVer,
952900
953901 llvm_cpu_name: ?[*:0]const u8,
954902 llvm_cpu_features: ?[*:0]const u8,
955 builtin_str: ?[*:0]const u8,
903 cpu_builtin_str: ?[*:0]const u8,
956904 cache_hash: ?[*:0]const u8,
905 os_builtin_str: ?[*:0]const u8,
957906
958 fn toTarget(in_target: Stage2Target) Target {
959 if (in_target.is_native) return .Native;
907 dynamic_linker: ?[*:0]const u8,
908
909 fn toTarget(in_target: Stage2Target) CrossTarget {
910 if (in_target.is_native) return .{};
960911
961912 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
962913 const in_os = in_target.os;
......@@ -965,66 +916,270 @@ const Stage2Target = extern struct {
965916 return .{
966917 .Cross = .{
967918 .cpu = Target.Cpu.baseline(enumInt(Target.Cpu.Arch, in_arch)),
968 .os = enumInt(Target.Os, in_os),
919 .os = Target.Os.defaultVersionRange(enumInt(Target.Os.Tag, in_os)),
969920 .abi = enumInt(Target.Abi, in_abi),
970921 },
971922 };
972923 }
973924
974 fn fromTarget(self: *Stage2Target, target: Target) !void {
975 const cpu = switch (target) {
976 .Native => blk: {
977 // TODO self-host CPU model and feature detection instead of relying on LLVM
978 const llvm = @import("llvm.zig");
979 const llvm_cpu_name = llvm.GetHostCPUName();
980 const llvm_cpu_features = llvm.GetNativeFeatures();
981 break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);
982 },
983 .Cross => target.getCpu(),
925 fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
926 const allocator = std.heap.c_allocator;
927
928 var dynamic_linker: ?[*:0]u8 = null;
929 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
930
931 var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{
932 target.cpu.model.name,
933 target.cpu.features.asBytes(),
934 });
935 defer cache_hash.deinit();
936
937 const generic_arch_name = target.cpu.arch.genericName();
938 var cpu_builtin_str_buffer = try std.Buffer.allocPrint(allocator,
939 \\Cpu{{
940 \\ .arch = .{},
941 \\ .model = &Target.{}.cpu.{},
942 \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
943 \\
944 , .{
945 @tagName(target.cpu.arch),
946 generic_arch_name,
947 target.cpu.model.name,
948 generic_arch_name,
949 generic_arch_name,
950 });
951 defer cpu_builtin_str_buffer.deinit();
952
953 var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
954 defer llvm_features_buffer.deinit();
955
956 for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
957 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
958 const is_enabled = target.cpu.features.isEnabled(index);
959
960 if (feature.llvm_name) |llvm_name| {
961 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
962 try llvm_features_buffer.appendByte(plus_or_minus);
963 try llvm_features_buffer.append(llvm_name);
964 try llvm_features_buffer.append(",");
965 }
966
967 if (is_enabled) {
968 // TODO some kind of "zig identifier escape" function rather than
969 // unconditionally using @"" syntax
970 try cpu_builtin_str_buffer.append(" .@\"");
971 try cpu_builtin_str_buffer.append(feature.name);
972 try cpu_builtin_str_buffer.append("\",\n");
973 }
974 }
975
976 try cpu_builtin_str_buffer.append(
977 \\ }),
978 \\};
979 \\
980 );
981
982 assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
983 llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
984
985 var os_builtin_str_buffer = try std.Buffer.allocPrint(allocator,
986 \\Os{{
987 \\ .tag = .{},
988 \\ .version_range = .{{
989 , .{@tagName(target.os.tag)});
990 defer os_builtin_str_buffer.deinit();
991
992 // We'll re-use the OS version range builtin string for the cache hash.
993 const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
994
995 @setEvalBranchQuota(2000);
996 switch (target.os.tag) {
997 .freestanding,
998 .ananas,
999 .cloudabi,
1000 .dragonfly,
1001 .fuchsia,
1002 .ios,
1003 .kfreebsd,
1004 .lv2,
1005 .solaris,
1006 .haiku,
1007 .minix,
1008 .rtems,
1009 .nacl,
1010 .cnk,
1011 .aix,
1012 .cuda,
1013 .nvcl,
1014 .amdhsa,
1015 .ps4,
1016 .elfiamcu,
1017 .tvos,
1018 .watchos,
1019 .mesa3d,
1020 .contiki,
1021 .amdpal,
1022 .hermit,
1023 .hurd,
1024 .wasi,
1025 .emscripten,
1026 .uefi,
1027 .other,
1028 => try os_builtin_str_buffer.append(" .none = {} }\n"),
1029
1030 .freebsd,
1031 .macosx,
1032 .netbsd,
1033 .openbsd,
1034 => try os_builtin_str_buffer.print(
1035 \\ .semver = .{{
1036 \\ .min = .{{
1037 \\ .major = {},
1038 \\ .minor = {},
1039 \\ .patch = {},
1040 \\ }},
1041 \\ .max = .{{
1042 \\ .major = {},
1043 \\ .minor = {},
1044 \\ .patch = {},
1045 \\ }},
1046 \\ }}}},
1047 \\
1048 , .{
1049 target.os.version_range.semver.min.major,
1050 target.os.version_range.semver.min.minor,
1051 target.os.version_range.semver.min.patch,
1052
1053 target.os.version_range.semver.max.major,
1054 target.os.version_range.semver.max.minor,
1055 target.os.version_range.semver.max.patch,
1056 }),
1057
1058 .linux => try os_builtin_str_buffer.print(
1059 \\ .linux = .{{
1060 \\ .range = .{{
1061 \\ .min = .{{
1062 \\ .major = {},
1063 \\ .minor = {},
1064 \\ .patch = {},
1065 \\ }},
1066 \\ .max = .{{
1067 \\ .major = {},
1068 \\ .minor = {},
1069 \\ .patch = {},
1070 \\ }},
1071 \\ }},
1072 \\ .glibc = .{{
1073 \\ .major = {},
1074 \\ .minor = {},
1075 \\ .patch = {},
1076 \\ }},
1077 \\ }}}},
1078 \\
1079 , .{
1080 target.os.version_range.linux.range.min.major,
1081 target.os.version_range.linux.range.min.minor,
1082 target.os.version_range.linux.range.min.patch,
1083
1084 target.os.version_range.linux.range.max.major,
1085 target.os.version_range.linux.range.max.minor,
1086 target.os.version_range.linux.range.max.patch,
1087
1088 target.os.version_range.linux.glibc.major,
1089 target.os.version_range.linux.glibc.minor,
1090 target.os.version_range.linux.glibc.patch,
1091 }),
1092
1093 .windows => try os_builtin_str_buffer.print(
1094 \\ .windows = .{{
1095 \\ .min = .{},
1096 \\ .max = .{},
1097 \\ }}}},
1098 \\
1099 , .{
1100 @tagName(target.os.version_range.windows.min),
1101 @tagName(target.os.version_range.windows.max),
1102 }),
1103 }
1104 try os_builtin_str_buffer.append("};\n");
1105
1106 try cache_hash.append(
1107 os_builtin_str_buffer.toSlice()[os_builtin_str_ver_start_index..os_builtin_str_buffer.len()],
1108 );
1109
1110 const glibc_or_darwin_version = blk: {
1111 if (target.isGnuLibC()) {
1112 const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
1113 const stage2_glibc = target.os.version_range.linux.glibc;
1114 stage1_glibc.* = .{
1115 .major = stage2_glibc.major,
1116 .minor = stage2_glibc.minor,
1117 .patch = stage2_glibc.patch,
1118 };
1119 break :blk stage1_glibc;
1120 } else if (target.isDarwin()) {
1121 const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
1122 const stage2_semver = target.os.version_range.semver.min;
1123 stage1_semver.* = .{
1124 .major = stage2_semver.major,
1125 .minor = stage2_semver.minor,
1126 .patch = stage2_semver.patch,
1127 };
1128 break :blk stage1_semver;
1129 } else {
1130 break :blk null;
1131 }
9841132 };
1133
9851134 self.* = .{
986 .arch = @enumToInt(target.getArch()) + 1, // skip over ZigLLVM_UnknownArch
1135 .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
9871136 .vendor = 0,
988 .os = @enumToInt(target.getOs()),
989 .abi = @enumToInt(target.getAbi()),
990 .llvm_cpu_name = null,
991 .llvm_cpu_features = null,
992 .builtin_str = null,
993 .cache_hash = null,
994 .is_native = target == .Native,
995 .glibc_version = null,
1137 .os = @enumToInt(target.os.tag),
1138 .abi = @enumToInt(target.abi),
1139 .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
1140 .llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
1141 .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
1142 .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
1143 .cache_hash = cache_hash.toOwnedSlice().ptr,
1144 .is_native = cross_target.isNative(),
1145 .glibc_or_darwin_version = glibc_or_darwin_version,
1146 .dynamic_linker = dynamic_linker,
9961147 };
997 try initStage1TargetCpuFeatures(self, cpu);
9981148 }
9991149};
10001150
1151fn enumInt(comptime Enum: type, int: c_int) Enum {
1152 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
1153}
1154
1155fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
1156 var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
1157 if (cross_target.cpu_arch == null or cross_target.cpu_model == .native) {
1158 // TODO We want to just use detected_info.target but implementing
1159 // CPU model & feature detection is todo so here we rely on LLVM.
1160 const llvm = @import("llvm.zig");
1161 const llvm_cpu_name = llvm.GetHostCPUName();
1162 const llvm_cpu_features = llvm.GetNativeFeatures();
1163 const arch = std.Target.current.cpu.arch;
1164 info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
1165 cross_target.updateCpuFeatures(&info.target.cpu.features);
1166 info.target.cpu.arch = cross_target.getCpuArch();
1167 }
1168 if (info.dynamic_linker.get()) |dl| {
1169 dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
1170 } else {
1171 dynamic_linker_ptr.* = null;
1172 }
1173 return info.target;
1174}
1175
10011176// ABI warning
1002const Stage2GLibCVersion = extern struct {
1177const Stage2SemVer = extern struct {
10031178 major: u32,
10041179 minor: u32,
10051180 patch: u32,
10061181};
10071182
1008// ABI warning
1009export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
1010 const target = in_target.toTarget();
1011 const result = @import("introspect.zig").detectDynamicLinker(
1012 std.heap.c_allocator,
1013 target,
1014 ) catch |err| switch (err) {
1015 error.OutOfMemory => return .OutOfMemory,
1016 error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
1017 error.TargetHasNoDynamicLinker => return .TargetHasNoDynamicLinker,
1018 };
1019 out_ptr.* = result.ptr;
1020 out_len.* = result.len;
1021 return .None;
1022}
1023
1024fn enumInt(comptime Enum: type, int: c_int) Enum {
1025 return @intToEnum(Enum, @intCast(@TagType(Enum), int));
1026}
1027
10281183// ABI warning
10291184const Stage2NativePaths = extern struct {
10301185 include_dirs_ptr: [*][*:0]u8,
src-self-hosted/util.zig-22
......@@ -34,25 +34,3 @@ pub fn initializeAllTargets() void {
3434 llvm.InitializeAllAsmPrinters();
3535 llvm.InitializeAllAsmParsers();
3636}
37
38pub fn getTriple(allocator: *std.mem.Allocator, self: std.Target) !std.Buffer {
39 var result = try std.Buffer.initSize(allocator, 0);
40 errdefer result.deinit();
41
42 // LLVM WebAssembly output support requires the target to be activated at
43 // build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
44 //
45 // LLVM determines the output format based on the abi suffix,
46 // defaulting to an object based on the architecture. The default format in
47 // LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
48 // explicitly set this ourself in order for it to work.
49 //
50 // This is fixed in LLVM 7 and you will be able to get wasm output by
51 // using the target triple `wasm32-unknown-unknown-unknown`.
52 const env_name = if (self.isWasm()) "wasm" else @tagName(self.getAbi());
53
54 var out = &std.io.BufferOutStream.init(&result).stream;
55 try out.print("{}-unknown-{}-{}", .{ @tagName(self.getArch()), @tagName(self.getOs()), env_name });
56
57 return result;
58}
src/all_types.hpp-3
......@@ -2250,14 +2250,11 @@ struct CodeGen {
22502250 bool test_is_evented;
22512251 CodeModel code_model;
22522252
2253 Buf *mmacosx_version_min;
2254 Buf *mios_version_min;
22552253 Buf *root_out_name;
22562254 Buf *test_filter;
22572255 Buf *test_name_prefix;
22582256 Buf *zig_lib_dir;
22592257 Buf *zig_std_dir;
2260 Buf *dynamic_linker_path;
22612258 Buf *version_script_path;
22622259
22632260 const char **llvm_argv;
src/analyze.cpp+20-23
......@@ -3963,7 +3963,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
39633963
39643964 // TODO more validation for types that can't be used for export/extern variables
39653965 ZigType *implicit_type = nullptr;
3966 if (explicit_type != nullptr && explicit_type->id == ZigTypeIdInvalid) {
3966 if (explicit_type != nullptr && type_is_invalid(explicit_type)) {
39673967 implicit_type = explicit_type;
39683968 } else if (var_decl->expr) {
39693969 init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type,
......@@ -5401,6 +5401,8 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
54015401
54025402static bool can_mutate_comptime_var_state(ZigValue *value) {
54035403 assert(value != nullptr);
5404 if (value->special == ConstValSpecialUndef)
5405 return false;
54045406 switch (value->type->id) {
54055407 case ZigTypeIdInvalid:
54065408 zig_unreachable();
......@@ -6734,8 +6736,6 @@ static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_
67346736
67356737bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
67366738 if (a->type->id != b->type->id) return false;
6737 assert(a->special == ConstValSpecialStatic);
6738 assert(b->special == ConstValSpecialStatic);
67396739 if (a->type == b->type) {
67406740 switch (type_has_one_possible_value(g, a->type)) {
67416741 case OnePossibleValueInvalid:
......@@ -6746,6 +6746,11 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
67466746 return true;
67476747 }
67486748 }
6749 if (a->special == ConstValSpecialUndef || b->special == ConstValSpecialUndef) {
6750 return a->special == b->special;
6751 }
6752 assert(a->special == ConstValSpecialStatic);
6753 assert(b->special == ConstValSpecialStatic);
67496754 switch (a->type->id) {
67506755 case ZigTypeIdOpaque:
67516756 zig_unreachable();
......@@ -8729,7 +8734,6 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
87298734 if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return;
87308735 }
87318736
8732 LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
87338737 ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
87348738 if (type->data.maybe.resolve_status >= wanted_resolve_status) return;
87358739
......@@ -8739,35 +8743,28 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
87398743 };
87408744 LLVMStructSetBody(type->llvm_type, elem_types, 2, false);
87418745
8742 uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type);
8743 uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type);
8744 uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
8746 uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_child_index);
8747 uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_null_index);
87458748
8746 uint64_t maybe_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, bool_llvm_type);
8747 uint64_t maybe_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, bool_llvm_type);
8748 uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1);
8749
8750 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
8751 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
8752
8753 ZigLLVMDIType *di_element_types[] = {
8749 ZigLLVMDIType *di_element_types[2];
8750 di_element_types[maybe_child_index] =
87548751 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
87558752 "val", di_file, line,
8756 val_debug_size_in_bits,
8757 val_debug_align_in_bits,
8753 8 * child_type->abi_size,
8754 8 * child_type->abi_align,
87588755 val_offset_in_bits,
8759 ZigLLVM_DIFlags_Zero, child_llvm_di_type),
8756 ZigLLVM_DIFlags_Zero, child_llvm_di_type);
8757 di_element_types[maybe_null_index] =
87608758 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
87618759 "maybe", di_file, line,
8762 maybe_debug_size_in_bits,
8763 maybe_debug_align_in_bits,
8760 8*g->builtin_types.entry_bool->abi_size,
8761 8*g->builtin_types.entry_bool->abi_align,
87648762 maybe_offset_in_bits,
8765 ZigLLVM_DIFlags_Zero, bool_llvm_di_type),
8766 };
8763 ZigLLVM_DIFlags_Zero, bool_llvm_di_type);
87678764 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
87688765 compile_unit_scope,
87698766 buf_ptr(&type->name),
8770 di_file, line, debug_size_in_bits, debug_align_in_bits, ZigLLVM_DIFlags_Zero,
8767 di_file, line, 8 * type->abi_size, 8 * type->abi_align, ZigLLVM_DIFlags_Zero,
87718768 nullptr, di_element_types, 2, 0, nullptr, "");
87728769
87738770 ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
src/codegen.cpp+23-89
......@@ -32,31 +32,6 @@ enum ResumeId {
3232 ResumeIdCall,
3333};
3434
35static void init_darwin_native(CodeGen *g) {
36 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
37 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
38
39 // Allow conflicts among OSX and iOS, but choose the default platform.
40 if (osx_target && ios_target) {
41 if (g->zig_target->arch == ZigLLVM_arm ||
42 g->zig_target->arch == ZigLLVM_aarch64 ||
43 g->zig_target->arch == ZigLLVM_thumb)
44 {
45 osx_target = nullptr;
46 } else {
47 ios_target = nullptr;
48 }
49 }
50
51 if (osx_target) {
52 g->mmacosx_version_min = buf_create_from_str(osx_target);
53 } else if (ios_target) {
54 g->mios_version_min = buf_create_from_str(ios_target);
55 } else if (g->zig_target->os != OsIOS) {
56 g->mmacosx_version_min = buf_create_from_str("10.14");
57 }
58}
59
6035static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
6136 ZigPackage *entry = heap::c_allocator.create<ZigPackage>();
6237 entry->package_table.init(4);
......@@ -160,14 +135,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) {
160135 g->darwin_frameworks.append(buf_create_from_str(framework));
161136}
162137
163void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) {
164 g->mmacosx_version_min = mmacosx_version_min;
165}
166
167void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min) {
168 g->mios_version_min = mios_version_min;
169}
170
171138void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
172139 g->linker_rdynamic = rdynamic;
173140}
......@@ -4483,7 +4450,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutableGen *execu
44834450
44844451 if (!type_has_bits(field->type_entry)) {
44854452 ZigType *tag_type = union_type->data.unionation.tag_type;
4486 if (!instruction->initializing || !type_has_bits(tag_type))
4453 if (!instruction->initializing || tag_type == nullptr || !type_has_bits(tag_type))
44874454 return nullptr;
44884455
44894456 // The field has no bits but we still have to change the discriminant
......@@ -8543,25 +8510,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
85438510 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
85448511 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
85458512 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
8546 buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
8513 buf_append_str(contents, "/// Deprecated: use `std.Target.cpu.arch`\n");
85478514 buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
85488515 buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
85498516 {
85508517 buf_append_str(contents, "pub const cpu: Cpu = ");
8551 if (g->zig_target->builtin_str != nullptr) {
8552 buf_append_str(contents, g->zig_target->builtin_str);
8518 if (g->zig_target->cpu_builtin_str != nullptr) {
8519 buf_append_str(contents, g->zig_target->cpu_builtin_str);
85538520 } else {
8554 buf_append_str(contents, "Target.Cpu.baseline(arch);\n");
8521 buf_appendf(contents, "Target.Cpu.baseline(.%s);\n", cur_arch);
85558522 }
85568523 }
8557 if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {
8558 buf_appendf(contents,
8559 "pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n",
8560 g->zig_target->glibc_version->major,
8561 g->zig_target->glibc_version->minor,
8562 g->zig_target->glibc_version->patch);
8563 } else {
8564 buf_appendf(contents, "pub const glibc_version: ?Version = null;\n");
8524 {
8525 buf_append_str(contents, "pub const os = ");
8526 if (g->zig_target->os_builtin_str != nullptr) {
8527 buf_append_str(contents, g->zig_target->os_builtin_str);
8528 } else {
8529 buf_appendf(contents, "Target.Os.defaultVersionRange(.%s);\n", cur_os);
8530 }
85658531 }
85668532 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
85678533 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
......@@ -8656,10 +8622,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {
86568622 if (g->zig_target->cache_hash != nullptr) {
86578623 cache_str(&cache_hash, g->zig_target->cache_hash);
86588624 }
8659 if (g->zig_target->glibc_version != nullptr) {
8660 cache_int(&cache_hash, g->zig_target->glibc_version->major);
8661 cache_int(&cache_hash, g->zig_target->glibc_version->minor);
8662 cache_int(&cache_hash, g->zig_target->glibc_version->patch);
8625 if (g->zig_target->glibc_or_darwin_version != nullptr) {
8626 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->major);
8627 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->minor);
8628 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->patch);
86638629 }
86648630 cache_bool(&cache_hash, g->have_err_ret_tracing);
86658631 cache_bool(&cache_hash, g->libc_link_lib != nullptr);
......@@ -8866,28 +8832,6 @@ static void init(CodeGen *g) {
88668832 }
88678833}
88688834
8869static void detect_dynamic_linker(CodeGen *g) {
8870 Error err;
8871
8872 if (g->dynamic_linker_path != nullptr)
8873 return;
8874 if (!g->have_dynamic_link)
8875 return;
8876 if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
8877 return;
8878
8879 char *dynamic_linker_ptr;
8880 size_t dynamic_linker_len;
8881 if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
8882 if (err == ErrorTargetHasNoDynamicLinker) return;
8883 fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
8884 exit(1);
8885 }
8886 g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
8887 // Skips heap::c_allocator because the memory is allocated by stage2 library.
8888 free(dynamic_linker_ptr);
8889}
8890
88918835static void detect_libc(CodeGen *g) {
88928836 Error err;
88938837
......@@ -10323,10 +10267,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
1032310267 if (g->zig_target->cache_hash != nullptr) {
1032410268 cache_str(ch, g->zig_target->cache_hash);
1032510269 }
10326 if (g->zig_target->glibc_version != nullptr) {
10327 cache_int(ch, g->zig_target->glibc_version->major);
10328 cache_int(ch, g->zig_target->glibc_version->minor);
10329 cache_int(ch, g->zig_target->glibc_version->patch);
10270 if (g->zig_target->glibc_or_darwin_version != nullptr) {
10271 cache_int(ch, g->zig_target->glibc_or_darwin_version->major);
10272 cache_int(ch, g->zig_target->glibc_or_darwin_version->minor);
10273 cache_int(ch, g->zig_target->glibc_or_darwin_version->patch);
10274 }
10275 if (g->zig_target->dynamic_linker != nullptr) {
10276 cache_str(ch, g->zig_target->dynamic_linker);
1033010277 }
1033110278 cache_int(ch, detect_subsystem(g));
1033210279 cache_bool(ch, g->strip_debug_symbols);
......@@ -10354,8 +10301,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
1035410301 cache_bool(ch, g->emit_bin);
1035510302 cache_bool(ch, g->emit_llvm_ir);
1035610303 cache_bool(ch, g->emit_asm);
10357 cache_buf_opt(ch, g->mmacosx_version_min);
10358 cache_buf_opt(ch, g->mios_version_min);
1035910304 cache_usize(ch, g->version_major);
1036010305 cache_usize(ch, g->version_minor);
1036110306 cache_usize(ch, g->version_patch);
......@@ -10370,7 +10315,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
1037010315 cache_str(ch, g->libc->msvc_lib_dir);
1037110316 cache_str(ch, g->libc->kernel32_lib_dir);
1037210317 }
10373 cache_buf_opt(ch, g->dynamic_linker_path);
1037410318 cache_buf_opt(ch, g->version_script_path);
1037510319
1037610320 // gen_c_objects appends objects to g->link_objects which we want to include in the hash
......@@ -10467,7 +10411,6 @@ void codegen_build_and_link(CodeGen *g) {
1046710411 g->have_err_ret_tracing = detect_err_ret_tracing(g);
1046810412 g->have_sanitize_c = detect_sanitize_c(g);
1046910413 detect_libc(g);
10470 detect_dynamic_linker(g);
1047110414
1047210415 Buf digest = BUF_INIT;
1047310416 if (g->enable_cache) {
......@@ -10664,7 +10607,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
1066410607 child_gen->verbose_cc = parent_gen->verbose_cc;
1066510608 child_gen->verbose_llvm_cpu_features = parent_gen->verbose_llvm_cpu_features;
1066610609 child_gen->llvm_argv = parent_gen->llvm_argv;
10667 child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path;
1066810610
1066910611 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
1067010612 child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled;
......@@ -10672,9 +10614,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
1067210614
1067310615 codegen_set_errmsg_color(child_gen, parent_gen->err_color);
1067410616
10675 codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
10676 codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
10677
1067810617 child_gen->enable_cache = true;
1067910618
1068010619 return child_gen;
......@@ -10782,11 +10721,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
1078210721 g->each_lib_rpath = false;
1078310722 } else {
1078410723 g->each_lib_rpath = true;
10785
10786 if (target_os_is_darwin(g->zig_target->os)) {
10787 init_darwin_native(g);
10788 }
10789
1079010724 }
1079110725
1079210726 if (target_os_requires_libc(g->zig_target->os)) {
src/codegen.hpp-2
......@@ -35,8 +35,6 @@ LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
3535void codegen_add_framework(CodeGen *codegen, const char *name);
3636void codegen_add_rpath(CodeGen *codegen, const char *name);
3737void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
38void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
39void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
4038void codegen_set_linker_script(CodeGen *g, const char *linker_script);
4139void codegen_set_test_filter(CodeGen *g, Buf *filter);
4240void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
src/compiler.cpp-25
......@@ -4,31 +4,6 @@
44
55#include <stdio.h>
66
7Buf *get_self_libc_path(void) {
8 static Buf saved_libc_path = BUF_INIT;
9 static bool searched_for_libc = false;
10
11 for (;;) {
12 if (saved_libc_path.list.length != 0) {
13 return &saved_libc_path;
14 }
15 if (searched_for_libc)
16 return nullptr;
17 ZigList<Buf *> lib_paths = {};
18 Error err;
19 if ((err = os_self_exe_shared_libs(lib_paths)))
20 return nullptr;
21 for (size_t i = 0; i < lib_paths.length; i += 1) {
22 Buf *lib_path = lib_paths.at(i);
23 if (buf_ends_with_str(lib_path, "libc.so.6")) {
24 buf_init_from_buf(&saved_libc_path, lib_path);
25 return &saved_libc_path;
26 }
27 }
28 searched_for_libc = true;
29 }
30}
31
327Error get_compiler_id(Buf **result) {
338 static Buf saved_compiler_id = BUF_INIT;
349
src/compiler.hpp-1
......@@ -12,7 +12,6 @@
1212#include "error.hpp"
1313
1414Error get_compiler_id(Buf **result);
15Buf *get_self_libc_path(void);
1615
1716Buf *get_zig_lib_dir(void);
1817Buf *get_zig_special_dir(Buf *zig_lib_dir);
src/error.cpp+2
......@@ -81,6 +81,8 @@ const char *err_str(Error err) {
8181 case ErrorWindowsSdkNotFound: return "Windows SDK not found";
8282 case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path";
8383 case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker";
84 case ErrorInvalidAbiVersion: return "invalid C ABI version";
85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
8486 }
8587 return "(invalid error)";
8688}
src/glibc.cpp+13-50
......@@ -55,7 +55,7 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
5555 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
5656 if (!opt_component.is_some) break;
5757 Buf *ver_buf = buf_create_from_slice(opt_component.value);
58 ZigGLibCVersion *this_ver = glibc_abi->all_versions.add_one();
58 Stage2SemVer *this_ver = glibc_abi->all_versions.add_one();
5959 if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {
6060 if (verbose) {
6161 fprintf(stderr, "Unable to parse glibc version '%s': %s\n", buf_ptr(ver_buf), err_str(err));
......@@ -186,9 +186,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
186186 cache_buf(cache_hash, compiler_id);
187187 cache_int(cache_hash, target->arch);
188188 cache_int(cache_hash, target->abi);
189 cache_int(cache_hash, target->glibc_version->major);
190 cache_int(cache_hash, target->glibc_version->minor);
191 cache_int(cache_hash, target->glibc_version->patch);
189 cache_int(cache_hash, target->glibc_or_darwin_version->major);
190 cache_int(cache_hash, target->glibc_or_darwin_version->minor);
191 cache_int(cache_hash, target->glibc_or_darwin_version->patch);
192192
193193 Buf digest = BUF_INIT;
194194 buf_resize(&digest, 0);
......@@ -224,10 +224,10 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
224224
225225 uint8_t target_ver_index = 0;
226226 for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) {
227 const ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(target_ver_index);
228 if (this_ver->major == target->glibc_version->major &&
229 this_ver->minor == target->glibc_version->minor &&
230 this_ver->patch == target->glibc_version->patch)
227 const Stage2SemVer *this_ver = &glibc_abi->all_versions.at(target_ver_index);
228 if (this_ver->major == target->glibc_or_darwin_version->major &&
229 this_ver->minor == target->glibc_or_darwin_version->minor &&
230 this_ver->patch == target->glibc_or_darwin_version->patch)
231231 {
232232 break;
233233 }
......@@ -235,9 +235,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
235235 if (target_ver_index == glibc_abi->all_versions.length) {
236236 if (verbose) {
237237 fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",
238 target->glibc_version->major,
239 target->glibc_version->minor,
240 target->glibc_version->patch);
238 target->glibc_or_darwin_version->major,
239 target->glibc_or_darwin_version->minor,
240 target->glibc_or_darwin_version->patch);
241241 }
242242 return ErrorUnknownABI;
243243 }
......@@ -246,7 +246,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
246246 Buf *map_contents = buf_alloc();
247247
248248 for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) {
249 const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_i);
249 const Stage2SemVer *ver = &glibc_abi->all_versions.at(ver_i);
250250 if (ver->patch == 0) {
251251 buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);
252252 } else {
......@@ -294,7 +294,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
294294 uint8_t ver_index = ver_list->versions[ver_i];
295295
296296 Buf *stub_name;
297 const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_index);
297 const Stage2SemVer *ver = &glibc_abi->all_versions.at(ver_index);
298298 const char *sym_name = buf_ptr(libc_fn->name);
299299 if (ver->patch == 0) {
300300 stub_name = buf_sprintf("%s_%d_%d", sym_name, ver->major, ver->minor);
......@@ -362,43 +362,6 @@ bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) {
362362 a->abi == b->abi;
363363}
364364
365#ifdef ZIG_OS_LINUX
366#include <unistd.h>
367Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
368 Buf *self_libc_path = get_self_libc_path();
369 if (self_libc_path == nullptr) {
370 // TODO There is still more we could do to detect the native glibc version. For example,
371 // we could look at the ELF file of `/usr/bin/env`, find `libc.so.6`, and then `readlink`
372 // to find out the glibc version. This is relevant for the static zig builds distributed
373 // on the download page, since the above detection based on zig's own dynamic linking
374 // will not work.
375
376 return ErrorUnknownABI;
377 }
378 Buf *link_name = buf_alloc();
379 buf_resize(link_name, 4096);
380 ssize_t amt = readlink(buf_ptr(self_libc_path), buf_ptr(link_name), buf_len(link_name));
381 if (amt == -1) {
382 return ErrorUnknownABI;
383 }
384 buf_resize(link_name, amt);
385 if (!buf_starts_with_str(link_name, "libc-") || !buf_ends_with_str(link_name, ".so")) {
386 return ErrorUnknownABI;
387 }
388 // example: "libc-2.3.4.so"
389 // example: "libc-2.27.so"
390 buf_resize(link_name, buf_len(link_name) - 3); // chop off ".so"
391 glibc_ver->major = 2;
392 glibc_ver->minor = 0;
393 glibc_ver->patch = 0;
394 return target_parse_glibc_version(glibc_ver, buf_ptr(link_name) + 5);
395}
396#else
397Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
398 return ErrorUnknownABI;
399}
400#endif
401
402365size_t glibc_lib_count(void) {
403366 return array_length(glibc_libs);
404367}
src/glibc.hpp+1-4
......@@ -32,7 +32,7 @@ struct ZigGLibCAbi {
3232 Buf *abi_txt_path;
3333 Buf *vers_txt_path;
3434 Buf *fns_txt_path;
35 ZigList<ZigGLibCVersion> all_versions;
35 ZigList<Stage2SemVer> all_versions;
3636 ZigList<ZigGLibCFn> all_functions;
3737 // The value is a pointer to all_functions.length items and each item is an index
3838 // into all_functions.
......@@ -43,9 +43,6 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
4343Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
4444 Buf **out_dir, bool verbose, Stage2ProgressNode *progress_node);
4545
46// returns ErrorUnknownABI when glibc is not the native libc
47Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver);
48
4946size_t glibc_lib_count(void);
5047const ZigGLibCLib *glibc_lib_enum(size_t index);
5148const ZigGLibCLib *glibc_lib_find(const char *name);
src/link.cpp+19-112
......@@ -1751,9 +1751,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
17511751 }
17521752
17531753 if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {
1754 assert(g->dynamic_linker_path != nullptr);
1754 assert(g->zig_target->dynamic_linker != nullptr);
17551755 lj->args.append("-dynamic-linker");
1756 lj->args.append(buf_ptr(g->dynamic_linker_path));
1756 lj->args.append(g->zig_target->dynamic_linker);
17571757 }
17581758 }
17591759
......@@ -2371,99 +2371,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
23712371 }
23722372}
23732373
2374
2375// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
2376// grouped values as integers. Numbers which are not provided are set to 0.
2377// return true if the entire string was parsed (9.2), or all groups were
2378// parsed (10.3.5extrastuff).
2379static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
2380 *had_extra = false;
2381
2382 *major = 0;
2383 *minor = 0;
2384 *micro = 0;
2385
2386 if (*str == '\0')
2387 return false;
2388
2389 char *end;
2390 *major = (int)strtol(str, &end, 10);
2391 if (*str != '\0' && *end == '\0')
2392 return true;
2393 if (*end != '.')
2394 return false;
2395
2396 str = end + 1;
2397 *minor = (int)strtol(str, &end, 10);
2398 if (*str != '\0' && *end == '\0')
2399 return true;
2400 if (*end != '.')
2401 return false;
2402
2403 str = end + 1;
2404 *micro = (int)strtol(str, &end, 10);
2405 if (*str != '\0' && *end == '\0')
2406 return true;
2407 if (str == end)
2408 return false;
2409 *had_extra = true;
2410 return true;
2411}
2412
2413enum DarwinPlatformKind {
2414 MacOS,
2415 IPhoneOS,
2416 IPhoneOSSimulator,
2417};
2418
2419struct DarwinPlatform {
2420 DarwinPlatformKind kind;
2421 int major;
2422 int minor;
2423 int micro;
2424};
2425
2426static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
2427 CodeGen *g = lj->codegen;
2428
2429 if (g->mmacosx_version_min) {
2430 platform->kind = MacOS;
2431 } else if (g->mios_version_min) {
2432 platform->kind = IPhoneOS;
2433 } else if (g->zig_target->os == OsMacOSX) {
2434 platform->kind = MacOS;
2435 g->mmacosx_version_min = buf_create_from_str("10.14");
2436 } else {
2437 zig_panic("unable to infer -mmacosx-version-min or -mios-version-min");
2438 }
2439
2440 bool had_extra;
2441 if (platform->kind == MacOS) {
2442 if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
2443 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
2444 had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
2445 {
2446 zig_panic("invalid -mmacosx-version-min");
2447 }
2448 } else if (platform->kind == IPhoneOS) {
2449 if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
2450 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
2451 had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
2452 {
2453 zig_panic("invalid -mios-version-min");
2454 }
2455 } else {
2456 zig_unreachable();
2457 }
2458
2459 if (platform->kind == IPhoneOS &&
2460 (g->zig_target->arch == ZigLLVM_x86 ||
2461 g->zig_target->arch == ZigLLVM_x86_64))
2462 {
2463 platform->kind = IPhoneOSSimulator;
2464 }
2465}
2466
24672374static void construct_linker_job_macho(LinkJob *lj) {
24682375 CodeGen *g = lj->codegen;
24692376
......@@ -2507,25 +2414,25 @@ static void construct_linker_job_macho(LinkJob *lj) {
25072414 lj->args.append("-arch");
25082415 lj->args.append(get_darwin_arch_string(g->zig_target));
25092416
2510 DarwinPlatform platform;
2511 get_darwin_platform(lj, &platform);
2512 switch (platform.kind) {
2513 case MacOS:
2417 if (g->zig_target->glibc_or_darwin_version != nullptr) {
2418 if (g->zig_target->os == OsMacOSX) {
25142419 lj->args.append("-macosx_version_min");
2515 break;
2516 case IPhoneOS:
2517 lj->args.append("-iphoneos_version_min");
2518 break;
2519 case IPhoneOSSimulator:
2520 lj->args.append("-ios_simulator_version_min");
2521 break;
2522 }
2523 Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
2524 lj->args.append(buf_ptr(version_string));
2525
2526 lj->args.append("-sdk_version");
2527 lj->args.append(buf_ptr(version_string));
2420 } else if (g->zig_target->os == OsIOS) {
2421 if (g->zig_target->arch == ZigLLVM_x86 || g->zig_target->arch == ZigLLVM_x86_64) {
2422 lj->args.append("-ios_simulator_version_min");
2423 } else {
2424 lj->args.append("-iphoneos_version_min");
2425 }
2426 }
2427 Buf *version_string = buf_sprintf("%d.%d.%d",
2428 g->zig_target->glibc_or_darwin_version->major,
2429 g->zig_target->glibc_or_darwin_version->minor,
2430 g->zig_target->glibc_or_darwin_version->patch);
2431 lj->args.append(buf_ptr(version_string));
25282432
2433 lj->args.append("-sdk_version");
2434 lj->args.append(buf_ptr(version_string));
2435 }
25292436
25302437 if (g->out_type == OutTypeExe) {
25312438 lj->args.append("-pie");
src/main.cpp+12-54
......@@ -89,8 +89,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
8989 " --single-threaded source may assume it is only used single-threaded\n"
9090 " -dynamic create a shared library (.so; .dll; .dylib)\n"
9191 " --strip exclude debug symbols\n"
92 " -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
93 " -target-glibc [version] target a specific glibc version (default: 2.17)\n"
92 " -target [name] <arch>-<os>-<abi> see the targets command\n"
9493 " --verbose-tokenize enable compiler debug output for tokenization\n"
9594 " --verbose-ast enable compiler debug output for AST parsing\n"
9695 " --verbose-link enable compiler debug output for linking\n"
......@@ -128,8 +127,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
128127 " --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
129128 " -F[dir] (darwin) add search path for frameworks\n"
130129 " -framework [name] (darwin) link against framework\n"
131 " -mios-version-min [ver] (darwin) set iOS deployment target\n"
132 " -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
133130 " --ver-major [ver] dynamic library semver major version\n"
134131 " --ver-minor [ver] dynamic library semver minor version\n"
135132 " --ver-patch [ver] dynamic library semver patch version\n"
......@@ -404,7 +401,7 @@ static int main0(int argc, char **argv) {
404401 bool link_eh_frame_hdr = false;
405402 ErrColor color = ErrColorAuto;
406403 CacheOpt enable_cache = CacheOptAuto;
407 Buf *dynamic_linker = nullptr;
404 const char *dynamic_linker = nullptr;
408405 const char *libc_txt = nullptr;
409406 ZigList<const char *> clang_argv = {0};
410407 ZigList<const char *> lib_dirs = {0};
......@@ -415,11 +412,8 @@ static int main0(int argc, char **argv) {
415412 bool have_libc = false;
416413 const char *target_string = nullptr;
417414 bool rdynamic = false;
418 const char *mmacosx_version_min = nullptr;
419 const char *mios_version_min = nullptr;
420415 const char *linker_script = nullptr;
421416 Buf *version_script = nullptr;
422 const char *target_glibc = nullptr;
423417 ZigList<const char *> rpath_list = {0};
424418 bool each_lib_rpath = false;
425419 ZigList<const char *> objects = {0};
......@@ -502,7 +496,10 @@ static int main0(int argc, char **argv) {
502496 os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("build_runner.zig"), build_runner_path);
503497
504498 ZigTarget target;
505 get_native_target(&target);
499 if ((err = target_parse_triple(&target, "native", nullptr, nullptr))) {
500 fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
501 return EXIT_FAILURE;
502 }
506503
507504 Buf *build_file_buf = buf_create_from_str((build_file != nullptr) ? build_file : "build.zig");
508505 Buf build_file_abs = os_path_resolve(&build_file_buf, 1);
......@@ -769,7 +766,7 @@ static int main0(int argc, char **argv) {
769766 } else if (strcmp(arg, "--name") == 0) {
770767 out_name = argv[i];
771768 } else if (strcmp(arg, "--dynamic-linker") == 0) {
772 dynamic_linker = buf_create_from_str(argv[i]);
769 dynamic_linker = argv[i];
773770 } else if (strcmp(arg, "--libc") == 0) {
774771 libc_txt = argv[i];
775772 } else if (strcmp(arg, "-D") == 0) {
......@@ -843,18 +840,12 @@ static int main0(int argc, char **argv) {
843840 cache_dir = argv[i];
844841 } else if (strcmp(arg, "-target") == 0) {
845842 target_string = argv[i];
846 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
847 mmacosx_version_min = argv[i];
848 } else if (strcmp(arg, "-mios-version-min") == 0) {
849 mios_version_min = argv[i];
850843 } else if (strcmp(arg, "-framework") == 0) {
851844 frameworks.append(argv[i]);
852845 } else if (strcmp(arg, "--linker-script") == 0) {
853846 linker_script = argv[i];
854847 } else if (strcmp(arg, "--version-script") == 0) {
855848 version_script = buf_create_from_str(argv[i]);
856 } else if (strcmp(arg, "-target-glibc") == 0) {
857 target_glibc = argv[i];
858849 } else if (strcmp(arg, "-rpath") == 0) {
859850 rpath_list.append(argv[i]);
860851 } else if (strcmp(arg, "--test-filter") == 0) {
......@@ -977,34 +968,11 @@ static int main0(int argc, char **argv) {
977968 init_all_targets();
978969
979970 ZigTarget target;
980 if ((err = target_parse_triple(&target, target_string, mcpu))) {
971 if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) {
981972 fprintf(stderr, "invalid target: %s\n"
982973 "See `%s targets` to display valid targets.\n", err_str(err), arg0);
983974 return print_error_usage(arg0);
984975 }
985 if (target_is_glibc(&target)) {
986 target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>();
987
988 if (target_glibc != nullptr) {
989 if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) {
990 fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err));
991 return print_error_usage(arg0);
992 }
993 } else {
994 target_init_default_glibc_version(&target);
995#if defined(ZIG_OS_LINUX)
996 if (target.is_native) {
997 // TODO self-host glibc version detection, and then this logic can go away
998 if ((err = glibc_detect_native_version(target.glibc_version))) {
999 // Fall back to the default version.
1000 }
1001 }
1002#endif
1003 }
1004 } else if (target_glibc != nullptr) {
1005 fprintf(stderr, "'%s' is not a glibc-compatible target", target_string);
1006 return print_error_usage(arg0);
1007 }
1008976
1009977 Buf zig_triple_buf = BUF_INIT;
1010978 target_triple_zig(&zig_triple_buf, &target);
......@@ -1225,7 +1193,6 @@ static int main0(int argc, char **argv) {
12251193
12261194 codegen_set_strip(g, strip);
12271195 g->is_dynamic = is_dynamic;
1228 g->dynamic_linker_path = dynamic_linker;
12291196 g->verbose_tokenize = verbose_tokenize;
12301197 g->verbose_ast = verbose_ast;
12311198 g->verbose_link = verbose_link;
......@@ -1264,18 +1231,6 @@ static int main0(int argc, char **argv) {
12641231 }
12651232
12661233 codegen_set_rdynamic(g, rdynamic);
1267 if (mmacosx_version_min && mios_version_min) {
1268 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
1269 return main_exit(root_progress_node, EXIT_FAILURE);
1270 }
1271
1272 if (mmacosx_version_min) {
1273 codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
1274 }
1275
1276 if (mios_version_min) {
1277 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
1278 }
12791234
12801235 if (test_filter) {
12811236 codegen_set_test_filter(g, buf_create_from_str(test_filter));
......@@ -1364,7 +1319,10 @@ static int main0(int argc, char **argv) {
13641319 return main_exit(root_progress_node, EXIT_SUCCESS);
13651320 } else if (cmd == CmdTest) {
13661321 ZigTarget native;
1367 get_native_target(&native);
1322 if ((err = target_parse_triple(&native, "native", nullptr, nullptr))) {
1323 fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
1324 return EXIT_FAILURE;
1325 }
13681326
13691327 g->enable_cache = get_cache_opt(enable_cache, output_dir == nullptr);
13701328 codegen_build_and_link(g);
src/stage2.cpp+106-9
......@@ -91,7 +91,109 @@ void stage2_progress_complete_one(Stage2ProgressNode *node) {}
9191void stage2_progress_disable_tty(Stage2Progress *progress) {}
9292void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
9393
94Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) {
94static Os get_zig_os_type(ZigLLVM_OSType os_type) {
95 switch (os_type) {
96 case ZigLLVM_UnknownOS:
97 return OsFreestanding;
98 case ZigLLVM_Ananas:
99 return OsAnanas;
100 case ZigLLVM_CloudABI:
101 return OsCloudABI;
102 case ZigLLVM_DragonFly:
103 return OsDragonFly;
104 case ZigLLVM_FreeBSD:
105 return OsFreeBSD;
106 case ZigLLVM_Fuchsia:
107 return OsFuchsia;
108 case ZigLLVM_IOS:
109 return OsIOS;
110 case ZigLLVM_KFreeBSD:
111 return OsKFreeBSD;
112 case ZigLLVM_Linux:
113 return OsLinux;
114 case ZigLLVM_Lv2:
115 return OsLv2;
116 case ZigLLVM_Darwin:
117 case ZigLLVM_MacOSX:
118 return OsMacOSX;
119 case ZigLLVM_NetBSD:
120 return OsNetBSD;
121 case ZigLLVM_OpenBSD:
122 return OsOpenBSD;
123 case ZigLLVM_Solaris:
124 return OsSolaris;
125 case ZigLLVM_Win32:
126 return OsWindows;
127 case ZigLLVM_Haiku:
128 return OsHaiku;
129 case ZigLLVM_Minix:
130 return OsMinix;
131 case ZigLLVM_RTEMS:
132 return OsRTEMS;
133 case ZigLLVM_NaCl:
134 return OsNaCl;
135 case ZigLLVM_CNK:
136 return OsCNK;
137 case ZigLLVM_AIX:
138 return OsAIX;
139 case ZigLLVM_CUDA:
140 return OsCUDA;
141 case ZigLLVM_NVCL:
142 return OsNVCL;
143 case ZigLLVM_AMDHSA:
144 return OsAMDHSA;
145 case ZigLLVM_PS4:
146 return OsPS4;
147 case ZigLLVM_ELFIAMCU:
148 return OsELFIAMCU;
149 case ZigLLVM_TvOS:
150 return OsTvOS;
151 case ZigLLVM_WatchOS:
152 return OsWatchOS;
153 case ZigLLVM_Mesa3D:
154 return OsMesa3D;
155 case ZigLLVM_Contiki:
156 return OsContiki;
157 case ZigLLVM_AMDPAL:
158 return OsAMDPAL;
159 case ZigLLVM_HermitCore:
160 return OsHermitCore;
161 case ZigLLVM_Hurd:
162 return OsHurd;
163 case ZigLLVM_WASI:
164 return OsWASI;
165 case ZigLLVM_Emscripten:
166 return OsEmscripten;
167 }
168 zig_unreachable();
169}
170
171static void get_native_target(ZigTarget *target) {
172 // first zero initialize
173 *target = {};
174
175 ZigLLVM_OSType os_type;
176 ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
177 ZigLLVMGetNativeTarget(
178 &target->arch,
179 &target->vendor,
180 &os_type,
181 &target->abi,
182 &oformat);
183 target->os = get_zig_os_type(os_type);
184 target->is_native = true;
185 if (target->abi == ZigLLVM_UnknownEnvironment) {
186 target->abi = target_default_abi(target->arch, target->os);
187 }
188 if (target_is_glibc(target)) {
189 target->glibc_or_darwin_version = heap::c_allocator.create<Stage2SemVer>();
190 target_init_default_glibc_version(target);
191 }
192}
193
194Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
195 const char *dynamic_linker)
196{
95197 Error err;
96198
97199 if (zig_triple == nullptr) {
......@@ -100,13 +202,11 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
100202 if (mcpu == nullptr) {
101203 target->llvm_cpu_name = ZigLLVMGetHostCPUName();
102204 target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
103 target->builtin_str = "Target.Cpu.baseline(arch);\n";
104205 target->cache_hash = "native\n\n";
105206 } else if (strcmp(mcpu, "baseline") == 0) {
106207 target->is_native = false;
107208 target->llvm_cpu_name = "";
108209 target->llvm_cpu_features = "";
109 target->builtin_str = "Target.Cpu.baseline(arch);\n";
110210 target->cache_hash = "baseline\n\n";
111211 } else {
112212 const char *msg = "stage0 can't handle CPU/features in the target";
......@@ -148,10 +248,12 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
148248 const char *msg = "stage0 can't handle CPU/features in the target";
149249 stage2_panic(msg, strlen(msg));
150250 }
151 target->builtin_str = "Target.Cpu.baseline(arch);\n";
152251 target->cache_hash = "\n\n";
153252 }
154253
254 if (dynamic_linker != nullptr) {
255 target->dynamic_linker = dynamic_linker;
256 }
155257 return ErrorNone;
156258}
157259
......@@ -186,11 +288,6 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
186288 stage2_panic(msg, strlen(msg));
187289}
188290
189enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
190 const char *msg = "stage0 called stage2_detect_dynamic_linker";
191 stage2_panic(msg, strlen(msg));
192}
193
194291enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {
195292 native_paths->include_dirs_ptr = nullptr;
196293 native_paths->include_dirs_len = 0;
src/stage2.h+11-11
......@@ -103,6 +103,8 @@ enum Error {
103103 ErrorWindowsSdkNotFound,
104104 ErrorUnknownDynamicLinkerPath,
105105 ErrorTargetHasNoDynamicLinker,
106 ErrorInvalidAbiVersion,
107 ErrorInvalidOperatingSystemVersion,
106108};
107109
108110// ABI warning
......@@ -268,14 +270,12 @@ enum Os {
268270};
269271
270272// ABI warning
271struct ZigGLibCVersion {
272 uint32_t major; // always 2
273struct Stage2SemVer {
274 uint32_t major;
273275 uint32_t minor;
274276 uint32_t patch;
275277};
276278
277struct Stage2TargetData;
278
279279// ABI warning
280280struct ZigTarget {
281281 enum ZigLLVM_ArchType arch;
......@@ -286,20 +286,20 @@ struct ZigTarget {
286286
287287 bool is_native;
288288
289 struct ZigGLibCVersion *glibc_version; // null means default
289 // null means default. this is double-purposed to be darwin min version
290 struct Stage2SemVer *glibc_or_darwin_version;
290291
291292 const char *llvm_cpu_name;
292293 const char *llvm_cpu_features;
293 const char *builtin_str;
294 const char *cpu_builtin_str;
294295 const char *cache_hash;
296 const char *os_builtin_str;
297 const char *dynamic_linker;
295298};
296299
297300// ABI warning
298ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
299 char **out_ptr, size_t *out_len);
300
301// ABI warning
302ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu);
301ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
302 const char *dynamic_linker);
303303
304304
305305// ABI warning
src/target.cpp+4-104
......@@ -287,83 +287,6 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {
287287 zig_unreachable();
288288}
289289
290static Os get_zig_os_type(ZigLLVM_OSType os_type) {
291 switch (os_type) {
292 case ZigLLVM_UnknownOS:
293 return OsFreestanding;
294 case ZigLLVM_Ananas:
295 return OsAnanas;
296 case ZigLLVM_CloudABI:
297 return OsCloudABI;
298 case ZigLLVM_DragonFly:
299 return OsDragonFly;
300 case ZigLLVM_FreeBSD:
301 return OsFreeBSD;
302 case ZigLLVM_Fuchsia:
303 return OsFuchsia;
304 case ZigLLVM_IOS:
305 return OsIOS;
306 case ZigLLVM_KFreeBSD:
307 return OsKFreeBSD;
308 case ZigLLVM_Linux:
309 return OsLinux;
310 case ZigLLVM_Lv2:
311 return OsLv2;
312 case ZigLLVM_Darwin:
313 case ZigLLVM_MacOSX:
314 return OsMacOSX;
315 case ZigLLVM_NetBSD:
316 return OsNetBSD;
317 case ZigLLVM_OpenBSD:
318 return OsOpenBSD;
319 case ZigLLVM_Solaris:
320 return OsSolaris;
321 case ZigLLVM_Win32:
322 return OsWindows;
323 case ZigLLVM_Haiku:
324 return OsHaiku;
325 case ZigLLVM_Minix:
326 return OsMinix;
327 case ZigLLVM_RTEMS:
328 return OsRTEMS;
329 case ZigLLVM_NaCl:
330 return OsNaCl;
331 case ZigLLVM_CNK:
332 return OsCNK;
333 case ZigLLVM_AIX:
334 return OsAIX;
335 case ZigLLVM_CUDA:
336 return OsCUDA;
337 case ZigLLVM_NVCL:
338 return OsNVCL;
339 case ZigLLVM_AMDHSA:
340 return OsAMDHSA;
341 case ZigLLVM_PS4:
342 return OsPS4;
343 case ZigLLVM_ELFIAMCU:
344 return OsELFIAMCU;
345 case ZigLLVM_TvOS:
346 return OsTvOS;
347 case ZigLLVM_WatchOS:
348 return OsWatchOS;
349 case ZigLLVM_Mesa3D:
350 return OsMesa3D;
351 case ZigLLVM_Contiki:
352 return OsContiki;
353 case ZigLLVM_AMDPAL:
354 return OsAMDPAL;
355 case ZigLLVM_HermitCore:
356 return OsHermitCore;
357 case ZigLLVM_Hurd:
358 return OsHurd;
359 case ZigLLVM_WASI:
360 return OsWASI;
361 case ZigLLVM_Emscripten:
362 return OsEmscripten;
363 }
364 zig_unreachable();
365}
366
367290const char *target_os_name(Os os_type) {
368291 switch (os_type) {
369292 case OsFreestanding:
......@@ -424,7 +347,7 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) {
424347 return ZigLLVMGetEnvironmentTypeName(abi);
425348}
426349
427Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
350Error target_parse_glibc_version(Stage2SemVer *glibc_ver, const char *text) {
428351 glibc_ver->major = 2;
429352 glibc_ver->minor = 0;
430353 glibc_ver->patch = 0;
......@@ -447,31 +370,8 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
447370 return ErrorNone;
448371}
449372
450void get_native_target(ZigTarget *target) {
451 // first zero initialize
452 *target = {};
453
454 ZigLLVM_OSType os_type;
455 ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
456 ZigLLVMGetNativeTarget(
457 &target->arch,
458 &target->vendor,
459 &os_type,
460 &target->abi,
461 &oformat);
462 target->os = get_zig_os_type(os_type);
463 target->is_native = true;
464 if (target->abi == ZigLLVM_UnknownEnvironment) {
465 target->abi = target_default_abi(target->arch, target->os);
466 }
467 if (target_is_glibc(target)) {
468 target->glibc_version = heap::c_allocator.create<ZigGLibCVersion>();
469 target_init_default_glibc_version(target);
470 }
471}
472
473373void target_init_default_glibc_version(ZigTarget *target) {
474 *target->glibc_version = {2, 17, 0};
374 *target->glibc_or_darwin_version = {2, 17, 0};
475375}
476376
477377Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) {
......@@ -510,8 +410,8 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
510410 return ErrorUnknownABI;
511411}
512412
513Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu) {
514 return stage2_target_parse(target, triple, mcpu);
413Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker) {
414 return stage2_target_parse(target, triple, mcpu, dynamic_linker);
515415}
516416
517417const char *target_arch_name(ZigLLVM_ArchType arch) {
src/target.hpp+2-3
......@@ -41,12 +41,12 @@ enum CIntType {
4141 CIntTypeCount,
4242};
4343
44Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu);
44Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker);
4545Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);
4646Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
4747Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
4848
49Error target_parse_glibc_version(ZigGLibCVersion *out, const char *text);
49Error target_parse_glibc_version(Stage2SemVer *out, const char *text);
5050void target_init_default_glibc_version(ZigTarget *target);
5151
5252size_t target_arch_count(void);
......@@ -73,7 +73,6 @@ ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
7373const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
7474ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
7575
76void get_native_target(ZigTarget *target);
7776void target_triple_llvm(Buf *triple, const ZigTarget *target);
7877void target_triple_zig(Buf *triple, const ZigTarget *target);
7978
test/assemble_and_link.zig+2-2
......@@ -1,8 +1,8 @@
1const builtin = @import("builtin");
1const std = @import("std");
22const tests = @import("tests.zig");
33
44pub fn addCases(cases: *tests.CompareOutputContext) void {
5 if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
5 if (std.Target.current.os.tag == .linux and std.Target.current.cpu.arch == .x86_64) {
66 cases.addAsm("hello world linux x86_64",
77 \\.text
88 \\.globl _start
test/cli.zig+2-3
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const builtin = @import("builtin");
32const testing = std.testing;
43const process = std.process;
54const fs = std.fs;
......@@ -93,11 +92,11 @@ fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void {
9392fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
9493 _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" });
9594 const run_result = try exec(dir_path, &[_][]const u8{ zig_exe, "build", "run" });
96 testing.expect(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n"));
95 testing.expect(std.mem.eql(u8, run_result.stderr, "All your codebase are belong to us.\n"));
9796}
9897
9998fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
100 if (builtin.os != .linux or builtin.arch != .x86_64) return;
99 if (std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64) return;
101100
102101 const example_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.zig" });
103102 const example_s_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.s" });
test/compare_output.zig+4-5
......@@ -1,4 +1,3 @@
1const builtin = @import("builtin");
21const std = @import("std");
32const os = std.os;
43const tests = @import("tests.zig");
......@@ -131,8 +130,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
131130 , "Hello, world!\n 12 12 a\n");
132131
133132 cases.addC("number literals",
134 \\const builtin = @import("builtin");
135 \\const is_windows = builtin.os == builtin.Os.windows;
133 \\const std = @import("std");
134 \\const is_windows = std.Target.current.os.tag == .windows;
136135 \\const c = @cImport({
137136 \\ if (is_windows) {
138137 \\ // See https://github.com/ziglang/zig/issues/515
......@@ -306,8 +305,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
306305 , "");
307306
308307 cases.addC("casting between float and integer types",
309 \\const builtin = @import("builtin");
310 \\const is_windows = builtin.os == builtin.Os.windows;
308 \\const std = @import("std");
309 \\const is_windows = std.Target.current.os.tag == .windows;
311310 \\const c = @cImport({
312311 \\ if (is_windows) {
313312 \\ // See https://github.com/ziglang/zig/issues/515
test/compile_errors.zig+10-15
......@@ -1,6 +1,5 @@
11const tests = @import("tests.zig");
2const builtin = @import("builtin");
3const Target = @import("std").Target;
2const std = @import("std");
43
54pub fn addCases(cases: *tests.CompileErrorContext) void {
65 cases.addTest("type mismatch with tuple concatenation",
......@@ -387,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
387386 , &[_][]const u8{
388387 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
389388 });
390 tc.target = Target{
391 .Cross = .{
392 .cpu = Target.Cpu.baseline(.wasm32),
393 .os = .wasi,
394 .abi = .none,
395 },
389 tc.target = std.zig.CrossTarget{
390 .cpu_arch = .wasm32,
391 .os_tag = .wasi,
392 .abi = .none,
396393 };
397394 break :x tc;
398395 });
......@@ -788,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
788785 , &[_][]const u8{
789786 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
790787 });
791 tc.target = Target{
792 .Cross = .{
793 .cpu = Target.Cpu.baseline(.x86_64),
794 .os = .linux,
795 .abi = .gnu,
796 },
788 tc.target = std.zig.CrossTarget{
789 .cpu_arch = .x86_64,
790 .os_tag = .linux,
791 .abi = .gnu,
797792 };
798793 break :x tc;
799794 });
......@@ -1453,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
14531448 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
14541449 });
14551450
1456 if (builtin.os == builtin.Os.linux) {
1451 if (std.Target.current.os.tag == .linux) {
14571452 cases.addTest("implicit dependency on libc",
14581453 \\extern "c" fn exit(u8) void;
14591454 \\export fn entry() void {
test/src/translate_c.zig+3-2
......@@ -7,6 +7,7 @@ const fmt = std.fmt;
77const mem = std.mem;
88const fs = std.fs;
99const warn = std.debug.warn;
10const CrossTarget = std.zig.CrossTarget;
1011
1112pub const TranslateCContext = struct {
1213 b: *build.Builder,
......@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {
1920 sources: ArrayList(SourceFile),
2021 expected_lines: ArrayList([]const u8),
2122 allow_warnings: bool,
22 target: std.Target = .Native,
23 target: CrossTarget = CrossTarget{},
2324
2425 const SourceFile = struct {
2526 filename: []const u8,
......@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {
7576 pub fn addWithTarget(
7677 self: *TranslateCContext,
7778 name: []const u8,
78 target: std.Target,
79 target: CrossTarget,
7980 source: []const u8,
8081 expected_lines: []const []const u8,
8182 ) void {
test/stack_traces.zig+38-39
......@@ -1,4 +1,3 @@
1const builtin = @import("builtin");
21const std = @import("std");
32const os = std.os;
43const tests = @import("tests.zig");
......@@ -43,32 +42,32 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
4342 \\}
4443 ;
4544
46 switch (builtin.os) {
45 switch (std.Target.current.os.tag) {
4746 .freebsd => {
4847 cases.addCase(
4948 "return",
5049 source_return,
5150 [_][]const u8{
5251 // debug
53 \\error: TheSkyIsFalling
52 \\error: TheSkyIsFalling
5453 \\source.zig:4:5: [address] in main (test)
5554 \\ return error.TheSkyIsFalling;
5655 \\ ^
5756 \\
5857 ,
5958 // release-safe
60 \\error: TheSkyIsFalling
59 \\error: TheSkyIsFalling
6160 \\source.zig:4:5: [address] in std.start.main (test)
6261 \\ return error.TheSkyIsFalling;
6362 \\ ^
6463 \\
6564 ,
6665 // release-fast
67 \\error: TheSkyIsFalling
66 \\error: TheSkyIsFalling
6867 \\
6968 ,
7069 // release-small
71 \\error: TheSkyIsFalling
70 \\error: TheSkyIsFalling
7271 \\
7372 },
7473 );
......@@ -77,7 +76,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
7776 source_try_return,
7877 [_][]const u8{
7978 // debug
80 \\error: TheSkyIsFalling
79 \\error: TheSkyIsFalling
8180 \\source.zig:4:5: [address] in foo (test)
8281 \\ return error.TheSkyIsFalling;
8382 \\ ^
......@@ -87,7 +86,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
8786 \\
8887 ,
8988 // release-safe
90 \\error: TheSkyIsFalling
89 \\error: TheSkyIsFalling
9190 \\source.zig:4:5: [address] in std.start.main (test)
9291 \\ return error.TheSkyIsFalling;
9392 \\ ^
......@@ -97,11 +96,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
9796 \\
9897 ,
9998 // release-fast
100 \\error: TheSkyIsFalling
99 \\error: TheSkyIsFalling
101100 \\
102101 ,
103102 // release-small
104 \\error: TheSkyIsFalling
103 \\error: TheSkyIsFalling
105104 \\
106105 },
107106 );
......@@ -110,7 +109,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
110109 source_try_try_return_return,
111110 [_][]const u8{
112111 // debug
113 \\error: TheSkyIsFalling
112 \\error: TheSkyIsFalling
114113 \\source.zig:12:5: [address] in make_error (test)
115114 \\ return error.TheSkyIsFalling;
116115 \\ ^
......@@ -126,7 +125,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
126125 \\
127126 ,
128127 // release-safe
129 \\error: TheSkyIsFalling
128 \\error: TheSkyIsFalling
130129 \\source.zig:12:5: [address] in std.start.main (test)
131130 \\ return error.TheSkyIsFalling;
132131 \\ ^
......@@ -142,11 +141,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
142141 \\
143142 ,
144143 // release-fast
145 \\error: TheSkyIsFalling
144 \\error: TheSkyIsFalling
146145 \\
147146 ,
148147 // release-small
149 \\error: TheSkyIsFalling
148 \\error: TheSkyIsFalling
150149 \\
151150 },
152151 );
......@@ -157,25 +156,25 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
157156 source_return,
158157 [_][]const u8{
159158 // debug
160 \\error: TheSkyIsFalling
159 \\error: TheSkyIsFalling
161160 \\source.zig:4:5: [address] in main (test)
162161 \\ return error.TheSkyIsFalling;
163162 \\ ^
164163 \\
165164 ,
166165 // release-safe
167 \\error: TheSkyIsFalling
166 \\error: TheSkyIsFalling
168167 \\source.zig:4:5: [address] in std.start.posixCallMainAndExit (test)
169168 \\ return error.TheSkyIsFalling;
170169 \\ ^
171170 \\
172171 ,
173172 // release-fast
174 \\error: TheSkyIsFalling
173 \\error: TheSkyIsFalling
175174 \\
176175 ,
177176 // release-small
178 \\error: TheSkyIsFalling
177 \\error: TheSkyIsFalling
179178 \\
180179 },
181180 );
......@@ -184,7 +183,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
184183 source_try_return,
185184 [_][]const u8{
186185 // debug
187 \\error: TheSkyIsFalling
186 \\error: TheSkyIsFalling
188187 \\source.zig:4:5: [address] in foo (test)
189188 \\ return error.TheSkyIsFalling;
190189 \\ ^
......@@ -194,7 +193,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
194193 \\
195194 ,
196195 // release-safe
197 \\error: TheSkyIsFalling
196 \\error: TheSkyIsFalling
198197 \\source.zig:4:5: [address] in std.start.posixCallMainAndExit (test)
199198 \\ return error.TheSkyIsFalling;
200199 \\ ^
......@@ -204,11 +203,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
204203 \\
205204 ,
206205 // release-fast
207 \\error: TheSkyIsFalling
206 \\error: TheSkyIsFalling
208207 \\
209208 ,
210209 // release-small
211 \\error: TheSkyIsFalling
210 \\error: TheSkyIsFalling
212211 \\
213212 },
214213 );
......@@ -217,7 +216,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
217216 source_try_try_return_return,
218217 [_][]const u8{
219218 // debug
220 \\error: TheSkyIsFalling
219 \\error: TheSkyIsFalling
221220 \\source.zig:12:5: [address] in make_error (test)
222221 \\ return error.TheSkyIsFalling;
223222 \\ ^
......@@ -233,7 +232,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
233232 \\
234233 ,
235234 // release-safe
236 \\error: TheSkyIsFalling
235 \\error: TheSkyIsFalling
237236 \\source.zig:12:5: [address] in std.start.posixCallMainAndExit (test)
238237 \\ return error.TheSkyIsFalling;
239238 \\ ^
......@@ -249,11 +248,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
249248 \\
250249 ,
251250 // release-fast
252 \\error: TheSkyIsFalling
251 \\error: TheSkyIsFalling
253252 \\
254253 ,
255254 // release-small
256 \\error: TheSkyIsFalling
255 \\error: TheSkyIsFalling
257256 \\
258257 },
259258 );
......@@ -278,11 +277,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
278277 \\
279278 ,
280279 // release-fast
281 \\error: TheSkyIsFalling
280 \\error: TheSkyIsFalling
282281 \\
283282 ,
284283 // release-small
285 \\error: TheSkyIsFalling
284 \\error: TheSkyIsFalling
286285 \\
287286 },
288287 );
......@@ -311,11 +310,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
311310 \\
312311 ,
313312 // release-fast
314 \\error: TheSkyIsFalling
313 \\error: TheSkyIsFalling
315314 \\
316315 ,
317316 // release-small
318 \\error: TheSkyIsFalling
317 \\error: TheSkyIsFalling
319318 \\
320319 },
321320 );
......@@ -356,11 +355,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
356355 \\
357356 ,
358357 // release-fast
359 \\error: TheSkyIsFalling
358 \\error: TheSkyIsFalling
360359 \\
361360 ,
362361 // release-small
363 \\error: TheSkyIsFalling
362 \\error: TheSkyIsFalling
364363 \\
365364 },
366365 );
......@@ -371,7 +370,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
371370 source_return,
372371 [_][]const u8{
373372 // debug
374 \\error: TheSkyIsFalling
373 \\error: TheSkyIsFalling
375374 \\source.zig:4:5: [address] in main (test.obj)
376375 \\ return error.TheSkyIsFalling;
377376 \\ ^
......@@ -381,11 +380,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
381380 // --disabled-- results in segmenetation fault
382381 "",
383382 // release-fast
384 \\error: TheSkyIsFalling
383 \\error: TheSkyIsFalling
385384 \\
386385 ,
387386 // release-small
388 \\error: TheSkyIsFalling
387 \\error: TheSkyIsFalling
389388 \\
390389 },
391390 );
......@@ -407,11 +406,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
407406 // --disabled-- results in segmenetation fault
408407 "",
409408 // release-fast
410 \\error: TheSkyIsFalling
409 \\error: TheSkyIsFalling
411410 \\
412411 ,
413412 // release-small
414 \\error: TheSkyIsFalling
413 \\error: TheSkyIsFalling
415414 \\
416415 },
417416 );
......@@ -439,11 +438,11 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
439438 // --disabled-- results in segmenetation fault
440439 "",
441440 // release-fast
442 \\error: TheSkyIsFalling
441 \\error: TheSkyIsFalling
443442 \\
444443 ,
445444 // release-small
446 \\error: TheSkyIsFalling
445 \\error: TheSkyIsFalling
447446 \\
448447 },
449448 );
test/stage1/behavior/asm.zig+4-3
......@@ -1,9 +1,10 @@
11const std = @import("std");
2const config = @import("builtin");
32const expect = std.testing.expect;
43
4const is_x86_64_linux = std.Target.current.cpu.arch == .x86_64 and std.Target.current.os.tag == .linux;
5
56comptime {
6 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
7 if (is_x86_64_linux) {
78 asm (
89 \\.globl this_is_my_alias;
910 \\.type this_is_my_alias, @function;
......@@ -13,7 +14,7 @@ comptime {
1314}
1415
1516test "module level assembly" {
16 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
17 if (is_x86_64_linux) {
1718 expect(this_is_my_alias() == 1234);
1819 }
1920}
test/stage1/behavior/byteswap.zig+2-3
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const builtin = @import("builtin");
43
54test "@byteSwap integers" {
65 const ByteSwapIntTest = struct {
......@@ -41,10 +40,10 @@ test "@byteSwap integers" {
4140
4241test "@byteSwap vectors" {
4342 // https://github.com/ziglang/zig/issues/3563
44 if (builtin.os == .dragonfly) return error.SkipZigTest;
43 if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest;
4544
4645 // https://github.com/ziglang/zig/issues/3317
47 if (builtin.arch == .mipsel) return error.SkipZigTest;
46 if (std.Target.current.cpu.arch == .mipsel) return error.SkipZigTest;
4847
4948 const ByteSwapVectorTest = struct {
5049 fn run() void {
test/stage1/behavior/math.zig+10-10
......@@ -529,7 +529,7 @@ test "comptime_int xor" {
529529}
530530
531531test "f128" {
532 if (std.Target.current.isWindows()) {
532 if (std.Target.current.os.tag == .windows) {
533533 // TODO https://github.com/ziglang/zig/issues/508
534534 return error.SkipZigTest;
535535 }
......@@ -631,7 +631,7 @@ test "NaN comparison" {
631631 // TODO: https://github.com/ziglang/zig/issues/3338
632632 return error.SkipZigTest;
633633 }
634 if (std.Target.current.isWindows()) {
634 if (std.Target.current.os.tag == .windows) {
635635 // TODO https://github.com/ziglang/zig/issues/508
636636 return error.SkipZigTest;
637637 }
......@@ -666,14 +666,14 @@ test "128-bit multiplication" {
666666test "vector comparison" {
667667 const S = struct {
668668 fn doTheTest() void {
669 var a: @Vector(6, i32) = [_]i32{1, 3, -1, 5, 7, 9};
670 var b: @Vector(6, i32) = [_]i32{-1, 3, 0, 6, 10, -10};
671 expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{false, false, true, true, true, false}));
672 expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{false, true, true, true, true, false}));
673 expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{false, true, false, false, false, false}));
674 expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{true, false, true, true, true, true}));
675 expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{true, false, false, false, false, true}));
676 expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{true, true, false, false, false, true}));
669 var a: @Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 };
670 var b: @Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 };
671 expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false }));
672 expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false }));
673 expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false }));
674 expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true }));
675 expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true }));
676 expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true }));
677677 }
678678 };
679679 S.doTheTest();
test/stage1/behavior/namespace_depends_on_compile_var.zig+4-4
......@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const expect = @import("std").testing.expect;
1const std = @import("std");
2const expect = std.testing.expect;
33
44test "namespace depends on compile var" {
55 if (some_namespace.a_bool) {
......@@ -8,7 +8,7 @@ test "namespace depends on compile var" {
88 expect(!some_namespace.a_bool);
99 }
1010}
11const some_namespace = switch (builtin.os) {
12 builtin.Os.linux => @import("namespace_depends_on_compile_var/a.zig"),
11const some_namespace = switch (std.builtin.os.tag) {
12 .linux => @import("namespace_depends_on_compile_var/a.zig"),
1313 else => @import("namespace_depends_on_compile_var/b.zig"),
1414};
test/stage1/behavior/vector.zig+1-2
......@@ -2,7 +2,6 @@ const std = @import("std");
22const mem = std.mem;
33const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
5const builtin = @import("builtin");
65
76test "implicit cast vector to array - bool" {
87 const S = struct {
......@@ -114,7 +113,7 @@ test "array to vector" {
114113
115114test "vector casts of sizes not divisable by 8" {
116115 // https://github.com/ziglang/zig/issues/3563
117 if (builtin.os == .dragonfly) return error.SkipZigTest;
116 if (std.Target.current.os.tag == .dragonfly) return error.SkipZigTest;
118117
119118 const S = struct {
120119 fn doTheTest() void {
test/standalone.zig+2-2
......@@ -18,10 +18,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
1818 cases.addBuildFile("test/standalone/use_alias/build.zig");
1919 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
2020 cases.addBuildFile("test/standalone/empty_env/build.zig");
21 if (std.Target.current.getOs() != .wasi) {
21 if (std.Target.current.os.tag != .wasi) {
2222 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
2323 }
24 if (std.Target.current.getArch() == .x86_64) { // TODO add C ABI support for other architectures
24 if (std.Target.current.cpu.arch == .x86_64) { // TODO add C ABI support for other architectures
2525 cases.addBuildFile("test/stage1/c_abi/build.zig");
2626 }
2727}
test/tests.zig+78-115
......@@ -1,16 +1,15 @@
11const std = @import("std");
2const builtin = std.builtin;
23const debug = std.debug;
34const warn = debug.warn;
45const build = std.build;
5pub const Target = build.Target;
6pub const CrossTarget = build.CrossTarget;
6const CrossTarget = std.zig.CrossTarget;
77const Buffer = std.Buffer;
88const io = std.io;
99const fs = std.fs;
1010const mem = std.mem;
1111const fmt = std.fmt;
1212const ArrayList = std.ArrayList;
13const builtin = @import("builtin");
1413const Mode = builtin.Mode;
1514const LibExeObjStep = build.LibExeObjStep;
1615
......@@ -31,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
3130pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
3231
3332const TestTarget = struct {
34 target: Target = .Native,
33 target: CrossTarget = @as(CrossTarget, .{}),
3534 mode: builtin.Mode = .Debug,
3635 link_libc: bool = false,
3736 single_threaded: bool = false,
......@@ -53,93 +52,77 @@ const test_targets = blk: {
5352 },
5453
5554 TestTarget{
56 .target = Target{
57 .Cross = CrossTarget{
58 .cpu = Target.Cpu.baseline(.x86_64),
59 .os = .linux,
60 .abi = .none,
61 },
55 .target = .{
56 .cpu_arch = .x86_64,
57 .os_tag = .linux,
58 .abi = .none,
6259 },
6360 },
6461 TestTarget{
65 .target = Target{
66 .Cross = CrossTarget{
67 .cpu = Target.Cpu.baseline(.x86_64),
68 .os = .linux,
69 .abi = .gnu,
70 },
62 .target = .{
63 .cpu_arch = .x86_64,
64 .os_tag = .linux,
65 .abi = .gnu,
7166 },
7267 .link_libc = true,
7368 },
7469 TestTarget{
75 .target = Target{
76 .Cross = CrossTarget{
77 .cpu = Target.Cpu.baseline(.x86_64),
78 .os = .linux,
79 .abi = .musl,
80 },
70 .target = .{
71 .cpu_arch = .x86_64,
72 .os_tag = .linux,
73 .abi = .musl,
8174 },
8275 .link_libc = true,
8376 },
8477
8578 TestTarget{
86 .target = Target{
87 .Cross = CrossTarget{
88 .cpu = Target.Cpu.baseline(.i386),
89 .os = .linux,
90 .abi = .none,
91 },
79 .target = .{
80 .cpu_arch = .i386,
81 .os_tag = .linux,
82 .abi = .none,
9283 },
9384 },
9485 TestTarget{
95 .target = Target{
96 .Cross = CrossTarget{
97 .cpu = Target.Cpu.baseline(.i386),
98 .os = .linux,
99 .abi = .musl,
100 },
86 .target = .{
87 .cpu_arch = .i386,
88 .os_tag = .linux,
89 .abi = .musl,
10190 },
10291 .link_libc = true,
10392 },
10493
10594 TestTarget{
106 .target = Target{
107 .Cross = CrossTarget{
108 .cpu = Target.Cpu.baseline(.aarch64),
109 .os = .linux,
110 .abi = .none,
111 },
95 .target = .{
96 .cpu_arch = .aarch64,
97 .os_tag = .linux,
98 .abi = .none,
11299 },
113100 },
114101 TestTarget{
115 .target = Target{
116 .Cross = CrossTarget{
117 .cpu = Target.Cpu.baseline(.aarch64),
118 .os = .linux,
119 .abi = .musl,
120 },
102 .target = .{
103 .cpu_arch = .aarch64,
104 .os_tag = .linux,
105 .abi = .musl,
121106 },
122107 .link_libc = true,
123108 },
124109 TestTarget{
125 .target = Target{
126 .Cross = CrossTarget{
127 .cpu = Target.Cpu.baseline(.aarch64),
128 .os = .linux,
129 .abi = .gnu,
130 },
110 .target = .{
111 .cpu_arch = .aarch64,
112 .os_tag = .linux,
113 .abi = .gnu,
131114 },
132115 .link_libc = true,
133116 },
134117
135118 TestTarget{
136 .target = Target.parse(.{
119 .target = CrossTarget.parse(.{
137120 .arch_os_abi = "arm-linux-none",
138121 .cpu_features = "generic+v8a",
139122 }) catch unreachable,
140123 },
141124 TestTarget{
142 .target = Target.parse(.{
125 .target = CrossTarget.parse(.{
143126 .arch_os_abi = "arm-linux-musleabihf",
144127 .cpu_features = "generic+v8a",
145128 }) catch unreachable,
......@@ -147,7 +130,7 @@ const test_targets = blk: {
147130 },
148131 // TODO https://github.com/ziglang/zig/issues/3287
149132 //TestTarget{
150 // .target = Target.parse(.{
133 // .target = CrossTarget.parse(.{
151134 // .arch_os_abi = "arm-linux-gnueabihf",
152135 // .cpu_features = "generic+v8a",
153136 // }) catch unreachable,
......@@ -155,75 +138,61 @@ const test_targets = blk: {
155138 //},
156139
157140 TestTarget{
158 .target = Target{
159 .Cross = CrossTarget{
160 .cpu = Target.Cpu.baseline(.mipsel),
161 .os = .linux,
162 .abi = .none,
163 },
141 .target = .{
142 .cpu_arch = .mipsel,
143 .os_tag = .linux,
144 .abi = .none,
164145 },
165146 },
166147 TestTarget{
167 .target = Target{
168 .Cross = CrossTarget{
169 .cpu = Target.Cpu.baseline(.mipsel),
170 .os = .linux,
171 .abi = .musl,
172 },
148 .target = .{
149 .cpu_arch = .mipsel,
150 .os_tag = .linux,
151 .abi = .musl,
173152 },
174153 .link_libc = true,
175154 },
176155
177156 TestTarget{
178 .target = Target{
179 .Cross = CrossTarget{
180 .cpu = Target.Cpu.baseline(.x86_64),
181 .os = .macosx,
182 .abi = .gnu,
183 },
157 .target = .{
158 .cpu_arch = .x86_64,
159 .os_tag = .macosx,
160 .abi = .gnu,
184161 },
185162 // TODO https://github.com/ziglang/zig/issues/3295
186163 .disable_native = true,
187164 },
188165
189166 TestTarget{
190 .target = Target{
191 .Cross = CrossTarget{
192 .cpu = Target.Cpu.baseline(.i386),
193 .os = .windows,
194 .abi = .msvc,
195 },
167 .target = .{
168 .cpu_arch = .i386,
169 .os_tag = .windows,
170 .abi = .msvc,
196171 },
197172 },
198173
199174 TestTarget{
200 .target = Target{
201 .Cross = CrossTarget{
202 .cpu = Target.Cpu.baseline(.x86_64),
203 .os = .windows,
204 .abi = .msvc,
205 },
175 .target = .{
176 .cpu_arch = .x86_64,
177 .os_tag = .windows,
178 .abi = .msvc,
206179 },
207180 },
208181
209182 TestTarget{
210 .target = Target{
211 .Cross = CrossTarget{
212 .cpu = Target.Cpu.baseline(.i386),
213 .os = .windows,
214 .abi = .gnu,
215 },
183 .target = .{
184 .cpu_arch = .i386,
185 .os_tag = .windows,
186 .abi = .gnu,
216187 },
217188 .link_libc = true,
218189 },
219190
220191 TestTarget{
221 .target = Target{
222 .Cross = CrossTarget{
223 .cpu = Target.Cpu.baseline(.x86_64),
224 .os = .windows,
225 .abi = .gnu,
226 },
192 .target = .{
193 .cpu_arch = .x86_64,
194 .os_tag = .windows,
195 .abi = .gnu,
227196 },
228197 .link_libc = true,
229198 },
......@@ -432,13 +401,13 @@ pub fn addPkgTests(
432401 const step = b.step(b.fmt("test-{}", .{name}), desc);
433402
434403 for (test_targets) |test_target| {
435 if (skip_non_native and test_target.target != .Native)
404 if (skip_non_native and !test_target.target.isNative())
436405 continue;
437406
438407 if (skip_libc and test_target.link_libc)
439408 continue;
440409
441 if (test_target.link_libc and test_target.target.osRequiresLibC()) {
410 if (test_target.link_libc and test_target.target.getOs().requiresLibC()) {
442411 // This would be a redundant test.
443412 continue;
444413 }
......@@ -448,8 +417,8 @@ pub fn addPkgTests(
448417
449418 const ArchTag = @TagType(builtin.Arch);
450419 if (test_target.disable_native and
451 test_target.target.getOs() == builtin.os and
452 test_target.target.getArch() == builtin.arch)
420 test_target.target.getOsTag() == std.Target.current.os.tag and
421 test_target.target.getCpuArch() == std.Target.current.cpu.arch)
453422 {
454423 continue;
455424 }
......@@ -459,17 +428,14 @@ pub fn addPkgTests(
459428 } else false;
460429 if (!want_this_mode) continue;
461430
462 const libc_prefix = if (test_target.target.osRequiresLibC())
431 const libc_prefix = if (test_target.target.getOs().requiresLibC())
463432 ""
464433 else if (test_target.link_libc)
465434 "c"
466435 else
467436 "bare";
468437
469 const triple_prefix = if (test_target.target == .Native)
470 @as([]const u8, "native")
471 else
472 test_target.target.zigTripleNoSubArch(b.allocator) catch unreachable;
438 const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
473439
474440 const these_tests = b.addTest(root_src);
475441 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
......@@ -483,7 +449,7 @@ pub fn addPkgTests(
483449 these_tests.single_threaded = test_target.single_threaded;
484450 these_tests.setFilter(test_filter);
485451 these_tests.setBuildMode(test_target.mode);
486 these_tests.setTheTarget(test_target.target);
452 these_tests.setTarget(test_target.target);
487453 if (test_target.link_libc) {
488454 these_tests.linkSystemLibrary("c");
489455 }
......@@ -660,7 +626,7 @@ pub const StackTracesContext = struct {
660626 const delims = [_][]const u8{ ":", ":", ":", " in " };
661627 var marks = [_]usize{0} ** 4;
662628 // offset search past `[drive]:` on windows
663 var pos: usize = if (builtin.os == .windows) 2 else 0;
629 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
664630 for (delims) |delim, i| {
665631 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
666632 try buf.append(line);
......@@ -713,7 +679,7 @@ pub const CompileErrorContext = struct {
713679 link_libc: bool,
714680 is_exe: bool,
715681 is_test: bool,
716 target: Target = .Native,
682 target: CrossTarget = CrossTarget{},
717683
718684 const SourceFile = struct {
719685 filename: []const u8,
......@@ -805,12 +771,9 @@ pub const CompileErrorContext = struct {
805771 zig_args.append("--output-dir") catch unreachable;
806772 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
807773
808 switch (self.case.target) {
809 .Native => {},
810 .Cross => {
811 try zig_args.append("-target");
812 try zig_args.append(try self.case.target.zigTriple(b.allocator));
813 },
774 if (!self.case.target.isNative()) {
775 try zig_args.append("-target");
776 try zig_args.append(try self.case.target.zigTriple(b.allocator));
814777 }
815778
816779 switch (self.build_mode) {
test/translate_c.zig+11-13
......@@ -1,6 +1,6 @@
11const tests = @import("tests.zig");
2const builtin = @import("builtin");
3const Target = @import("std").Target;
2const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
66 cases.add("macro line continuation",
......@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
665665 \\}
666666 });
667667
668 if (builtin.os != builtin.Os.windows) {
668 if (std.Target.current.os.tag != .windows) {
669669 // Windows treats this as an enum with type c_int
670670 cases.add("big negative enum init values when C ABI supports long long enums",
671671 \\enum EnumWithInits {
......@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10641064 \\}
10651065 });
10661066
1067 if (builtin.os != builtin.Os.windows) {
1067 if (std.Target.current.os.tag != .windows) {
10681068 // sysv_abi not currently supported on windows
10691069 cases.add("Macro qualified functions",
10701070 \\void __attribute__((sysv_abi)) foo(void);
......@@ -1093,12 +1093,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10931093 \\pub const fn1 = ?fn (u8) callconv(.C) void;
10941094 });
10951095
1096 cases.addWithTarget("Calling convention", tests.Target{
1097 .Cross = .{
1098 .cpu = Target.Cpu.baseline(.i386),
1099 .os = .linux,
1100 .abi = .none,
1101 },
1096 cases.addWithTarget("Calling convention", .{
1097 .cpu_arch = .i386,
1098 .os_tag = .linux,
1099 .abi = .none,
11021100 },
11031101 \\void __attribute__((fastcall)) foo1(float *a);
11041102 \\void __attribute__((stdcall)) foo2(float *a);
......@@ -1113,7 +1111,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11131111 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
11141112 });
11151113
1116 cases.addWithTarget("Calling convention", Target.parse(.{
1114 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
11171115 .arch_os_abi = "arm-linux-none",
11181116 .cpu_features = "generic+v8_5a",
11191117 }) catch unreachable,
......@@ -1124,7 +1122,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11241122 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
11251123 });
11261124
1127 cases.addWithTarget("Calling convention", Target.parse(.{
1125 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
11281126 .arch_os_abi = "aarch64-linux-none",
11291127 .cpu_features = "generic+v8_5a",
11301128 }) catch unreachable,
......@@ -1596,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15961594 \\}
15971595 });
15981596
1599 if (builtin.os != .windows) {
1597 if (std.Target.current.os.tag != .windows) {
16001598 // When clang uses the <arch>-windows-none triple it behaves as MSVC and
16011599 // interprets the inner `struct Bar` as an anonymous structure
16021600 cases.add("type referenced struct",