authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-03 09:44:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-03 09:44:13-05:00
logd1cb16aace5f5996cf2556d07fd3418a951b31df
treee154f475be8de6f0b0c486cf1baa1557c3f12b65
parent3418a332ab3a120f21354d98579d7a3a2dcb523b
parent387418277a4964714ddaec3336a602ec87dde0f9
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm10


132 files changed, 6563 insertions(+), 4268 deletions(-)

build.zig+1-1
...@@ -305,7 +305,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {...@@ -305,7 +305,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
305 }305 }
306 dependOnLib(b, exe, ctx.llvm);306 dependOnLib(b, exe, ctx.llvm);
307307
308 if (exe.target.getOs() == .linux) {308 if (exe.target.getOsTag() == .linux) {
309 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",309 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
310 \\Unable to determine path to libstdc++.a310 \\Unable to determine path to libstdc++.a
311 \\On Fedora, install libstdc++-static and try again.311 \\On Fedora, install libstdc++-static and try again.
doc/docgen.zig+42-41
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const process = std.process;5const process = std.process;
...@@ -10,8 +10,8 @@ const testing = std.testing;...@@ -10,8 +10,8 @@ const testing = std.testing;
1010
11const max_doc_file_size = 10 * 1024 * 1024;11const max_doc_file_size = 10 * 1024 * 1024;
1212
13const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt();13const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
14const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt();14const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
15const tmp_dir_name = "docgen_tmp";15const tmp_dir_name = "docgen_tmp";
16const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;16const 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 {...@@ -521,7 +521,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
521 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", .{code_kind_str});521 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", .{code_kind_str});
522 }522 }
523523
524 var mode = builtin.Mode.Debug;524 var mode: builtin.Mode = .Debug;
525 var link_objects = std.ArrayList([]const u8).init(allocator);525 var link_objects = std.ArrayList([]const u8).init(allocator);
526 defer link_objects.deinit();526 defer link_objects.deinit();
527 var target_str: ?[]const u8 = null;527 var target_str: ?[]const u8 = null;
...@@ -533,9 +533,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {...@@ -533,9 +533,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
533 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);533 const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);
534 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];534 const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];
535 if (mem.eql(u8, end_tag_name, "code_release_fast")) {535 if (mem.eql(u8, end_tag_name, "code_release_fast")) {
536 mode = builtin.Mode.ReleaseFast;536 mode = .ReleaseFast;
537 } else if (mem.eql(u8, end_tag_name, "code_release_safe")) {537 } else if (mem.eql(u8, end_tag_name, "code_release_safe")) {
538 mode = builtin.Mode.ReleaseSafe;538 mode = .ReleaseSafe;
539 } else if (mem.eql(u8, end_tag_name, "code_link_object")) {539 } else if (mem.eql(u8, end_tag_name, "code_link_object")) {
540 _ = try eatToken(tokenizer, Token.Id.Separator);540 _ = try eatToken(tokenizer, Token.Id.Separator);
541 const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);541 const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
...@@ -1001,30 +1001,30 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1001,30 +1001,30 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
10011001
1002 for (toc.nodes) |node| {1002 for (toc.nodes) |node| {
1003 switch (node) {1003 switch (node) {
1004 Node.Content => |data| {1004 .Content => |data| {
1005 try out.write(data);1005 try out.write(data);
1006 },1006 },
1007 Node.Link => |info| {1007 .Link => |info| {
1008 if (!toc.urls.contains(info.url)) {1008 if (!toc.urls.contains(info.url)) {
1009 return parseError(tokenizer, info.token, "url not found: {}", .{info.url});1009 return parseError(tokenizer, info.token, "url not found: {}", .{info.url});
1010 }1010 }
1011 try out.print("<a href=\"#{}\">{}</a>", .{ info.url, info.name });1011 try out.print("<a href=\"#{}\">{}</a>", .{ info.url, info.name });
1012 },1012 },
1013 Node.Nav => {1013 .Nav => {
1014 try out.write(toc.toc);1014 try out.write(toc.toc);
1015 },1015 },
1016 Node.Builtin => |tok| {1016 .Builtin => |tok| {
1017 try out.write("<pre>");1017 try out.write("<pre>");
1018 try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);1018 try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
1019 try out.write("</pre>");1019 try out.write("</pre>");
1020 },1020 },
1021 Node.HeaderOpen => |info| {1021 .HeaderOpen => |info| {
1022 try out.print(1022 try out.print(
1023 "<h{} id=\"{}\"><a href=\"#toc-{}\">{}</a> <a class=\"hdr\" href=\"#{}\">§</a></h{}>\n",1023 "<h{} id=\"{}\"><a href=\"#toc-{}\">{}</a> <a class=\"hdr\" href=\"#{}\">§</a></h{}>\n",
1024 .{ info.n, info.url, info.url, info.name, info.url, info.n },1024 .{ info.n, info.url, info.url, info.name, info.url, info.n },
1025 );1025 );
1026 },1026 },
1027 Node.SeeAlso => |items| {1027 .SeeAlso => |items| {
1028 try out.write("<p>See also:</p><ul>\n");1028 try out.write("<p>See also:</p><ul>\n");
1029 for (items) |item| {1029 for (items) |item| {
1030 const url = try urlize(allocator, item.name);1030 const url = try urlize(allocator, item.name);
...@@ -1035,10 +1035,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1035,10 +1035,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1035 }1035 }
1036 try out.write("</ul>\n");1036 try out.write("</ul>\n");
1037 },1037 },
1038 Node.Syntax => |content_tok| {1038 .Syntax => |content_tok| {
1039 try tokenizeAndPrint(tokenizer, out, content_tok);1039 try tokenizeAndPrint(tokenizer, out, content_tok);
1040 },1040 },
1041 Node.Code => |code| {1041 .Code => |code| {
1042 code_progress_index += 1;1042 code_progress_index += 1;
1043 warn("docgen example code {}/{}...", .{ code_progress_index, tokenizer.code_node_count });1043 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...@@ -1075,16 +1075,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1075 });1075 });
1076 try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", .{code.name});1076 try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", .{code.name});
1077 switch (code.mode) {1077 switch (code.mode) {
1078 builtin.Mode.Debug => {},1078 .Debug => {},
1079 builtin.Mode.ReleaseSafe => {1079 .ReleaseSafe => {
1080 try build_args.append("--release-safe");1080 try build_args.append("--release-safe");
1081 try out.print(" --release-safe", .{});1081 try out.print(" --release-safe", .{});
1082 },1082 },
1083 builtin.Mode.ReleaseFast => {1083 .ReleaseFast => {
1084 try build_args.append("--release-fast");1084 try build_args.append("--release-fast");
1085 try out.print(" --release-fast", .{});1085 try out.print(" --release-fast", .{});
1086 },1086 },
1087 builtin.Mode.ReleaseSmall => {1087 .ReleaseSmall => {
1088 try build_args.append("--release-small");1088 try build_args.append("--release-small");
1089 try out.print(" --release-small", .{});1089 try out.print(" --release-small", .{});
1090 },1090 },
...@@ -1142,13 +1142,14 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1142,13 +1142,14 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1142 try out.print("\n{}</code></pre>\n", .{colored_stderr});1142 try out.print("\n{}</code></pre>\n", .{colored_stderr});
1143 break :code_block;1143 break :code_block;
1144 }1144 }
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
1147 if (code.target_str) |triple| {1148 if (code.target_str) |triple| {
1148 if (mem.startsWith(u8, triple, "wasm32") or1149 if (mem.startsWith(u8, triple, "wasm32") or
1149 mem.startsWith(u8, triple, "riscv64-linux") or1150 mem.startsWith(u8, triple, "riscv64-linux") or
1150 mem.startsWith(u8, triple, "x86_64-linux") and1151 (mem.startsWith(u8, triple, "x86_64-linux") and
1151 (builtin.os != .linux or builtin.arch != .x86_64))1152 std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64))
1152 {1153 {
1153 // skip execution1154 // skip execution
1154 try out.print("</code></pre>\n", .{});1155 try out.print("</code></pre>\n", .{});
...@@ -1207,16 +1208,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1207,16 +1208,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1207 });1208 });
1208 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});1209 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
1209 switch (code.mode) {1210 switch (code.mode) {
1210 builtin.Mode.Debug => {},1211 .Debug => {},
1211 builtin.Mode.ReleaseSafe => {1212 .ReleaseSafe => {
1212 try test_args.append("--release-safe");1213 try test_args.append("--release-safe");
1213 try out.print(" --release-safe", .{});1214 try out.print(" --release-safe", .{});
1214 },1215 },
1215 builtin.Mode.ReleaseFast => {1216 .ReleaseFast => {
1216 try test_args.append("--release-fast");1217 try test_args.append("--release-fast");
1217 try out.print(" --release-fast", .{});1218 try out.print(" --release-fast", .{});
1218 },1219 },
1219 builtin.Mode.ReleaseSmall => {1220 .ReleaseSmall => {
1220 try test_args.append("--release-small");1221 try test_args.append("--release-small");
1221 try out.print(" --release-small", .{});1222 try out.print(" --release-small", .{});
1222 },1223 },
...@@ -1249,16 +1250,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1249,16 +1250,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1249 });1250 });
1250 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});1251 try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
1251 switch (code.mode) {1252 switch (code.mode) {
1252 builtin.Mode.Debug => {},1253 .Debug => {},
1253 builtin.Mode.ReleaseSafe => {1254 .ReleaseSafe => {
1254 try test_args.append("--release-safe");1255 try test_args.append("--release-safe");
1255 try out.print(" --release-safe", .{});1256 try out.print(" --release-safe", .{});
1256 },1257 },
1257 builtin.Mode.ReleaseFast => {1258 .ReleaseFast => {
1258 try test_args.append("--release-fast");1259 try test_args.append("--release-fast");
1259 try out.print(" --release-fast", .{});1260 try out.print(" --release-fast", .{});
1260 },1261 },
1261 builtin.Mode.ReleaseSmall => {1262 .ReleaseSmall => {
1262 try test_args.append("--release-small");1263 try test_args.append("--release-small");
1263 try out.print(" --release-small", .{});1264 try out.print(" --release-small", .{});
1264 },1265 },
...@@ -1306,16 +1307,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1306,16 +1307,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1306 });1307 });
1307 var mode_arg: []const u8 = "";1308 var mode_arg: []const u8 = "";
1308 switch (code.mode) {1309 switch (code.mode) {
1309 builtin.Mode.Debug => {},1310 .Debug => {},
1310 builtin.Mode.ReleaseSafe => {1311 .ReleaseSafe => {
1311 try test_args.append("--release-safe");1312 try test_args.append("--release-safe");
1312 mode_arg = " --release-safe";1313 mode_arg = " --release-safe";
1313 },1314 },
1314 builtin.Mode.ReleaseFast => {1315 .ReleaseFast => {
1315 try test_args.append("--release-fast");1316 try test_args.append("--release-fast");
1316 mode_arg = " --release-fast";1317 mode_arg = " --release-fast";
1317 },1318 },
1318 builtin.Mode.ReleaseSmall => {1319 .ReleaseSmall => {
1319 try test_args.append("--release-small");1320 try test_args.append("--release-small");
1320 mode_arg = " --release-small";1321 mode_arg = " --release-small";
1321 },1322 },
...@@ -1386,20 +1387,20 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1386,20 +1387,20 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1386 }1387 }
13871388
1388 switch (code.mode) {1389 switch (code.mode) {
1389 builtin.Mode.Debug => {},1390 .Debug => {},
1390 builtin.Mode.ReleaseSafe => {1391 .ReleaseSafe => {
1391 try build_args.append("--release-safe");1392 try build_args.append("--release-safe");
1392 if (!code.is_inline) {1393 if (!code.is_inline) {
1393 try out.print(" --release-safe", .{});1394 try out.print(" --release-safe", .{});
1394 }1395 }
1395 },1396 },
1396 builtin.Mode.ReleaseFast => {1397 .ReleaseFast => {
1397 try build_args.append("--release-fast");1398 try build_args.append("--release-fast");
1398 if (!code.is_inline) {1399 if (!code.is_inline) {
1399 try out.print(" --release-fast", .{});1400 try out.print(" --release-fast", .{});
1400 }1401 }
1401 },1402 },
1402 builtin.Mode.ReleaseSmall => {1403 .ReleaseSmall => {
1403 try build_args.append("--release-small");1404 try build_args.append("--release-small");
1404 if (!code.is_inline) {1405 if (!code.is_inline) {
1405 try out.print(" --release-small", .{});1406 try out.print(" --release-small", .{});
...@@ -1461,16 +1462,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1461,16 +1462,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1461 });1462 });
1462 try out.print("<pre><code class=\"shell\">$ zig build-lib {}.zig", .{code.name});1463 try out.print("<pre><code class=\"shell\">$ zig build-lib {}.zig", .{code.name});
1463 switch (code.mode) {1464 switch (code.mode) {
1464 builtin.Mode.Debug => {},1465 .Debug => {},
1465 builtin.Mode.ReleaseSafe => {1466 .ReleaseSafe => {
1466 try test_args.append("--release-safe");1467 try test_args.append("--release-safe");
1467 try out.print(" --release-safe", .{});1468 try out.print(" --release-safe", .{});
1468 },1469 },
1469 builtin.Mode.ReleaseFast => {1470 .ReleaseFast => {
1470 try test_args.append("--release-fast");1471 try test_args.append("--release-fast");
1471 try out.print(" --release-fast", .{});1472 try out.print(" --release-fast", .{});
1472 },1473 },
1473 builtin.Mode.ReleaseSmall => {1474 .ReleaseSmall => {
1474 try test_args.append("--release-small");1475 try test_args.append("--release-small");
1475 try out.print(" --release-small", .{});1476 try out.print(" --release-small", .{});
1476 },1477 },
doc/langref.html.in+15-15
...@@ -965,7 +965,8 @@ const nan = std.math.nan(f128);...@@ -965,7 +965,8 @@ const nan = std.math.nan(f128);
965 but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:</p>965 but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:</p>
966 {#code_begin|obj|foo#}966 {#code_begin|obj|foo#}
967 {#code_release_fast#}967 {#code_release_fast#}
968const builtin = @import("builtin");968const std = @import("std");
969const builtin = std.builtin;
969const big = @as(f64, 1 << 40);970const big = @as(f64, 1 << 40);
970971
971export fn foo_strict(x: f64) f64 {972export fn foo_strict(x: f64) f64 {
...@@ -2063,15 +2064,15 @@ test "pointer child type" {...@@ -2063,15 +2064,15 @@ test "pointer child type" {
2063 alignment of the underlying type, it can be omitted from the type:2064 alignment of the underlying type, it can be omitted from the type:
2064 </p>2065 </p>
2065 {#code_begin|test#}2066 {#code_begin|test#}
2066const assert = @import("std").debug.assert;2067const std = @import("std");
2067const builtin = @import("builtin");2068const assert = std.debug.assert;
20682069
2069test "variable alignment" {2070test "variable alignment" {
2070 var x: i32 = 1234;2071 var x: i32 = 1234;
2071 const align_of_i32 = @alignOf(@TypeOf(x));2072 const align_of_i32 = @alignOf(@TypeOf(x));
2072 assert(@TypeOf(&x) == *i32);2073 assert(@TypeOf(&x) == *i32);
2073 assert(*i32 == *align(align_of_i32) i32);2074 assert(*i32 == *align(align_of_i32) i32);
2074 if (builtin.arch == builtin.Arch.x86_64) {2075 if (std.Target.current.cpu.arch == .x86_64) {
2075 assert((*i32).alignment == 4);2076 assert((*i32).alignment == 4);
2076 }2077 }
2077}2078}
...@@ -2474,7 +2475,7 @@ test "default struct initialization fields" {...@@ -2474,7 +2475,7 @@ test "default struct initialization fields" {
2474 </p>2475 </p>
2475 {#code_begin|test#}2476 {#code_begin|test#}
2476const std = @import("std");2477const std = @import("std");
2477const builtin = @import("builtin");2478const builtin = std.builtin;
2478const assert = std.debug.assert;2479const assert = std.debug.assert;
24792480
2480const Full = packed struct {2481const Full = packed struct {
...@@ -3204,8 +3205,8 @@ test "separate scopes" {...@@ -3204,8 +3205,8 @@ test "separate scopes" {
32043205
3205 {#header_open|switch#}3206 {#header_open|switch#}
3206 {#code_begin|test|switch#}3207 {#code_begin|test|switch#}
3207const assert = @import("std").debug.assert;3208const std = @import("std");
3208const builtin = @import("builtin");3209const assert = std.debug.assert;
32093210
3210test "switch simple" {3211test "switch simple" {
3211 const a: u64 = 10;3212 const a: u64 = 10;
...@@ -3249,16 +3250,16 @@ test "switch simple" {...@@ -3249,16 +3250,16 @@ test "switch simple" {
3249}3250}
32503251
3251// Switch expressions can be used outside a function:3252// Switch expressions can be used outside a function:
3252const os_msg = switch (builtin.os) {3253const os_msg = switch (std.Target.current.os.tag) {
3253 builtin.Os.linux => "we found a linux user",3254 .linux => "we found a linux user",
3254 else => "not a linux user",3255 else => "not a linux user",
3255};3256};
32563257
3257// Inside a function, switch statements implicitly are compile-time3258// Inside a function, switch statements implicitly are compile-time
3258// evaluated if the target expression is compile-time known.3259// evaluated if the target expression is compile-time known.
3259test "switch inside function" {3260test "switch inside function" {
3260 switch (builtin.os) {3261 switch (std.Target.current.os.tag) {
3261 builtin.Os.fuchsia => {3262 .fuchsia => {
3262 // On an OS other than fuchsia, block is not even analyzed,3263 // On an OS other than fuchsia, block is not even analyzed,
3263 // so this compile error is not triggered.3264 // so this compile error is not triggered.
3264 // On fuchsia this compile error would be triggered.3265 // On fuchsia this compile error would be triggered.
...@@ -7330,8 +7331,6 @@ test "main" {...@@ -7330,8 +7331,6 @@ test "main" {
7330 the {#syntax#}export{#endsyntax#} keyword used on a function:7331 the {#syntax#}export{#endsyntax#} keyword used on a function:
7331 </p>7332 </p>
7332 {#code_begin|obj#}7333 {#code_begin|obj#}
7333const builtin = @import("builtin");
7334
7335comptime {7334comptime {
7336 @export(internalName, .{ .name = "foo", .linkage = .Strong });7335 @export(internalName, .{ .name = "foo", .linkage = .Strong });
7337}7336}
...@@ -9363,7 +9362,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';...@@ -9363,7 +9362,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
9363 </p>9362 </p>
9364 {#code_begin|test|detect_test#}9363 {#code_begin|test|detect_test#}
9365const std = @import("std");9364const std = @import("std");
9366const builtin = @import("builtin");9365const builtin = std.builtin;
9367const assert = std.debug.assert;9366const assert = std.debug.assert;
93689367
9369test "builtin.is_test" {9368test "builtin.is_test" {
...@@ -9681,7 +9680,8 @@ WebAssembly.instantiate(typedArray, {...@@ -9681,7 +9680,8 @@ WebAssembly.instantiate(typedArray, {
9681 <pre><code>$ node test.js9680 <pre><code>$ node test.js
9682The result is 3</code></pre>9681The result is 3</code></pre>
9683 {#header_open|WASI#}9682 {#header_open|WASI#}
9684 <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>9683 <p>Zig's support for WebAssembly System Interface (WASI) is under active development.
9684 Example of using the standard library and reading command line arguments:</p>
9685 {#code_begin|exe|wasi#}9685 {#code_begin|exe|wasi#}
9686 {#target_wasi#}9686 {#target_wasi#}
9687const std = @import("std");9687const std = @import("std");
lib/std/build.zig+137-110
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = std.builtin;
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const mem = std.mem;5const mem = std.mem;
...@@ -15,6 +15,7 @@ const BufSet = std.BufSet;...@@ -15,6 +15,7 @@ const BufSet = std.BufSet;
15const BufMap = std.BufMap;15const BufMap = std.BufMap;
16const fmt_lib = std.fmt;16const fmt_lib = std.fmt;
17const File = std.fs.File;17const File = std.fs.File;
18const CrossTarget = std.zig.CrossTarget;
1819
19pub const FmtStep = @import("build/fmt.zig").FmtStep;20pub const FmtStep = @import("build/fmt.zig").FmtStep;
20pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;21pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
...@@ -521,24 +522,91 @@ pub const Builder = struct {...@@ -521,24 +522,91 @@ pub const Builder = struct {
521 return mode;522 return mode;
522 }523 }
523524
524 /// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.525 pub const StandardTargetOptionsArgs = struct {
525 pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {526 whitelist: ?[]const CrossTarget = null,
526 if (supported_targets) |target_list| {527
527 // TODO detect multiple args and emit an error message528 default_target: CrossTarget = CrossTarget{},
528 // there's probably a better way to collect the target529 };
529 for (target_list) |targ| {530
530 const targ_str = targ.zigTriple(self.allocator) catch unreachable;531 /// Exposes standard `zig build` options for choosing a target.
531 const targ_desc = targ.allocDescription(self.allocator) catch unreachable;532 pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
532 const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;533 const triple = self.option(
533 if (this_targ_opt) {534 []const u8,
534 return targ;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;
535 }595 }
536 }596 }
537 return Target.Native;597 std.debug.warn("Chosen target '{}' does not match one of the supported targets:\n", .{
538 } else {598 selected_canonicalized_triple,
539 const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;599 });
540 return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target600 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);
541 }607 }
608
609 return selected_target;
542 }610 }
543611
544 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {612 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
...@@ -796,7 +864,7 @@ pub const Builder = struct {...@@ -796,7 +864,7 @@ pub const Builder = struct {
796864
797 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {865 pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
798 // TODO report error for ambiguous situations866 // TODO report error for ambiguous situations
799 const exe_extension = (Target{ .Native = {} }).exeFileExt();867 const exe_extension = @as(CrossTarget, .{}).exeFileExt();
800 for (self.search_prefixes.toSliceConst()) |search_prefix| {868 for (self.search_prefixes.toSliceConst()) |search_prefix| {
801 for (names) |name| {869 for (names) |name| {
802 if (fs.path.isAbsolute(name)) {870 if (fs.path.isAbsolute(name)) {
...@@ -971,21 +1039,19 @@ pub const Builder = struct {...@@ -971,21 +1039,19 @@ pub const Builder = struct {
971};1039};
9721040
973test "builder.findProgram compiles" {1041test "builder.findProgram compiles" {
974 // TODO: uncomment and fix the leak1042 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
975 // const builder = try Builder.create(std.testing.allocator, "zig", "zig-cache", "zig-cache");1043 defer arena.deinit();
976 const builder = try Builder.create(std.heap.page_allocator, "zig", "zig-cache", "zig-cache");1044
1045 const builder = try Builder.create(&arena.allocator, "zig", "zig-cache", "zig-cache");
977 defer builder.destroy();1046 defer builder.destroy();
978 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;1047 _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
979}1048}
9801049
981/// Deprecated. Use `builtin.Version`.1050/// Deprecated. Use `std.builtin.Version`.
982pub const Version = builtin.Version;1051pub const Version = builtin.Version;
9831052
984/// Deprecated. Use `std.Target.Cross`.1053/// Deprecated. Use `std.zig.CrossTarget`.
985pub const CrossTarget = std.Target.Cross;1054pub const Target = std.zig.CrossTarget;
986
987/// Deprecated. Use `std.Target`.
988pub const Target = std.Target;
9891055
990pub const Pkg = struct {1056pub const Pkg = struct {
991 name: []const u8,1057 name: []const u8,
...@@ -1038,7 +1104,7 @@ pub const LibExeObjStep = struct {...@@ -1038,7 +1104,7 @@ pub const LibExeObjStep = struct {
1038 step: Step,1104 step: Step,
1039 builder: *Builder,1105 builder: *Builder,
1040 name: []const u8,1106 name: []const u8,
1041 target: Target,1107 target: CrossTarget = CrossTarget{},
1042 linker_script: ?[]const u8 = null,1108 linker_script: ?[]const u8 = null,
1043 version_script: ?[]const u8 = null,1109 version_script: ?[]const u8 = null,
1044 out_filename: []const u8,1110 out_filename: []const u8,
...@@ -1076,7 +1142,7 @@ pub const LibExeObjStep = struct {...@@ -1076,7 +1142,7 @@ pub const LibExeObjStep = struct {
1076 out_pdb_filename: []const u8,1142 out_pdb_filename: []const u8,
1077 packages: ArrayList(Pkg),1143 packages: ArrayList(Pkg),
1078 build_options_contents: std.Buffer,1144 build_options_contents: std.Buffer,
1079 system_linker_hack: bool,1145 system_linker_hack: bool = false,
10801146
1081 object_src: []const u8,1147 object_src: []const u8,
10821148
...@@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct {...@@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct {
1091 install_step: ?*InstallArtifactStep,1157 install_step: ?*InstallArtifactStep,
10921158
1093 libc_file: ?[]const u8 = null,1159 libc_file: ?[]const u8 = null,
1094 target_glibc: ?Version = null,
10951160
1096 valgrind_support: ?bool = null,1161 valgrind_support: ?bool = null,
10971162
...@@ -1112,8 +1177,6 @@ pub const LibExeObjStep = struct {...@@ -1112,8 +1177,6 @@ pub const LibExeObjStep = struct {
1112 /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.1177 /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
1113 glibc_multi_install_dir: ?[]const u8 = null,1178 glibc_multi_install_dir: ?[]const u8 = null,
11141179
1115 dynamic_linker: ?[]const u8 = null,
1116
1117 /// Position Independent Code1180 /// Position Independent Code
1118 force_pic: ?bool = null,1181 force_pic: ?bool = null,
11191182
...@@ -1191,7 +1254,6 @@ pub const LibExeObjStep = struct {...@@ -1191,7 +1254,6 @@ pub const LibExeObjStep = struct {
1191 .kind = kind,1254 .kind = kind,
1192 .root_src = root_src,1255 .root_src = root_src,
1193 .name = name,1256 .name = name,
1194 .target = Target.Native,
1195 .frameworks = BufSet.init(builder.allocator),1257 .frameworks = BufSet.init(builder.allocator),
1196 .step = Step.init(name, builder.allocator, make),1258 .step = Step.init(name, builder.allocator, make),
1197 .version = ver,1259 .version = ver,
...@@ -1210,7 +1272,6 @@ pub const LibExeObjStep = struct {...@@ -1210,7 +1272,6 @@ pub const LibExeObjStep = struct {
1210 .object_src = undefined,1272 .object_src = undefined,
1211 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,1273 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
1212 .c_std = Builder.CStd.C99,1274 .c_std = Builder.CStd.C99,
1213 .system_linker_hack = false,
1214 .override_lib_dir = null,1275 .override_lib_dir = null,
1215 .main_pkg_path = null,1276 .main_pkg_path = null,
1216 .exec_cmd_args = null,1277 .exec_cmd_args = null,
...@@ -1282,36 +1343,11 @@ pub const LibExeObjStep = struct {...@@ -1282,36 +1343,11 @@ pub const LibExeObjStep = struct {
1282 }1343 }
1283 }1344 }
12841345
1285 /// Deprecated. Use `setTheTarget`.1346 pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void {
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 {
1303 self.target = target;1347 self.target = target;
1304 self.computeOutFileNames();1348 self.computeOutFileNames();
1305 }1349 }
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
1315 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {1351 pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
1316 self.output_dir = self.builder.dupePath(dir);1352 self.output_dir = self.builder.dupePath(dir);
1317 }1353 }
...@@ -1692,7 +1728,7 @@ pub const LibExeObjStep = struct {...@@ -1692,7 +1728,7 @@ pub const LibExeObjStep = struct {
1692 .NotFound => return error.VcpkgNotFound,1728 .NotFound => return error.VcpkgNotFound,
1693 .Found => |root| {1729 .Found => |root| {
1694 const allocator = self.builder.allocator;1730 const allocator = self.builder.allocator;
1695 const triplet = try Target.vcpkgTriplet(allocator, self.target, linkage);1731 const triplet = try self.target.vcpkgTriplet(allocator, linkage);
1696 defer self.builder.allocator.free(triplet);1732 defer self.builder.allocator.free(triplet);
16971733
1698 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });1734 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });
...@@ -1862,10 +1898,10 @@ pub const LibExeObjStep = struct {...@@ -1862,10 +1898,10 @@ pub const LibExeObjStep = struct {
1862 }1898 }
18631899
1864 switch (self.build_mode) {1900 switch (self.build_mode) {
1865 builtin.Mode.Debug => {},1901 .Debug => {},
1866 builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,1902 .ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
1867 builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,1903 .ReleaseFast => zig_args.append("--release-fast") catch unreachable,
1868 builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,1904 .ReleaseSmall => zig_args.append("--release-small") catch unreachable,
1869 }1905 }
18701906
1871 try zig_args.append("--cache-dir");1907 try zig_args.append("--cache-dir");
...@@ -1905,47 +1941,46 @@ pub const LibExeObjStep = struct {...@@ -1905,47 +1941,46 @@ pub const LibExeObjStep = struct {
1905 try zig_args.append(@tagName(self.code_model));1941 try zig_args.append(@tagName(self.code_model));
1906 }1942 }
19071943
1908 switch (self.target) {1944 if (!self.target.isNative()) {
1909 .Native => {},1945 try zig_args.append("-target");
1910 .Cross => |cross| {1946 try zig_args.append(try self.target.zigTriple(builder.allocator));
1911 try zig_args.append("-target");
1912 try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
19131947
1914 const all_features = self.target.getArch().allFeaturesList();1948 // TODO this logic can disappear if cpu model + features becomes part of the target triple
1915 var populated_cpu_features = cross.cpu.model.features;1949 const cross = self.target.toTarget();
1916 populated_cpu_features.populateDependencies(all_features);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)) {1954 if (populated_cpu_features.eql(cross.cpu.features)) {
1919 // The CPU name alone is sufficient.1955 // The CPU name alone is sufficient.
1920 // If it is the baseline CPU, no command line args are required.1956 // If it is the baseline CPU, no command line args are required.
1921 if (cross.cpu.model != Target.Cpu.baseline(self.target.getArch()).model) {1957 if (cross.cpu.model != std.Target.Cpu.baseline(cross.cpu.arch).model) {
1922 try zig_args.append("-mcpu");1958 try zig_args.append("-mcpu");
1923 try zig_args.append(cross.cpu.model.name);1959 try zig_args.append(cross.cpu.model.name);
1924 }1960 }
1925 } else {1961 } else {
1926 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");1962 var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
1927 try mcpu_buffer.append(cross.cpu.model.name);1963 try mcpu_buffer.append(cross.cpu.model.name);
19281964
1929 for (all_features) |feature, i_usize| {1965 for (all_features) |feature, i_usize| {
1930 const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize);1966 const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
1931 const in_cpu_set = populated_cpu_features.isEnabled(i);1967 const in_cpu_set = populated_cpu_features.isEnabled(i);
1932 const in_actual_set = cross.cpu.features.isEnabled(i);1968 const in_actual_set = cross.cpu.features.isEnabled(i);
1933 if (in_cpu_set and !in_actual_set) {1969 if (in_cpu_set and !in_actual_set) {
1934 try mcpu_buffer.appendByte('-');1970 try mcpu_buffer.appendByte('-');
1935 try mcpu_buffer.append(feature.name);1971 try mcpu_buffer.append(feature.name);
1936 } else if (!in_cpu_set and in_actual_set) {1972 } else if (!in_cpu_set and in_actual_set) {
1937 try mcpu_buffer.appendByte('+');1973 try mcpu_buffer.appendByte('+');
1938 try mcpu_buffer.append(feature.name);1974 try mcpu_buffer.append(feature.name);
1939 }
1940 }1975 }
1941 try zig_args.append(mcpu_buffer.toSliceConst());
1942 }1976 }
1943 },1977 try zig_args.append(mcpu_buffer.toSliceConst());
1944 }1978 }
19451979
1946 if (self.target_glibc) |ver| {1980 if (self.target.dynamic_linker.get()) |dynamic_linker| {
1947 try zig_args.append("-target-glibc");1981 try zig_args.append("--dynamic-linker");
1948 try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));1982 try zig_args.append(dynamic_linker);
1983 }
1949 }1984 }
19501985
1951 if (self.linker_script) |linker_script| {1986 if (self.linker_script) |linker_script| {
...@@ -1953,11 +1988,6 @@ pub const LibExeObjStep = struct {...@@ -1953,11 +1988,6 @@ pub const LibExeObjStep = struct {
1953 zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;1988 zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
1954 }1989 }
19551990
1956 if (self.dynamic_linker) |dynamic_linker| {
1957 try zig_args.append("--dynamic-linker");
1958 try zig_args.append(dynamic_linker);
1959 }
1960
1961 if (self.version_script) |version_script| {1991 if (self.version_script) |version_script| {
1962 try zig_args.append("--version-script");1992 try zig_args.append("--version-script");
1963 try zig_args.append(builder.pathFromRoot(version_script));1993 try zig_args.append(builder.pathFromRoot(version_script));
...@@ -1975,7 +2005,7 @@ pub const LibExeObjStep = struct {...@@ -1975,7 +2005,7 @@ pub const LibExeObjStep = struct {
1975 } else switch (self.target.getExternalExecutor()) {2005 } else switch (self.target.getExternalExecutor()) {
1976 .native, .unavailable => {},2006 .native, .unavailable => {},
1977 .qemu => |bin_name| if (self.enable_qemu) qemu: {2007 .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;
1979 const glibc_dir_arg = if (need_cross_glibc)2009 const glibc_dir_arg = if (need_cross_glibc)
1980 self.glibc_multi_install_dir orelse break :qemu2010 self.glibc_multi_install_dir orelse break :qemu
1981 else2011 else
...@@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum {...@@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum {
2420 Found,2450 Found,
2421};2451};
24222452
2423pub const VcpkgLinkage = enum {2453pub const VcpkgLinkage = std.builtin.LinkMode;
2424 Static,
2425 Dynamic,
2426};
24272454
2428pub const InstallDir = enum {2455pub const InstallDir = enum {
2429 Prefix,2456 Prefix,
lib/std/build/run.zig+1-1
...@@ -82,7 +82,7 @@ pub const RunStep = struct {...@@ -82,7 +82,7 @@ pub const RunStep = struct {
8282
83 var key: []const u8 = undefined;83 var key: []const u8 = undefined;
84 var prev_path: ?[]const u8 = undefined;84 var prev_path: ?[]const u8 = undefined;
85 if (builtin.os == .windows) {85 if (builtin.os.tag == .windows) {
86 key = "Path";86 key = "Path";
87 prev_path = env_map.get(key);87 prev_path = env_map.get(key);
88 if (prev_path == null) {88 if (prev_path == null) {
lib/std/build/translate_c.zig+6-8
...@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;...@@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;
7const CheckFileStep = build.CheckFileStep;7const CheckFileStep = build.CheckFileStep;
8const fs = std.fs;8const fs = std.fs;
9const mem = std.mem;9const mem = std.mem;
10const CrossTarget = std.zig.CrossTarget;
1011
11pub const TranslateCStep = struct {12pub const TranslateCStep = struct {
12 step: Step,13 step: Step,
...@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {...@@ -14,7 +15,7 @@ pub const TranslateCStep = struct {
14 source: build.FileSource,15 source: build.FileSource,
15 output_dir: ?[]const u8,16 output_dir: ?[]const u8,
16 out_basename: []const u8,17 out_basename: []const u8,
17 target: std.Target = .Native,18 target: CrossTarget = CrossTarget{},
1819
19 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {20 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
20 const self = builder.allocator.create(TranslateCStep) catch unreachable;21 const self = builder.allocator.create(TranslateCStep) catch unreachable;
...@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {...@@ -39,7 +40,7 @@ pub const TranslateCStep = struct {
39 ) catch unreachable;40 ) catch unreachable;
40 }41 }
4142
42 pub fn setTarget(self: *TranslateCStep, target: std.Target) void {43 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
43 self.target = target;44 self.target = target;
44 }45 }
4546
...@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {...@@ -63,12 +64,9 @@ pub const TranslateCStep = struct {
63 try argv_list.append("--cache");64 try argv_list.append("--cache");
64 try argv_list.append("on");65 try argv_list.append("on");
6566
66 switch (self.target) {67 if (!self.target.isNative()) {
67 .Native => {},68 try argv_list.append("-target");
68 .Cross => {69 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
69 try argv_list.append("-target");
70 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
71 },
72 }70 }
7371
74 try argv_list.append(self.source.getPath(self.builder));72 try argv_list.append(self.source.getPath(self.builder));
lib/std/builtin.zig+57-2
...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
185 child: type,185 child: type,
186 is_allowzero: bool,186 is_allowzero: bool,
187187
188 /// This field is an optional type.
188 /// The type of the sentinel is the element type of the pointer, which is189 /// The type of the sentinel is the element type of the pointer, which is
189 /// the value of the `child` field in this struct. However there is no way190 /// the value of the `child` field in this struct. However there is no way
190 /// to refer to that type here, so we use `var`.191 /// to refer to that type here, so we use `var`.
...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
206 len: comptime_int,207 len: comptime_int,
207 child: type,208 child: type,
208209
210 /// This field is an optional type.
209 /// The type of the sentinel is the element type of the array, which is211 /// The type of the sentinel is the element type of the array, which is
210 /// the value of the `child` field in this struct. However there is no way212 /// the value of the `child` field in this struct. However there is no way
211 /// to refer to that type here, so we use `var`.213 /// to refer to that type here, so we use `var`.
...@@ -398,7 +400,60 @@ pub const LinkMode = enum {...@@ -398,7 +400,60 @@ pub const LinkMode = enum {
398pub const Version = struct {400pub const Version = struct {
399 major: u32,401 major: u32,
400 minor: u32,402 minor: u32,
401 patch: u32,403 patch: u32 = 0,
404
405 pub const Range = struct {
406 min: Version,
407 max: Version,
408
409 pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
410 if (self.min.compare(ver) == .gt) return false;
411 if (self.max.compare(ver) == .lt) return false;
412 return true;
413 }
414 };
415
416 pub fn order(lhs: Version, rhs: Version) std.math.Order {
417 if (lhs.major < rhs.major) return .lt;
418 if (lhs.major > rhs.major) return .gt;
419 if (lhs.minor < rhs.minor) return .lt;
420 if (lhs.minor > rhs.minor) return .gt;
421 if (lhs.patch < rhs.patch) return .lt;
422 if (lhs.patch > rhs.patch) return .gt;
423 return .eq;
424 }
425
426 pub fn parse(text: []const u8) !Version {
427 var it = std.mem.separate(text, ".");
428 return Version{
429 .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
430 .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
431 .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
432 };
433 }
434
435 pub fn format(
436 self: Version,
437 comptime fmt: []const u8,
438 options: std.fmt.FormatOptions,
439 context: var,
440 comptime Error: type,
441 comptime output: fn (@TypeOf(context), []const u8) Error!void,
442 ) Error!void {
443 if (fmt.len == 0) {
444 if (self.patch == 0) {
445 if (self.minor == 0) {
446 return std.fmt.format(context, Error, output, "{}", .{self.major});
447 } else {
448 return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
449 }
450 } else {
451 return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
452 }
453 } else {
454 @compileError("Unknown format string: '" ++ fmt ++ "'");
455 }
456 }
402};457};
403458
404/// This data structure is used by the Zig language code generation and459/// This data structure is used by the Zig language code generation and
...@@ -476,7 +531,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn...@@ -476,7 +531,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
476 root.os.panic(msg, error_return_trace);531 root.os.panic(msg, error_return_trace);
477 unreachable;532 unreachable;
478 }533 }
479 switch (os) {534 switch (os.tag) {
480 .freestanding => {535 .freestanding => {
481 while (true) {536 while (true) {
482 @breakpoint();537 @breakpoint();
lib/std/c.zig+14-13
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;
3const page_size = std.mem.page_size;3const page_size = std.mem.page_size;
44
5pub const tokenizer = @import("c/tokenizer.zig");5pub const tokenizer = @import("c/tokenizer.zig");
...@@ -10,7 +10,7 @@ pub const ast = @import("c/ast.zig");...@@ -10,7 +10,7 @@ pub const ast = @import("c/ast.zig");
1010
11pub usingnamespace @import("os/bits.zig");11pub usingnamespace @import("os/bits.zig");
1212
13pub usingnamespace switch (builtin.os) {13pub usingnamespace switch (std.Target.current.os.tag) {
14 .linux => @import("c/linux.zig"),14 .linux => @import("c/linux.zig"),
15 .windows => @import("c/windows.zig"),15 .windows => @import("c/windows.zig"),
16 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),16 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
...@@ -46,17 +46,16 @@ pub fn versionCheck(glibc_version: builtin.Version) type {...@@ -46,17 +46,16 @@ pub fn versionCheck(glibc_version: builtin.Version) type {
46 return struct {46 return struct {
47 pub const ok = blk: {47 pub const ok = blk: {
48 if (!builtin.link_libc) break :blk false;48 if (!builtin.link_libc) break :blk false;
49 switch (builtin.abi) {49 if (std.Target.current.abi.isMusl()) break :blk true;
50 .musl, .musleabi, .musleabihf => break :blk true,50 if (std.Target.current.isGnuLibC()) {
51 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => {51 const ver = std.Target.current.os.version_range.linux.glibc;
52 const ver = builtin.glibc_version orelse break :blk false;52 const order = ver.order(glibc_version);
53 if (ver.major < glibc_version.major) break :blk false;53 break :blk switch (order) {
54 if (ver.major > glibc_version.major) break :blk true;54 .gt, .eq => true,
55 if (ver.minor < glibc_version.minor) break :blk false;55 .lt => false,
56 if (ver.minor > glibc_version.minor) break :blk true;56 };
57 break :blk ver.patch >= glibc_version.patch;57 } else {
58 },58 break :blk false;
59 else => break :blk false,
60 }59 }
61 };60 };
62 };61 };
...@@ -109,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8...@@ -109,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8
109pub extern "c" fn dup(fd: fd_t) c_int;108pub extern "c" fn dup(fd: fd_t) c_int;
110pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;109pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
111pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;110pub 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;
112pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;112pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
113pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;113pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
114pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;114pub 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...@@ -125,6 +125,7 @@ pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*u
125pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;125pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;
126pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;126pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;
127pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;127pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;
128pub extern "c" fn uname(buf: *utsname) c_int;
128129
129pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;130pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
130pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;131pub 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 {...@@ -94,7 +94,7 @@ pub const pthread_cond_t = extern struct {
94 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,94 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
95};95};
96const __SIZEOF_PTHREAD_COND_T = 48;96const __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) {
98 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,98 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
99 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {99 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
100 .aarch64 => 48,100 .aarch64 => 48,
lib/std/child_process.zig+13-13
...@@ -17,9 +17,9 @@ const TailQueue = std.TailQueue;...@@ -17,9 +17,9 @@ const TailQueue = std.TailQueue;
17const maxInt = std.math.maxInt;17const maxInt = std.math.maxInt;
1818
19pub const ChildProcess = struct {19pub const ChildProcess = struct {
20 pid: if (builtin.os == .windows) void else i32,20 pid: if (builtin.os.tag == .windows) void else i32,
21 handle: if (builtin.os == .windows) windows.HANDLE else void,21 handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
22 thread_handle: if (builtin.os == .windows) windows.HANDLE else void,22 thread_handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
2323
24 allocator: *mem.Allocator,24 allocator: *mem.Allocator,
2525
...@@ -39,15 +39,15 @@ pub const ChildProcess = struct {...@@ -39,15 +39,15 @@ pub const ChildProcess = struct {
39 stderr_behavior: StdIo,39 stderr_behavior: StdIo,
4040
41 /// Set to change the user id when spawning the child process.41 /// 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
44 /// Set to change the group id when spawning the child process.44 /// 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
47 /// Set to change the current working directory when spawning the child process.47 /// Set to change the current working directory when spawning the child process.
48 cwd: ?[]const u8,48 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
52 expand_arg0: Arg0Expand,52 expand_arg0: Arg0Expand,
5353
...@@ -96,8 +96,8 @@ pub const ChildProcess = struct {...@@ -96,8 +96,8 @@ pub const ChildProcess = struct {
96 .term = null,96 .term = null,
97 .env_map = null,97 .env_map = null,
98 .cwd = null,98 .cwd = null,
99 .uid = if (builtin.os == .windows) {} else null,99 .uid = if (builtin.os.tag == .windows) {} else null,
100 .gid = if (builtin.os == .windows) {} else null,100 .gid = if (builtin.os.tag == .windows) {} else null,
101 .stdin = null,101 .stdin = null,
102 .stdout = null,102 .stdout = null,
103 .stderr = null,103 .stderr = null,
...@@ -118,7 +118,7 @@ pub const ChildProcess = struct {...@@ -118,7 +118,7 @@ pub const ChildProcess = struct {
118118
119 /// On success must call `kill` or `wait`.119 /// On success must call `kill` or `wait`.
120 pub fn spawn(self: *ChildProcess) SpawnError!void {120 pub fn spawn(self: *ChildProcess) SpawnError!void {
121 if (builtin.os == .windows) {121 if (builtin.os.tag == .windows) {
122 return self.spawnWindows();122 return self.spawnWindows();
123 } else {123 } else {
124 return self.spawnPosix();124 return self.spawnPosix();
...@@ -132,7 +132,7 @@ pub const ChildProcess = struct {...@@ -132,7 +132,7 @@ pub const ChildProcess = struct {
132132
133 /// Forcibly terminates child process and then cleans up all resources.133 /// Forcibly terminates child process and then cleans up all resources.
134 pub fn kill(self: *ChildProcess) !Term {134 pub fn kill(self: *ChildProcess) !Term {
135 if (builtin.os == .windows) {135 if (builtin.os.tag == .windows) {
136 return self.killWindows(1);136 return self.killWindows(1);
137 } else {137 } else {
138 return self.killPosix();138 return self.killPosix();
...@@ -162,7 +162,7 @@ pub const ChildProcess = struct {...@@ -162,7 +162,7 @@ pub const ChildProcess = struct {
162162
163 /// Blocks until child process terminates and then cleans up all resources.163 /// Blocks until child process terminates and then cleans up all resources.
164 pub fn wait(self: *ChildProcess) !Term {164 pub fn wait(self: *ChildProcess) !Term {
165 if (builtin.os == .windows) {165 if (builtin.os.tag == .windows) {
166 return self.waitWindows();166 return self.waitWindows();
167 } else {167 } else {
168 return self.waitPosix();168 return self.waitPosix();
...@@ -307,7 +307,7 @@ pub const ChildProcess = struct {...@@ -307,7 +307,7 @@ pub const ChildProcess = struct {
307 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {307 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
308 defer destroyPipe(self.err_pipe);308 defer destroyPipe(self.err_pipe);
309309
310 if (builtin.os == .linux) {310 if (builtin.os.tag == .linux) {
311 var fd = [1]std.os.pollfd{std.os.pollfd{311 var fd = [1]std.os.pollfd{std.os.pollfd{
312 .fd = self.err_pipe[0],312 .fd = self.err_pipe[0],
313 .events = std.os.POLLIN,313 .events = std.os.POLLIN,
...@@ -402,7 +402,7 @@ pub const ChildProcess = struct {...@@ -402,7 +402,7 @@ pub const ChildProcess = struct {
402 // This pipe is used to communicate errors between the time of fork402 // This pipe is used to communicate errors between the time of fork
403 // and execve from the child process to the parent process.403 // and execve from the child process to the parent process.
404 const err_pipe = blk: {404 const err_pipe = blk: {
405 if (builtin.os == .linux) {405 if (builtin.os.tag == .linux) {
406 const fd = try os.eventfd(0, 0);406 const fd = try os.eventfd(0, 0);
407 // There's no distinction between the readable and the writeable407 // There's no distinction between the readable and the writeable
408 // end with eventfd408 // end with eventfd
lib/std/crypto/benchmark.zig+1-1
...@@ -120,7 +120,7 @@ fn usage() void {...@@ -120,7 +120,7 @@ fn usage() void {
120}120}
121121
122fn mode(comptime x: comptime_int) comptime_int {122fn mode(comptime x: comptime_int) comptime_int {
123 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;123 return if (builtin.mode == .Debug) x / 64 else x;
124}124}
125125
126// TODO(#1358): Replace with builtin formatted padding when available.126// TODO(#1358): Replace with builtin formatted padding when available.
lib/std/cstr.zig+3-3
...@@ -4,8 +4,8 @@ const debug = std.debug;...@@ -4,8 +4,8 @@ const debug = std.debug;
4const mem = std.mem;4const mem = std.mem;
5const testing = std.testing;5const testing = std.testing;
66
7pub const line_sep = switch (builtin.os) {7pub const line_sep = switch (builtin.os.tag) {
8 builtin.Os.windows => "\r\n",8 .windows => "\r\n",
9 else => "\n",9 else => "\n",
10};10};
1111
...@@ -28,7 +28,7 @@ test "cstr fns" {...@@ -28,7 +28,7 @@ test "cstr fns" {
2828
29fn testCStrFnsImpl() void {29fn testCStrFnsImpl() void {
30 testing.expect(cmp("aoeu", "aoez") == -1);30 testing.expect(cmp("aoeu", "aoez") == -1);
31 testing.expect(mem.len(u8, "123456789") == 9);31 testing.expect(mem.len("123456789") == 9);
32}32}
3333
34/// Returns a mutable, null-terminated slice with the same length as `slice`.34/// Returns a mutable, null-terminated slice with the same length as `slice`.
lib/std/debug.zig+619-1242
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = std.builtin;
2const math = std.math;3const math = std.math;
3const mem = std.mem;4const mem = std.mem;
4const io = std.io;5const io = std.io;
...@@ -11,7 +12,6 @@ const macho = std.macho;...@@ -11,7 +12,6 @@ const macho = std.macho;
11const coff = std.coff;12const coff = std.coff;
12const pdb = std.pdb;13const pdb = std.pdb;
13const ArrayList = std.ArrayList;14const ArrayList = std.ArrayList;
14const builtin = @import("builtin");
15const root = @import("root");15const root = @import("root");
16const maxInt = std.math.maxInt;16const maxInt = std.math.maxInt;
17const File = std.fs.File;17const File = std.fs.File;
...@@ -38,6 +38,18 @@ const Module = struct {...@@ -38,6 +38,18 @@ const Module = struct {
38 checksum_offset: ?usize,38 checksum_offset: ?usize,
39};39};
4040
41pub const LineInfo = struct {
42 line: u64,
43 column: u64,
44 file_name: []const u8,
45 allocator: ?*mem.Allocator,
46
47 fn deinit(self: LineInfo) void {
48 const allocator = self.allocator orelse return;
49 allocator.free(self.file_name);
50 }
51};
52
41/// Tries to write to stderr, unbuffered, and ignores any error returned.53/// Tries to write to stderr, unbuffered, and ignores any error returned.
42/// Does not append a newline.54/// Does not append a newline.
43var stderr_file: File = undefined;55var stderr_file: File = undefined;
...@@ -89,7 +101,7 @@ pub fn detectTTYConfig() TTY.Config {...@@ -89,7 +101,7 @@ pub fn detectTTYConfig() TTY.Config {
89 } else |_| {101 } else |_| {
90 if (stderr_file.supportsAnsiEscapeCodes()) {102 if (stderr_file.supportsAnsiEscapeCodes()) {
91 return .escape_codes;103 return .escape_codes;
92 } else if (builtin.os == .windows and stderr_file.isTty()) {104 } else if (builtin.os.tag == .windows and stderr_file.isTty()) {
93 return .windows_api;105 return .windows_api;
94 } else {106 } else {
95 return .no_color;107 return .no_color;
...@@ -143,7 +155,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {...@@ -143,7 +155,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
143/// chopping off the irrelevant frames and shifting so that the returned addresses pointer155/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
144/// equals the passed in addresses pointer.156/// equals the passed in addresses pointer.
145pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {157pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
146 if (builtin.os == .windows) {158 if (builtin.os.tag == .windows) {
147 const addrs = stack_trace.instruction_addresses;159 const addrs = stack_trace.instruction_addresses;
148 const u32_addrs_len = @intCast(u32, addrs.len);160 const u32_addrs_len = @intCast(u32, addrs.len);
149 const first_addr = first_address orelse {161 const first_addr = first_address orelse {
...@@ -219,7 +231,7 @@ pub fn assert(ok: bool) void {...@@ -219,7 +231,7 @@ pub fn assert(ok: bool) void {
219pub fn panic(comptime format: []const u8, args: var) noreturn {231pub fn panic(comptime format: []const u8, args: var) noreturn {
220 @setCold(true);232 @setCold(true);
221 // TODO: remove conditional once wasi / LLVM defines __builtin_return_address233 // TODO: remove conditional once wasi / LLVM defines __builtin_return_address
222 const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress();234 const first_trace_addr = if (builtin.os.tag == .wasi) null else @returnAddress();
223 panicExtra(null, first_trace_addr, format, args);235 panicExtra(null, first_trace_addr, format, args);
224}236}
225237
...@@ -349,7 +361,7 @@ pub fn writeCurrentStackTrace(...@@ -349,7 +361,7 @@ pub fn writeCurrentStackTrace(
349 tty_config: TTY.Config,361 tty_config: TTY.Config,
350 start_addr: ?usize,362 start_addr: ?usize,
351) !void {363) !void {
352 if (builtin.os == .windows) {364 if (builtin.os.tag == .windows) {
353 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);365 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
354 }366 }
355 var it = StackIterator.init(start_addr, null);367 var it = StackIterator.init(start_addr, null);
...@@ -378,175 +390,6 @@ pub fn writeCurrentStackTraceWindows(...@@ -378,175 +390,6 @@ pub fn writeCurrentStackTraceWindows(
378 }390 }
379}391}
380392
381/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
382/// make this `noasync fn` and remove the individual noasync calls.
383pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
384 if (builtin.os == .windows) {
385 return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config);
386 }
387 if (comptime std.Target.current.isDarwin()) {
388 return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_config);
389 }
390 return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);
391}
392
393/// TODO resources https://github.com/ziglang/zig/issues/4353
394fn printSourceAtAddressWindows(
395 di: *DebugInfo,
396 out_stream: var,
397 relocated_address: usize,
398 tty_config: TTY.Config,
399) !void {
400 const allocator = getDebugInfoAllocator();
401 const base_address = process.getBaseAddress();
402 const relative_address = relocated_address - base_address;
403
404 var coff_section: *coff.Section = undefined;
405 const mod_index = for (di.sect_contribs) |sect_contrib| {
406 if (sect_contrib.Section > di.coff.sections.len) continue;
407 // Remember that SectionContribEntry.Section is 1-based.
408 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
409
410 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
411 const vaddr_end = vaddr_start + sect_contrib.Size;
412 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
413 break sect_contrib.ModuleIndex;
414 }
415 } else {
416 // we have no information to add to the address
417 return printLineInfo(out_stream, null, relocated_address, "???", "???", tty_config, printLineFromFileAnyOs);
418 };
419
420 const mod = &di.modules[mod_index];
421 try populateModule(di, mod);
422 const obj_basename = fs.path.basename(mod.obj_file_name);
423
424 var symbol_i: usize = 0;
425 const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
426 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
427 if (prefix.RecordLen < 2)
428 return error.InvalidDebugInfo;
429 switch (prefix.RecordKind) {
430 .S_LPROC32, .S_GPROC32 => {
431 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
432 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
433 const vaddr_end = vaddr_start + proc_sym.CodeSize;
434 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
435 break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym));
436 }
437 },
438 else => {},
439 }
440 symbol_i += prefix.RecordLen + @sizeOf(u16);
441 if (symbol_i > mod.symbols.len)
442 return error.InvalidDebugInfo;
443 } else "???";
444
445 const subsect_info = mod.subsect_info;
446
447 var sect_offset: usize = 0;
448 var skip_len: usize = undefined;
449 const opt_line_info = subsections: {
450 const checksum_offset = mod.checksum_offset orelse break :subsections null;
451 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
452 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
453 skip_len = subsect_hdr.Length;
454 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
455
456 switch (subsect_hdr.Kind) {
457 pdb.DebugSubsectionKind.Lines => {
458 var line_index = sect_offset;
459
460 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
461 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
462 line_index += @sizeOf(pdb.LineFragmentHeader);
463 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
464 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
465
466 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
467 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
468 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
469 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
470 const subsection_end_index = sect_offset + subsect_hdr.Length;
471
472 while (line_index < subsection_end_index) {
473 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
474 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
475 const start_line_index = line_index;
476
477 const has_column = line_hdr.Flags.LF_HaveColumns;
478
479 // All line entries are stored inside their line block by ascending start address.
480 // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address.
481 // This is done with a simple linear search.
482 var line_i: u32 = 0;
483 while (line_i < block_hdr.NumLines) : (line_i += 1) {
484 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
485 line_index += @sizeOf(pdb.LineNumberEntry);
486
487 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
488 if (relative_address < vaddr_start) {
489 break;
490 }
491 }
492
493 // line_i == 0 would mean that no matching LineNumberEntry was found.
494 if (line_i > 0) {
495 const subsect_index = checksum_offset + block_hdr.NameIndex;
496 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
497 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
498 try di.pdb.string_table.seekTo(strtab_offset);
499 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
500
501 const line_entry_idx = line_i - 1;
502
503 const column = if (has_column) blk: {
504 const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
505 const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
506 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
507 break :blk col_num_entry.StartColumn;
508 } else 0;
509
510 const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
511 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
512 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
513
514 break :subsections LineInfo{
515 .allocator = allocator,
516 .file_name = source_file_name,
517 .line = flags.Start,
518 .column = column,
519 };
520 }
521 }
522
523 // Checking that we are not reading garbage after the (possibly) multiple block fragments.
524 if (line_index != subsection_end_index) {
525 return error.InvalidDebugInfo;
526 }
527 }
528 },
529 else => {},
530 }
531
532 if (sect_offset > subsect_info.len)
533 return error.InvalidDebugInfo;
534 } else {
535 break :subsections null;
536 }
537 };
538
539 try printLineInfo(
540 out_stream,
541 opt_line_info,
542 relocated_address,
543 symbol_name,
544 obj_basename,
545 tty_config,
546 printLineFromFileAnyOs,
547 );
548}
549
550pub const TTY = struct {393pub const TTY = struct {
551 pub const Color = enum {394 pub const Color = enum {
552 Red,395 Red,
...@@ -575,7 +418,7 @@ pub const TTY = struct {...@@ -575,7 +418,7 @@ pub const TTY = struct {
575 .Dim => noasync out_stream.write(DIM) catch return,418 .Dim => noasync out_stream.write(DIM) catch return,
576 .Reset => noasync out_stream.write(RESET) catch return,419 .Reset => noasync out_stream.write(RESET) catch return,
577 },420 },
578 .windows_api => if (builtin.os == .windows) {421 .windows_api => if (builtin.os.tag == .windows) {
579 const S = struct {422 const S = struct {
580 var attrs: windows.WORD = undefined;423 var attrs: windows.WORD = undefined;
581 var init_attrs = false;424 var init_attrs = false;
...@@ -618,7 +461,7 @@ pub const TTY = struct {...@@ -618,7 +461,7 @@ pub const TTY = struct {
618};461};
619462
620/// TODO resources https://github.com/ziglang/zig/issues/4353463/// TODO resources https://github.com/ziglang/zig/issues/4353
621fn populateModule(di: *DebugInfo, mod: *Module) !void {464fn populateModule(di: *ModuleDebugInfo, mod: *Module) !void {
622 if (mod.populated)465 if (mod.populated)
623 return;466 return;
624 const allocator = getDebugInfoAllocator();467 const allocator = getDebugInfoAllocator();
...@@ -650,7 +493,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void {...@@ -650,7 +493,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void {
650 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);493 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
651494
652 switch (subsect_hdr.Kind) {495 switch (subsect_hdr.Kind) {
653 pdb.DebugSubsectionKind.FileChecksums => {496 .FileChecksums => {
654 mod.checksum_offset = sect_offset;497 mod.checksum_offset = sect_offset;
655 break;498 break;
656 },499 },
...@@ -682,41 +525,37 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach...@@ -682,41 +525,37 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
682 return null;525 return null;
683}526}
684527
685fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {528/// TODO resources https://github.com/ziglang/zig/issues/4353
686 const base_addr = process.getBaseAddress();529pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
687 const adjusted_addr = 0x100000000 + (address - base_addr);530 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
688531 error.MissingDebugInfo, error.InvalidDebugInfo => {
689 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {532 return printLineInfo(
690 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);533 out_stream,
691 };534 null,
692535 address,
693 const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx));536 "???",
694 const compile_unit_name = if (symbol.ofile) |ofile| blk: {537 "???",
695 const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));538 tty_config,
696 break :blk fs.path.basename(ofile_path);539 printLineFromFileAnyOs,
697 } else "???";540 );
698541 },
699 const line_info = getLineNumberInfoMacOs(di, symbol.*, adjusted_addr) catch |err| switch (err) {
700 error.MissingDebugInfo, error.InvalidDebugInfo => null,
701 else => return err,542 else => return err,
702 };543 };
703 defer if (line_info) |li| li.deinit();
704544
705 try printLineInfo(545 const symbol_info = try module.getSymbolAtAddress(address);
546 defer symbol_info.deinit();
547
548 return printLineInfo(
706 out_stream,549 out_stream,
707 line_info,550 symbol_info.line_info,
708 address,551 address,
709 symbol_name,552 symbol_info.symbol_name,
710 compile_unit_name,553 symbol_info.compile_unit_name,
711 tty_config,554 tty_config,
712 printLineFromFileAnyOs,555 printLineFromFileAnyOs,
713 );556 );
714}557}
715558
716pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
717 return debug_info.printSourceAtAddress(out_stream, address, tty_config, printLineFromFileAnyOs);
718}
719
720fn printLineInfo(559fn printLineInfo(
721 out_stream: var,560 out_stream: var,
722 line_info: ?LineInfo,561 line_info: ?LineInfo,
...@@ -772,29 +611,32 @@ pub const OpenSelfDebugInfoError = error{...@@ -772,29 +611,32 @@ pub const OpenSelfDebugInfoError = error{
772/// TODO resources https://github.com/ziglang/zig/issues/4353611/// TODO resources https://github.com/ziglang/zig/issues/4353
773/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,612/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
774/// make this `noasync fn` and remove the individual noasync calls.613/// make this `noasync fn` and remove the individual noasync calls.
775pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {614pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
776 if (builtin.strip_debug_info)615 if (builtin.strip_debug_info)
777 return error.MissingDebugInfo;616 return error.MissingDebugInfo;
778 if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {617 if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
779 return noasync root.os.debug.openSelfDebugInfo(allocator);618 return noasync root.os.debug.openSelfDebugInfo(allocator);
780 }619 }
781 if (builtin.os == .windows) {620 switch (builtin.os.tag) {
782 return noasync openSelfDebugInfoWindows(allocator);621 .linux,
783 }622 .freebsd,
784 if (comptime std.Target.current.isDarwin()) {623 .macosx,
785 return noasync openSelfDebugInfoMacOs(allocator);624 .windows,
625 => return DebugInfo.init(allocator),
626 else => @compileError("openSelfDebugInfo unsupported for this platform"),
786 }627 }
787 return noasync openSelfDebugInfoPosix(allocator);
788}628}
789629
790fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {630/// TODO resources https://github.com/ziglang/zig/issues/4353
791 const self_file = try fs.openSelfExe();631fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo {
792 defer self_file.close();632 const coff_file = try std.fs.openFileAbsoluteW(coff_file_path.ptr, .{});
633 errdefer coff_file.close();
793634
794 const coff_obj = try allocator.create(coff.Coff);635 const coff_obj = try allocator.create(coff.Coff);
795 coff_obj.* = coff.Coff.init(allocator, self_file);636 coff_obj.* = coff.Coff.init(allocator, coff_file);
796637
797 var di = DebugInfo{638 var di = ModuleDebugInfo{
639 .base_address = undefined,
798 .coff = coff_obj,640 .coff = coff_obj,
799 .pdb = undefined,641 .pdb = undefined,
800 .sect_contribs = undefined,642 .sect_contribs = undefined,
...@@ -958,109 +800,85 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {...@@ -958,109 +800,85 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
958 return list.toOwnedSlice();800 return list.toOwnedSlice();
959}801}
960802
961fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {803fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
962 const elf_header = (try elf_file.findSection(name)) orelse return null;804 const start = try math.cast(usize, offset);
963 return DwarfInfo.Section{805 const end = start + try math.cast(usize, size);
964 .offset = elf_header.sh_offset,806 return ptr[start..end];
965 .size = elf_header.sh_size,
966 };
967}
968
969/// Initialize DWARF info. The caller has the responsibility to initialize most
970/// the DwarfInfo fields before calling. These fields can be left undefined:
971/// * abbrev_table_list
972/// * compile_unit_list
973pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
974 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
975 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
976 di.func_list = ArrayList(Func).init(allocator);
977 try di.scanAllFunctions();
978 try di.scanAllCompileUnits();
979}807}
980808
981/// TODO resources https://github.com/ziglang/zig/issues/4353809/// TODO resources https://github.com/ziglang/zig/issues/4353
982pub fn openElfDebugInfo(810pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {
983 allocator: *mem.Allocator,811 const mapped_mem = try mapWholeFile(elf_file_path);
984 data: []u8,812
985) !DwarfInfo {813 var seekable_stream = io.SliceSeekableInStream.init(mapped_mem);
986 var seekable_stream = io.SliceSeekableInStream.init(data);814 var efile = try noasync elf.Elf.openStream(
987 var efile = try elf.Elf.openStream(
988 allocator,815 allocator,
989 @ptrCast(*DwarfSeekableStream, &seekable_stream.seekable_stream),816 @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream),
990 @ptrCast(*DwarfInStream, &seekable_stream.stream),817 @ptrCast(*DW.DwarfInStream, &seekable_stream.stream),
991 );818 );
992 defer efile.close();819 defer noasync efile.close();
993820
994 const debug_info = (try efile.findSection(".debug_info")) orelse821 const debug_info = (try noasync efile.findSection(".debug_info")) orelse
995 return error.MissingDebugInfo;822 return error.MissingDebugInfo;
996 const debug_abbrev = (try efile.findSection(".debug_abbrev")) orelse823 const debug_abbrev = (try noasync efile.findSection(".debug_abbrev")) orelse
997 return error.MissingDebugInfo;824 return error.MissingDebugInfo;
998 const debug_str = (try efile.findSection(".debug_str")) orelse825 const debug_str = (try noasync efile.findSection(".debug_str")) orelse
999 return error.MissingDebugInfo;826 return error.MissingDebugInfo;
1000 const debug_line = (try efile.findSection(".debug_line")) orelse827 const debug_line = (try noasync efile.findSection(".debug_line")) orelse
1001 return error.MissingDebugInfo;828 return error.MissingDebugInfo;
1002 const opt_debug_ranges = try efile.findSection(".debug_ranges");829 const opt_debug_ranges = try noasync efile.findSection(".debug_ranges");
1003830
1004 var di = DwarfInfo{831 var di = DW.DwarfInfo{
1005 .endian = efile.endian,832 .endian = efile.endian,
1006 .debug_info = (data[@intCast(usize, debug_info.sh_offset)..@intCast(usize, debug_info.sh_offset + debug_info.sh_size)]),833 .debug_info = try chopSlice(mapped_mem, debug_info.sh_offset, debug_info.sh_size),
1007 .debug_abbrev = (data[@intCast(usize, debug_abbrev.sh_offset)..@intCast(usize, debug_abbrev.sh_offset + debug_abbrev.sh_size)]),834 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.sh_offset, debug_abbrev.sh_size),
1008 .debug_str = (data[@intCast(usize, debug_str.sh_offset)..@intCast(usize, debug_str.sh_offset + debug_str.sh_size)]),835 .debug_str = try chopSlice(mapped_mem, debug_str.sh_offset, debug_str.sh_size),
1009 .debug_line = (data[@intCast(usize, debug_line.sh_offset)..@intCast(usize, debug_line.sh_offset + debug_line.sh_size)]),836 .debug_line = try chopSlice(mapped_mem, debug_line.sh_offset, debug_line.sh_size),
1010 .debug_ranges = if (opt_debug_ranges) |debug_ranges|837 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
1011 data[@intCast(usize, debug_ranges.sh_offset)..@intCast(usize, debug_ranges.sh_offset + debug_ranges.sh_size)]838 try chopSlice(mapped_mem, debug_ranges.sh_offset, debug_ranges.sh_size)
1012 else839 else
1013 null,840 null,
1014 };841 };
1015842
1016 try openDwarfDebugInfo(&di, allocator);843 try noasync DW.openDwarfDebugInfo(&di, allocator);
1017 return di;844
845 return ModuleDebugInfo{
846 .base_address = undefined,
847 .dwarf = di,
848 .mapped_memory = mapped_mem,
849 };
1018}850}
1019851
1020/// TODO resources https://github.com/ziglang/zig/issues/4353852/// TODO resources https://github.com/ziglang/zig/issues/4353
1021fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {853fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ModuleDebugInfo {
1022 var exe_file = try fs.openSelfExe();854 const mapped_mem = try mapWholeFile(macho_file_path);
1023 errdefer exe_file.close();
1024855
1025 const exe_len = math.cast(usize, try exe_file.getEndPos()) catch856 const hdr = @ptrCast(
1026 return error.DebugInfoTooLarge;857 *const macho.mach_header_64,
1027 const exe_mmap = try os.mmap(858 @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr),
1028 null,
1029 exe_len,
1030 os.PROT_READ,
1031 os.MAP_SHARED,
1032 exe_file.handle,
1033 0,
1034 );859 );
1035 errdefer os.munmap(exe_mmap);860 if (hdr.magic != macho.MH_MAGIC_64)
1036861 return error.InvalidDebugInfo;
1037 return openElfDebugInfo(allocator, exe_mmap);
1038}
1039
1040/// TODO resources https://github.com/ziglang/zig/issues/4353
1041fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1042 const hdr = &std.c._mh_execute_header;
1043 assert(hdr.magic == std.macho.MH_MAGIC_64);
1044862
1045 const hdr_base = @ptrCast([*]u8, hdr);863 const hdr_base = @ptrCast([*]const u8, hdr);
1046 var ptr = hdr_base + @sizeOf(macho.mach_header_64);864 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1047 var ncmd: u32 = hdr.ncmds;865 var ncmd: u32 = hdr.ncmds;
1048 const symtab = while (ncmd != 0) : (ncmd -= 1) {866 const symtab = while (ncmd != 0) : (ncmd -= 1) {
1049 const lc = @ptrCast(*std.macho.load_command, ptr);867 const lc = @ptrCast(*const std.macho.load_command, ptr);
1050 switch (lc.cmd) {868 switch (lc.cmd) {
1051 std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr),869 std.macho.LC_SYMTAB => break @ptrCast(*const std.macho.symtab_command, ptr),
1052 else => {},870 else => {},
1053 }871 }
1054 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);872 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
1055 } else {873 } else {
1056 return error.MissingDebugInfo;874 return error.MissingDebugInfo;
1057 };875 };
1058 const syms = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];876 const syms = @ptrCast([*]const macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff))[0..symtab.nsyms];
1059 const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize];877 const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0..symtab.strsize :0];
1060878
1061 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);879 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
1062880
1063 var ofile: ?*macho.nlist_64 = null;881 var ofile: ?*const macho.nlist_64 = null;
1064 var reloc: u64 = 0;882 var reloc: u64 = 0;
1065 var symbol_index: usize = 0;883 var symbol_index: usize = 0;
1066 var last_len: u64 = 0;884 var last_len: u64 = 0;
...@@ -1108,8 +926,10 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {...@@ -1108,8 +926,10 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1108 // This sort is so that we can binary search later.926 // This sort is so that we can binary search later.
1109 std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);927 std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan);
1110928
1111 return DebugInfo{929 return ModuleDebugInfo{
1112 .ofiles = DebugInfo.OFileTable.init(allocator),930 .base_address = undefined,
931 .mapped_memory = mapped_mem,
932 .ofiles = ModuleDebugInfo.OFileTable.init(allocator),
1113 .symbols = symbols,933 .symbols = symbols,
1114 .strings = strings,934 .strings = strings,
1115 };935 };
...@@ -1148,8 +968,8 @@ fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {...@@ -1148,8 +968,8 @@ fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
1148}968}
1149969
1150const MachoSymbol = struct {970const MachoSymbol = struct {
1151 nlist: *macho.nlist_64,971 nlist: *const macho.nlist_64,
1152 ofile: ?*macho.nlist_64,972 ofile: ?*const macho.nlist_64,
1153 reloc: u64,973 reloc: u64,
1154974
1155 /// Returns the address from the macho file975 /// Returns the address from the macho file
...@@ -1162,1057 +982,614 @@ const MachoSymbol = struct {...@@ -1162,1057 +982,614 @@ const MachoSymbol = struct {
1162 }982 }
1163};983};
1164984
1165pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);985fn mapWholeFile(path: []const u8) ![]const u8 {
1166pub const DwarfInStream = io.InStream(anyerror);986 const file = try noasync fs.openFileAbsolute(path, .{ .always_blocking = true });
1167987 defer noasync file.close();
1168pub const DwarfInfo = struct {
1169 endian: builtin.Endian,
1170 // No memory is owned by the DwarfInfo
1171 debug_info: []u8,
1172 debug_abbrev: []u8,
1173 debug_str: []u8,
1174 debug_line: []u8,
1175 debug_ranges: ?[]u8,
1176 // Filled later by the initializer
1177 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
1178 compile_unit_list: ArrayList(CompileUnit) = undefined,
1179 func_list: ArrayList(Func) = undefined,
1180
1181 pub fn allocator(self: DwarfInfo) *mem.Allocator {
1182 return self.abbrev_table_list.allocator;
1183 }
1184988
1185 /// This function works in freestanding mode.989 const file_len = try math.cast(usize, try file.getEndPos());
1186 /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void990 const mapped_mem = try os.mmap(
1187 pub fn printSourceAtAddress(991 null,
1188 self: *DwarfInfo,992 file_len,
1189 out_stream: var,993 os.PROT_READ,
1190 address: usize,994 os.MAP_SHARED,
1191 tty_config: TTY.Config,995 file.handle,
1192 comptime printLineFromFile: var,996 0,
1193 ) !void {997 );
1194 const compile_unit = self.findCompileUnit(address) catch {998 errdefer os.munmap(mapped_mem);
1195 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFile);
1196 };
1197999
1198 const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);1000 return mapped_mem;
1199 const symbol_name = self.getSymbolName(address) orelse "???";1001}
1200 const line_info = self.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) {
1201 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1202 else => return err,
1203 };
1204 defer if (line_info) |li| li.deinit();
1205
1206 try printLineInfo(
1207 out_stream,
1208 line_info,
1209 address,
1210 symbol_name,
1211 compile_unit_name,
1212 tty_config,
1213 printLineFromFile,
1214 );
1215 }
12161002
1217 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {1003pub const DebugInfo = struct {
1218 for (di.func_list.toSliceConst()) |*func| {1004 allocator: *mem.Allocator,
1219 if (func.pc_range) |range| {1005 address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
1220 if (address >= range.start and address < range.end) {
1221 return func.name;
1222 }
1223 }
1224 }
12251006
1226 return null;1007 pub fn init(allocator: *mem.Allocator) DebugInfo {
1008 return DebugInfo{
1009 .allocator = allocator,
1010 .address_map = std.AutoHashMap(usize, *ModuleDebugInfo).init(allocator),
1011 };
1227 }1012 }
12281013
1229 fn scanAllFunctions(di: *DwarfInfo) !void {1014 pub fn deinit(self: *DebugInfo) void {
1230 var s = io.SliceSeekableInStream.init(di.debug_info);1015 // TODO: resources https://github.com/ziglang/zig/issues/4353
1231 var this_unit_offset: u64 = 0;1016 self.address_map.deinit();
1232
1233 while (true) {
1234 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
1235 error.EndOfStream => return,
1236 else => return err,
1237 };
1238
1239 var is_64: bool = undefined;
1240 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
1241 if (unit_length == 0) return;
1242 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1243
1244 const version = try s.stream.readInt(u16, di.endian);
1245 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1246
1247 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
1248
1249 const address_size = try s.stream.readByte();
1250 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1251
1252 const compile_unit_pos = try s.seekable_stream.getPos();
1253 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
1254
1255 try s.seekable_stream.seekTo(compile_unit_pos);
1256
1257 const next_unit_pos = this_unit_offset + next_offset;
1258
1259 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
1260 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
1261 const after_die_offset = try s.seekable_stream.getPos();
1262
1263 switch (die_obj.tag_id) {
1264 DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
1265 const fn_name = x: {
1266 var depth: i32 = 3;
1267 var this_die_obj = die_obj;
1268 // Prenvent endless loops
1269 while (depth > 0) : (depth -= 1) {
1270 if (this_die_obj.getAttr(DW.AT_name)) |_| {
1271 const name = try this_die_obj.getAttrString(di, DW.AT_name);
1272 break :x name;
1273 } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
1274 // Follow the DIE it points to and repeat
1275 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
1276 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1277 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
1278 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1279 } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
1280 // Follow the DIE it points to and repeat
1281 const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
1282 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1283 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
1284 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1285 } else {
1286 break :x null;
1287 }
1288 }
1289
1290 break :x null;
1291 };
1292
1293 const pc_range = x: {
1294 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1295 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
1296 const pc_end = switch (high_pc_value.*) {
1297 FormValue.Address => |value| value,
1298 FormValue.Const => |value| b: {
1299 const offset = try value.asUnsignedLe();
1300 break :b (low_pc + offset);
1301 },
1302 else => return error.InvalidDebugInfo,
1303 };
1304 break :x PcRange{
1305 .start = low_pc,
1306 .end = pc_end,
1307 };
1308 } else {
1309 break :x null;
1310 }
1311 } else |err| {
1312 if (err != error.MissingDebugInfo) return err;
1313 break :x null;
1314 }
1315 };
1316
1317 try di.func_list.append(Func{
1318 .name = fn_name,
1319 .pc_range = pc_range,
1320 });
1321 },
1322 else => {},
1323 }
1324
1325 try s.seekable_stream.seekTo(after_die_offset);
1326 }
1327
1328 this_unit_offset += next_offset;
1329 }
1330 }1017 }
13311018
1332 fn scanAllCompileUnits(di: *DwarfInfo) !void {1019 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1333 var s = io.SliceSeekableInStream.init(di.debug_info);1020 if (comptime std.Target.current.isDarwin())
1334 var this_unit_offset: u64 = 0;1021 return self.lookupModuleDyld(address)
13351022 else if (builtin.os.tag == .windows)
1336 while (true) {1023 return self.lookupModuleWin32(address)
1337 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {1024 else
1338 error.EndOfStream => return,1025 return self.lookupModuleDl(address);
1339 else => return err,1026 }
1340 };
1341
1342 var is_64: bool = undefined;
1343 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
1344 if (unit_length == 0) return;
1345 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
13461027
1347 const version = try s.stream.readInt(u16, di.endian);1028 fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1348 if (version < 2 or version > 5) return error.InvalidDebugInfo;1029 const image_count = std.c._dyld_image_count();
13491030
1350 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);1031 var i: u32 = 0;
1032 while (i < image_count) : (i += 1) {
1033 const base_address = std.c._dyld_get_image_vmaddr_slide(i);
13511034
1352 const address_size = try s.stream.readByte();1035 if (address < base_address) continue;
1353 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
13541036
1355 const compile_unit_pos = try s.seekable_stream.getPos();1037 const header = std.c._dyld_get_image_header(i) orelse continue;
1356 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);1038 // The array of load commands is right after the header
1039 var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64));
13571040
1358 try s.seekable_stream.seekTo(compile_unit_pos);1041 var cmds = header.ncmds;
1042 while (cmds != 0) : (cmds -= 1) {
1043 const lc = @ptrCast(
1044 *macho.load_command,
1045 @alignCast(@alignOf(macho.load_command), cmd_ptr),
1046 );
1047 cmd_ptr += lc.cmdsize;
1048 if (lc.cmd != macho.LC_SEGMENT_64) continue;
13591049
1360 const compile_unit_die = try di.allocator().create(Die);1050 const segment_cmd = @ptrCast(
1361 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;1051 *const std.macho.segment_command_64,
1052 @alignCast(@alignOf(std.macho.segment_command_64), lc),
1053 );
13621054
1363 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;1055 const rebased_address = address - base_address;
1056 const seg_start = segment_cmd.vmaddr;
1057 const seg_end = seg_start + segment_cmd.vmsize;
13641058
1365 const pc_range = x: {1059 if (rebased_address >= seg_start and rebased_address < seg_end) {
1366 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {1060 if (self.address_map.getValue(base_address)) |obj_di| {
1367 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {1061 return obj_di;
1368 const pc_end = switch (high_pc_value.*) {
1369 FormValue.Address => |value| value,
1370 FormValue.Const => |value| b: {
1371 const offset = try value.asUnsignedLe();
1372 break :b (low_pc + offset);
1373 },
1374 else => return error.InvalidDebugInfo,
1375 };
1376 break :x PcRange{
1377 .start = low_pc,
1378 .end = pc_end,
1379 };
1380 } else {
1381 break :x null;
1382 }1062 }
1383 } else |err| {
1384 if (err != error.MissingDebugInfo) return err;
1385 break :x null;
1386 }
1387 };
1388
1389 try di.compile_unit_list.append(CompileUnit{
1390 .version = version,
1391 .is_64 = is_64,
1392 .pc_range = pc_range,
1393 .die = compile_unit_die,
1394 });
13951063
1396 this_unit_offset += next_offset;1064 const obj_di = try self.allocator.create(ModuleDebugInfo);
1397 }1065 errdefer self.allocator.destroy(obj_di);
1398 }
13991066
1400 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {1067 const macho_path = mem.toSliceConst(u8, std.c._dyld_get_image_name(i));
1401 for (di.compile_unit_list.toSlice()) |*compile_unit| {1068 obj_di.* = openMachODebugInfo(self.allocator, macho_path) catch |err| switch (err) {
1402 if (compile_unit.pc_range) |range| {1069 error.FileNotFound => return error.MissingDebugInfo,
1403 if (target_address >= range.start and target_address < range.end) return compile_unit;
1404 }
1405 if (di.debug_ranges) |debug_ranges| {
1406 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
1407 var s = io.SliceSeekableInStream.init(debug_ranges);
1408
1409 // All the addresses in the list are relative to the value
1410 // specified by DW_AT_low_pc or to some other value encoded
1411 // in the list itself.
1412 // If no starting value is specified use zero.
1413 var base_address = compile_unit.die.getAttrAddr(DW.AT_low_pc) catch |err| switch (err) {
1414 error.MissingDebugInfo => 0,
1415 else => return err,1070 else => return err,
1416 };1071 };
1072 obj_di.base_address = base_address;
14171073
1418 try s.seekable_stream.seekTo(ranges_offset);1074 try self.address_map.putNoClobber(base_address, obj_di);
14191075
1420 while (true) {1076 return obj_di;
1421 const begin_addr = try s.stream.readIntLittle(usize);
1422 const end_addr = try s.stream.readIntLittle(usize);
1423 if (begin_addr == 0 and end_addr == 0) {
1424 break;
1425 }
1426 // This entry selects a new value for the base address
1427 if (begin_addr == maxInt(usize)) {
1428 base_address = end_addr;
1429 continue;
1430 }
1431 if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) {
1432 return compile_unit;
1433 }
1434 }
1435 } else |err| {
1436 if (err != error.MissingDebugInfo) return err;
1437 continue;
1438 }1077 }
1439 }1078 }
1440 }1079 }
1441 return error.MissingDebugInfo;
1442 }
1443
1444 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1445 /// seeks in the stream and parses it.
1446 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1447 for (di.abbrev_table_list.toSlice()) |*header| {
1448 if (header.offset == abbrev_offset) {
1449 return &header.table;
1450 }
1451 }
1452 try di.abbrev_table_list.append(AbbrevTableHeader{
1453 .offset = abbrev_offset,
1454 .table = try di.parseAbbrevTable(abbrev_offset),
1455 });
1456 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1457 }
1458
1459 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
1460 var s = io.SliceSeekableInStream.init(di.debug_abbrev);
1461
1462 try s.seekable_stream.seekTo(offset);
1463 var result = AbbrevTable.init(di.allocator());
1464 errdefer result.deinit();
1465 while (true) {
1466 const abbrev_code = try leb.readULEB128(u64, &s.stream);
1467 if (abbrev_code == 0) return result;
1468 try result.append(AbbrevTableEntry{
1469 .abbrev_code = abbrev_code,
1470 .tag_id = try leb.readULEB128(u64, &s.stream),
1471 .has_children = (try s.stream.readByte()) == DW.CHILDREN_yes,
1472 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1473 });
1474 const attrs = &result.items[result.len - 1].attrs;
1475
1476 while (true) {
1477 const attr_id = try leb.readULEB128(u64, &s.stream);
1478 const form_id = try leb.readULEB128(u64, &s.stream);
1479 if (attr_id == 0 and form_id == 0) break;
1480 try attrs.append(AbbrevAttr{
1481 .attr_id = attr_id,
1482 .form_id = form_id,
1483 });
1484 }
1485 }
1486 }
1487
1488 fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1489 const abbrev_code = try leb.readULEB128(u64, in_stream);
1490 if (abbrev_code == 0) return null;
1491 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
14921080
1493 var result = Die{1081 return error.MissingDebugInfo;
1494 .tag_id = table_entry.tag_id,
1495 .has_children = table_entry.has_children,
1496 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1497 };
1498 try result.attrs.resize(table_entry.attrs.len);
1499 for (table_entry.attrs.toSliceConst()) |attr, i| {
1500 result.attrs.items[i] = Die.Attr{
1501 .id = attr.attr_id,
1502 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64),
1503 };
1504 }
1505 return result;
1506 }1082 }
15071083
1508 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {1084 fn lookupModuleWin32(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1509 var s = io.SliceSeekableInStream.init(di.debug_line);1085 const process_handle = windows.kernel32.GetCurrentProcess();
15101086
1511 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);1087 // Find how many modules are actually loaded
1512 const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);1088 var dummy: windows.HMODULE = undefined;
15131089 var bytes_needed: windows.DWORD = undefined;
1514 try s.seekable_stream.seekTo(line_info_offset);1090 if (windows.kernel32.K32EnumProcessModules(
1091 process_handle,
1092 @ptrCast([*]windows.HMODULE, &dummy),
1093 0,
1094 &bytes_needed,
1095 ) == 0)
1096 return error.MissingDebugInfo;
15151097
1516 var is_64: bool = undefined;1098 const needed_modules = bytes_needed / @sizeOf(windows.HMODULE);
1517 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);1099
1518 if (unit_length == 0) {1100 // Fetch the complete module list
1101 var modules = try self.allocator.alloc(windows.HMODULE, needed_modules);
1102 defer self.allocator.free(modules);
1103 if (windows.kernel32.K32EnumProcessModules(
1104 process_handle,
1105 modules.ptr,
1106 try math.cast(windows.DWORD, modules.len * @sizeOf(windows.HMODULE)),
1107 &bytes_needed,
1108 ) == 0)
1519 return error.MissingDebugInfo;1109 return error.MissingDebugInfo;
1520 }
1521 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
15221110
1523 const version = try s.stream.readInt(u16, di.endian);1111 // There's an unavoidable TOCTOU problem here, the module list may have
1524 // TODO support 3 and 51112 // changed between the two EnumProcessModules call.
1525 if (version != 2 and version != 4) return error.InvalidDebugInfo;1113 // Pick the smallest amount of elements to avoid processing garbage.
1114 const needed_modules_after = bytes_needed / @sizeOf(windows.HMODULE);
1115 const loaded_modules = math.min(needed_modules, needed_modules_after);
1116
1117 for (modules[0..loaded_modules]) |module| {
1118 var info: windows.MODULEINFO = undefined;
1119 if (windows.kernel32.K32GetModuleInformation(
1120 process_handle,
1121 module,
1122 &info,
1123 @sizeOf(@TypeOf(info)),
1124 ) == 0)
1125 return error.MissingDebugInfo;
15261126
1527 const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);1127 const seg_start = @ptrToInt(info.lpBaseOfDll);
1528 const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;1128 const seg_end = seg_start + info.SizeOfImage;
15291129
1530 const minimum_instruction_length = try s.stream.readByte();1130 if (address >= seg_start and address < seg_end) {
1531 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;1131 if (self.address_map.getValue(seg_start)) |obj_di| {
1132 return obj_di;
1133 }
15321134
1533 if (version >= 4) {1135 var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined;
1534 // maximum_operations_per_instruction1136 // openFileAbsoluteW requires the prefix to be present
1535 _ = try s.stream.readByte();1137 mem.copy(u16, name_buffer[0..4], &[_]u16{ '\\', '?', '?', '\\' });
1138 const len = windows.kernel32.K32GetModuleFileNameExW(
1139 process_handle,
1140 module,
1141 @ptrCast(windows.LPWSTR, &name_buffer[4]),
1142 windows.PATH_MAX_WIDE,
1143 );
1144 assert(len > 0);
1145
1146 const obj_di = try self.allocator.create(ModuleDebugInfo);
1147 errdefer self.allocator.destroy(obj_di);
1148
1149 obj_di.* = openCoffDebugInfo(self.allocator, name_buffer[0..:0]) catch |err| switch (err) {
1150 error.FileNotFound => return error.MissingDebugInfo,
1151 else => return err,
1152 };
1153 obj_di.base_address = seg_start;
1154
1155 try self.address_map.putNoClobber(seg_start, obj_di);
1156
1157 return obj_di;
1158 }
1536 }1159 }
15371160
1538 const default_is_stmt = (try s.stream.readByte()) != 0;1161 return error.MissingDebugInfo;
1539 const line_base = try s.stream.readByteSigned();1162 }
1540
1541 const line_range = try s.stream.readByte();
1542 if (line_range == 0) return error.InvalidDebugInfo;
1543
1544 const opcode_base = try s.stream.readByte();
15451163
1546 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);1164 fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
1165 var ctx: struct {
1166 // Input
1167 address: usize,
1168 // Output
1169 base_address: usize = undefined,
1170 name: []const u8 = undefined,
1171 } = .{ .address = address };
1172 const CtxTy = @TypeOf(ctx);
1173
1174 if (os.dl_iterate_phdr(&ctx, anyerror, struct {
1175 fn callback(info: *os.dl_phdr_info, size: usize, context: *CtxTy) !void {
1176 // The base address is too high
1177 if (context.address < info.dlpi_addr)
1178 return;
15471179
1548 {1180 const phdrs = info.dlpi_phdr[0..info.dlpi_phnum];
1549 var i: usize = 0;1181 for (phdrs) |*phdr| {
1550 while (i < opcode_base - 1) : (i += 1) {1182 if (phdr.p_type != elf.PT_LOAD) continue;
1551 standard_opcode_lengths[i] = try s.stream.readByte();1183
1184 const seg_start = info.dlpi_addr + phdr.p_vaddr;
1185 const seg_end = seg_start + phdr.p_memsz;
1186
1187 if (context.address >= seg_start and context.address < seg_end) {
1188 // Android libc uses NULL instead of an empty string to mark the
1189 // main program
1190 context.name = if (info.dlpi_name) |dlpi_name|
1191 mem.toSliceConst(u8, dlpi_name)
1192 else
1193 "";
1194 context.base_address = info.dlpi_addr;
1195 // Stop the iteration
1196 return error.Found;
1197 }
1198 }
1552 }1199 }
1200 }.callback)) {
1201 return error.MissingDebugInfo;
1202 } else |err| switch (err) {
1203 error.Found => {},
1204 else => return error.MissingDebugInfo,
1553 }1205 }
15541206
1555 var include_directories = ArrayList([]u8).init(di.allocator());1207 if (self.address_map.getValue(ctx.base_address)) |obj_di| {
1556 try include_directories.append(compile_unit_cwd);1208 return obj_di;
1557 while (true) {
1558 const dir = try readStringRaw(di.allocator(), &s.stream);
1559 if (dir.len == 0) break;
1560 try include_directories.append(dir);
1561 }1209 }
15621210
1563 var file_entries = ArrayList(FileEntry).init(di.allocator());1211 const elf_path = if (ctx.name.len > 0)
1564 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);1212 ctx.name
15651213 else blk: {
1566 while (true) {1214 var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
1567 const file_name = try readStringRaw(di.allocator(), &s.stream);1215 break :blk try fs.selfExePath(&buf);
1568 if (file_name.len == 0) break;1216 };
1569 const dir_index = try leb.readULEB128(usize, &s.stream);
1570 const mtime = try leb.readULEB128(usize, &s.stream);
1571 const len_bytes = try leb.readULEB128(usize, &s.stream);
1572 try file_entries.append(FileEntry{
1573 .file_name = file_name,
1574 .dir_index = dir_index,
1575 .mtime = mtime,
1576 .len_bytes = len_bytes,
1577 });
1578 }
15791217
1580 try s.seekable_stream.seekTo(prog_start_offset);1218 const obj_di = try self.allocator.create(ModuleDebugInfo);
1219 errdefer self.allocator.destroy(obj_di);
15811220
1582 const next_unit_pos = line_info_offset + next_offset;1221 obj_di.* = openElfDebugInfo(self.allocator, elf_path) catch |err| switch (err) {
1222 error.FileNotFound => return error.MissingDebugInfo,
1223 else => return err,
1224 };
1225 obj_di.base_address = ctx.base_address;
15831226
1584 while ((try s.seekable_stream.getPos()) < next_unit_pos) {1227 try self.address_map.putNoClobber(ctx.base_address, obj_di);
1585 const opcode = try s.stream.readByte();
15861228
1587 if (opcode == DW.LNS_extended_op) {1229 return obj_di;
1588 const op_size = try leb.readULEB128(u64, &s.stream);
1589 if (op_size < 1) return error.InvalidDebugInfo;
1590 var sub_op = try s.stream.readByte();
1591 switch (sub_op) {
1592 DW.LNE_end_sequence => {
1593 prog.end_sequence = true;
1594 if (try prog.checkLineMatch()) |info| return info;
1595 prog.reset();
1596 },
1597 DW.LNE_set_address => {
1598 const addr = try s.stream.readInt(usize, di.endian);
1599 prog.address = addr;
1600 },
1601 DW.LNE_define_file => {
1602 const file_name = try readStringRaw(di.allocator(), &s.stream);
1603 const dir_index = try leb.readULEB128(usize, &s.stream);
1604 const mtime = try leb.readULEB128(usize, &s.stream);
1605 const len_bytes = try leb.readULEB128(usize, &s.stream);
1606 try file_entries.append(FileEntry{
1607 .file_name = file_name,
1608 .dir_index = dir_index,
1609 .mtime = mtime,
1610 .len_bytes = len_bytes,
1611 });
1612 },
1613 else => {
1614 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1615 try s.seekable_stream.seekBy(fwd_amt);
1616 },
1617 }
1618 } else if (opcode >= opcode_base) {
1619 // special opcodes
1620 const adjusted_opcode = opcode - opcode_base;
1621 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1622 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
1623 prog.line += inc_line;
1624 prog.address += inc_addr;
1625 if (try prog.checkLineMatch()) |info| return info;
1626 prog.basic_block = false;
1627 } else {
1628 switch (opcode) {
1629 DW.LNS_copy => {
1630 if (try prog.checkLineMatch()) |info| return info;
1631 prog.basic_block = false;
1632 },
1633 DW.LNS_advance_pc => {
1634 const arg = try leb.readULEB128(usize, &s.stream);
1635 prog.address += arg * minimum_instruction_length;
1636 },
1637 DW.LNS_advance_line => {
1638 const arg = try leb.readILEB128(i64, &s.stream);
1639 prog.line += arg;
1640 },
1641 DW.LNS_set_file => {
1642 const arg = try leb.readULEB128(usize, &s.stream);
1643 prog.file = arg;
1644 },
1645 DW.LNS_set_column => {
1646 const arg = try leb.readULEB128(u64, &s.stream);
1647 prog.column = arg;
1648 },
1649 DW.LNS_negate_stmt => {
1650 prog.is_stmt = !prog.is_stmt;
1651 },
1652 DW.LNS_set_basic_block => {
1653 prog.basic_block = true;
1654 },
1655 DW.LNS_const_add_pc => {
1656 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1657 prog.address += inc_addr;
1658 },
1659 DW.LNS_fixed_advance_pc => {
1660 const arg = try s.stream.readInt(u16, di.endian);
1661 prog.address += arg;
1662 },
1663 DW.LNS_set_prologue_end => {},
1664 else => {
1665 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1666 const len_bytes = standard_opcode_lengths[opcode - 1];
1667 try s.seekable_stream.seekBy(len_bytes);
1668 },
1669 }
1670 }
1671 }
1672
1673 return error.MissingDebugInfo;
1674 }1230 }
1231};
16751232
1676 fn getString(di: *DwarfInfo, offset: u64) ![]u8 {1233const SymbolInfo = struct {
1677 if (offset > di.debug_str.len)1234 symbol_name: []const u8 = "???",
1678 return error.InvalidDebugInfo;1235 compile_unit_name: []const u8 = "???",
1679 const casted_offset = math.cast(usize, offset) catch1236 line_info: ?LineInfo = null,
1680 return error.InvalidDebugInfo;
16811237
1682 // Valid strings always have a terminating zero byte1238 fn deinit(self: @This()) void {
1683 if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {1239 if (self.line_info) |li| {
1684 return di.debug_str[casted_offset..last];1240 li.deinit();
1685 }1241 }
1686
1687 return error.InvalidDebugInfo;
1688 }1242 }
1689};1243};
16901244
1691pub const DebugInfo = switch (builtin.os) {1245pub const ModuleDebugInfo = switch (builtin.os.tag) {
1692 .macosx, .ios, .watchos, .tvos => struct {1246 .macosx, .ios, .watchos, .tvos => struct {
1247 base_address: usize,
1248 mapped_memory: []const u8,
1693 symbols: []const MachoSymbol,1249 symbols: []const MachoSymbol,
1694 strings: []const u8,1250 strings: [:0]const u8,
1695 ofiles: OFileTable,1251 ofiles: OFileTable,
16961252
1697 const OFileTable = std.HashMap(1253 const OFileTable = std.StringHashMap(DW.DwarfInfo);
1698 *macho.nlist_64,
1699 DwarfInfo,
1700 std.hash_map.getHashPtrAddrFn(*macho.nlist_64),
1701 std.hash_map.getTrivialEqlFn(*macho.nlist_64),
1702 );
17031254
1704 pub fn allocator(self: DebugInfo) *mem.Allocator {1255 pub fn allocator(self: @This()) *mem.Allocator {
1705 return self.ofiles.allocator;1256 return self.ofiles.allocator;
1706 }1257 }
1707 },
1708 .uefi, .windows => struct {
1709 pdb: pdb.Pdb,
1710 coff: *coff.Coff,
1711 sect_contribs: []pdb.SectionContribEntry,
1712 modules: []Module,
1713 },
1714 else => DwarfInfo,
1715};
1716
1717const PcRange = struct {
1718 start: u64,
1719 end: u64,
1720};
17211258
1722const CompileUnit = struct {1259 fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo {
1723 version: u16,1260 const mapped_mem = try mapWholeFile(o_file_path);
1724 is_64: bool,
1725 die: *Die,
1726 pc_range: ?PcRange,
1727};
1728
1729const AbbrevTable = ArrayList(AbbrevTableEntry);
1730
1731const AbbrevTableHeader = struct {
1732 // offset from .debug_abbrev
1733 offset: u64,
1734 table: AbbrevTable,
1735};
17361261
1737const AbbrevTableEntry = struct {1262 const hdr = @ptrCast(
1738 has_children: bool,1263 *const macho.mach_header_64,
1739 abbrev_code: u64,1264 @alignCast(@alignOf(macho.mach_header_64), mapped_mem.ptr),
1740 tag_id: u64,1265 );
1741 attrs: ArrayList(AbbrevAttr),1266 if (hdr.magic != std.macho.MH_MAGIC_64)
1742};1267 return error.InvalidDebugInfo;
17431268
1744const AbbrevAttr = struct {1269 const hdr_base = @ptrCast([*]const u8, hdr);
1745 attr_id: u64,1270 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1746 form_id: u64,1271 var ncmd: u32 = hdr.ncmds;
1747};1272 const segcmd = while (ncmd != 0) : (ncmd -= 1) {
1273 const lc = @ptrCast(*const std.macho.load_command, ptr);
1274 switch (lc.cmd) {
1275 std.macho.LC_SEGMENT_64 => {
1276 break @ptrCast(
1277 *const std.macho.segment_command_64,
1278 @alignCast(@alignOf(std.macho.segment_command_64), ptr),
1279 );
1280 },
1281 else => {},
1282 }
1283 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
1284 } else {
1285 return error.MissingDebugInfo;
1286 };
17481287
1749const FormValue = union(enum) {1288 var opt_debug_line: ?*const macho.section_64 = null;
1750 Address: u64,1289 var opt_debug_info: ?*const macho.section_64 = null;
1751 Block: []u8,1290 var opt_debug_abbrev: ?*const macho.section_64 = null;
1752 Const: Constant,1291 var opt_debug_str: ?*const macho.section_64 = null;
1753 ExprLoc: []u8,1292 var opt_debug_ranges: ?*const macho.section_64 = null;
1754 Flag: bool,1293
1755 SecOffset: u64,1294 const sections = @ptrCast(
1756 Ref: u64,1295 [*]const macho.section_64,
1757 RefAddr: u64,1296 @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)),
1758 String: []u8,1297 )[0..segcmd.nsects];
1759 StrPtr: u64,1298 for (sections) |*sect| {
1760};1299 // The section name may not exceed 16 chars and a trailing null may
1300 // not be present
1301 const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
1302 sect.sectname[0..last]
1303 else
1304 sect.sectname[0..];
1305
1306 if (mem.eql(u8, name, "__debug_line")) {
1307 opt_debug_line = sect;
1308 } else if (mem.eql(u8, name, "__debug_info")) {
1309 opt_debug_info = sect;
1310 } else if (mem.eql(u8, name, "__debug_abbrev")) {
1311 opt_debug_abbrev = sect;
1312 } else if (mem.eql(u8, name, "__debug_str")) {
1313 opt_debug_str = sect;
1314 } else if (mem.eql(u8, name, "__debug_ranges")) {
1315 opt_debug_ranges = sect;
1316 }
1317 }
17611318
1762const Constant = struct {1319 const debug_line = opt_debug_line orelse
1763 payload: u64,1320 return error.MissingDebugInfo;
1764 signed: bool,1321 const debug_info = opt_debug_info orelse
1322 return error.MissingDebugInfo;
1323 const debug_str = opt_debug_str orelse
1324 return error.MissingDebugInfo;
1325 const debug_abbrev = opt_debug_abbrev orelse
1326 return error.MissingDebugInfo;
17651327
1766 fn asUnsignedLe(self: *const Constant) !u64 {1328 var di = DW.DwarfInfo{
1767 if (self.signed) return error.InvalidDebugInfo;1329 .endian = .Little,
1768 return self.payload;1330 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
1769 }1331 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
1770};1332 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
1333 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
1334 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
1335 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
1336 else
1337 null,
1338 };
17711339
1772const Die = struct {1340 try DW.openDwarfDebugInfo(&di, self.allocator());
1773 tag_id: u64,
1774 has_children: bool,
1775 attrs: ArrayList(Attr),
17761341
1777 const Attr = struct {1342 // Add the debug info to the cache
1778 id: u64,1343 try self.ofiles.putNoClobber(o_file_path, di);
1779 value: FormValue,
1780 };
17811344
1782 fn getAttr(self: *const Die, id: u64) ?*const FormValue {1345 return di;
1783 for (self.attrs.toSliceConst()) |*attr| {
1784 if (attr.id == id) return &attr.value;
1785 }1346 }
1786 return null;
1787 }
1788
1789 fn getAttrAddr(self: *const Die, id: u64) !u64 {
1790 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1791 return switch (form_value.*) {
1792 FormValue.Address => |value| value,
1793 else => error.InvalidDebugInfo,
1794 };
1795 }
1796
1797 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
1798 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1799 return switch (form_value.*) {
1800 FormValue.Const => |value| value.asUnsignedLe(),
1801 FormValue.SecOffset => |value| value,
1802 else => error.InvalidDebugInfo,
1803 };
1804 }
1805
1806 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
1807 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1808 return switch (form_value.*) {
1809 FormValue.Const => |value| value.asUnsignedLe(),
1810 else => error.InvalidDebugInfo,
1811 };
1812 }
1813
1814 fn getAttrRef(self: *const Die, id: u64) !u64 {
1815 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1816 return switch (form_value.*) {
1817 FormValue.Ref => |value| value,
1818 else => error.InvalidDebugInfo,
1819 };
1820 }
18211347
1822 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {1348 fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1823 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;1349 // Translate the VA into an address into this object
1824 return switch (form_value.*) {1350 const relocated_address = address - self.base_address;
1825 FormValue.String => |value| value,1351 assert(relocated_address >= 0x100000000);
1826 FormValue.StrPtr => |offset| di.getString(offset),
1827 else => error.InvalidDebugInfo,
1828 };
1829 }
1830};
18311352
1832const FileEntry = struct {1353 // Find the .o file where this symbol is defined
1833 file_name: []const u8,1354 const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse
1834 dir_index: usize,1355 return SymbolInfo{};
1835 mtime: usize,
1836 len_bytes: usize,
1837};
18381356
1839pub const LineInfo = struct {1357 // XXX: Return the symbol name
1840 line: u64,1358 if (symbol.ofile == null)
1841 column: u64,1359 return SymbolInfo{};
1842 file_name: []const u8,
1843 allocator: ?*mem.Allocator,
18441360
1845 fn deinit(self: LineInfo) void {1361 assert(symbol.ofile.?.n_strx < self.strings.len);
1846 const allocator = self.allocator orelse return;1362 const o_file_path = mem.toSliceConst(u8, self.strings.ptr + symbol.ofile.?.n_strx);
1847 allocator.free(self.file_name);
1848 }
1849};
18501363
1851const LineNumberProgram = struct {1364 // Check if its debug infos are already in the cache
1852 address: usize,1365 var o_file_di = self.ofiles.getValue(o_file_path) orelse
1853 file: usize,1366 (self.loadOFile(o_file_path) catch |err| switch (err) {
1854 line: i64,1367 error.MissingDebugInfo, error.InvalidDebugInfo => {
1855 column: u64,1368 // XXX: Return the symbol name
1856 is_stmt: bool,1369 return SymbolInfo{};
1857 basic_block: bool,1370 },
1858 end_sequence: bool,1371 else => return err,
18591372 });
1860 default_is_stmt: bool,
1861 target_address: usize,
1862 include_dirs: []const []const u8,
1863 file_entries: *ArrayList(FileEntry),
1864
1865 prev_address: usize,
1866 prev_file: usize,
1867 prev_line: i64,
1868 prev_column: u64,
1869 prev_is_stmt: bool,
1870 prev_basic_block: bool,
1871 prev_end_sequence: bool,
1872
1873 // Reset the state machine following the DWARF specification
1874 pub fn reset(self: *LineNumberProgram) void {
1875 self.address = 0;
1876 self.file = 1;
1877 self.line = 1;
1878 self.column = 0;
1879 self.is_stmt = self.default_is_stmt;
1880 self.basic_block = false;
1881 self.end_sequence = false;
1882 // Invalidate all the remaining fields
1883 self.prev_address = 0;
1884 self.prev_file = undefined;
1885 self.prev_line = undefined;
1886 self.prev_column = undefined;
1887 self.prev_is_stmt = undefined;
1888 self.prev_basic_block = undefined;
1889 self.prev_end_sequence = undefined;
1890 }
18911373
1892 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {1374 // Translate again the address, this time into an address inside the
1893 return LineNumberProgram{1375 // .o file
1894 .address = 0,1376 const relocated_address_o = relocated_address - symbol.reloc;
1895 .file = 1,
1896 .line = 1,
1897 .column = 0,
1898 .is_stmt = is_stmt,
1899 .basic_block = false,
1900 .end_sequence = false,
1901 .include_dirs = include_dirs,
1902 .file_entries = file_entries,
1903 .default_is_stmt = is_stmt,
1904 .target_address = target_address,
1905 .prev_address = 0,
1906 .prev_file = undefined,
1907 .prev_line = undefined,
1908 .prev_column = undefined,
1909 .prev_is_stmt = undefined,
1910 .prev_basic_block = undefined,
1911 .prev_end_sequence = undefined,
1912 };
1913 }
19141377
1915 pub fn checkLineMatch(self: *LineNumberProgram) !?LineInfo {1378 if (o_file_di.findCompileUnit(relocated_address_o)) |compile_unit| {
1916 if (self.target_address >= self.prev_address and self.target_address < self.address) {1379 return SymbolInfo{
1917 const file_entry = if (self.prev_file == 0) {1380 .symbol_name = o_file_di.getSymbolName(relocated_address_o) orelse "???",
1918 return error.MissingDebugInfo;1381 .compile_unit_name = compile_unit.die.getAttrString(&o_file_di, DW.AT_name) catch |err| switch (err) {
1919 } else if (self.prev_file - 1 >= self.file_entries.len) {1382 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1920 return error.InvalidDebugInfo;1383 else => return err,
1921 } else1384 },
1922 &self.file_entries.items[self.prev_file - 1];1385 .line_info = o_file_di.getLineNumberInfo(compile_unit.*, relocated_address_o) catch |err| switch (err) {
1386 error.MissingDebugInfo, error.InvalidDebugInfo => null,
1387 else => return err,
1388 },
1389 };
1390 } else |err| switch (err) {
1391 error.MissingDebugInfo, error.InvalidDebugInfo => {
1392 return SymbolInfo{};
1393 },
1394 else => return err,
1395 }
19231396
1924 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {1397 unreachable;
1925 return error.InvalidDebugInfo;
1926 } else
1927 self.include_dirs[file_entry.dir_index];
1928 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
1929 errdefer self.file_entries.allocator.free(file_name);
1930 return LineInfo{
1931 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
1932 .column = self.prev_column,
1933 .file_name = file_name,
1934 .allocator = self.file_entries.allocator,
1935 };
1936 }1398 }
1399 },
1400 .uefi, .windows => struct {
1401 base_address: usize,
1402 pdb: pdb.Pdb,
1403 coff: *coff.Coff,
1404 sect_contribs: []pdb.SectionContribEntry,
1405 modules: []Module,
19371406
1938 self.prev_address = self.address;1407 pub fn allocator(self: @This()) *mem.Allocator {
1939 self.prev_file = self.file;1408 return self.coff.allocator;
1940 self.prev_line = self.line;1409 }
1941 self.prev_column = self.column;
1942 self.prev_is_stmt = self.is_stmt;
1943 self.prev_basic_block = self.basic_block;
1944 self.prev_end_sequence = self.end_sequence;
1945 return null;
1946 }
1947};
19481410
1949// TODO the noasyncs here are workarounds1411 fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
1950fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {1412 // Translate the VA into an address into this object
1951 var buf = ArrayList(u8).init(allocator);1413 const relocated_address = address - self.base_address;
1952 while (true) {
1953 const byte = try noasync in_stream.readByte();
1954 if (byte == 0) break;
1955 try buf.append(byte);
1956 }
1957 return buf.toSlice();
1958}
19591414
1960// TODO the noasyncs here are workarounds1415 var coff_section: *coff.Section = undefined;
1961fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {1416 const mod_index = for (self.sect_contribs) |sect_contrib| {
1962 const buf = try allocator.alloc(u8, size);1417 if (sect_contrib.Section > self.coff.sections.len) continue;
1963 errdefer allocator.free(buf);1418 // Remember that SectionContribEntry.Section is 1-based.
1964 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;1419 coff_section = &self.coff.sections.toSlice()[sect_contrib.Section - 1];
1965 return buf;
1966}
19671420
1968fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {1421 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
1969 const buf = try readAllocBytes(allocator, in_stream, size);1422 const vaddr_end = vaddr_start + sect_contrib.Size;
1970 return FormValue{ .Block = buf };1423 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
1971}1424 break sect_contrib.ModuleIndex;
1425 }
1426 } else {
1427 // we have no information to add to the address
1428 return SymbolInfo{};
1429 };
19721430
1973// TODO the noasyncs here are workarounds1431 const mod = &self.modules[mod_index];
1974fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {1432 try populateModule(self, mod);
1975 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);1433 const obj_basename = fs.path.basename(mod.obj_file_name);
1976 return parseFormValueBlockLen(allocator, in_stream, block_len);1434
1977}1435 var symbol_i: usize = 0;
1436 const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
1437 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
1438 if (prefix.RecordLen < 2)
1439 return error.InvalidDebugInfo;
1440 switch (prefix.RecordKind) {
1441 .S_LPROC32, .S_GPROC32 => {
1442 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
1443 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
1444 const vaddr_end = vaddr_start + proc_sym.CodeSize;
1445 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
1446 break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym));
1447 }
1448 },
1449 else => {},
1450 }
1451 symbol_i += prefix.RecordLen + @sizeOf(u16);
1452 if (symbol_i > mod.symbols.len)
1453 return error.InvalidDebugInfo;
1454 } else "???";
1455
1456 const subsect_info = mod.subsect_info;
1457
1458 var sect_offset: usize = 0;
1459 var skip_len: usize = undefined;
1460 const opt_line_info = subsections: {
1461 const checksum_offset = mod.checksum_offset orelse break :subsections null;
1462 while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
1463 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
1464 skip_len = subsect_hdr.Length;
1465 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
1466
1467 switch (subsect_hdr.Kind) {
1468 .Lines => {
1469 var line_index = sect_offset;
1470
1471 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
1472 if (line_hdr.RelocSegment == 0)
1473 return error.MissingDebugInfo;
1474 line_index += @sizeOf(pdb.LineFragmentHeader);
1475 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
1476 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
1477
1478 if (relocated_address >= frag_vaddr_start and relocated_address < frag_vaddr_end) {
1479 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
1480 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
1481 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
1482 const subsection_end_index = sect_offset + subsect_hdr.Length;
1483
1484 while (line_index < subsection_end_index) {
1485 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
1486 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
1487 const start_line_index = line_index;
1488
1489 const has_column = line_hdr.Flags.LF_HaveColumns;
1490
1491 // All line entries are stored inside their line block by ascending start address.
1492 // Heuristic: we want to find the last line entry
1493 // that has a vaddr_start <= relocated_address.
1494 // This is done with a simple linear search.
1495 var line_i: u32 = 0;
1496 while (line_i < block_hdr.NumLines) : (line_i += 1) {
1497 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
1498 line_index += @sizeOf(pdb.LineNumberEntry);
1499
1500 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
1501 if (relocated_address < vaddr_start) {
1502 break;
1503 }
1504 }
1505
1506 // line_i == 0 would mean that no matching LineNumberEntry was found.
1507 if (line_i > 0) {
1508 const subsect_index = checksum_offset + block_hdr.NameIndex;
1509 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[subsect_index]);
1510 const strtab_offset = @sizeOf(pdb.PDBStringTableHeader) + chksum_hdr.FileNameOffset;
1511 try self.pdb.string_table.seekTo(strtab_offset);
1512 const source_file_name = try self.pdb.string_table.readNullTermString(self.allocator());
1513
1514 const line_entry_idx = line_i - 1;
1515
1516 const column = if (has_column) blk: {
1517 const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
1518 const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx;
1519 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[col_index]);
1520 break :blk col_num_entry.StartColumn;
1521 } else 0;
1522
1523 const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry);
1524 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[found_line_index]);
1525 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
1526
1527 break :subsections LineInfo{
1528 .allocator = self.allocator(),
1529 .file_name = source_file_name,
1530 .line = flags.Start,
1531 .column = column,
1532 };
1533 }
1534 }
19781535
1979fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {1536 // Checking that we are not reading garbage after the (possibly) multiple block fragments.
1980 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.1537 if (line_index != subsection_end_index) {
1981 // `noasync` should be removed from all the function calls once it is fixed.1538 return error.InvalidDebugInfo;
1982 return FormValue{1539 }
1983 .Const = Constant{1540 }
1984 .signed = signed,1541 },
1985 .payload = switch (size) {1542 else => {},
1986 1 => try noasync in_stream.readIntLittle(u8),
1987 2 => try noasync in_stream.readIntLittle(u16),
1988 4 => try noasync in_stream.readIntLittle(u32),
1989 8 => try noasync in_stream.readIntLittle(u64),
1990 -1 => blk: {
1991 if (signed) {
1992 const x = try noasync leb.readILEB128(i64, in_stream);
1993 break :blk @bitCast(u64, x);
1994 } else {
1995 const x = try noasync leb.readULEB128(u64, in_stream);
1996 break :blk x;
1997 }1543 }
1998 },
1999 else => @compileError("Invalid size"),
2000 },
2001 },
2002 };
2003}
2004
2005// TODO the noasyncs here are workarounds
2006fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
2007 return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32));
2008}
2009
2010// TODO the noasyncs here are workarounds
2011fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
2012 if (@sizeOf(usize) == 4) {
2013 // TODO this cast should not be needed
2014 return @as(u64, try noasync in_stream.readIntLittle(u32));
2015 } else if (@sizeOf(usize) == 8) {
2016 return noasync in_stream.readIntLittle(u64);
2017 } else {
2018 unreachable;
2019 }
2020}
20211544
2022// TODO the noasyncs here are workarounds1545 if (sect_offset > subsect_info.len)
2023fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {1546 return error.InvalidDebugInfo;
2024 return FormValue{1547 } else {
2025 .Ref = switch (size) {1548 break :subsections null;
2026 1 => try noasync in_stream.readIntLittle(u8),1549 }
2027 2 => try noasync in_stream.readIntLittle(u16),1550 };
2028 4 => try noasync in_stream.readIntLittle(u32),
2029 8 => try noasync in_stream.readIntLittle(u64),
2030 -1 => try noasync leb.readULEB128(u64, in_stream),
2031 else => unreachable,
2032 },
2033 };
2034}
2035
2036// TODO the noasyncs here are workarounds
2037fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
2038 return switch (form_id) {
2039 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
2040 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
2041 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
2042 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
2043 DW.FORM_block => x: {
2044 const block_len = try noasync leb.readULEB128(usize, in_stream);
2045 return parseFormValueBlockLen(allocator, in_stream, block_len);
2046 },
2047 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
2048 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
2049 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
2050 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
2051 DW.FORM_udata, DW.FORM_sdata => {
2052 const signed = form_id == DW.FORM_sdata;
2053 return parseFormValueConstant(allocator, in_stream, signed, -1);
2054 },
2055 DW.FORM_exprloc => {
2056 const size = try noasync leb.readULEB128(usize, in_stream);
2057 const buf = try readAllocBytes(allocator, in_stream, size);
2058 return FormValue{ .ExprLoc = buf };
2059 },
2060 DW.FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
2061 DW.FORM_flag_present => FormValue{ .Flag = true },
2062 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2063
2064 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
2065 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
2066 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
2067 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
2068 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
2069
2070 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2071 DW.FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
2072
2073 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
2074 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
2075 DW.FORM_indirect => {
2076 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
2077 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
2078 var frame = try allocator.create(F);
2079 defer allocator.destroy(frame);
2080 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
2081 },
2082 else => error.InvalidDebugInfo,
2083 };
2084}
2085
2086fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
2087 for (abbrev_table.toSliceConst()) |*table_entry| {
2088 if (table_entry.abbrev_code == abbrev_code) return table_entry;
2089 }
2090 return null;
2091}
20921551
2093/// TODO resources https://github.com/ziglang/zig/issues/43531552 return SymbolInfo{
2094fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {1553 .symbol_name = symbol_name,
2095 const ofile = symbol.ofile orelse return error.MissingDebugInfo;1554 .compile_unit_name = obj_basename,
2096 const gop = try di.ofiles.getOrPut(ofile);1555 .line_info = opt_line_info,
2097 const dwarf_info = if (gop.found_existing) &gop.kv.value else blk: {1556 };
2098 errdefer _ = di.ofiles.remove(ofile);1557 }
2099 const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));1558 },
21001559 .linux, .freebsd => struct {
2101 var exe_file = try std.fs.openFileAbsoluteC(ofile_path, .{});1560 base_address: usize,
2102 errdefer exe_file.close();1561 dwarf: DW.DwarfInfo,
21031562 mapped_memory: []const u8,
2104 const exe_len = math.cast(usize, try exe_file.getEndPos()) catch1563
2105 return error.DebugInfoTooLarge;1564 fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo {
2106 const exe_mmap = try os.mmap(1565 // Translate the VA into an address into this object
2107 null,1566 const relocated_address = address - self.base_address;
2108 exe_len,1567
2109 os.PROT_READ,1568 if (noasync self.dwarf.findCompileUnit(relocated_address)) |compile_unit| {
2110 os.MAP_SHARED,1569 return SymbolInfo{
2111 exe_file.handle,1570 .symbol_name = noasync self.dwarf.getSymbolName(relocated_address) orelse "???",
2112 0,1571 .compile_unit_name = compile_unit.die.getAttrString(&self.dwarf, DW.AT_name) catch |err| switch (err) {
2113 );1572 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
2114 errdefer os.munmap(exe_mmap);1573 else => return err,
21151574 },
2116 const hdr = @ptrCast(1575 .line_info = noasync self.dwarf.getLineNumberInfo(compile_unit.*, relocated_address) catch |err| switch (err) {
2117 *const macho.mach_header_64,1576 error.MissingDebugInfo, error.InvalidDebugInfo => null,
2118 @alignCast(@alignOf(macho.mach_header_64), exe_mmap.ptr),1577 else => return err,
2119 );1578 },
2120 if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo;1579 };
21211580 } else |err| switch (err) {
2122 const hdr_base = @ptrCast([*]const u8, hdr);1581 error.MissingDebugInfo, error.InvalidDebugInfo => {
2123 var ptr = hdr_base + @sizeOf(macho.mach_header_64);1582 return SymbolInfo{};
2124 var ncmd: u32 = hdr.ncmds;
2125 const segcmd = while (ncmd != 0) : (ncmd -= 1) {
2126 const lc = @ptrCast(*const std.macho.load_command, ptr);
2127 switch (lc.cmd) {
2128 std.macho.LC_SEGMENT_64 => {
2129 break @ptrCast(
2130 *const std.macho.segment_command_64,
2131 @alignCast(@alignOf(std.macho.segment_command_64), ptr),
2132 );
2133 },1583 },
2134 else => {},1584 else => return err,
2135 }1585 }
2136 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
2137 } else {
2138 return error.MissingDebugInfo;
2139 };
21401586
2141 var opt_debug_line: ?*const macho.section_64 = null;1587 unreachable;
2142 var opt_debug_info: ?*const macho.section_64 = null;
2143 var opt_debug_abbrev: ?*const macho.section_64 = null;
2144 var opt_debug_str: ?*const macho.section_64 = null;
2145 var opt_debug_ranges: ?*const macho.section_64 = null;
2146
2147 const sections = @ptrCast([*]const macho.section_64, @alignCast(@alignOf(macho.section_64), ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects];
2148 for (sections) |*sect| {
2149 // The section name may not exceed 16 chars and a trailing null may
2150 // not be present
2151 const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
2152 sect.sectname[0..last]
2153 else
2154 sect.sectname[0..];
2155
2156 if (mem.eql(u8, name, "__debug_line")) {
2157 opt_debug_line = sect;
2158 } else if (mem.eql(u8, name, "__debug_info")) {
2159 opt_debug_info = sect;
2160 } else if (mem.eql(u8, name, "__debug_abbrev")) {
2161 opt_debug_abbrev = sect;
2162 } else if (mem.eql(u8, name, "__debug_str")) {
2163 opt_debug_str = sect;
2164 } else if (mem.eql(u8, name, "__debug_ranges")) {
2165 opt_debug_ranges = sect;
2166 }
2167 }1588 }
21681589 },
2169 var debug_line = opt_debug_line orelse1590 else => DW.DwarfInfo,
2170 return error.MissingDebugInfo;
2171 var debug_info = opt_debug_info orelse
2172 return error.MissingDebugInfo;
2173 var debug_str = opt_debug_str orelse
2174 return error.MissingDebugInfo;
2175 var debug_abbrev = opt_debug_abbrev orelse
2176 return error.MissingDebugInfo;
2177
2178 gop.kv.value = DwarfInfo{
2179 .endian = .Little,
2180 .debug_info = exe_mmap[@intCast(usize, debug_info.offset)..@intCast(usize, debug_info.offset + debug_info.size)],
2181 .debug_abbrev = exe_mmap[@intCast(usize, debug_abbrev.offset)..@intCast(usize, debug_abbrev.offset + debug_abbrev.size)],
2182 .debug_str = exe_mmap[@intCast(usize, debug_str.offset)..@intCast(usize, debug_str.offset + debug_str.size)],
2183 .debug_line = exe_mmap[@intCast(usize, debug_line.offset)..@intCast(usize, debug_line.offset + debug_line.size)],
2184 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
2185 exe_mmap[@intCast(usize, debug_ranges.offset)..@intCast(usize, debug_ranges.offset + debug_ranges.size)]
2186 else
2187 null,
2188 };
2189 try openDwarfDebugInfo(&gop.kv.value, di.allocator());
2190
2191 break :blk &gop.kv.value;
2192 };
2193
2194 const o_file_address = address - symbol.reloc;
2195 const compile_unit = try dwarf_info.findCompileUnit(o_file_address);
2196 return dwarf_info.getLineNumberInfo(compile_unit.*, o_file_address);
2197}
2198
2199const Func = struct {
2200 pc_range: ?PcRange,
2201 name: ?[]u8,
2202};1591};
22031592
2204fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
2205 const first_32_bits = try in_stream.readIntLittle(u32);
2206 is_64.* = (first_32_bits == 0xffffffff);
2207 if (is_64.*) {
2208 return in_stream.readIntLittle(u64);
2209 } else {
2210 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
2211 // TODO this cast should not be needed
2212 return @as(u64, first_32_bits);
2213 }
2214}
2215
2216/// TODO multithreaded awareness1593/// TODO multithreaded awareness
2217var debug_info_allocator: ?*mem.Allocator = null;1594var debug_info_allocator: ?*mem.Allocator = null;
2218var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;1595var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined;
...@@ -2225,7 +1602,7 @@ fn getDebugInfoAllocator() *mem.Allocator {...@@ -2225,7 +1602,7 @@ fn getDebugInfoAllocator() *mem.Allocator {
2225}1602}
22261603
2227/// Whether or not the current target can print useful debug information when a segfault occurs.1604/// Whether or not the current target can print useful debug information when a segfault occurs.
2228pub 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;
2229pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))1606pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
2230 root.enable_segfault_handler1607 root.enable_segfault_handler
2231else1608else
...@@ -2244,7 +1621,7 @@ pub fn attachSegfaultHandler() void {...@@ -2244,7 +1621,7 @@ pub fn attachSegfaultHandler() void {
2244 if (!have_segfault_handling_support) {1621 if (!have_segfault_handling_support) {
2245 @compileError("segfault handler not supported for this target");1622 @compileError("segfault handler not supported for this target");
2246 }1623 }
2247 if (builtin.os == .windows) {1624 if (builtin.os.tag == .windows) {
2248 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);1625 windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
2249 return;1626 return;
2250 }1627 }
...@@ -2260,7 +1637,7 @@ pub fn attachSegfaultHandler() void {...@@ -2260,7 +1637,7 @@ pub fn attachSegfaultHandler() void {
2260}1637}
22611638
2262fn resetSegfaultHandler() void {1639fn resetSegfaultHandler() void {
2263 if (builtin.os == .windows) {1640 if (builtin.os.tag == .windows) {
2264 if (windows_segfault_handle) |handle| {1641 if (windows_segfault_handle) |handle| {
2265 assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);1642 assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
2266 windows_segfault_handle = null;1643 windows_segfault_handle = null;
lib/std/dwarf.zig+891-682
...@@ -1,682 +1,891 @@...@@ -1,682 +1,891 @@
1pub const TAG_padding = 0x00;1const std = @import("std.zig");
2pub const TAG_array_type = 0x01;2const builtin = @import("builtin");
3pub const TAG_class_type = 0x02;3const debug = std.debug;
4pub const TAG_entry_point = 0x03;4const fs = std.fs;
5pub const TAG_enumeration_type = 0x04;5const io = std.io;
6pub const TAG_formal_parameter = 0x05;6const mem = std.mem;
7pub const TAG_imported_declaration = 0x08;7const math = std.math;
8pub const TAG_label = 0x0a;8const leb = @import("debug/leb128.zig");
9pub const TAG_lexical_block = 0x0b;9
10pub const TAG_member = 0x0d;10const ArrayList = std.ArrayList;
11pub const TAG_pointer_type = 0x0f;11
12pub const TAG_reference_type = 0x10;12usingnamespace @import("dwarf_bits.zig");
13pub const TAG_compile_unit = 0x11;13
14pub const TAG_string_type = 0x12;14pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
15pub const TAG_structure_type = 0x13;15pub const DwarfInStream = io.InStream(anyerror);
16pub const TAG_subroutine = 0x14;16
17pub const TAG_subroutine_type = 0x15;17const PcRange = struct {
18pub const TAG_typedef = 0x16;18 start: u64,
19pub const TAG_union_type = 0x17;19 end: u64,
20pub const TAG_unspecified_parameters = 0x18;20};
21pub const TAG_variant = 0x19;21
22pub const TAG_common_block = 0x1a;22const Func = struct {
23pub const TAG_common_inclusion = 0x1b;23 pc_range: ?PcRange,
24pub const TAG_inheritance = 0x1c;24 name: ?[]const u8,
25pub const TAG_inlined_subroutine = 0x1d;25};
26pub const TAG_module = 0x1e;26
27pub const TAG_ptr_to_member_type = 0x1f;27const CompileUnit = struct {
28pub const TAG_set_type = 0x20;28 version: u16,
29pub const TAG_subrange_type = 0x21;29 is_64: bool,
30pub const TAG_with_stmt = 0x22;30 die: *Die,
31pub const TAG_access_declaration = 0x23;31 pc_range: ?PcRange,
32pub const TAG_base_type = 0x24;32};
33pub const TAG_catch_block = 0x25;33
34pub const TAG_const_type = 0x26;34const AbbrevTable = ArrayList(AbbrevTableEntry);
35pub const TAG_constant = 0x27;35
36pub const TAG_enumerator = 0x28;36const AbbrevTableHeader = struct {
37pub const TAG_file_type = 0x29;37 // offset from .debug_abbrev
38pub const TAG_friend = 0x2a;38 offset: u64,
39pub const TAG_namelist = 0x2b;39 table: AbbrevTable,
40pub const TAG_namelist_item = 0x2c;40};
41pub const TAG_packed_type = 0x2d;41
42pub const TAG_subprogram = 0x2e;42const AbbrevTableEntry = struct {
43pub const TAG_template_type_param = 0x2f;43 has_children: bool,
44pub const TAG_template_value_param = 0x30;44 abbrev_code: u64,
45pub const TAG_thrown_type = 0x31;45 tag_id: u64,
46pub const TAG_try_block = 0x32;46 attrs: ArrayList(AbbrevAttr),
47pub const TAG_variant_part = 0x33;47};
48pub const TAG_variable = 0x34;48
49pub const TAG_volatile_type = 0x35;49const AbbrevAttr = struct {
5050 attr_id: u64,
51// DWARF 351 form_id: u64,
52pub const TAG_dwarf_procedure = 0x36;52};
53pub const TAG_restrict_type = 0x37;53
54pub const TAG_interface_type = 0x38;54const FormValue = union(enum) {
55pub const TAG_namespace = 0x39;55 Address: u64,
56pub const TAG_imported_module = 0x3a;56 Block: []u8,
57pub const TAG_unspecified_type = 0x3b;57 Const: Constant,
58pub const TAG_partial_unit = 0x3c;58 ExprLoc: []u8,
59pub const TAG_imported_unit = 0x3d;59 Flag: bool,
60pub const TAG_condition = 0x3f;60 SecOffset: u64,
61pub const TAG_shared_type = 0x40;61 Ref: u64,
6262 RefAddr: u64,
63// DWARF 463 String: []const u8,
64pub const TAG_type_unit = 0x41;64 StrPtr: u64,
65pub const TAG_rvalue_reference_type = 0x42;65};
66pub const TAG_template_alias = 0x43;66
6767const Constant = struct {
68pub const TAG_lo_user = 0x4080;68 payload: u64,
69pub const TAG_hi_user = 0xffff;69 signed: bool,
7070
71// SGI/MIPS Extensions.71 fn asUnsignedLe(self: *const Constant) !u64 {
72pub const DW_TAG_MIPS_loop = 0x4081;72 if (self.signed) return error.InvalidDebugInfo;
7373 return self.payload;
74// HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .74 }
75pub const TAG_HP_array_descriptor = 0x4090;75};
76pub const TAG_HP_Bliss_field = 0x4091;76
77pub const TAG_HP_Bliss_field_set = 0x4092;77const Die = struct {
7878 tag_id: u64,
79// GNU extensions.79 has_children: bool,
80pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90.80 attrs: ArrayList(Attr),
81pub const TAG_function_template = 0x4102; // For C++.81
82pub const TAG_class_template = 0x4103; //For C++.82 const Attr = struct {
83pub const TAG_GNU_BINCL = 0x4104;83 id: u64,
84pub const TAG_GNU_EINCL = 0x4105;84 value: FormValue,
8585 };
86// Template template parameter.86
87// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .87 fn getAttr(self: *const Die, id: u64) ?*const FormValue {
88pub const TAG_GNU_template_template_param = 0x4106;88 for (self.attrs.toSliceConst()) |*attr| {
8989 if (attr.id == id) return &attr.value;
90// Template parameter pack extension = specified at90 }
91// http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates91 return null;
92// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags92 }
93// are properly part of DWARF 5.93
94pub const TAG_GNU_template_parameter_pack = 0x4107;94 fn getAttrAddr(self: *const Die, id: u64) !u64 {
95pub const TAG_GNU_formal_parameter_pack = 0x4108;95 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
96// The GNU call site extension = specified at96 return switch (form_value.*) {
97// http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .97 FormValue.Address => |value| value,
98// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags98 else => error.InvalidDebugInfo,
99// are properly part of DWARF 5.99 };
100pub const TAG_GNU_call_site = 0x4109;100 }
101pub const TAG_GNU_call_site_parameter = 0x410a;101
102// Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf.102 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
103pub const TAG_upc_shared_type = 0x8765;103 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
104pub const TAG_upc_strict_type = 0x8766;104 return switch (form_value.*) {
105pub const TAG_upc_relaxed_type = 0x8767;105 FormValue.Const => |value| value.asUnsignedLe(),
106// PGI (STMicroelectronics; extensions. No documentation available.106 FormValue.SecOffset => |value| value,
107pub const TAG_PGI_kanji_type = 0xA000;107 else => error.InvalidDebugInfo,
108pub const TAG_PGI_interface_block = 0xA020;108 };
109109 }
110pub const FORM_addr = 0x01;110
111pub const FORM_block2 = 0x03;111 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
112pub const FORM_block4 = 0x04;112 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
113pub const FORM_data2 = 0x05;113 return switch (form_value.*) {
114pub const FORM_data4 = 0x06;114 FormValue.Const => |value| value.asUnsignedLe(),
115pub const FORM_data8 = 0x07;115 else => error.InvalidDebugInfo,
116pub const FORM_string = 0x08;116 };
117pub const FORM_block = 0x09;117 }
118pub const FORM_block1 = 0x0a;118
119pub const FORM_data1 = 0x0b;119 fn getAttrRef(self: *const Die, id: u64) !u64 {
120pub const FORM_flag = 0x0c;120 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
121pub const FORM_sdata = 0x0d;121 return switch (form_value.*) {
122pub const FORM_strp = 0x0e;122 FormValue.Ref => |value| value,
123pub const FORM_udata = 0x0f;123 else => error.InvalidDebugInfo,
124pub const FORM_ref_addr = 0x10;124 };
125pub const FORM_ref1 = 0x11;125 }
126pub const FORM_ref2 = 0x12;126
127pub const FORM_ref4 = 0x13;127 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 {
128pub const FORM_ref8 = 0x14;128 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
129pub const FORM_ref_udata = 0x15;129 return switch (form_value.*) {
130pub const FORM_indirect = 0x16;130 FormValue.String => |value| value,
131pub const FORM_sec_offset = 0x17;131 FormValue.StrPtr => |offset| di.getString(offset),
132pub const FORM_exprloc = 0x18;132 else => error.InvalidDebugInfo,
133pub const FORM_flag_present = 0x19;133 };
134pub const FORM_ref_sig8 = 0x20;134 }
135135};
136// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.136
137pub const FORM_GNU_addr_index = 0x1f01;137const FileEntry = struct {
138pub const FORM_GNU_str_index = 0x1f02;138 file_name: []const u8,
139139 dir_index: usize,
140// Extensions for DWZ multifile.140 mtime: usize,
141// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .141 len_bytes: usize,
142pub const FORM_GNU_ref_alt = 0x1f20;142};
143pub const FORM_GNU_strp_alt = 0x1f21;143
144144const LineNumberProgram = struct {
145pub const AT_sibling = 0x01;145 address: usize,
146pub const AT_location = 0x02;146 file: usize,
147pub const AT_name = 0x03;147 line: i64,
148pub const AT_ordering = 0x09;148 column: u64,
149pub const AT_subscr_data = 0x0a;149 is_stmt: bool,
150pub const AT_byte_size = 0x0b;150 basic_block: bool,
151pub const AT_bit_offset = 0x0c;151 end_sequence: bool,
152pub const AT_bit_size = 0x0d;152
153pub const AT_element_list = 0x0f;153 default_is_stmt: bool,
154pub const AT_stmt_list = 0x10;154 target_address: usize,
155pub const AT_low_pc = 0x11;155 include_dirs: []const []const u8,
156pub const AT_high_pc = 0x12;156 file_entries: *ArrayList(FileEntry),
157pub const AT_language = 0x13;157
158pub const AT_member = 0x14;158 prev_address: usize,
159pub const AT_discr = 0x15;159 prev_file: usize,
160pub const AT_discr_value = 0x16;160 prev_line: i64,
161pub const AT_visibility = 0x17;161 prev_column: u64,
162pub const AT_import = 0x18;162 prev_is_stmt: bool,
163pub const AT_string_length = 0x19;163 prev_basic_block: bool,
164pub const AT_common_reference = 0x1a;164 prev_end_sequence: bool,
165pub const AT_comp_dir = 0x1b;165
166pub const AT_const_value = 0x1c;166 // Reset the state machine following the DWARF specification
167pub const AT_containing_type = 0x1d;167 pub fn reset(self: *LineNumberProgram) void {
168pub const AT_default_value = 0x1e;168 self.address = 0;
169pub const AT_inline = 0x20;169 self.file = 1;
170pub const AT_is_optional = 0x21;170 self.line = 1;
171pub const AT_lower_bound = 0x22;171 self.column = 0;
172pub const AT_producer = 0x25;172 self.is_stmt = self.default_is_stmt;
173pub const AT_prototyped = 0x27;173 self.basic_block = false;
174pub const AT_return_addr = 0x2a;174 self.end_sequence = false;
175pub const AT_start_scope = 0x2c;175 // Invalidate all the remaining fields
176pub const AT_bit_stride = 0x2e;176 self.prev_address = 0;
177pub const AT_upper_bound = 0x2f;177 self.prev_file = undefined;
178pub const AT_abstract_origin = 0x31;178 self.prev_line = undefined;
179pub const AT_accessibility = 0x32;179 self.prev_column = undefined;
180pub const AT_address_class = 0x33;180 self.prev_is_stmt = undefined;
181pub const AT_artificial = 0x34;181 self.prev_basic_block = undefined;
182pub const AT_base_types = 0x35;182 self.prev_end_sequence = undefined;
183pub const AT_calling_convention = 0x36;183 }
184pub const AT_count = 0x37;184
185pub const AT_data_member_location = 0x38;185 pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: usize) LineNumberProgram {
186pub const AT_decl_column = 0x39;186 return LineNumberProgram{
187pub const AT_decl_file = 0x3a;187 .address = 0,
188pub const AT_decl_line = 0x3b;188 .file = 1,
189pub const AT_declaration = 0x3c;189 .line = 1,
190pub const AT_discr_list = 0x3d;190 .column = 0,
191pub const AT_encoding = 0x3e;191 .is_stmt = is_stmt,
192pub const AT_external = 0x3f;192 .basic_block = false,
193pub const AT_frame_base = 0x40;193 .end_sequence = false,
194pub const AT_friend = 0x41;194 .include_dirs = include_dirs,
195pub const AT_identifier_case = 0x42;195 .file_entries = file_entries,
196pub const AT_macro_info = 0x43;196 .default_is_stmt = is_stmt,
197pub const AT_namelist_items = 0x44;197 .target_address = target_address,
198pub const AT_priority = 0x45;198 .prev_address = 0,
199pub const AT_segment = 0x46;199 .prev_file = undefined,
200pub const AT_specification = 0x47;200 .prev_line = undefined,
201pub const AT_static_link = 0x48;201 .prev_column = undefined,
202pub const AT_type = 0x49;202 .prev_is_stmt = undefined,
203pub const AT_use_location = 0x4a;203 .prev_basic_block = undefined,
204pub const AT_variable_parameter = 0x4b;204 .prev_end_sequence = undefined,
205pub const AT_virtuality = 0x4c;205 };
206pub const AT_vtable_elem_location = 0x4d;206 }
207207
208// DWARF 3 values.208 pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo {
209pub const AT_allocated = 0x4e;209 if (self.target_address >= self.prev_address and self.target_address < self.address) {
210pub const AT_associated = 0x4f;210 const file_entry = if (self.prev_file == 0) {
211pub const AT_data_location = 0x50;211 return error.MissingDebugInfo;
212pub const AT_byte_stride = 0x51;212 } else if (self.prev_file - 1 >= self.file_entries.len) {
213pub const AT_entry_pc = 0x52;213 return error.InvalidDebugInfo;
214pub const AT_use_UTF8 = 0x53;214 } else
215pub const AT_extension = 0x54;215 &self.file_entries.items[self.prev_file - 1];
216pub const AT_ranges = 0x55;216
217pub const AT_trampoline = 0x56;217 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
218pub const AT_call_column = 0x57;218 return error.InvalidDebugInfo;
219pub const AT_call_file = 0x58;219 } else
220pub const AT_call_line = 0x59;220 self.include_dirs[file_entry.dir_index];
221pub const AT_description = 0x5a;221 const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name });
222pub const AT_binary_scale = 0x5b;222 errdefer self.file_entries.allocator.free(file_name);
223pub const AT_decimal_scale = 0x5c;223 return debug.LineInfo{
224pub const AT_small = 0x5d;224 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
225pub const AT_decimal_sign = 0x5e;225 .column = self.prev_column,
226pub const AT_digit_count = 0x5f;226 .file_name = file_name,
227pub const AT_picture_string = 0x60;227 .allocator = self.file_entries.allocator,
228pub const AT_mutable = 0x61;228 };
229pub const AT_threads_scaled = 0x62;229 }
230pub const AT_explicit = 0x63;230
231pub const AT_object_pointer = 0x64;231 self.prev_address = self.address;
232pub const AT_endianity = 0x65;232 self.prev_file = self.file;
233pub const AT_elemental = 0x66;233 self.prev_line = self.line;
234pub const AT_pure = 0x67;234 self.prev_column = self.column;
235pub const AT_recursive = 0x68;235 self.prev_is_stmt = self.is_stmt;
236236 self.prev_basic_block = self.basic_block;
237// DWARF 4.237 self.prev_end_sequence = self.end_sequence;
238pub const AT_signature = 0x69;238 return null;
239pub const AT_main_subprogram = 0x6a;239 }
240pub const AT_data_bit_offset = 0x6b;240};
241pub const AT_const_expr = 0x6c;241
242pub const AT_enum_class = 0x6d;242fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
243pub const AT_linkage_name = 0x6e;243 const first_32_bits = try in_stream.readIntLittle(u32);
244244 is_64.* = (first_32_bits == 0xffffffff);
245// DWARF 5245 if (is_64.*) {
246pub const AT_alignment = 0x88;246 return in_stream.readIntLittle(u64);
247247 } else {
248pub const AT_lo_user = 0x2000; // Implementation-defined range start.248 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
249pub const AT_hi_user = 0x3fff; // Implementation-defined range end.249 // TODO this cast should not be needed
250250 return @as(u64, first_32_bits);
251// SGI/MIPS extensions.251 }
252pub const AT_MIPS_fde = 0x2001;252}
253pub const AT_MIPS_loop_begin = 0x2002;253
254pub const AT_MIPS_tail_loop_begin = 0x2003;254// TODO the noasyncs here are workarounds
255pub const AT_MIPS_epilog_begin = 0x2004;255fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
256pub const AT_MIPS_loop_unroll_factor = 0x2005;256 const buf = try allocator.alloc(u8, size);
257pub const AT_MIPS_software_pipeline_depth = 0x2006;257 errdefer allocator.free(buf);
258pub const AT_MIPS_linkage_name = 0x2007;258 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
259pub const AT_MIPS_stride = 0x2008;259 return buf;
260pub const AT_MIPS_abstract_name = 0x2009;260}
261pub const AT_MIPS_clone_origin = 0x200a;261
262pub const AT_MIPS_has_inlines = 0x200b;262fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
263263 const buf = try readAllocBytes(allocator, in_stream, size);
264// HP extensions.264 return FormValue{ .Block = buf };
265pub const AT_HP_block_index = 0x2000;265}
266pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde.266
267pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll.267// TODO the noasyncs here are workarounds
268pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride.268fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
269pub const AT_HP_actuals_stmt_list = 0x2010;269 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
270pub const AT_HP_proc_per_section = 0x2011;270 return parseFormValueBlockLen(allocator, in_stream, block_len);
271pub const AT_HP_raw_data_ptr = 0x2012;271}
272pub const AT_HP_pass_by_reference = 0x2013;272
273pub const AT_HP_opt_level = 0x2014;273fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
274pub const AT_HP_prof_version_id = 0x2015;274 // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here.
275pub const AT_HP_opt_flags = 0x2016;275 // `noasync` should be removed from all the function calls once it is fixed.
276pub const AT_HP_cold_region_low_pc = 0x2017;276 return FormValue{
277pub const AT_HP_cold_region_high_pc = 0x2018;277 .Const = Constant{
278pub const AT_HP_all_variables_modifiable = 0x2019;278 .signed = signed,
279pub const AT_HP_linkage_name = 0x201a;279 .payload = switch (size) {
280pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g.280 1 => try noasync in_stream.readIntLittle(u8),
281pub const AT_HP_unit_name = 0x201f;281 2 => try noasync in_stream.readIntLittle(u16),
282pub const AT_HP_unit_size = 0x2020;282 4 => try noasync in_stream.readIntLittle(u32),
283pub const AT_HP_widened_byte_size = 0x2021;283 8 => try noasync in_stream.readIntLittle(u64),
284pub const AT_HP_definition_points = 0x2022;284 -1 => blk: {
285pub const AT_HP_default_location = 0x2023;285 if (signed) {
286pub const AT_HP_is_result_param = 0x2029;286 const x = try noasync leb.readILEB128(i64, in_stream);
287287 break :blk @bitCast(u64, x);
288// GNU extensions.288 } else {
289pub const AT_sf_names = 0x2101;289 const x = try noasync leb.readULEB128(u64, in_stream);
290pub const AT_src_info = 0x2102;290 break :blk x;
291pub const AT_mac_info = 0x2103;291 }
292pub const AT_src_coords = 0x2104;292 },
293pub const AT_body_begin = 0x2105;293 else => @compileError("Invalid size"),
294pub const AT_body_end = 0x2106;294 },
295pub const AT_GNU_vector = 0x2107;295 },
296// Thread-safety annotations.296 };
297// See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation .297}
298pub const AT_GNU_guarded_by = 0x2108;298
299pub const AT_GNU_pt_guarded_by = 0x2109;299// TODO the noasyncs here are workarounds
300pub const AT_GNU_guarded = 0x210a;300fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
301pub const AT_GNU_pt_guarded = 0x210b;301 return if (is_64) try noasync in_stream.readIntLittle(u64) else @as(u64, try noasync in_stream.readIntLittle(u32));
302pub const AT_GNU_locks_excluded = 0x210c;302}
303pub const AT_GNU_exclusive_locks_required = 0x210d;303
304pub const AT_GNU_shared_locks_required = 0x210e;304// TODO the noasyncs here are workarounds
305// One-definition rule violation detection.305fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
306// See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo .306 if (@sizeOf(usize) == 4) {
307pub const AT_GNU_odr_signature = 0x210f;307 // TODO this cast should not be needed
308// Template template argument name.308 return @as(u64, try noasync in_stream.readIntLittle(u32));
309// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .309 } else if (@sizeOf(usize) == 8) {
310pub const AT_GNU_template_name = 0x2110;310 return noasync in_stream.readIntLittle(u64);
311// The GNU call site extension.311 } else {
312// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .312 unreachable;
313pub const AT_GNU_call_site_value = 0x2111;313 }
314pub const AT_GNU_call_site_data_value = 0x2112;314}
315pub const AT_GNU_call_site_target = 0x2113;315
316pub const AT_GNU_call_site_target_clobbered = 0x2114;316// TODO the noasyncs here are workarounds
317pub const AT_GNU_tail_call = 0x2115;317fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
318pub const AT_GNU_all_tail_call_sites = 0x2116;318 return FormValue{
319pub const AT_GNU_all_call_sites = 0x2117;319 .Ref = switch (size) {
320pub const AT_GNU_all_source_call_sites = 0x2118;320 1 => try noasync in_stream.readIntLittle(u8),
321// Section offset into .debug_macro section.321 2 => try noasync in_stream.readIntLittle(u16),
322pub const AT_GNU_macros = 0x2119;322 4 => try noasync in_stream.readIntLittle(u32),
323// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.323 8 => try noasync in_stream.readIntLittle(u64),
324pub const AT_GNU_dwo_name = 0x2130;324 -1 => try noasync leb.readULEB128(u64, in_stream),
325pub const AT_GNU_dwo_id = 0x2131;325 else => unreachable,
326pub const AT_GNU_ranges_base = 0x2132;326 },
327pub const AT_GNU_addr_base = 0x2133;327 };
328pub const AT_GNU_pubnames = 0x2134;328}
329pub const AT_GNU_pubtypes = 0x2135;329
330// VMS extensions.330// TODO the noasyncs here are workarounds
331pub const AT_VMS_rtnbeg_pd_address = 0x2201;331fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
332// GNAT extensions.332 return switch (form_id) {
333// GNAT descriptive type.333 FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
334// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .334 FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
335pub const AT_use_GNAT_descriptive_type = 0x2301;335 FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
336pub const AT_GNAT_descriptive_type = 0x2302;336 FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
337// UPC extension.337 FORM_block => x: {
338pub const AT_upc_threads_scaled = 0x3210;338 const block_len = try noasync leb.readULEB128(usize, in_stream);
339// PGI (STMicroelectronics) extensions.339 return parseFormValueBlockLen(allocator, in_stream, block_len);
340pub const AT_PGI_lbase = 0x3a00;340 },
341pub const AT_PGI_soffset = 0x3a01;341 FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
342pub const AT_PGI_lstride = 0x3a02;342 FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
343343 FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
344pub const OP_addr = 0x03;344 FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
345pub const OP_deref = 0x06;345 FORM_udata, FORM_sdata => {
346pub const OP_const1u = 0x08;346 const signed = form_id == FORM_sdata;
347pub const OP_const1s = 0x09;347 return parseFormValueConstant(allocator, in_stream, signed, -1);
348pub const OP_const2u = 0x0a;348 },
349pub const OP_const2s = 0x0b;349 FORM_exprloc => {
350pub const OP_const4u = 0x0c;350 const size = try noasync leb.readULEB128(usize, in_stream);
351pub const OP_const4s = 0x0d;351 const buf = try readAllocBytes(allocator, in_stream, size);
352pub const OP_const8u = 0x0e;352 return FormValue{ .ExprLoc = buf };
353pub const OP_const8s = 0x0f;353 },
354pub const OP_constu = 0x10;354 FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
355pub const OP_consts = 0x11;355 FORM_flag_present => FormValue{ .Flag = true },
356pub const OP_dup = 0x12;356 FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
357pub const OP_drop = 0x13;357
358pub const OP_over = 0x14;358 FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
359pub const OP_pick = 0x15;359 FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
360pub const OP_swap = 0x16;360 FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
361pub const OP_rot = 0x17;361 FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
362pub const OP_xderef = 0x18;362 FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
363pub const OP_abs = 0x19;363
364pub const OP_and = 0x1a;364 FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
365pub const OP_div = 0x1b;365 FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
366pub const OP_minus = 0x1c;366
367pub const OP_mod = 0x1d;367 FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
368pub const OP_mul = 0x1e;368 FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
369pub const OP_neg = 0x1f;369 FORM_indirect => {
370pub const OP_not = 0x20;370 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
371pub const OP_or = 0x21;371 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
372pub const OP_plus = 0x22;372 var frame = try allocator.create(F);
373pub const OP_plus_uconst = 0x23;373 defer allocator.destroy(frame);
374pub const OP_shl = 0x24;374 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64);
375pub const OP_shr = 0x25;375 },
376pub const OP_shra = 0x26;376 else => error.InvalidDebugInfo,
377pub const OP_xor = 0x27;377 };
378pub const OP_bra = 0x28;378}
379pub const OP_eq = 0x29;379
380pub const OP_ge = 0x2a;380fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
381pub const OP_gt = 0x2b;381 for (abbrev_table.toSliceConst()) |*table_entry| {
382pub const OP_le = 0x2c;382 if (table_entry.abbrev_code == abbrev_code) return table_entry;
383pub const OP_lt = 0x2d;383 }
384pub const OP_ne = 0x2e;384 return null;
385pub const OP_skip = 0x2f;385}
386pub const OP_lit0 = 0x30;386
387pub const OP_lit1 = 0x31;387pub const DwarfInfo = struct {
388pub const OP_lit2 = 0x32;388 endian: builtin.Endian,
389pub const OP_lit3 = 0x33;389 // No memory is owned by the DwarfInfo
390pub const OP_lit4 = 0x34;390 debug_info: []const u8,
391pub const OP_lit5 = 0x35;391 debug_abbrev: []const u8,
392pub const OP_lit6 = 0x36;392 debug_str: []const u8,
393pub const OP_lit7 = 0x37;393 debug_line: []const u8,
394pub const OP_lit8 = 0x38;394 debug_ranges: ?[]const u8,
395pub const OP_lit9 = 0x39;395 // Filled later by the initializer
396pub const OP_lit10 = 0x3a;396 abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined,
397pub const OP_lit11 = 0x3b;397 compile_unit_list: ArrayList(CompileUnit) = undefined,
398pub const OP_lit12 = 0x3c;398 func_list: ArrayList(Func) = undefined,
399pub const OP_lit13 = 0x3d;399
400pub const OP_lit14 = 0x3e;400 pub fn allocator(self: DwarfInfo) *mem.Allocator {
401pub const OP_lit15 = 0x3f;401 return self.abbrev_table_list.allocator;
402pub const OP_lit16 = 0x40;402 }
403pub const OP_lit17 = 0x41;403
404pub const OP_lit18 = 0x42;404 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
405pub const OP_lit19 = 0x43;405 for (di.func_list.toSliceConst()) |*func| {
406pub const OP_lit20 = 0x44;406 if (func.pc_range) |range| {
407pub const OP_lit21 = 0x45;407 if (address >= range.start and address < range.end) {
408pub const OP_lit22 = 0x46;408 return func.name;
409pub const OP_lit23 = 0x47;409 }
410pub const OP_lit24 = 0x48;410 }
411pub const OP_lit25 = 0x49;411 }
412pub const OP_lit26 = 0x4a;412
413pub const OP_lit27 = 0x4b;413 return null;
414pub const OP_lit28 = 0x4c;414 }
415pub const OP_lit29 = 0x4d;415
416pub const OP_lit30 = 0x4e;416 fn scanAllFunctions(di: *DwarfInfo) !void {
417pub const OP_lit31 = 0x4f;417 var s = io.SliceSeekableInStream.init(di.debug_info);
418pub const OP_reg0 = 0x50;418 var this_unit_offset: u64 = 0;
419pub const OP_reg1 = 0x51;419
420pub const OP_reg2 = 0x52;420 while (this_unit_offset < try s.seekable_stream.getEndPos()) {
421pub const OP_reg3 = 0x53;421 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
422pub const OP_reg4 = 0x54;422 error.EndOfStream => unreachable,
423pub const OP_reg5 = 0x55;423 else => return err,
424pub const OP_reg6 = 0x56;424 };
425pub const OP_reg7 = 0x57;425
426pub const OP_reg8 = 0x58;426 var is_64: bool = undefined;
427pub const OP_reg9 = 0x59;427 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
428pub const OP_reg10 = 0x5a;428 if (unit_length == 0) return;
429pub const OP_reg11 = 0x5b;429 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
430pub const OP_reg12 = 0x5c;430
431pub const OP_reg13 = 0x5d;431 const version = try s.stream.readInt(u16, di.endian);
432pub const OP_reg14 = 0x5e;432 if (version < 2 or version > 5) return error.InvalidDebugInfo;
433pub const OP_reg15 = 0x5f;433
434pub const OP_reg16 = 0x60;434 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
435pub const OP_reg17 = 0x61;435
436pub const OP_reg18 = 0x62;436 const address_size = try s.stream.readByte();
437pub const OP_reg19 = 0x63;437 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
438pub const OP_reg20 = 0x64;438
439pub const OP_reg21 = 0x65;439 const compile_unit_pos = try s.seekable_stream.getPos();
440pub const OP_reg22 = 0x66;440 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
441pub const OP_reg23 = 0x67;441
442pub const OP_reg24 = 0x68;442 try s.seekable_stream.seekTo(compile_unit_pos);
443pub const OP_reg25 = 0x69;443
444pub const OP_reg26 = 0x6a;444 const next_unit_pos = this_unit_offset + next_offset;
445pub const OP_reg27 = 0x6b;445
446pub const OP_reg28 = 0x6c;446 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
447pub const OP_reg29 = 0x6d;447 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
448pub const OP_reg30 = 0x6e;448 defer die_obj.attrs.deinit();
449pub const OP_reg31 = 0x6f;449
450pub const OP_breg0 = 0x70;450 const after_die_offset = try s.seekable_stream.getPos();
451pub const OP_breg1 = 0x71;451
452pub const OP_breg2 = 0x72;452 switch (die_obj.tag_id) {
453pub const OP_breg3 = 0x73;453 TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {
454pub const OP_breg4 = 0x74;454 const fn_name = x: {
455pub const OP_breg5 = 0x75;455 var depth: i32 = 3;
456pub const OP_breg6 = 0x76;456 var this_die_obj = die_obj;
457pub const OP_breg7 = 0x77;457 // Prenvent endless loops
458pub const OP_breg8 = 0x78;458 while (depth > 0) : (depth -= 1) {
459pub const OP_breg9 = 0x79;459 if (this_die_obj.getAttr(AT_name)) |_| {
460pub const OP_breg10 = 0x7a;460 const name = try this_die_obj.getAttrString(di, AT_name);
461pub const OP_breg11 = 0x7b;461 break :x name;
462pub const OP_breg12 = 0x7c;462 } else if (this_die_obj.getAttr(AT_abstract_origin)) |ref| {
463pub const OP_breg13 = 0x7d;463 // Follow the DIE it points to and repeat
464pub const OP_breg14 = 0x7e;464 const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);
465pub const OP_breg15 = 0x7f;465 if (ref_offset > next_offset) return error.InvalidDebugInfo;
466pub const OP_breg16 = 0x80;466 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
467pub const OP_breg17 = 0x81;467 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
468pub const OP_breg18 = 0x82;468 } else if (this_die_obj.getAttr(AT_specification)) |ref| {
469pub const OP_breg19 = 0x83;469 // Follow the DIE it points to and repeat
470pub const OP_breg20 = 0x84;470 const ref_offset = try this_die_obj.getAttrRef(AT_specification);
471pub const OP_breg21 = 0x85;471 if (ref_offset > next_offset) return error.InvalidDebugInfo;
472pub const OP_breg22 = 0x86;472 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
473pub const OP_breg23 = 0x87;473 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
474pub const OP_breg24 = 0x88;474 } else {
475pub const OP_breg25 = 0x89;475 break :x null;
476pub const OP_breg26 = 0x8a;476 }
477pub const OP_breg27 = 0x8b;477 }
478pub const OP_breg28 = 0x8c;478
479pub const OP_breg29 = 0x8d;479 break :x null;
480pub const OP_breg30 = 0x8e;480 };
481pub const OP_breg31 = 0x8f;481
482pub const OP_regx = 0x90;482 const pc_range = x: {
483pub const OP_fbreg = 0x91;483 if (die_obj.getAttrAddr(AT_low_pc)) |low_pc| {
484pub const OP_bregx = 0x92;484 if (die_obj.getAttr(AT_high_pc)) |high_pc_value| {
485pub const OP_piece = 0x93;485 const pc_end = switch (high_pc_value.*) {
486pub const OP_deref_size = 0x94;486 FormValue.Address => |value| value,
487pub const OP_xderef_size = 0x95;487 FormValue.Const => |value| b: {
488pub const OP_nop = 0x96;488 const offset = try value.asUnsignedLe();
489489 break :b (low_pc + offset);
490// DWARF 3 extensions.490 },
491pub const OP_push_object_address = 0x97;491 else => return error.InvalidDebugInfo,
492pub const OP_call2 = 0x98;492 };
493pub const OP_call4 = 0x99;493 break :x PcRange{
494pub const OP_call_ref = 0x9a;494 .start = low_pc,
495pub const OP_form_tls_address = 0x9b;495 .end = pc_end,
496pub const OP_call_frame_cfa = 0x9c;496 };
497pub const OP_bit_piece = 0x9d;497 } else {
498498 break :x null;
499// DWARF 4 extensions.499 }
500pub const OP_implicit_value = 0x9e;500 } else |err| {
501pub const OP_stack_value = 0x9f;501 if (err != error.MissingDebugInfo) return err;
502502 break :x null;
503pub const OP_lo_user = 0xe0; // Implementation-defined range start.503 }
504pub const OP_hi_user = 0xff; // Implementation-defined range end.504 };
505505
506// GNU extensions.506 try di.func_list.append(Func{
507pub const OP_GNU_push_tls_address = 0xe0;507 .name = fn_name,
508// The following is for marking variables that are uninitialized.508 .pc_range = pc_range,
509pub const OP_GNU_uninit = 0xf0;509 });
510pub const OP_GNU_encoded_addr = 0xf1;510 },
511// The GNU implicit pointer extension.511 else => {},
512// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .512 }
513pub const OP_GNU_implicit_pointer = 0xf2;513
514// The GNU entry value extension.514 try s.seekable_stream.seekTo(after_die_offset);
515// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .515 }
516pub const OP_GNU_entry_value = 0xf3;516
517// The GNU typed stack extension.517 this_unit_offset += next_offset;
518// See http://www.dwarfstd.org/doc/040408.1.html .518 }
519pub const OP_GNU_const_type = 0xf4;519 }
520pub const OP_GNU_regval_type = 0xf5;520
521pub const OP_GNU_deref_type = 0xf6;521 fn scanAllCompileUnits(di: *DwarfInfo) !void {
522pub const OP_GNU_convert = 0xf7;522 var s = io.SliceSeekableInStream.init(di.debug_info);
523pub const OP_GNU_reinterpret = 0xf9;523 var this_unit_offset: u64 = 0;
524// The GNU parameter ref extension.524
525pub const OP_GNU_parameter_ref = 0xfa;525 while (this_unit_offset < try s.seekable_stream.getEndPos()) {
526// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.526 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
527pub const OP_GNU_addr_index = 0xfb;527 error.EndOfStream => unreachable,
528pub const OP_GNU_const_index = 0xfc;528 else => return err,
529// HP extensions.529 };
530pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.530
531pub const OP_HP_is_value = 0xe1;531 var is_64: bool = undefined;
532pub const OP_HP_fltconst4 = 0xe2;532 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
533pub const OP_HP_fltconst8 = 0xe3;533 if (unit_length == 0) return;
534pub const OP_HP_mod_range = 0xe4;534 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
535pub const OP_HP_unmod_range = 0xe5;535
536pub const OP_HP_tls = 0xe6;536 const version = try s.stream.readInt(u16, di.endian);
537// PGI (STMicroelectronics) extensions.537 if (version < 2 or version > 5) return error.InvalidDebugInfo;
538pub const OP_PGI_omp_thread_num = 0xf8;538
539539 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
540pub const ATE_void = 0x0;540
541pub const ATE_address = 0x1;541 const address_size = try s.stream.readByte();
542pub const ATE_boolean = 0x2;542 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
543pub const ATE_complex_float = 0x3;543
544pub const ATE_float = 0x4;544 const compile_unit_pos = try s.seekable_stream.getPos();
545pub const ATE_signed = 0x5;545 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
546pub const ATE_signed_char = 0x6;546
547pub const ATE_unsigned = 0x7;547 try s.seekable_stream.seekTo(compile_unit_pos);
548pub const ATE_unsigned_char = 0x8;548
549549 const compile_unit_die = try di.allocator().create(Die);
550// DWARF 3.550 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
551pub const ATE_imaginary_float = 0x9;551
552pub const ATE_packed_decimal = 0xa;552 if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;
553pub const ATE_numeric_string = 0xb;553
554pub const ATE_edited = 0xc;554 const pc_range = x: {
555pub const ATE_signed_fixed = 0xd;555 if (compile_unit_die.getAttrAddr(AT_low_pc)) |low_pc| {
556pub const ATE_unsigned_fixed = 0xe;556 if (compile_unit_die.getAttr(AT_high_pc)) |high_pc_value| {
557pub const ATE_decimal_float = 0xf;557 const pc_end = switch (high_pc_value.*) {
558558 FormValue.Address => |value| value,
559// DWARF 4.559 FormValue.Const => |value| b: {
560pub const ATE_UTF = 0x10;560 const offset = try value.asUnsignedLe();
561561 break :b (low_pc + offset);
562pub const ATE_lo_user = 0x80;562 },
563pub const ATE_hi_user = 0xff;563 else => return error.InvalidDebugInfo,
564564 };
565// HP extensions.565 break :x PcRange{
566pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit).566 .start = low_pc,
567pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit).567 .end = pc_end,
568pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit).568 };
569pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit).569 } else {
570pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64).570 break :x null;
571pub const ATE_HP_imaginary_float80 = 0x85;571 }
572pub const ATE_HP_imaginary_float128 = 0x86;572 } else |err| {
573pub const ATE_HP_VAX_float = 0x88; // F or G floating.573 if (err != error.MissingDebugInfo) return err;
574pub const ATE_HP_VAX_float_d = 0x89; // D floating.574 break :x null;
575pub const ATE_HP_packed_decimal = 0x8a; // Cobol.575 }
576pub const ATE_HP_zoned_decimal = 0x8b; // Cobol.576 };
577pub const ATE_HP_edited = 0x8c; // Cobol.577
578pub const ATE_HP_signed_fixed = 0x8d; // Cobol.578 try di.compile_unit_list.append(CompileUnit{
579pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.579 .version = version,
580pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.580 .is_64 = is_64,
581pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.581 .pc_range = pc_range,
582582 .die = compile_unit_die,
583pub const CFA_advance_loc = 0x40;583 });
584pub const CFA_offset = 0x80;584
585pub const CFA_restore = 0xc0;585 this_unit_offset += next_offset;
586pub const CFA_nop = 0x00;586 }
587pub const CFA_set_loc = 0x01;587 }
588pub const CFA_advance_loc1 = 0x02;588
589pub const CFA_advance_loc2 = 0x03;589 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
590pub const CFA_advance_loc4 = 0x04;590 for (di.compile_unit_list.toSlice()) |*compile_unit| {
591pub const CFA_offset_extended = 0x05;591 if (compile_unit.pc_range) |range| {
592pub const CFA_restore_extended = 0x06;592 if (target_address >= range.start and target_address < range.end) return compile_unit;
593pub const CFA_undefined = 0x07;593 }
594pub const CFA_same_value = 0x08;594 if (di.debug_ranges) |debug_ranges| {
595pub const CFA_register = 0x09;595 if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {
596pub const CFA_remember_state = 0x0a;596 var s = io.SliceSeekableInStream.init(debug_ranges);
597pub const CFA_restore_state = 0x0b;597
598pub const CFA_def_cfa = 0x0c;598 // All the addresses in the list are relative to the value
599pub const CFA_def_cfa_register = 0x0d;599 // specified by DW_AT_low_pc or to some other value encoded
600pub const CFA_def_cfa_offset = 0x0e;600 // in the list itself.
601601 // If no starting value is specified use zero.
602// DWARF 3.602 var base_address = compile_unit.die.getAttrAddr(AT_low_pc) catch |err| switch (err) {
603pub const CFA_def_cfa_expression = 0x0f;603 error.MissingDebugInfo => 0,
604pub const CFA_expression = 0x10;604 else => return err,
605pub const CFA_offset_extended_sf = 0x11;605 };
606pub const CFA_def_cfa_sf = 0x12;606
607pub const CFA_def_cfa_offset_sf = 0x13;607 try s.seekable_stream.seekTo(ranges_offset);
608pub const CFA_val_offset = 0x14;608
609pub const CFA_val_offset_sf = 0x15;609 while (true) {
610pub const CFA_val_expression = 0x16;610 const begin_addr = try s.stream.readIntLittle(usize);
611611 const end_addr = try s.stream.readIntLittle(usize);
612pub const CFA_lo_user = 0x1c;612 if (begin_addr == 0 and end_addr == 0) {
613pub const CFA_hi_user = 0x3f;613 break;
614614 }
615// SGI/MIPS specific.615 // This entry selects a new value for the base address
616pub const CFA_MIPS_advance_loc8 = 0x1d;616 if (begin_addr == math.maxInt(usize)) {
617617 base_address = end_addr;
618// GNU extensions.618 continue;
619pub const CFA_GNU_window_save = 0x2d;619 }
620pub const CFA_GNU_args_size = 0x2e;620 if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) {
621pub const CFA_GNU_negative_offset_extended = 0x2f;621 return compile_unit;
622622 }
623pub const CHILDREN_no = 0x00;623 }
624pub const CHILDREN_yes = 0x01;624 } else |err| {
625625 if (err != error.MissingDebugInfo) return err;
626pub const LNS_extended_op = 0x00;626 continue;
627pub const LNS_copy = 0x01;627 }
628pub const LNS_advance_pc = 0x02;628 }
629pub const LNS_advance_line = 0x03;629 }
630pub const LNS_set_file = 0x04;630 return error.MissingDebugInfo;
631pub const LNS_set_column = 0x05;631 }
632pub const LNS_negate_stmt = 0x06;632
633pub const LNS_set_basic_block = 0x07;633 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
634pub const LNS_const_add_pc = 0x08;634 /// seeks in the stream and parses it.
635pub const LNS_fixed_advance_pc = 0x09;635 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
636pub const LNS_set_prologue_end = 0x0a;636 for (di.abbrev_table_list.toSlice()) |*header| {
637pub const LNS_set_epilogue_begin = 0x0b;637 if (header.offset == abbrev_offset) {
638pub const LNS_set_isa = 0x0c;638 return &header.table;
639639 }
640pub const LNE_end_sequence = 0x01;640 }
641pub const LNE_set_address = 0x02;641 try di.abbrev_table_list.append(AbbrevTableHeader{
642pub const LNE_define_file = 0x03;642 .offset = abbrev_offset,
643pub const LNE_set_discriminator = 0x04;643 .table = try di.parseAbbrevTable(abbrev_offset),
644pub const LNE_lo_user = 0x80;644 });
645pub const LNE_hi_user = 0xff;645 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
646646 }
647pub const LANG_C89 = 0x0001;647
648pub const LANG_C = 0x0002;648 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
649pub const LANG_Ada83 = 0x0003;649 var s = io.SliceSeekableInStream.init(di.debug_abbrev);
650pub const LANG_C_plus_plus = 0x0004;650
651pub const LANG_Cobol74 = 0x0005;651 try s.seekable_stream.seekTo(offset);
652pub const LANG_Cobol85 = 0x0006;652 var result = AbbrevTable.init(di.allocator());
653pub const LANG_Fortran77 = 0x0007;653 errdefer result.deinit();
654pub const LANG_Fortran90 = 0x0008;654 while (true) {
655pub const LANG_Pascal83 = 0x0009;655 const abbrev_code = try leb.readULEB128(u64, &s.stream);
656pub const LANG_Modula2 = 0x000a;656 if (abbrev_code == 0) return result;
657pub const LANG_Java = 0x000b;657 try result.append(AbbrevTableEntry{
658pub const LANG_C99 = 0x000c;658 .abbrev_code = abbrev_code,
659pub const LANG_Ada95 = 0x000d;659 .tag_id = try leb.readULEB128(u64, &s.stream),
660pub const LANG_Fortran95 = 0x000e;660 .has_children = (try s.stream.readByte()) == CHILDREN_yes,
661pub const LANG_PLI = 0x000f;661 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
662pub const LANG_ObjC = 0x0010;662 });
663pub const LANG_ObjC_plus_plus = 0x0011;663 const attrs = &result.items[result.len - 1].attrs;
664pub const LANG_UPC = 0x0012;664
665pub const LANG_D = 0x0013;665 while (true) {
666pub const LANG_Python = 0x0014;666 const attr_id = try leb.readULEB128(u64, &s.stream);
667pub const LANG_Go = 0x0016;667 const form_id = try leb.readULEB128(u64, &s.stream);
668pub const LANG_C_plus_plus_11 = 0x001a;668 if (attr_id == 0 and form_id == 0) break;
669pub const LANG_Rust = 0x001c;669 try attrs.append(AbbrevAttr{
670pub const LANG_C11 = 0x001d;670 .attr_id = attr_id,
671pub const LANG_C_plus_plus_14 = 0x0021;671 .form_id = form_id,
672pub const LANG_Fortran03 = 0x0022;672 });
673pub const LANG_Fortran08 = 0x0023;673 }
674pub const LANG_lo_user = 0x8000;674 }
675pub const LANG_hi_user = 0xffff;675 }
676pub const LANG_Mips_Assembler = 0x8001;676
677pub const LANG_Upc = 0x8765;677 fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
678pub const LANG_HP_Bliss = 0x8003;678 const abbrev_code = try leb.readULEB128(u64, in_stream);
679pub const LANG_HP_Basic91 = 0x8004;679 if (abbrev_code == 0) return null;
680pub const LANG_HP_Pascal91 = 0x8005;680 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
681pub const LANG_HP_IMacro = 0x8006;681
682pub const LANG_HP_Assembler = 0x8007;682 var result = Die{
683 .tag_id = table_entry.tag_id,
684 .has_children = table_entry.has_children,
685 .attrs = ArrayList(Die.Attr).init(di.allocator()),
686 };
687 try result.attrs.resize(table_entry.attrs.len);
688 for (table_entry.attrs.toSliceConst()) |attr, i| {
689 result.attrs.items[i] = Die.Attr{
690 .id = attr.attr_id,
691 .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, is_64),
692 };
693 }
694 return result;
695 }
696
697 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
698 var s = io.SliceSeekableInStream.init(di.debug_line);
699
700 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT_comp_dir);
701 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT_stmt_list);
702
703 try s.seekable_stream.seekTo(line_info_offset);
704
705 var is_64: bool = undefined;
706 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
707 if (unit_length == 0) {
708 return error.MissingDebugInfo;
709 }
710 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
711
712 const version = try s.stream.readInt(u16, di.endian);
713 // TODO support 3 and 5
714 if (version != 2 and version != 4) return error.InvalidDebugInfo;
715
716 const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
717 const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;
718
719 const minimum_instruction_length = try s.stream.readByte();
720 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
721
722 if (version >= 4) {
723 // maximum_operations_per_instruction
724 _ = try s.stream.readByte();
725 }
726
727 const default_is_stmt = (try s.stream.readByte()) != 0;
728 const line_base = try s.stream.readByteSigned();
729
730 const line_range = try s.stream.readByte();
731 if (line_range == 0) return error.InvalidDebugInfo;
732
733 const opcode_base = try s.stream.readByte();
734
735 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
736 defer di.allocator().free(standard_opcode_lengths);
737
738 {
739 var i: usize = 0;
740 while (i < opcode_base - 1) : (i += 1) {
741 standard_opcode_lengths[i] = try s.stream.readByte();
742 }
743 }
744
745 var include_directories = ArrayList([]const u8).init(di.allocator());
746 try include_directories.append(compile_unit_cwd);
747 while (true) {
748 const dir = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
749 if (dir.len == 0) break;
750 try include_directories.append(dir);
751 }
752
753 var file_entries = ArrayList(FileEntry).init(di.allocator());
754 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
755
756 while (true) {
757 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
758 if (file_name.len == 0) break;
759 const dir_index = try leb.readULEB128(usize, &s.stream);
760 const mtime = try leb.readULEB128(usize, &s.stream);
761 const len_bytes = try leb.readULEB128(usize, &s.stream);
762 try file_entries.append(FileEntry{
763 .file_name = file_name,
764 .dir_index = dir_index,
765 .mtime = mtime,
766 .len_bytes = len_bytes,
767 });
768 }
769
770 try s.seekable_stream.seekTo(prog_start_offset);
771
772 const next_unit_pos = line_info_offset + next_offset;
773
774 while ((try s.seekable_stream.getPos()) < next_unit_pos) {
775 const opcode = try s.stream.readByte();
776
777 if (opcode == LNS_extended_op) {
778 const op_size = try leb.readULEB128(u64, &s.stream);
779 if (op_size < 1) return error.InvalidDebugInfo;
780 var sub_op = try s.stream.readByte();
781 switch (sub_op) {
782 LNE_end_sequence => {
783 prog.end_sequence = true;
784 if (try prog.checkLineMatch()) |info| return info;
785 prog.reset();
786 },
787 LNE_set_address => {
788 const addr = try s.stream.readInt(usize, di.endian);
789 prog.address = addr;
790 },
791 LNE_define_file => {
792 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
793 const dir_index = try leb.readULEB128(usize, &s.stream);
794 const mtime = try leb.readULEB128(usize, &s.stream);
795 const len_bytes = try leb.readULEB128(usize, &s.stream);
796 try file_entries.append(FileEntry{
797 .file_name = file_name,
798 .dir_index = dir_index,
799 .mtime = mtime,
800 .len_bytes = len_bytes,
801 });
802 },
803 else => {
804 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
805 try s.seekable_stream.seekBy(fwd_amt);
806 },
807 }
808 } else if (opcode >= opcode_base) {
809 // special opcodes
810 const adjusted_opcode = opcode - opcode_base;
811 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
812 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
813 prog.line += inc_line;
814 prog.address += inc_addr;
815 if (try prog.checkLineMatch()) |info| return info;
816 prog.basic_block = false;
817 } else {
818 switch (opcode) {
819 LNS_copy => {
820 if (try prog.checkLineMatch()) |info| return info;
821 prog.basic_block = false;
822 },
823 LNS_advance_pc => {
824 const arg = try leb.readULEB128(usize, &s.stream);
825 prog.address += arg * minimum_instruction_length;
826 },
827 LNS_advance_line => {
828 const arg = try leb.readILEB128(i64, &s.stream);
829 prog.line += arg;
830 },
831 LNS_set_file => {
832 const arg = try leb.readULEB128(usize, &s.stream);
833 prog.file = arg;
834 },
835 LNS_set_column => {
836 const arg = try leb.readULEB128(u64, &s.stream);
837 prog.column = arg;
838 },
839 LNS_negate_stmt => {
840 prog.is_stmt = !prog.is_stmt;
841 },
842 LNS_set_basic_block => {
843 prog.basic_block = true;
844 },
845 LNS_const_add_pc => {
846 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
847 prog.address += inc_addr;
848 },
849 LNS_fixed_advance_pc => {
850 const arg = try s.stream.readInt(u16, di.endian);
851 prog.address += arg;
852 },
853 LNS_set_prologue_end => {},
854 else => {
855 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
856 const len_bytes = standard_opcode_lengths[opcode - 1];
857 try s.seekable_stream.seekBy(len_bytes);
858 },
859 }
860 }
861 }
862
863 return error.MissingDebugInfo;
864 }
865
866 fn getString(di: *DwarfInfo, offset: u64) ![]const u8 {
867 if (offset > di.debug_str.len)
868 return error.InvalidDebugInfo;
869 const casted_offset = math.cast(usize, offset) catch
870 return error.InvalidDebugInfo;
871
872 // Valid strings always have a terminating zero byte
873 if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
874 return di.debug_str[casted_offset..last];
875 }
876
877 return error.InvalidDebugInfo;
878 }
879};
880
881/// Initialize DWARF info. The caller has the responsibility to initialize most
882/// the DwarfInfo fields before calling. These fields can be left undefined:
883/// * abbrev_table_list
884/// * compile_unit_list
885pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
886 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
887 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
888 di.func_list = ArrayList(Func).init(allocator);
889 try di.scanAllFunctions();
890 try di.scanAllCompileUnits();
891}
lib/std/dwarf_bits.zig created+682
...@@ -0,0 +1,682 @@
1pub const TAG_padding = 0x00;
2pub const TAG_array_type = 0x01;
3pub const TAG_class_type = 0x02;
4pub const TAG_entry_point = 0x03;
5pub const TAG_enumeration_type = 0x04;
6pub const TAG_formal_parameter = 0x05;
7pub const TAG_imported_declaration = 0x08;
8pub const TAG_label = 0x0a;
9pub const TAG_lexical_block = 0x0b;
10pub const TAG_member = 0x0d;
11pub const TAG_pointer_type = 0x0f;
12pub const TAG_reference_type = 0x10;
13pub const TAG_compile_unit = 0x11;
14pub const TAG_string_type = 0x12;
15pub const TAG_structure_type = 0x13;
16pub const TAG_subroutine = 0x14;
17pub const TAG_subroutine_type = 0x15;
18pub const TAG_typedef = 0x16;
19pub const TAG_union_type = 0x17;
20pub const TAG_unspecified_parameters = 0x18;
21pub const TAG_variant = 0x19;
22pub const TAG_common_block = 0x1a;
23pub const TAG_common_inclusion = 0x1b;
24pub const TAG_inheritance = 0x1c;
25pub const TAG_inlined_subroutine = 0x1d;
26pub const TAG_module = 0x1e;
27pub const TAG_ptr_to_member_type = 0x1f;
28pub const TAG_set_type = 0x20;
29pub const TAG_subrange_type = 0x21;
30pub const TAG_with_stmt = 0x22;
31pub const TAG_access_declaration = 0x23;
32pub const TAG_base_type = 0x24;
33pub const TAG_catch_block = 0x25;
34pub const TAG_const_type = 0x26;
35pub const TAG_constant = 0x27;
36pub const TAG_enumerator = 0x28;
37pub const TAG_file_type = 0x29;
38pub const TAG_friend = 0x2a;
39pub const TAG_namelist = 0x2b;
40pub const TAG_namelist_item = 0x2c;
41pub const TAG_packed_type = 0x2d;
42pub const TAG_subprogram = 0x2e;
43pub const TAG_template_type_param = 0x2f;
44pub const TAG_template_value_param = 0x30;
45pub const TAG_thrown_type = 0x31;
46pub const TAG_try_block = 0x32;
47pub const TAG_variant_part = 0x33;
48pub const TAG_variable = 0x34;
49pub const TAG_volatile_type = 0x35;
50
51// DWARF 3
52pub const TAG_dwarf_procedure = 0x36;
53pub const TAG_restrict_type = 0x37;
54pub const TAG_interface_type = 0x38;
55pub const TAG_namespace = 0x39;
56pub const TAG_imported_module = 0x3a;
57pub const TAG_unspecified_type = 0x3b;
58pub const TAG_partial_unit = 0x3c;
59pub const TAG_imported_unit = 0x3d;
60pub const TAG_condition = 0x3f;
61pub const TAG_shared_type = 0x40;
62
63// DWARF 4
64pub const TAG_type_unit = 0x41;
65pub const TAG_rvalue_reference_type = 0x42;
66pub const TAG_template_alias = 0x43;
67
68pub const TAG_lo_user = 0x4080;
69pub const TAG_hi_user = 0xffff;
70
71// SGI/MIPS Extensions.
72pub const DW_TAG_MIPS_loop = 0x4081;
73
74// HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .
75pub const TAG_HP_array_descriptor = 0x4090;
76pub const TAG_HP_Bliss_field = 0x4091;
77pub const TAG_HP_Bliss_field_set = 0x4092;
78
79// GNU extensions.
80pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90.
81pub const TAG_function_template = 0x4102; // For C++.
82pub const TAG_class_template = 0x4103; //For C++.
83pub const TAG_GNU_BINCL = 0x4104;
84pub const TAG_GNU_EINCL = 0x4105;
85
86// Template template parameter.
87// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
88pub const TAG_GNU_template_template_param = 0x4106;
89
90// Template parameter pack extension = specified at
91// http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates
92// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
93// are properly part of DWARF 5.
94pub const TAG_GNU_template_parameter_pack = 0x4107;
95pub const TAG_GNU_formal_parameter_pack = 0x4108;
96// The GNU call site extension = specified at
97// http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
98// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
99// are properly part of DWARF 5.
100pub const TAG_GNU_call_site = 0x4109;
101pub const TAG_GNU_call_site_parameter = 0x410a;
102// Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf.
103pub const TAG_upc_shared_type = 0x8765;
104pub const TAG_upc_strict_type = 0x8766;
105pub const TAG_upc_relaxed_type = 0x8767;
106// PGI (STMicroelectronics; extensions. No documentation available.
107pub const TAG_PGI_kanji_type = 0xA000;
108pub const TAG_PGI_interface_block = 0xA020;
109
110pub const FORM_addr = 0x01;
111pub const FORM_block2 = 0x03;
112pub const FORM_block4 = 0x04;
113pub const FORM_data2 = 0x05;
114pub const FORM_data4 = 0x06;
115pub const FORM_data8 = 0x07;
116pub const FORM_string = 0x08;
117pub const FORM_block = 0x09;
118pub const FORM_block1 = 0x0a;
119pub const FORM_data1 = 0x0b;
120pub const FORM_flag = 0x0c;
121pub const FORM_sdata = 0x0d;
122pub const FORM_strp = 0x0e;
123pub const FORM_udata = 0x0f;
124pub const FORM_ref_addr = 0x10;
125pub const FORM_ref1 = 0x11;
126pub const FORM_ref2 = 0x12;
127pub const FORM_ref4 = 0x13;
128pub const FORM_ref8 = 0x14;
129pub const FORM_ref_udata = 0x15;
130pub const FORM_indirect = 0x16;
131pub const FORM_sec_offset = 0x17;
132pub const FORM_exprloc = 0x18;
133pub const FORM_flag_present = 0x19;
134pub const FORM_ref_sig8 = 0x20;
135
136// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
137pub const FORM_GNU_addr_index = 0x1f01;
138pub const FORM_GNU_str_index = 0x1f02;
139
140// Extensions for DWZ multifile.
141// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .
142pub const FORM_GNU_ref_alt = 0x1f20;
143pub const FORM_GNU_strp_alt = 0x1f21;
144
145pub const AT_sibling = 0x01;
146pub const AT_location = 0x02;
147pub const AT_name = 0x03;
148pub const AT_ordering = 0x09;
149pub const AT_subscr_data = 0x0a;
150pub const AT_byte_size = 0x0b;
151pub const AT_bit_offset = 0x0c;
152pub const AT_bit_size = 0x0d;
153pub const AT_element_list = 0x0f;
154pub const AT_stmt_list = 0x10;
155pub const AT_low_pc = 0x11;
156pub const AT_high_pc = 0x12;
157pub const AT_language = 0x13;
158pub const AT_member = 0x14;
159pub const AT_discr = 0x15;
160pub const AT_discr_value = 0x16;
161pub const AT_visibility = 0x17;
162pub const AT_import = 0x18;
163pub const AT_string_length = 0x19;
164pub const AT_common_reference = 0x1a;
165pub const AT_comp_dir = 0x1b;
166pub const AT_const_value = 0x1c;
167pub const AT_containing_type = 0x1d;
168pub const AT_default_value = 0x1e;
169pub const AT_inline = 0x20;
170pub const AT_is_optional = 0x21;
171pub const AT_lower_bound = 0x22;
172pub const AT_producer = 0x25;
173pub const AT_prototyped = 0x27;
174pub const AT_return_addr = 0x2a;
175pub const AT_start_scope = 0x2c;
176pub const AT_bit_stride = 0x2e;
177pub const AT_upper_bound = 0x2f;
178pub const AT_abstract_origin = 0x31;
179pub const AT_accessibility = 0x32;
180pub const AT_address_class = 0x33;
181pub const AT_artificial = 0x34;
182pub const AT_base_types = 0x35;
183pub const AT_calling_convention = 0x36;
184pub const AT_count = 0x37;
185pub const AT_data_member_location = 0x38;
186pub const AT_decl_column = 0x39;
187pub const AT_decl_file = 0x3a;
188pub const AT_decl_line = 0x3b;
189pub const AT_declaration = 0x3c;
190pub const AT_discr_list = 0x3d;
191pub const AT_encoding = 0x3e;
192pub const AT_external = 0x3f;
193pub const AT_frame_base = 0x40;
194pub const AT_friend = 0x41;
195pub const AT_identifier_case = 0x42;
196pub const AT_macro_info = 0x43;
197pub const AT_namelist_items = 0x44;
198pub const AT_priority = 0x45;
199pub const AT_segment = 0x46;
200pub const AT_specification = 0x47;
201pub const AT_static_link = 0x48;
202pub const AT_type = 0x49;
203pub const AT_use_location = 0x4a;
204pub const AT_variable_parameter = 0x4b;
205pub const AT_virtuality = 0x4c;
206pub const AT_vtable_elem_location = 0x4d;
207
208// DWARF 3 values.
209pub const AT_allocated = 0x4e;
210pub const AT_associated = 0x4f;
211pub const AT_data_location = 0x50;
212pub const AT_byte_stride = 0x51;
213pub const AT_entry_pc = 0x52;
214pub const AT_use_UTF8 = 0x53;
215pub const AT_extension = 0x54;
216pub const AT_ranges = 0x55;
217pub const AT_trampoline = 0x56;
218pub const AT_call_column = 0x57;
219pub const AT_call_file = 0x58;
220pub const AT_call_line = 0x59;
221pub const AT_description = 0x5a;
222pub const AT_binary_scale = 0x5b;
223pub const AT_decimal_scale = 0x5c;
224pub const AT_small = 0x5d;
225pub const AT_decimal_sign = 0x5e;
226pub const AT_digit_count = 0x5f;
227pub const AT_picture_string = 0x60;
228pub const AT_mutable = 0x61;
229pub const AT_threads_scaled = 0x62;
230pub const AT_explicit = 0x63;
231pub const AT_object_pointer = 0x64;
232pub const AT_endianity = 0x65;
233pub const AT_elemental = 0x66;
234pub const AT_pure = 0x67;
235pub const AT_recursive = 0x68;
236
237// DWARF 4.
238pub const AT_signature = 0x69;
239pub const AT_main_subprogram = 0x6a;
240pub const AT_data_bit_offset = 0x6b;
241pub const AT_const_expr = 0x6c;
242pub const AT_enum_class = 0x6d;
243pub const AT_linkage_name = 0x6e;
244
245// DWARF 5
246pub const AT_alignment = 0x88;
247
248pub const AT_lo_user = 0x2000; // Implementation-defined range start.
249pub const AT_hi_user = 0x3fff; // Implementation-defined range end.
250
251// SGI/MIPS extensions.
252pub const AT_MIPS_fde = 0x2001;
253pub const AT_MIPS_loop_begin = 0x2002;
254pub const AT_MIPS_tail_loop_begin = 0x2003;
255pub const AT_MIPS_epilog_begin = 0x2004;
256pub const AT_MIPS_loop_unroll_factor = 0x2005;
257pub const AT_MIPS_software_pipeline_depth = 0x2006;
258pub const AT_MIPS_linkage_name = 0x2007;
259pub const AT_MIPS_stride = 0x2008;
260pub const AT_MIPS_abstract_name = 0x2009;
261pub const AT_MIPS_clone_origin = 0x200a;
262pub const AT_MIPS_has_inlines = 0x200b;
263
264// HP extensions.
265pub const AT_HP_block_index = 0x2000;
266pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde.
267pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll.
268pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride.
269pub const AT_HP_actuals_stmt_list = 0x2010;
270pub const AT_HP_proc_per_section = 0x2011;
271pub const AT_HP_raw_data_ptr = 0x2012;
272pub const AT_HP_pass_by_reference = 0x2013;
273pub const AT_HP_opt_level = 0x2014;
274pub const AT_HP_prof_version_id = 0x2015;
275pub const AT_HP_opt_flags = 0x2016;
276pub const AT_HP_cold_region_low_pc = 0x2017;
277pub const AT_HP_cold_region_high_pc = 0x2018;
278pub const AT_HP_all_variables_modifiable = 0x2019;
279pub const AT_HP_linkage_name = 0x201a;
280pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g.
281pub const AT_HP_unit_name = 0x201f;
282pub const AT_HP_unit_size = 0x2020;
283pub const AT_HP_widened_byte_size = 0x2021;
284pub const AT_HP_definition_points = 0x2022;
285pub const AT_HP_default_location = 0x2023;
286pub const AT_HP_is_result_param = 0x2029;
287
288// GNU extensions.
289pub const AT_sf_names = 0x2101;
290pub const AT_src_info = 0x2102;
291pub const AT_mac_info = 0x2103;
292pub const AT_src_coords = 0x2104;
293pub const AT_body_begin = 0x2105;
294pub const AT_body_end = 0x2106;
295pub const AT_GNU_vector = 0x2107;
296// Thread-safety annotations.
297// See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation .
298pub const AT_GNU_guarded_by = 0x2108;
299pub const AT_GNU_pt_guarded_by = 0x2109;
300pub const AT_GNU_guarded = 0x210a;
301pub const AT_GNU_pt_guarded = 0x210b;
302pub const AT_GNU_locks_excluded = 0x210c;
303pub const AT_GNU_exclusive_locks_required = 0x210d;
304pub const AT_GNU_shared_locks_required = 0x210e;
305// One-definition rule violation detection.
306// See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo .
307pub const AT_GNU_odr_signature = 0x210f;
308// Template template argument name.
309// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
310pub const AT_GNU_template_name = 0x2110;
311// The GNU call site extension.
312// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
313pub const AT_GNU_call_site_value = 0x2111;
314pub const AT_GNU_call_site_data_value = 0x2112;
315pub const AT_GNU_call_site_target = 0x2113;
316pub const AT_GNU_call_site_target_clobbered = 0x2114;
317pub const AT_GNU_tail_call = 0x2115;
318pub const AT_GNU_all_tail_call_sites = 0x2116;
319pub const AT_GNU_all_call_sites = 0x2117;
320pub const AT_GNU_all_source_call_sites = 0x2118;
321// Section offset into .debug_macro section.
322pub const AT_GNU_macros = 0x2119;
323// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
324pub const AT_GNU_dwo_name = 0x2130;
325pub const AT_GNU_dwo_id = 0x2131;
326pub const AT_GNU_ranges_base = 0x2132;
327pub const AT_GNU_addr_base = 0x2133;
328pub const AT_GNU_pubnames = 0x2134;
329pub const AT_GNU_pubtypes = 0x2135;
330// VMS extensions.
331pub const AT_VMS_rtnbeg_pd_address = 0x2201;
332// GNAT extensions.
333// GNAT descriptive type.
334// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .
335pub const AT_use_GNAT_descriptive_type = 0x2301;
336pub const AT_GNAT_descriptive_type = 0x2302;
337// UPC extension.
338pub const AT_upc_threads_scaled = 0x3210;
339// PGI (STMicroelectronics) extensions.
340pub const AT_PGI_lbase = 0x3a00;
341pub const AT_PGI_soffset = 0x3a01;
342pub const AT_PGI_lstride = 0x3a02;
343
344pub const OP_addr = 0x03;
345pub const OP_deref = 0x06;
346pub const OP_const1u = 0x08;
347pub const OP_const1s = 0x09;
348pub const OP_const2u = 0x0a;
349pub const OP_const2s = 0x0b;
350pub const OP_const4u = 0x0c;
351pub const OP_const4s = 0x0d;
352pub const OP_const8u = 0x0e;
353pub const OP_const8s = 0x0f;
354pub const OP_constu = 0x10;
355pub const OP_consts = 0x11;
356pub const OP_dup = 0x12;
357pub const OP_drop = 0x13;
358pub const OP_over = 0x14;
359pub const OP_pick = 0x15;
360pub const OP_swap = 0x16;
361pub const OP_rot = 0x17;
362pub const OP_xderef = 0x18;
363pub const OP_abs = 0x19;
364pub const OP_and = 0x1a;
365pub const OP_div = 0x1b;
366pub const OP_minus = 0x1c;
367pub const OP_mod = 0x1d;
368pub const OP_mul = 0x1e;
369pub const OP_neg = 0x1f;
370pub const OP_not = 0x20;
371pub const OP_or = 0x21;
372pub const OP_plus = 0x22;
373pub const OP_plus_uconst = 0x23;
374pub const OP_shl = 0x24;
375pub const OP_shr = 0x25;
376pub const OP_shra = 0x26;
377pub const OP_xor = 0x27;
378pub const OP_bra = 0x28;
379pub const OP_eq = 0x29;
380pub const OP_ge = 0x2a;
381pub const OP_gt = 0x2b;
382pub const OP_le = 0x2c;
383pub const OP_lt = 0x2d;
384pub const OP_ne = 0x2e;
385pub const OP_skip = 0x2f;
386pub const OP_lit0 = 0x30;
387pub const OP_lit1 = 0x31;
388pub const OP_lit2 = 0x32;
389pub const OP_lit3 = 0x33;
390pub const OP_lit4 = 0x34;
391pub const OP_lit5 = 0x35;
392pub const OP_lit6 = 0x36;
393pub const OP_lit7 = 0x37;
394pub const OP_lit8 = 0x38;
395pub const OP_lit9 = 0x39;
396pub const OP_lit10 = 0x3a;
397pub const OP_lit11 = 0x3b;
398pub const OP_lit12 = 0x3c;
399pub const OP_lit13 = 0x3d;
400pub const OP_lit14 = 0x3e;
401pub const OP_lit15 = 0x3f;
402pub const OP_lit16 = 0x40;
403pub const OP_lit17 = 0x41;
404pub const OP_lit18 = 0x42;
405pub const OP_lit19 = 0x43;
406pub const OP_lit20 = 0x44;
407pub const OP_lit21 = 0x45;
408pub const OP_lit22 = 0x46;
409pub const OP_lit23 = 0x47;
410pub const OP_lit24 = 0x48;
411pub const OP_lit25 = 0x49;
412pub const OP_lit26 = 0x4a;
413pub const OP_lit27 = 0x4b;
414pub const OP_lit28 = 0x4c;
415pub const OP_lit29 = 0x4d;
416pub const OP_lit30 = 0x4e;
417pub const OP_lit31 = 0x4f;
418pub const OP_reg0 = 0x50;
419pub const OP_reg1 = 0x51;
420pub const OP_reg2 = 0x52;
421pub const OP_reg3 = 0x53;
422pub const OP_reg4 = 0x54;
423pub const OP_reg5 = 0x55;
424pub const OP_reg6 = 0x56;
425pub const OP_reg7 = 0x57;
426pub const OP_reg8 = 0x58;
427pub const OP_reg9 = 0x59;
428pub const OP_reg10 = 0x5a;
429pub const OP_reg11 = 0x5b;
430pub const OP_reg12 = 0x5c;
431pub const OP_reg13 = 0x5d;
432pub const OP_reg14 = 0x5e;
433pub const OP_reg15 = 0x5f;
434pub const OP_reg16 = 0x60;
435pub const OP_reg17 = 0x61;
436pub const OP_reg18 = 0x62;
437pub const OP_reg19 = 0x63;
438pub const OP_reg20 = 0x64;
439pub const OP_reg21 = 0x65;
440pub const OP_reg22 = 0x66;
441pub const OP_reg23 = 0x67;
442pub const OP_reg24 = 0x68;
443pub const OP_reg25 = 0x69;
444pub const OP_reg26 = 0x6a;
445pub const OP_reg27 = 0x6b;
446pub const OP_reg28 = 0x6c;
447pub const OP_reg29 = 0x6d;
448pub const OP_reg30 = 0x6e;
449pub const OP_reg31 = 0x6f;
450pub const OP_breg0 = 0x70;
451pub const OP_breg1 = 0x71;
452pub const OP_breg2 = 0x72;
453pub const OP_breg3 = 0x73;
454pub const OP_breg4 = 0x74;
455pub const OP_breg5 = 0x75;
456pub const OP_breg6 = 0x76;
457pub const OP_breg7 = 0x77;
458pub const OP_breg8 = 0x78;
459pub const OP_breg9 = 0x79;
460pub const OP_breg10 = 0x7a;
461pub const OP_breg11 = 0x7b;
462pub const OP_breg12 = 0x7c;
463pub const OP_breg13 = 0x7d;
464pub const OP_breg14 = 0x7e;
465pub const OP_breg15 = 0x7f;
466pub const OP_breg16 = 0x80;
467pub const OP_breg17 = 0x81;
468pub const OP_breg18 = 0x82;
469pub const OP_breg19 = 0x83;
470pub const OP_breg20 = 0x84;
471pub const OP_breg21 = 0x85;
472pub const OP_breg22 = 0x86;
473pub const OP_breg23 = 0x87;
474pub const OP_breg24 = 0x88;
475pub const OP_breg25 = 0x89;
476pub const OP_breg26 = 0x8a;
477pub const OP_breg27 = 0x8b;
478pub const OP_breg28 = 0x8c;
479pub const OP_breg29 = 0x8d;
480pub const OP_breg30 = 0x8e;
481pub const OP_breg31 = 0x8f;
482pub const OP_regx = 0x90;
483pub const OP_fbreg = 0x91;
484pub const OP_bregx = 0x92;
485pub const OP_piece = 0x93;
486pub const OP_deref_size = 0x94;
487pub const OP_xderef_size = 0x95;
488pub const OP_nop = 0x96;
489
490// DWARF 3 extensions.
491pub const OP_push_object_address = 0x97;
492pub const OP_call2 = 0x98;
493pub const OP_call4 = 0x99;
494pub const OP_call_ref = 0x9a;
495pub const OP_form_tls_address = 0x9b;
496pub const OP_call_frame_cfa = 0x9c;
497pub const OP_bit_piece = 0x9d;
498
499// DWARF 4 extensions.
500pub const OP_implicit_value = 0x9e;
501pub const OP_stack_value = 0x9f;
502
503pub const OP_lo_user = 0xe0; // Implementation-defined range start.
504pub const OP_hi_user = 0xff; // Implementation-defined range end.
505
506// GNU extensions.
507pub const OP_GNU_push_tls_address = 0xe0;
508// The following is for marking variables that are uninitialized.
509pub const OP_GNU_uninit = 0xf0;
510pub const OP_GNU_encoded_addr = 0xf1;
511// The GNU implicit pointer extension.
512// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .
513pub const OP_GNU_implicit_pointer = 0xf2;
514// The GNU entry value extension.
515// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .
516pub const OP_GNU_entry_value = 0xf3;
517// The GNU typed stack extension.
518// See http://www.dwarfstd.org/doc/040408.1.html .
519pub const OP_GNU_const_type = 0xf4;
520pub const OP_GNU_regval_type = 0xf5;
521pub const OP_GNU_deref_type = 0xf6;
522pub const OP_GNU_convert = 0xf7;
523pub const OP_GNU_reinterpret = 0xf9;
524// The GNU parameter ref extension.
525pub const OP_GNU_parameter_ref = 0xfa;
526// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.
527pub const OP_GNU_addr_index = 0xfb;
528pub const OP_GNU_const_index = 0xfc;
529// HP extensions.
530pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.
531pub const OP_HP_is_value = 0xe1;
532pub const OP_HP_fltconst4 = 0xe2;
533pub const OP_HP_fltconst8 = 0xe3;
534pub const OP_HP_mod_range = 0xe4;
535pub const OP_HP_unmod_range = 0xe5;
536pub const OP_HP_tls = 0xe6;
537// PGI (STMicroelectronics) extensions.
538pub const OP_PGI_omp_thread_num = 0xf8;
539
540pub const ATE_void = 0x0;
541pub const ATE_address = 0x1;
542pub const ATE_boolean = 0x2;
543pub const ATE_complex_float = 0x3;
544pub const ATE_float = 0x4;
545pub const ATE_signed = 0x5;
546pub const ATE_signed_char = 0x6;
547pub const ATE_unsigned = 0x7;
548pub const ATE_unsigned_char = 0x8;
549
550// DWARF 3.
551pub const ATE_imaginary_float = 0x9;
552pub const ATE_packed_decimal = 0xa;
553pub const ATE_numeric_string = 0xb;
554pub const ATE_edited = 0xc;
555pub const ATE_signed_fixed = 0xd;
556pub const ATE_unsigned_fixed = 0xe;
557pub const ATE_decimal_float = 0xf;
558
559// DWARF 4.
560pub const ATE_UTF = 0x10;
561
562pub const ATE_lo_user = 0x80;
563pub const ATE_hi_user = 0xff;
564
565// HP extensions.
566pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit).
567pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit).
568pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit).
569pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit).
570pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64).
571pub const ATE_HP_imaginary_float80 = 0x85;
572pub const ATE_HP_imaginary_float128 = 0x86;
573pub const ATE_HP_VAX_float = 0x88; // F or G floating.
574pub const ATE_HP_VAX_float_d = 0x89; // D floating.
575pub const ATE_HP_packed_decimal = 0x8a; // Cobol.
576pub const ATE_HP_zoned_decimal = 0x8b; // Cobol.
577pub const ATE_HP_edited = 0x8c; // Cobol.
578pub const ATE_HP_signed_fixed = 0x8d; // Cobol.
579pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
580pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
581pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
582
583pub const CFA_advance_loc = 0x40;
584pub const CFA_offset = 0x80;
585pub const CFA_restore = 0xc0;
586pub const CFA_nop = 0x00;
587pub const CFA_set_loc = 0x01;
588pub const CFA_advance_loc1 = 0x02;
589pub const CFA_advance_loc2 = 0x03;
590pub const CFA_advance_loc4 = 0x04;
591pub const CFA_offset_extended = 0x05;
592pub const CFA_restore_extended = 0x06;
593pub const CFA_undefined = 0x07;
594pub const CFA_same_value = 0x08;
595pub const CFA_register = 0x09;
596pub const CFA_remember_state = 0x0a;
597pub const CFA_restore_state = 0x0b;
598pub const CFA_def_cfa = 0x0c;
599pub const CFA_def_cfa_register = 0x0d;
600pub const CFA_def_cfa_offset = 0x0e;
601
602// DWARF 3.
603pub const CFA_def_cfa_expression = 0x0f;
604pub const CFA_expression = 0x10;
605pub const CFA_offset_extended_sf = 0x11;
606pub const CFA_def_cfa_sf = 0x12;
607pub const CFA_def_cfa_offset_sf = 0x13;
608pub const CFA_val_offset = 0x14;
609pub const CFA_val_offset_sf = 0x15;
610pub const CFA_val_expression = 0x16;
611
612pub const CFA_lo_user = 0x1c;
613pub const CFA_hi_user = 0x3f;
614
615// SGI/MIPS specific.
616pub const CFA_MIPS_advance_loc8 = 0x1d;
617
618// GNU extensions.
619pub const CFA_GNU_window_save = 0x2d;
620pub const CFA_GNU_args_size = 0x2e;
621pub const CFA_GNU_negative_offset_extended = 0x2f;
622
623pub const CHILDREN_no = 0x00;
624pub const CHILDREN_yes = 0x01;
625
626pub const LNS_extended_op = 0x00;
627pub const LNS_copy = 0x01;
628pub const LNS_advance_pc = 0x02;
629pub const LNS_advance_line = 0x03;
630pub const LNS_set_file = 0x04;
631pub const LNS_set_column = 0x05;
632pub const LNS_negate_stmt = 0x06;
633pub const LNS_set_basic_block = 0x07;
634pub const LNS_const_add_pc = 0x08;
635pub const LNS_fixed_advance_pc = 0x09;
636pub const LNS_set_prologue_end = 0x0a;
637pub const LNS_set_epilogue_begin = 0x0b;
638pub const LNS_set_isa = 0x0c;
639
640pub const LNE_end_sequence = 0x01;
641pub const LNE_set_address = 0x02;
642pub const LNE_define_file = 0x03;
643pub const LNE_set_discriminator = 0x04;
644pub const LNE_lo_user = 0x80;
645pub const LNE_hi_user = 0xff;
646
647pub const LANG_C89 = 0x0001;
648pub const LANG_C = 0x0002;
649pub const LANG_Ada83 = 0x0003;
650pub const LANG_C_plus_plus = 0x0004;
651pub const LANG_Cobol74 = 0x0005;
652pub const LANG_Cobol85 = 0x0006;
653pub const LANG_Fortran77 = 0x0007;
654pub const LANG_Fortran90 = 0x0008;
655pub const LANG_Pascal83 = 0x0009;
656pub const LANG_Modula2 = 0x000a;
657pub const LANG_Java = 0x000b;
658pub const LANG_C99 = 0x000c;
659pub const LANG_Ada95 = 0x000d;
660pub const LANG_Fortran95 = 0x000e;
661pub const LANG_PLI = 0x000f;
662pub const LANG_ObjC = 0x0010;
663pub const LANG_ObjC_plus_plus = 0x0011;
664pub const LANG_UPC = 0x0012;
665pub const LANG_D = 0x0013;
666pub const LANG_Python = 0x0014;
667pub const LANG_Go = 0x0016;
668pub const LANG_C_plus_plus_11 = 0x001a;
669pub const LANG_Rust = 0x001c;
670pub const LANG_C11 = 0x001d;
671pub const LANG_C_plus_plus_14 = 0x0021;
672pub const LANG_Fortran03 = 0x0022;
673pub const LANG_Fortran08 = 0x0023;
674pub const LANG_lo_user = 0x8000;
675pub const LANG_hi_user = 0xffff;
676pub const LANG_Mips_Assembler = 0x8001;
677pub const LANG_Upc = 0x8765;
678pub const LANG_HP_Bliss = 0x8003;
679pub const LANG_HP_Basic91 = 0x8004;
680pub const LANG_HP_Pascal91 = 0x8005;
681pub const LANG_HP_IMacro = 0x8006;
682pub const LANG_HP_Assembler = 0x8007;
lib/std/dynamic_library.zig+4-4
...@@ -11,7 +11,7 @@ const system = std.os.system;...@@ -11,7 +11,7 @@ const system = std.os.system;
11const maxInt = std.math.maxInt;11const maxInt = std.math.maxInt;
12const max = std.math.max;12const max = std.math.max;
1313
14pub const DynLib = switch (builtin.os) {14pub const DynLib = switch (builtin.os.tag) {
15 .linux => if (builtin.link_libc) DlDynlib else ElfDynLib,15 .linux => if (builtin.link_libc) DlDynlib else ElfDynLib,
16 .windows => WindowsDynLib,16 .windows => WindowsDynLib,
17 .macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib,17 .macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib,
...@@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {...@@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
82 for (dyn_table) |*dyn| {82 for (dyn_table) |*dyn| {
83 switch (dyn.d_tag) {83 switch (dyn.d_tag) {
84 elf.DT_DEBUG => {84 elf.DT_DEBUG => {
85 const r_debug = @intToPtr(*RDebug, dyn.d_un.d_ptr);85 const r_debug = @intToPtr(*RDebug, dyn.d_val);
86 if (r_debug.r_version != 1) return error.InvalidExe;86 if (r_debug.r_version != 1) return error.InvalidExe;
87 break :init r_debug.r_map;87 break :init r_debug.r_map;
88 },88 },
89 elf.DT_PLTGOT => {89 elf.DT_PLTGOT => {
90 const got_table = @intToPtr([*]usize, dyn.d_un.d_ptr);90 const got_table = @intToPtr([*]usize, dyn.d_val);
91 // The address to the link_map structure is stored in the91 // The address to the link_map structure is stored in the
92 // second slot92 // second slot
93 break :init @intToPtr(?*LinkMap, got_table[1]);93 break :init @intToPtr(?*LinkMap, got_table[1]);
...@@ -390,7 +390,7 @@ pub const DlDynlib = struct {...@@ -390,7 +390,7 @@ pub const DlDynlib = struct {
390};390};
391391
392test "dynamic_library" {392test "dynamic_library" {
393 const libname = switch (builtin.os) {393 const libname = switch (builtin.os.tag) {
394 .linux, .freebsd => "invalid_so.so",394 .linux, .freebsd => "invalid_so.so",
395 .windows => "invalid_dll.dll",395 .windows => "invalid_dll.dll",
396 .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib",396 .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib",
lib/std/elf.zig+19-20
...@@ -349,16 +349,6 @@ pub const Elf = struct {...@@ -349,16 +349,6 @@ pub const Elf = struct {
349 program_headers: []ProgramHeader,349 program_headers: []ProgramHeader,
350 allocator: *mem.Allocator,350 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
362 pub fn openStream(352 pub fn openStream(
363 allocator: *mem.Allocator,353 allocator: *mem.Allocator,
364 seekable_stream: *io.SeekableStream(anyerror, anyerror),354 seekable_stream: *io.SeekableStream(anyerror, anyerror),
...@@ -380,8 +370,8 @@ pub const Elf = struct {...@@ -380,8 +370,8 @@ pub const Elf = struct {
380 };370 };
381371
382 elf.endian = switch (try in.readByte()) {372 elf.endian = switch (try in.readByte()) {
383 1 => builtin.Endian.Little,373 1 => .Little,
384 2 => builtin.Endian.Big,374 2 => .Big,
385 else => return error.InvalidFormat,375 else => return error.InvalidFormat,
386 };376 };
387377
...@@ -554,6 +544,21 @@ pub const Elf = struct {...@@ -554,6 +544,21 @@ pub const Elf = struct {
554};544};
555545
556pub const EI_NIDENT = 16;546pub 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
557pub const Elf32_Half = u16;562pub const Elf32_Half = u16;
558pub const Elf64_Half = u16;563pub const Elf64_Half = u16;
559pub const Elf32_Word = u32;564pub const Elf32_Word = u32;
...@@ -703,17 +708,11 @@ pub const Elf64_Rela = extern struct {...@@ -703,17 +708,11 @@ pub const Elf64_Rela = extern struct {
703};708};
704pub const Elf32_Dyn = extern struct {709pub const Elf32_Dyn = extern struct {
705 d_tag: Elf32_Sword,710 d_tag: Elf32_Sword,
706 d_un: extern union {711 d_val: Elf32_Addr,
707 d_val: Elf32_Word,
708 d_ptr: Elf32_Addr,
709 },
710};712};
711pub const Elf64_Dyn = extern struct {713pub const Elf64_Dyn = extern struct {
712 d_tag: Elf64_Sxword,714 d_tag: Elf64_Sxword,
713 d_un: extern union {715 d_val: Elf64_Addr,
714 d_val: Elf64_Xword,
715 d_ptr: Elf64_Addr,
716 },
717};716};
718pub const Elf32_Verdef = extern struct {717pub const Elf32_Verdef = extern struct {
719 vd_version: Elf32_Half,718 vd_version: Elf32_Half,
lib/std/event/channel.zig+1-1
...@@ -273,7 +273,7 @@ test "std.event.Channel" {...@@ -273,7 +273,7 @@ test "std.event.Channel" {
273 if (builtin.single_threaded) return error.SkipZigTest;273 if (builtin.single_threaded) return error.SkipZigTest;
274274
275 // https://github.com/ziglang/zig/issues/3251275 // 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
278 var channel: Channel(i32) = undefined;278 var channel: Channel(i32) = undefined;
279 channel.init(&[0]i32{});279 channel.init(&[0]i32{});
lib/std/event/future.zig+1-1
...@@ -86,7 +86,7 @@ test "std.event.Future" {...@@ -86,7 +86,7 @@ test "std.event.Future" {
86 // https://github.com/ziglang/zig/issues/190886 // https://github.com/ziglang/zig/issues/1908
87 if (builtin.single_threaded) return error.SkipZigTest;87 if (builtin.single_threaded) return error.SkipZigTest;
88 // https://github.com/ziglang/zig/issues/325188 // https://github.com/ziglang/zig/issues/3251
89 if (builtin.os == .freebsd) return error.SkipZigTest;89 if (builtin.os.tag == .freebsd) return error.SkipZigTest;
90 // TODO provide a way to run tests in evented I/O mode90 // TODO provide a way to run tests in evented I/O mode
91 if (!std.io.is_async) return error.SkipZigTest;91 if (!std.io.is_async) return error.SkipZigTest;
9292
lib/std/event/lock.zig+1-1
...@@ -123,7 +123,7 @@ test "std.event.Lock" {...@@ -123,7 +123,7 @@ test "std.event.Lock" {
123 if (builtin.single_threaded) return error.SkipZigTest;123 if (builtin.single_threaded) return error.SkipZigTest;
124124
125 // TODO https://github.com/ziglang/zig/issues/3251125 // 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
128 var lock = Lock.init();128 var lock = Lock.init();
129 defer lock.deinit();129 defer lock.deinit();
lib/std/event/loop.zig+13-13
...@@ -34,7 +34,7 @@ pub const Loop = struct {...@@ -34,7 +34,7 @@ pub const Loop = struct {
34 handle: anyframe,34 handle: anyframe,
35 overlapped: Overlapped,35 overlapped: Overlapped,
3636
37 pub const overlapped_init = switch (builtin.os) {37 pub const overlapped_init = switch (builtin.os.tag) {
38 .windows => windows.OVERLAPPED{38 .windows => windows.OVERLAPPED{
39 .Internal = 0,39 .Internal = 0,
40 .InternalHigh = 0,40 .InternalHigh = 0,
...@@ -52,7 +52,7 @@ pub const Loop = struct {...@@ -52,7 +52,7 @@ pub const Loop = struct {
52 EventFd,52 EventFd,
53 };53 };
5454
55 pub const EventFd = switch (builtin.os) {55 pub const EventFd = switch (builtin.os.tag) {
56 .macosx, .freebsd, .netbsd, .dragonfly => KEventFd,56 .macosx, .freebsd, .netbsd, .dragonfly => KEventFd,
57 .linux => struct {57 .linux => struct {
58 base: ResumeNode,58 base: ResumeNode,
...@@ -71,7 +71,7 @@ pub const Loop = struct {...@@ -71,7 +71,7 @@ pub const Loop = struct {
71 kevent: os.Kevent,71 kevent: os.Kevent,
72 };72 };
7373
74 pub const Basic = switch (builtin.os) {74 pub const Basic = switch (builtin.os.tag) {
75 .macosx, .freebsd, .netbsd, .dragonfly => KEventBasic,75 .macosx, .freebsd, .netbsd, .dragonfly => KEventBasic,
76 .linux => struct {76 .linux => struct {
77 base: ResumeNode,77 base: ResumeNode,
...@@ -173,7 +173,7 @@ pub const Loop = struct {...@@ -173,7 +173,7 @@ pub const Loop = struct {
173 const wakeup_bytes = [_]u8{0x1} ** 8;173 const wakeup_bytes = [_]u8{0x1} ** 8;
174174
175 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {175 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
176 switch (builtin.os) {176 switch (builtin.os.tag) {
177 .linux => {177 .linux => {
178 self.os_data.fs_queue = std.atomic.Queue(Request).init();178 self.os_data.fs_queue = std.atomic.Queue(Request).init();
179 self.os_data.fs_queue_item = 0;179 self.os_data.fs_queue_item = 0;
...@@ -404,7 +404,7 @@ pub const Loop = struct {...@@ -404,7 +404,7 @@ pub const Loop = struct {
404 }404 }
405405
406 fn deinitOsData(self: *Loop) void {406 fn deinitOsData(self: *Loop) void {
407 switch (builtin.os) {407 switch (builtin.os.tag) {
408 .linux => {408 .linux => {
409 noasync os.close(self.os_data.final_eventfd);409 noasync os.close(self.os_data.final_eventfd);
410 while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);410 while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);
...@@ -568,7 +568,7 @@ pub const Loop = struct {...@@ -568,7 +568,7 @@ pub const Loop = struct {
568 };568 };
569 const eventfd_node = &resume_stack_node.data;569 const eventfd_node = &resume_stack_node.data;
570 eventfd_node.base.handle = next_tick_node.data;570 eventfd_node.base.handle = next_tick_node.data;
571 switch (builtin.os) {571 switch (builtin.os.tag) {
572 .macosx, .freebsd, .netbsd, .dragonfly => {572 .macosx, .freebsd, .netbsd, .dragonfly => {
573 const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent);573 const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent);
574 const empty_kevs = &[0]os.Kevent{};574 const empty_kevs = &[0]os.Kevent{};
...@@ -628,7 +628,7 @@ pub const Loop = struct {...@@ -628,7 +628,7 @@ pub const Loop = struct {
628628
629 self.workerRun();629 self.workerRun();
630630
631 switch (builtin.os) {631 switch (builtin.os.tag) {
632 .linux,632 .linux,
633 .macosx,633 .macosx,
634 .freebsd,634 .freebsd,
...@@ -678,7 +678,7 @@ pub const Loop = struct {...@@ -678,7 +678,7 @@ pub const Loop = struct {
678 const prev = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);678 const prev = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
679 if (prev == 1) {679 if (prev == 1) {
680 // cause all the threads to stop680 // cause all the threads to stop
681 switch (builtin.os) {681 switch (builtin.os.tag) {
682 .linux => {682 .linux => {
683 self.posixFsRequest(&self.os_data.fs_end_request);683 self.posixFsRequest(&self.os_data.fs_end_request);
684 // writing 8 bytes to an eventfd cannot fail684 // writing 8 bytes to an eventfd cannot fail
...@@ -902,7 +902,7 @@ pub const Loop = struct {...@@ -902,7 +902,7 @@ pub const Loop = struct {
902 self.finishOneEvent();902 self.finishOneEvent();
903 }903 }
904904
905 switch (builtin.os) {905 switch (builtin.os.tag) {
906 .linux => {906 .linux => {
907 // only process 1 event so we don't steal from other threads907 // only process 1 event so we don't steal from other threads
908 var events: [1]os.linux.epoll_event = undefined;908 var events: [1]os.linux.epoll_event = undefined;
...@@ -989,7 +989,7 @@ pub const Loop = struct {...@@ -989,7 +989,7 @@ pub const Loop = struct {
989 fn posixFsRequest(self: *Loop, request_node: *Request.Node) void {989 fn posixFsRequest(self: *Loop, request_node: *Request.Node) void {
990 self.beginOneEvent(); // finished in posixFsRun after processing the msg990 self.beginOneEvent(); // finished in posixFsRun after processing the msg
991 self.os_data.fs_queue.put(request_node);991 self.os_data.fs_queue.put(request_node);
992 switch (builtin.os) {992 switch (builtin.os.tag) {
993 .macosx, .freebsd, .netbsd, .dragonfly => {993 .macosx, .freebsd, .netbsd, .dragonfly => {
994 const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wake);994 const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wake);
995 const empty_kevs = &[0]os.Kevent{};995 const empty_kevs = &[0]os.Kevent{};
...@@ -1018,7 +1018,7 @@ pub const Loop = struct {...@@ -1018,7 +1018,7 @@ pub const Loop = struct {
1018 // https://github.com/ziglang/zig/issues/31571018 // https://github.com/ziglang/zig/issues/3157
1019 fn posixFsRun(self: *Loop) void {1019 fn posixFsRun(self: *Loop) void {
1020 while (true) {1020 while (true) {
1021 if (builtin.os == .linux) {1021 if (builtin.os.tag == .linux) {
1022 @atomicStore(i32, &self.os_data.fs_queue_item, 0, .SeqCst);1022 @atomicStore(i32, &self.os_data.fs_queue_item, 0, .SeqCst);
1023 }1023 }
1024 while (self.os_data.fs_queue.get()) |node| {1024 while (self.os_data.fs_queue.get()) |node| {
...@@ -1053,7 +1053,7 @@ pub const Loop = struct {...@@ -1053,7 +1053,7 @@ pub const Loop = struct {
1053 }1053 }
1054 self.finishOneEvent();1054 self.finishOneEvent();
1055 }1055 }
1056 switch (builtin.os) {1056 switch (builtin.os.tag) {
1057 .linux => {1057 .linux => {
1058 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);1058 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
1059 switch (os.linux.getErrno(rc)) {1059 switch (os.linux.getErrno(rc)) {
...@@ -1071,7 +1071,7 @@ pub const Loop = struct {...@@ -1071,7 +1071,7 @@ pub const Loop = struct {
1071 }1071 }
1072 }1072 }
10731073
1074 const OsData = switch (builtin.os) {1074 const OsData = switch (builtin.os.tag) {
1075 .linux => LinuxOsData,1075 .linux => LinuxOsData,
1076 .macosx, .freebsd, .netbsd, .dragonfly => KEventData,1076 .macosx, .freebsd, .netbsd, .dragonfly => KEventData,
1077 .windows => struct {1077 .windows => struct {
lib/std/fmt.zig+6-6
...@@ -414,10 +414,9 @@ pub fn formatType(...@@ -414,10 +414,9 @@ pub fn formatType(
414 if (max_depth == 0) {414 if (max_depth == 0) {
415 return output(context, "{ ... }");415 return output(context, "{ ... }");
416 }416 }
417 comptime var field_i = 0;
418 try output(context, "{");417 try output(context, "{");
419 inline for (StructT.fields) |f| {418 inline for (StructT.fields) |f, i| {
420 if (field_i == 0) {419 if (i == 0) {
421 try output(context, " .");420 try output(context, " .");
422 } else {421 } else {
423 try output(context, ", .");422 try output(context, ", .");
...@@ -425,7 +424,6 @@ pub fn formatType(...@@ -425,7 +424,6 @@ pub fn formatType(
425 try output(context, f.name);424 try output(context, f.name);
426 try output(context, " = ");425 try output(context, " = ");
427 try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);426 try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
428 field_i += 1;
429 }427 }
430 try output(context, " }");428 try output(context, " }");
431 },429 },
...@@ -443,10 +441,12 @@ pub fn formatType(...@@ -443,10 +441,12 @@ pub fn formatType(
443 else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),441 else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
444 },442 },
445 .Many, .C => {443 .Many, .C => {
444 if (ptr_info.sentinel) |sentinel| {
445 return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
446 }
446 if (ptr_info.child == u8) {447 if (ptr_info.child == u8) {
447 if (fmt.len > 0 and fmt[0] == 's') {448 if (fmt.len > 0 and fmt[0] == 's') {
448 const len = mem.len(u8, value);449 return formatText(mem.span(value), fmt, options, context, Errors, output);
449 return formatText(value[0..len], fmt, options, context, Errors, output);
450 }450 }
451 }451 }
452 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });452 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
lib/std/fs.zig+32-25
...@@ -29,7 +29,7 @@ pub const Watch = @import("fs/watch.zig").Watch;...@@ -29,7 +29,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
29/// All file system operations which return a path are guaranteed to29/// All file system operations which return a path are guaranteed to
30/// fit into a UTF-8 encoded array of this length.30/// fit into a UTF-8 encoded array of this length.
31/// The byte count includes room for a null sentinel byte.31/// 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) {
33 .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX,33 .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX,
34 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.34 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
35 // If it would require 4 UTF-8 bytes, then there would be a surrogate35 // 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(...@@ -47,7 +47,7 @@ pub const base64_encoder = base64.Base64Encoder.init(
4747
48/// Whether or not async file system syscalls need a dedicated thread because the operating48/// Whether or not async file system syscalls need a dedicated thread because the operating
49/// system does not support non-blocking I/O on the file system.49/// 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) {
51 .windows, .other => false,51 .windows, .other => false,
52 else => true,52 else => true,
53};53};
...@@ -270,7 +270,7 @@ pub const AtomicFile = struct {...@@ -270,7 +270,7 @@ pub const AtomicFile = struct {
270 assert(!self.finished);270 assert(!self.finished);
271 self.file.close();271 self.file.close();
272 self.finished = true;272 self.finished = true;
273 if (builtin.os == .windows) {273 if (builtin.os.tag == .windows) {
274 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);274 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
275 const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));275 const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));
276 return os.renameW(&tmp_path_w, &dest_path_w);276 return os.renameW(&tmp_path_w, &dest_path_w);
...@@ -394,7 +394,7 @@ pub const Dir = struct {...@@ -394,7 +394,7 @@ pub const Dir = struct {
394394
395 const IteratorError = error{AccessDenied} || os.UnexpectedError;395 const IteratorError = error{AccessDenied} || os.UnexpectedError;
396396
397 pub const Iterator = switch (builtin.os) {397 pub const Iterator = switch (builtin.os.tag) {
398 .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct {398 .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct {
399 dir: Dir,399 dir: Dir,
400 seek: i64,400 seek: i64,
...@@ -409,7 +409,7 @@ pub const Dir = struct {...@@ -409,7 +409,7 @@ pub const Dir = struct {
409 /// Memory such as file names referenced in this returned entry becomes invalid409 /// Memory such as file names referenced in this returned entry becomes invalid
410 /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.410 /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
411 pub fn next(self: *Self) Error!?Entry {411 pub fn next(self: *Self) Error!?Entry {
412 switch (builtin.os) {412 switch (builtin.os.tag) {
413 .macosx, .ios => return self.nextDarwin(),413 .macosx, .ios => return self.nextDarwin(),
414 .freebsd, .netbsd, .dragonfly => return self.nextBsd(),414 .freebsd, .netbsd, .dragonfly => return self.nextBsd(),
415 else => @compileError("unimplemented"),415 else => @compileError("unimplemented"),
...@@ -644,7 +644,7 @@ pub const Dir = struct {...@@ -644,7 +644,7 @@ pub const Dir = struct {
644 };644 };
645645
646 pub fn iterate(self: Dir) Iterator {646 pub fn iterate(self: Dir) Iterator {
647 switch (builtin.os) {647 switch (builtin.os.tag) {
648 .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{648 .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{
649 .dir = self,649 .dir = self,
650 .seek = 0,650 .seek = 0,
...@@ -710,7 +710,7 @@ pub const Dir = struct {...@@ -710,7 +710,7 @@ pub const Dir = struct {
710 /// Asserts that the path parameter has no null bytes.710 /// Asserts that the path parameter has no null bytes.
711 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {711 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
712 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);712 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
713 if (builtin.os == .windows) {713 if (builtin.os.tag == .windows) {
714 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);714 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
715 return self.openFileW(&path_w, flags);715 return self.openFileW(&path_w, flags);
716 }716 }
...@@ -720,7 +720,7 @@ pub const Dir = struct {...@@ -720,7 +720,7 @@ pub const Dir = struct {
720720
721 /// Same as `openFile` but the path parameter is null-terminated.721 /// Same as `openFile` but the path parameter is null-terminated.
722 pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {722 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) {
724 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);724 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
725 return self.openFileW(&path_w, flags);725 return self.openFileW(&path_w, flags);
726 }726 }
...@@ -731,11 +731,18 @@ pub const Dir = struct {...@@ -731,11 +731,18 @@ pub const Dir = struct {
731 @as(u32, os.O_WRONLY)731 @as(u32, os.O_WRONLY)
732 else732 else
733 @as(u32, os.O_RDONLY);733 @as(u32, os.O_RDONLY);
734 const fd = if (need_async_thread)734 const fd = if (need_async_thread and !flags.always_blocking)
735 try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0)735 try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0)
736 else736 else
737 try os.openatC(self.fd, sub_path, os_flags, 0);737 try os.openatC(self.fd, sub_path, os_flags, 0);
738 return File{ .handle = fd, .io_mode = .blocking };738 return File{
739 .handle = fd,
740 .io_mode = .blocking,
741 .async_block_allowed = if (flags.always_blocking)
742 File.async_block_allowed_yes
743 else
744 File.async_block_allowed_no,
745 };
739 }746 }
740747
741 /// Same as `openFile` but Windows-only and the path parameter is748 /// Same as `openFile` but Windows-only and the path parameter is
...@@ -753,7 +760,7 @@ pub const Dir = struct {...@@ -753,7 +760,7 @@ pub const Dir = struct {
753 /// Asserts that the path parameter has no null bytes.760 /// Asserts that the path parameter has no null bytes.
754 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {761 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
755 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);762 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
756 if (builtin.os == .windows) {763 if (builtin.os.tag == .windows) {
757 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);764 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
758 return self.createFileW(&path_w, flags);765 return self.createFileW(&path_w, flags);
759 }766 }
...@@ -763,7 +770,7 @@ pub const Dir = struct {...@@ -763,7 +770,7 @@ pub const Dir = struct {
763770
764 /// Same as `createFile` but the path parameter is null-terminated.771 /// Same as `createFile` but the path parameter is null-terminated.
765 pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {772 pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
766 if (builtin.os == .windows) {773 if (builtin.os.tag == .windows) {
767 const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);774 const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
768 return self.createFileW(&path_w, flags);775 return self.createFileW(&path_w, flags);
769 }776 }
...@@ -894,7 +901,7 @@ pub const Dir = struct {...@@ -894,7 +901,7 @@ pub const Dir = struct {
894 /// Asserts that the path parameter has no null bytes.901 /// Asserts that the path parameter has no null bytes.
895 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {902 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
896 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);903 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
897 if (builtin.os == .windows) {904 if (builtin.os.tag == .windows) {
898 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);905 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
899 return self.openDirTraverseW(&sub_path_w);906 return self.openDirTraverseW(&sub_path_w);
900 }907 }
...@@ -912,7 +919,7 @@ pub const Dir = struct {...@@ -912,7 +919,7 @@ pub const Dir = struct {
912 /// Asserts that the path parameter has no null bytes.919 /// Asserts that the path parameter has no null bytes.
913 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {920 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {
914 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);921 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
915 if (builtin.os == .windows) {922 if (builtin.os.tag == .windows) {
916 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);923 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
917 return self.openDirListW(&sub_path_w);924 return self.openDirListW(&sub_path_w);
918 }925 }
...@@ -923,7 +930,7 @@ pub const Dir = struct {...@@ -923,7 +930,7 @@ pub const Dir = struct {
923930
924 /// Same as `openDirTraverse` except the parameter is null-terminated.931 /// Same as `openDirTraverse` except the parameter is null-terminated.
925 pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {932 pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
926 if (builtin.os == .windows) {933 if (builtin.os.tag == .windows) {
927 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);934 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
928 return self.openDirTraverseW(&sub_path_w);935 return self.openDirTraverseW(&sub_path_w);
929 } else {936 } else {
...@@ -934,7 +941,7 @@ pub const Dir = struct {...@@ -934,7 +941,7 @@ pub const Dir = struct {
934941
935 /// Same as `openDirList` except the parameter is null-terminated.942 /// Same as `openDirList` except the parameter is null-terminated.
936 pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {943 pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
937 if (builtin.os == .windows) {944 if (builtin.os.tag == .windows) {
938 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);945 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
939 return self.openDirListW(&sub_path_w);946 return self.openDirListW(&sub_path_w);
940 } else {947 } else {
...@@ -1076,7 +1083,7 @@ pub const Dir = struct {...@@ -1076,7 +1083,7 @@ pub const Dir = struct {
1076 /// Asserts that the path parameter has no null bytes.1083 /// Asserts that the path parameter has no null bytes.
1077 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {1084 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
1078 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);1085 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
1079 if (builtin.os == .windows) {1086 if (builtin.os.tag == .windows) {
1080 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1087 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1081 return self.deleteDirW(&sub_path_w);1088 return self.deleteDirW(&sub_path_w);
1082 }1089 }
...@@ -1333,7 +1340,7 @@ pub const Dir = struct {...@@ -1333,7 +1340,7 @@ pub const Dir = struct {
1333 /// For example, instead of testing if a file exists and then opening it, just1340 /// For example, instead of testing if a file exists and then opening it, just
1334 /// open it and handle the error for file not found.1341 /// open it and handle the error for file not found.
1335 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {1342 pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
1336 if (builtin.os == .windows) {1343 if (builtin.os.tag == .windows) {
1337 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1344 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
1338 return self.accessW(&sub_path_w, flags);1345 return self.accessW(&sub_path_w, flags);
1339 }1346 }
...@@ -1343,7 +1350,7 @@ pub const Dir = struct {...@@ -1343,7 +1350,7 @@ pub const Dir = struct {
13431350
1344 /// Same as `access` except the path parameter is null-terminated.1351 /// Same as `access` except the path parameter is null-terminated.
1345 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {1352 pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
1346 if (builtin.os == .windows) {1353 if (builtin.os.tag == .windows) {
1347 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);1354 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
1348 return self.accessW(&sub_path_w, flags);1355 return self.accessW(&sub_path_w, flags);
1349 }1356 }
...@@ -1374,7 +1381,7 @@ pub const Dir = struct {...@@ -1374,7 +1381,7 @@ pub const Dir = struct {
1374/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.1381/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
1375/// On POSIX targets, this function is comptime-callable.1382/// On POSIX targets, this function is comptime-callable.
1376pub fn cwd() Dir {1383pub fn cwd() Dir {
1377 if (builtin.os == .windows) {1384 if (builtin.os.tag == .windows) {
1378 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };1385 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
1379 } else {1386 } else {
1380 return Dir{ .fd = os.AT_FDCWD };1387 return Dir{ .fd = os.AT_FDCWD };
...@@ -1553,10 +1560,10 @@ pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {...@@ -1553,10 +1560,10 @@ pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
1553pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;1560pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;
15541561
1555pub fn openSelfExe() OpenSelfExeError!File {1562pub fn openSelfExe() OpenSelfExeError!File {
1556 if (builtin.os == .linux) {1563 if (builtin.os.tag == .linux) {
1557 return openFileAbsoluteC("/proc/self/exe", .{});1564 return openFileAbsoluteC("/proc/self/exe", .{});
1558 }1565 }
1559 if (builtin.os == .windows) {1566 if (builtin.os.tag == .windows) {
1560 const wide_slice = selfExePathW();1567 const wide_slice = selfExePathW();
1561 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);1568 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
1562 return cwd().openReadW(&prefixed_path_w);1569 return cwd().openReadW(&prefixed_path_w);
...@@ -1568,7 +1575,7 @@ pub fn openSelfExe() OpenSelfExeError!File {...@@ -1568,7 +1575,7 @@ pub fn openSelfExe() OpenSelfExeError!File {
1568}1575}
15691576
1570test "openSelfExe" {1577test "openSelfExe" {
1571 switch (builtin.os) {1578 switch (builtin.os.tag) {
1572 .linux, .macosx, .ios, .windows, .freebsd, .dragonfly => (try openSelfExe()).close(),1579 .linux, .macosx, .ios, .windows, .freebsd, .dragonfly => (try openSelfExe()).close(),
1573 else => return error.SkipZigTest, // Unsupported OS.1580 else => return error.SkipZigTest, // Unsupported OS.
1574 }1581 }
...@@ -1593,7 +1600,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {...@@ -1593,7 +1600,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
1593 if (rc != 0) return error.NameTooLong;1600 if (rc != 0) return error.NameTooLong;
1594 return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer));1601 return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer));
1595 }1602 }
1596 switch (builtin.os) {1603 switch (builtin.os.tag) {
1597 .linux => return os.readlinkC("/proc/self/exe", out_buffer),1604 .linux => return os.readlinkC("/proc/self/exe", out_buffer),
1598 .freebsd, .dragonfly => {1605 .freebsd, .dragonfly => {
1599 var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };1606 var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };
...@@ -1635,7 +1642,7 @@ pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {...@@ -1635,7 +1642,7 @@ pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
1635/// Get the directory path that contains the current executable.1642/// Get the directory path that contains the current executable.
1636/// Returned value is a slice of out_buffer.1643/// Returned value is a slice of out_buffer.
1637pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {1644pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {
1638 if (builtin.os == .linux) {1645 if (builtin.os.tag == .linux) {
1639 // If the currently executing binary has been deleted,1646 // If the currently executing binary has been deleted,
1640 // the file path looks something like `/a/b/c/exe (deleted)`1647 // the file path looks something like `/a/b/c/exe (deleted)`
1641 // This path cannot be opened, but it's valid for determining the directory1648 // This path cannot be opened, but it's valid for determining the directory
lib/std/fs/file.zig+12-7
...@@ -20,7 +20,7 @@ pub const File = struct {...@@ -20,7 +20,7 @@ pub const File = struct {
20 /// or, more specifically, whether the I/O is blocking.20 /// or, more specifically, whether the I/O is blocking.
21 io_mode: io.Mode,21 io_mode: io.Mode,
2222
23 /// Even when std.io.mode is async, it is still sometimes desirable to perform blocking I/O, although23 /// Even when 'std.io.mode' is async, it is still sometimes desirable to perform blocking I/O, although
24 /// not by default. For example, when printing a stack trace to stderr.24 /// not by default. For example, when printing a stack trace to stderr.
25 async_block_allowed: @TypeOf(async_block_allowed_no) = async_block_allowed_no,25 async_block_allowed: @TypeOf(async_block_allowed_no) = async_block_allowed_no,
2626
...@@ -29,7 +29,7 @@ pub const File = struct {...@@ -29,7 +29,7 @@ pub const File = struct {
2929
30 pub const Mode = os.mode_t;30 pub const Mode = os.mode_t;
3131
32 pub const default_mode = switch (builtin.os) {32 pub const default_mode = switch (builtin.os.tag) {
33 .windows => 0,33 .windows => 0,
34 else => 0o666,34 else => 0o666,
35 };35 };
...@@ -40,6 +40,11 @@ pub const File = struct {...@@ -40,6 +40,11 @@ pub const File = struct {
40 pub const OpenFlags = struct {40 pub const OpenFlags = struct {
41 read: bool = true,41 read: bool = true,
42 write: bool = false,42 write: bool = false,
43
44 /// This prevents `O_NONBLOCK` from being passed even if `std.io.is_async`.
45 /// It allows the use of `noasync` when calling functions related to opening
46 /// the file, reading, and writing.
47 always_blocking: bool = false,
43 };48 };
4449
45 /// TODO https://github.com/ziglang/zig/issues/380250 /// TODO https://github.com/ziglang/zig/issues/3802
...@@ -78,7 +83,7 @@ pub const File = struct {...@@ -78,7 +83,7 @@ pub const File = struct {
7883
79 /// Test whether ANSI escape codes will be treated as such.84 /// Test whether ANSI escape codes will be treated as such.
80 pub fn supportsAnsiEscapeCodes(self: File) bool {85 pub fn supportsAnsiEscapeCodes(self: File) bool {
81 if (builtin.os == .windows) {86 if (builtin.os.tag == .windows) {
82 return os.isCygwinPty(self.handle);87 return os.isCygwinPty(self.handle);
83 }88 }
84 if (self.isTty()) {89 if (self.isTty()) {
...@@ -123,7 +128,7 @@ pub const File = struct {...@@ -123,7 +128,7 @@ pub const File = struct {
123128
124 /// TODO: integrate with async I/O129 /// TODO: integrate with async I/O
125 pub fn getEndPos(self: File) GetPosError!u64 {130 pub fn getEndPos(self: File) GetPosError!u64 {
126 if (builtin.os == .windows) {131 if (builtin.os.tag == .windows) {
127 return windows.GetFileSizeEx(self.handle);132 return windows.GetFileSizeEx(self.handle);
128 }133 }
129 return (try self.stat()).size;134 return (try self.stat()).size;
...@@ -133,7 +138,7 @@ pub const File = struct {...@@ -133,7 +138,7 @@ pub const File = struct {
133138
134 /// TODO: integrate with async I/O139 /// TODO: integrate with async I/O
135 pub fn mode(self: File) ModeError!Mode {140 pub fn mode(self: File) ModeError!Mode {
136 if (builtin.os == .windows) {141 if (builtin.os.tag == .windows) {
137 return {};142 return {};
138 }143 }
139 return (try self.stat()).mode;144 return (try self.stat()).mode;
...@@ -157,7 +162,7 @@ pub const File = struct {...@@ -157,7 +162,7 @@ pub const File = struct {
157162
158 /// TODO: integrate with async I/O163 /// TODO: integrate with async I/O
159 pub fn stat(self: File) StatError!Stat {164 pub fn stat(self: File) StatError!Stat {
160 if (builtin.os == .windows) {165 if (builtin.os.tag == .windows) {
161 var io_status_block: windows.IO_STATUS_BLOCK = undefined;166 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
162 var info: windows.FILE_ALL_INFORMATION = undefined;167 var info: windows.FILE_ALL_INFORMATION = undefined;
163 const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);168 const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
...@@ -204,7 +209,7 @@ pub const File = struct {...@@ -204,7 +209,7 @@ pub const File = struct {
204 /// last modification timestamp in nanoseconds209 /// last modification timestamp in nanoseconds
205 mtime: i64,210 mtime: i64,
206 ) UpdateTimesError!void {211 ) UpdateTimesError!void {
207 if (builtin.os == .windows) {212 if (builtin.os.tag == .windows) {
208 const atime_ft = windows.nanoSecondsToFileTime(atime);213 const atime_ft = windows.nanoSecondsToFileTime(atime);
209 const mtime_ft = windows.nanoSecondsToFileTime(mtime);214 const mtime_ft = windows.nanoSecondsToFileTime(mtime);
210 return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);215 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{...@@ -13,7 +13,7 @@ pub const GetAppDataDirError = error{
13/// Caller owns returned memory.13/// Caller owns returned memory.
14/// TODO determine if we can remove the allocator requirement14/// TODO determine if we can remove the allocator requirement
15pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {15pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
16 switch (builtin.os) {16 switch (builtin.os.tag) {
17 .windows => {17 .windows => {
18 var dir_path_ptr: [*:0]u16 = undefined;18 var dir_path_ptr: [*:0]u16 = undefined;
19 switch (os.windows.shell32.SHGetKnownFolderPath(19 switch (os.windows.shell32.SHGetKnownFolderPath(
lib/std/fs/path.zig+19-19
...@@ -13,18 +13,18 @@ const process = std.process;...@@ -13,18 +13,18 @@ const process = std.process;
1313
14pub const sep_windows = '\\';14pub const sep_windows = '\\';
15pub const sep_posix = '/';15pub 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
18pub const sep_str_windows = "\\";18pub const sep_str_windows = "\\";
19pub const sep_str_posix = "/";19pub 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
22pub const delimiter_windows = ';';22pub const delimiter_windows = ';';
23pub const delimiter_posix = ':';23pub 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
26pub fn isSep(byte: u8) bool {26pub fn isSep(byte: u8) bool {
27 if (builtin.os == .windows) {27 if (builtin.os.tag == .windows) {
28 return byte == '/' or byte == '\\';28 return byte == '/' or byte == '\\';
29 } else {29 } else {
30 return byte == '/';30 return byte == '/';
...@@ -74,7 +74,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u...@@ -74,7 +74,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u
74 return buf;74 return buf;
75}75}
7676
77pub const join = if (builtin.os == .windows) joinWindows else joinPosix;77pub const join = if (builtin.os.tag == .windows) joinWindows else joinPosix;
7878
79/// Naively combines a series of paths with the native path seperator.79/// Naively combines a series of paths with the native path seperator.
80/// Allocates memory for the result, which must be freed by the caller.80/// Allocates memory for the result, which must be freed by the caller.
...@@ -129,7 +129,7 @@ test "join" {...@@ -129,7 +129,7 @@ test "join" {
129}129}
130130
131pub fn isAbsoluteC(path_c: [*:0]const u8) bool {131pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
132 if (builtin.os == .windows) {132 if (builtin.os.tag == .windows) {
133 return isAbsoluteWindowsC(path_c);133 return isAbsoluteWindowsC(path_c);
134 } else {134 } else {
135 return isAbsolutePosixC(path_c);135 return isAbsolutePosixC(path_c);
...@@ -137,7 +137,7 @@ pub fn isAbsoluteC(path_c: [*:0]const u8) bool {...@@ -137,7 +137,7 @@ pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
137}137}
138138
139pub fn isAbsolute(path: []const u8) bool {139pub fn isAbsolute(path: []const u8) bool {
140 if (builtin.os == .windows) {140 if (builtin.os.tag == .windows) {
141 return isAbsoluteWindows(path);141 return isAbsoluteWindows(path);
142 } else {142 } else {
143 return isAbsolutePosix(path);143 return isAbsolutePosix(path);
...@@ -318,7 +318,7 @@ test "windowsParsePath" {...@@ -318,7 +318,7 @@ test "windowsParsePath" {
318}318}
319319
320pub fn diskDesignator(path: []const u8) []const u8 {320pub fn diskDesignator(path: []const u8) []const u8 {
321 if (builtin.os == .windows) {321 if (builtin.os.tag == .windows) {
322 return diskDesignatorWindows(path);322 return diskDesignatorWindows(path);
323 } else {323 } else {
324 return "";324 return "";
...@@ -383,7 +383,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {...@@ -383,7 +383,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
383383
384/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.384/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
385pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {385pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
386 if (builtin.os == .windows) {386 if (builtin.os.tag == .windows) {
387 return resolveWindows(allocator, paths);387 return resolveWindows(allocator, paths);
388 } else {388 } else {
389 return resolvePosix(allocator, paths);389 return resolvePosix(allocator, paths);
...@@ -400,7 +400,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -400,7 +400,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
400/// Without performing actual syscalls, resolving `..` could be incorrect.400/// Without performing actual syscalls, resolving `..` could be incorrect.
401pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {401pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
402 if (paths.len == 0) {402 if (paths.len == 0) {
403 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd403 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
404 return process.getCwdAlloc(allocator);404 return process.getCwdAlloc(allocator);
405 }405 }
406406
...@@ -495,7 +495,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -495,7 +495,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
495 result_disk_designator = result[0..result_index];495 result_disk_designator = result[0..result_index];
496 },496 },
497 WindowsPath.Kind.None => {497 WindowsPath.Kind.None => {
498 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd498 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
499 const cwd = try process.getCwdAlloc(allocator);499 const cwd = try process.getCwdAlloc(allocator);
500 defer allocator.free(cwd);500 defer allocator.free(cwd);
501 const parsed_cwd = windowsParsePath(cwd);501 const parsed_cwd = windowsParsePath(cwd);
...@@ -510,7 +510,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -510,7 +510,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
510 },510 },
511 }511 }
512 } else {512 } else {
513 assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd513 assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
514 // TODO call get cwd for the result_disk_designator instead of the global one514 // TODO call get cwd for the result_disk_designator instead of the global one
515 const cwd = try process.getCwdAlloc(allocator);515 const cwd = try process.getCwdAlloc(allocator);
516 defer allocator.free(cwd);516 defer allocator.free(cwd);
...@@ -581,7 +581,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -581,7 +581,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
581/// Without performing actual syscalls, resolving `..` could be incorrect.581/// Without performing actual syscalls, resolving `..` could be incorrect.
582pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {582pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
583 if (paths.len == 0) {583 if (paths.len == 0) {
584 assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd584 assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
585 return process.getCwdAlloc(allocator);585 return process.getCwdAlloc(allocator);
586 }586 }
587587
...@@ -603,7 +603,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -603,7 +603,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
603 if (have_abs) {603 if (have_abs) {
604 result = try allocator.alloc(u8, max_size);604 result = try allocator.alloc(u8, max_size);
605 } else {605 } else {
606 assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd606 assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
607 const cwd = try process.getCwdAlloc(allocator);607 const cwd = try process.getCwdAlloc(allocator);
608 defer allocator.free(cwd);608 defer allocator.free(cwd);
609 result = try allocator.alloc(u8, max_size + cwd.len + 1);609 result = try allocator.alloc(u8, max_size + cwd.len + 1);
...@@ -645,7 +645,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {...@@ -645,7 +645,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
645test "resolve" {645test "resolve" {
646 const cwd = try process.getCwdAlloc(testing.allocator);646 const cwd = try process.getCwdAlloc(testing.allocator);
647 defer testing.allocator.free(cwd);647 defer testing.allocator.free(cwd);
648 if (builtin.os == .windows) {648 if (builtin.os.tag == .windows) {
649 if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {649 if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
650 cwd[0] = asciiUpper(cwd[0]);650 cwd[0] = asciiUpper(cwd[0]);
651 }651 }
...@@ -661,7 +661,7 @@ test "resolveWindows" {...@@ -661,7 +661,7 @@ test "resolveWindows" {
661 // TODO https://github.com/ziglang/zig/issues/3288661 // TODO https://github.com/ziglang/zig/issues/3288
662 return error.SkipZigTest;662 return error.SkipZigTest;
663 }663 }
664 if (builtin.os == .windows) {664 if (builtin.os.tag == .windows) {
665 const cwd = try process.getCwdAlloc(testing.allocator);665 const cwd = try process.getCwdAlloc(testing.allocator);
666 defer testing.allocator.free(cwd);666 defer testing.allocator.free(cwd);
667 const parsed_cwd = windowsParsePath(cwd);667 const parsed_cwd = windowsParsePath(cwd);
...@@ -732,7 +732,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {...@@ -732,7 +732,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {
732/// If the path is a file in the current directory (no directory component)732/// If the path is a file in the current directory (no directory component)
733/// then returns null733/// then returns null
734pub fn dirname(path: []const u8) ?[]const u8 {734pub fn dirname(path: []const u8) ?[]const u8 {
735 if (builtin.os == .windows) {735 if (builtin.os.tag == .windows) {
736 return dirnameWindows(path);736 return dirnameWindows(path);
737 } else {737 } else {
738 return dirnamePosix(path);738 return dirnamePosix(path);
...@@ -864,7 +864,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {...@@ -864,7 +864,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
864}864}
865865
866pub fn basename(path: []const u8) []const u8 {866pub fn basename(path: []const u8) []const u8 {
867 if (builtin.os == .windows) {867 if (builtin.os.tag == .windows) {
868 return basenameWindows(path);868 return basenameWindows(path);
869 } else {869 } else {
870 return basenamePosix(path);870 return basenamePosix(path);
...@@ -980,7 +980,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {...@@ -980,7 +980,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
980/// string is returned.980/// string is returned.
981/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.981/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
982pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {982pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
983 if (builtin.os == .windows) {983 if (builtin.os.tag == .windows) {
984 return relativeWindows(allocator, from, to);984 return relativeWindows(allocator, from, to);
985 } else {985 } else {
986 return relativePosix(allocator, from, to);986 return relativePosix(allocator, from, to);
lib/std/fs/watch.zig+4-4
...@@ -42,7 +42,7 @@ pub fn Watch(comptime V: type) type {...@@ -42,7 +42,7 @@ pub fn Watch(comptime V: type) type {
42 os_data: OsData,42 os_data: OsData,
43 allocator: *Allocator,43 allocator: *Allocator,
4444
45 const OsData = switch (builtin.os) {45 const OsData = switch (builtin.os.tag) {
46 // TODO https://github.com/ziglang/zig/issues/377846 // TODO https://github.com/ziglang/zig/issues/3778
47 .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,47 .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
48 .linux => LinuxOsData,48 .linux => LinuxOsData,
...@@ -121,7 +121,7 @@ pub fn Watch(comptime V: type) type {...@@ -121,7 +121,7 @@ pub fn Watch(comptime V: type) type {
121 const self = try allocator.create(Self);121 const self = try allocator.create(Self);
122 errdefer allocator.destroy(self);122 errdefer allocator.destroy(self);
123123
124 switch (builtin.os) {124 switch (builtin.os.tag) {
125 .linux => {125 .linux => {
126 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);126 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
127 errdefer os.close(inotify_fd);127 errdefer os.close(inotify_fd);
...@@ -172,7 +172,7 @@ pub fn Watch(comptime V: type) type {...@@ -172,7 +172,7 @@ pub fn Watch(comptime V: type) type {
172172
173 /// All addFile calls and removeFile calls must have completed.173 /// All addFile calls and removeFile calls must have completed.
174 pub fn deinit(self: *Self) void {174 pub fn deinit(self: *Self) void {
175 switch (builtin.os) {175 switch (builtin.os.tag) {
176 .macosx, .freebsd, .netbsd, .dragonfly => {176 .macosx, .freebsd, .netbsd, .dragonfly => {
177 // TODO we need to cancel the frames before destroying the lock177 // TODO we need to cancel the frames before destroying the lock
178 self.os_data.table_lock.deinit();178 self.os_data.table_lock.deinit();
...@@ -223,7 +223,7 @@ pub fn Watch(comptime V: type) type {...@@ -223,7 +223,7 @@ pub fn Watch(comptime V: type) type {
223 }223 }
224224
225 pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V {225 pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
226 switch (builtin.os) {226 switch (builtin.os.tag) {
227 .macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value),227 .macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value),
228 .linux => return addFileLinux(self, file_path, value),228 .linux => return addFileLinux(self, file_path, value),
229 .windows => return addFileWindows(self, file_path, value),229 .windows => return addFileWindows(self, file_path, value),
lib/std/hash/auto_hash.zig+3-5
...@@ -25,13 +25,13 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {...@@ -25,13 +25,13 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
25 const info = @typeInfo(@TypeOf(key));25 const info = @typeInfo(@TypeOf(key));
2626
27 switch (info.Pointer.size) {27 switch (info.Pointer.size) {
28 builtin.TypeInfo.Pointer.Size.One => switch (strat) {28 .One => switch (strat) {
29 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),29 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),
30 .Deep => hash(hasher, key.*, .Shallow),30 .Deep => hash(hasher, key.*, .Shallow),
31 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),31 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),
32 },32 },
3333
34 builtin.TypeInfo.Pointer.Size.Slice => switch (strat) {34 .Slice => switch (strat) {
35 .Shallow => {35 .Shallow => {
36 hashPointer(hasher, key.ptr, .Shallow);36 hashPointer(hasher, key.ptr, .Shallow);
37 hash(hasher, key.len, .Shallow);37 hash(hasher, key.len, .Shallow);
...@@ -40,9 +40,7 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {...@@ -40,9 +40,7 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
41 },41 },
4242
43 builtin.TypeInfo.Pointer.Size.Many,43 .Many, .C, => switch (strat) {
44 builtin.TypeInfo.Pointer.Size.C,
45 => switch (strat) {
46 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),44 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),
47 else => @compileError(45 else => @compileError(
48 \\ unknown-length pointers and C pointers cannot be hashed deeply.46 \\ unknown-length pointers and C pointers cannot be hashed deeply.
lib/std/hash/benchmark.zig+1-1
...@@ -168,7 +168,7 @@ fn usage() void {...@@ -168,7 +168,7 @@ fn usage() void {
168}168}
169169
170fn mode(comptime x: comptime_int) comptime_int {170fn mode(comptime x: comptime_int) comptime_int {
171 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;171 return if (builtin.mode == .Debug) x / 64 else x;
172}172}
173173
174pub fn main() !void {174pub fn main() !void {
lib/std/hash/cityhash.zig+4-4
...@@ -11,7 +11,7 @@ pub const CityHash32 = struct {...@@ -11,7 +11,7 @@ pub const CityHash32 = struct {
11 fn fetch32(ptr: [*]const u8) u32 {11 fn fetch32(ptr: [*]const u8) u32 {
12 var v: u32 = undefined;12 var v: u32 = undefined;
13 @memcpy(@ptrCast([*]u8, &v), ptr, 4);13 @memcpy(@ptrCast([*]u8, &v), ptr, 4);
14 if (builtin.endian == builtin.Endian.Big)14 if (builtin.endian == .Big)
15 return @byteSwap(u32, v);15 return @byteSwap(u32, v);
16 return v;16 return v;
17 }17 }
...@@ -174,7 +174,7 @@ pub const CityHash64 = struct {...@@ -174,7 +174,7 @@ pub const CityHash64 = struct {
174 fn fetch32(ptr: [*]const u8) u32 {174 fn fetch32(ptr: [*]const u8) u32 {
175 var v: u32 = undefined;175 var v: u32 = undefined;
176 @memcpy(@ptrCast([*]u8, &v), ptr, 4);176 @memcpy(@ptrCast([*]u8, &v), ptr, 4);
177 if (builtin.endian == builtin.Endian.Big)177 if (builtin.endian == .Big)
178 return @byteSwap(u32, v);178 return @byteSwap(u32, v);
179 return v;179 return v;
180 }180 }
...@@ -182,7 +182,7 @@ pub const CityHash64 = struct {...@@ -182,7 +182,7 @@ pub const CityHash64 = struct {
182 fn fetch64(ptr: [*]const u8) u64 {182 fn fetch64(ptr: [*]const u8) u64 {
183 var v: u64 = undefined;183 var v: u64 = undefined;
184 @memcpy(@ptrCast([*]u8, &v), ptr, 8);184 @memcpy(@ptrCast([*]u8, &v), ptr, 8);
185 if (builtin.endian == builtin.Endian.Big)185 if (builtin.endian == .Big)
186 return @byteSwap(u64, v);186 return @byteSwap(u64, v);
187 return v;187 return v;
188 }188 }
...@@ -369,7 +369,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {...@@ -369,7 +369,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {
369 key[i] = @intCast(u8, i);369 key[i] = @intCast(u8, i);
370370
371 var h = hash_fn(key[0..i], 256 - i);371 var h = hash_fn(key[0..i], 256 - i);
372 if (builtin.endian == builtin.Endian.Big)372 if (builtin.endian == .Big)
373 h = @byteSwap(@TypeOf(h), h);373 h = @byteSwap(@TypeOf(h), h);
374 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);374 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
375 }375 }
lib/std/hash/murmur.zig+8-8
...@@ -17,7 +17,7 @@ pub const Murmur2_32 = struct {...@@ -17,7 +17,7 @@ pub const Murmur2_32 = struct {
17 var h1: u32 = seed ^ len;17 var h1: u32 = seed ^ len;
18 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {18 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
19 var k1: u32 = v;19 var k1: u32 = v;
20 if (builtin.endian == builtin.Endian.Big)20 if (builtin.endian == .Big)
21 k1 = @byteSwap(u32, k1);21 k1 = @byteSwap(u32, k1);
22 k1 *%= m;22 k1 *%= m;
23 k1 ^= k1 >> 24;23 k1 ^= k1 >> 24;
...@@ -102,7 +102,7 @@ pub const Murmur2_64 = struct {...@@ -102,7 +102,7 @@ pub const Murmur2_64 = struct {
102 var h1: u64 = seed ^ (len *% m);102 var h1: u64 = seed ^ (len *% m);
103 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {103 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
104 var k1: u64 = v;104 var k1: u64 = v;
105 if (builtin.endian == builtin.Endian.Big)105 if (builtin.endian == .Big)
106 k1 = @byteSwap(u64, k1);106 k1 = @byteSwap(u64, k1);
107 k1 *%= m;107 k1 *%= m;
108 k1 ^= k1 >> 47;108 k1 ^= k1 >> 47;
...@@ -115,7 +115,7 @@ pub const Murmur2_64 = struct {...@@ -115,7 +115,7 @@ pub const Murmur2_64 = struct {
115 if (rest > 0) {115 if (rest > 0) {
116 var k1: u64 = 0;116 var k1: u64 = 0;
117 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));117 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));
118 if (builtin.endian == builtin.Endian.Big)118 if (builtin.endian == .Big)
119 k1 = @byteSwap(u64, k1);119 k1 = @byteSwap(u64, k1);
120 h1 ^= k1;120 h1 ^= k1;
121 h1 *%= m;121 h1 *%= m;
...@@ -182,7 +182,7 @@ pub const Murmur3_32 = struct {...@@ -182,7 +182,7 @@ pub const Murmur3_32 = struct {
182 var h1: u32 = seed;182 var h1: u32 = seed;
183 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {183 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
184 var k1: u32 = v;184 var k1: u32 = v;
185 if (builtin.endian == builtin.Endian.Big)185 if (builtin.endian == .Big)
186 k1 = @byteSwap(u32, k1);186 k1 = @byteSwap(u32, k1);
187 k1 *%= c1;187 k1 *%= c1;
188 k1 = rotl32(k1, 15);188 k1 = rotl32(k1, 15);
...@@ -294,7 +294,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {...@@ -294,7 +294,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {
294 key[i] = @truncate(u8, i);294 key[i] = @truncate(u8, i);
295295
296 var h = hash_fn(key[0..i], 256 - i);296 var h = hash_fn(key[0..i], 256 - i);
297 if (builtin.endian == builtin.Endian.Big)297 if (builtin.endian == .Big)
298 h = @byteSwap(@TypeOf(h), h);298 h = @byteSwap(@TypeOf(h), h);
299 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);299 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
300 }300 }
...@@ -308,7 +308,7 @@ test "murmur2_32" {...@@ -308,7 +308,7 @@ test "murmur2_32" {
308 var v1: u64 = 0x1234567812345678;308 var v1: u64 = 0x1234567812345678;
309 var v0le: u32 = v0;309 var v0le: u32 = v0;
310 var v1le: u64 = v1;310 var v1le: u64 = v1;
311 if (builtin.endian == builtin.Endian.Big) {311 if (builtin.endian == .Big) {
312 v0le = @byteSwap(u32, v0le);312 v0le = @byteSwap(u32, v0le);
313 v1le = @byteSwap(u64, v1le);313 v1le = @byteSwap(u64, v1le);
314 }314 }
...@@ -322,7 +322,7 @@ test "murmur2_64" {...@@ -322,7 +322,7 @@ test "murmur2_64" {
322 var v1: u64 = 0x1234567812345678;322 var v1: u64 = 0x1234567812345678;
323 var v0le: u32 = v0;323 var v0le: u32 = v0;
324 var v1le: u64 = v1;324 var v1le: u64 = v1;
325 if (builtin.endian == builtin.Endian.Big) {325 if (builtin.endian == .Big) {
326 v0le = @byteSwap(u32, v0le);326 v0le = @byteSwap(u32, v0le);
327 v1le = @byteSwap(u64, v1le);327 v1le = @byteSwap(u64, v1le);
328 }328 }
...@@ -336,7 +336,7 @@ test "murmur3_32" {...@@ -336,7 +336,7 @@ test "murmur3_32" {
336 var v1: u64 = 0x1234567812345678;336 var v1: u64 = 0x1234567812345678;
337 var v0le: u32 = v0;337 var v0le: u32 = v0;
338 var v1le: u64 = v1;338 var v1le: u64 = v1;
339 if (builtin.endian == builtin.Endian.Big) {339 if (builtin.endian == .Big) {
340 v0le = @byteSwap(u32, v0le);340 v0le = @byteSwap(u32, v0le);
341 v1le = @byteSwap(u64, v1le);341 v1le = @byteSwap(u64, v1le);
342 }342 }
lib/std/hash_map.zig+1-1
...@@ -10,7 +10,7 @@ const Wyhash = std.hash.Wyhash;...@@ -10,7 +10,7 @@ const Wyhash = std.hash.Wyhash;
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const builtin = @import("builtin");11const builtin = @import("builtin");
1212
13const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;13const want_modification_safety = builtin.mode != .ReleaseFast;
14const debug_u32 = if (want_modification_safety) u32 else void;14const debug_u32 = if (want_modification_safety) u32 else void;
1515
16pub fn AutoHashMap(comptime K: type, comptime V: type) type {16pub fn AutoHashMap(comptime K: type, comptime V: type) type {
lib/std/heap.zig+7-7
...@@ -36,7 +36,7 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new...@@ -36,7 +36,7 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new
36/// Thread-safe and lock-free.36/// Thread-safe and lock-free.
37pub const page_allocator = if (std.Target.current.isWasm())37pub const page_allocator = if (std.Target.current.isWasm())
38 &wasm_page_allocator_state38 &wasm_page_allocator_state
39else if (std.Target.current.getOs() == .freestanding)39else if (std.Target.current.os.tag == .freestanding)
40 root.os.heap.page_allocator40 root.os.heap.page_allocator
41else41else
42 &page_allocator_state;42 &page_allocator_state;
...@@ -57,7 +57,7 @@ const PageAllocator = struct {...@@ -57,7 +57,7 @@ const PageAllocator = struct {
57 fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {57 fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
58 if (n == 0) return &[0]u8{};58 if (n == 0) return &[0]u8{};
5959
60 if (builtin.os == .windows) {60 if (builtin.os.tag == .windows) {
61 const w = os.windows;61 const w = os.windows;
6262
63 // Although officially it's at least aligned to page boundary,63 // Although officially it's at least aligned to page boundary,
...@@ -143,7 +143,7 @@ const PageAllocator = struct {...@@ -143,7 +143,7 @@ const PageAllocator = struct {
143143
144 fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {144 fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
145 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);145 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
146 if (builtin.os == .windows) {146 if (builtin.os.tag == .windows) {
147 const w = os.windows;147 const w = os.windows;
148 if (new_size == 0) {148 if (new_size == 0) {
149 // From the docs:149 // From the docs:
...@@ -183,7 +183,7 @@ const PageAllocator = struct {...@@ -183,7 +183,7 @@ const PageAllocator = struct {
183183
184 fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {184 fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
185 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);185 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
186 if (builtin.os == .windows) {186 if (builtin.os.tag == .windows) {
187 if (old_mem.len == 0) {187 if (old_mem.len == 0) {
188 return alloc(allocator, new_size, new_align);188 return alloc(allocator, new_size, new_align);
189 }189 }
...@@ -412,7 +412,7 @@ const WasmPageAllocator = struct {...@@ -412,7 +412,7 @@ const WasmPageAllocator = struct {
412 }412 }
413};413};
414414
415pub const HeapAllocator = switch (builtin.os) {415pub const HeapAllocator = switch (builtin.os.tag) {
416 .windows => struct {416 .windows => struct {
417 allocator: Allocator,417 allocator: Allocator,
418 heap_handle: ?HeapHandle,418 heap_handle: ?HeapHandle,
...@@ -855,7 +855,7 @@ test "PageAllocator" {...@@ -855,7 +855,7 @@ test "PageAllocator" {
855 try testAllocatorAlignedShrink(allocator);855 try testAllocatorAlignedShrink(allocator);
856 }856 }
857857
858 if (builtin.os == .windows) {858 if (builtin.os.tag == .windows) {
859 // Trying really large alignment. As mentionned in the implementation,859 // Trying really large alignment. As mentionned in the implementation,
860 // VirtualAlloc returns 64K aligned addresses. We want to make sure860 // VirtualAlloc returns 64K aligned addresses. We want to make sure
861 // PageAllocator works beyond that, as it's not tested by861 // PageAllocator works beyond that, as it's not tested by
...@@ -868,7 +868,7 @@ test "PageAllocator" {...@@ -868,7 +868,7 @@ test "PageAllocator" {
868}868}
869869
870test "HeapAllocator" {870test "HeapAllocator" {
871 if (builtin.os == .windows) {871 if (builtin.os.tag == .windows) {
872 var heap_allocator = HeapAllocator.init();872 var heap_allocator = HeapAllocator.init();
873 defer heap_allocator.deinit();873 defer heap_allocator.deinit();
874874
lib/std/io.zig+17-17
...@@ -35,7 +35,7 @@ else...@@ -35,7 +35,7 @@ else
35pub const is_async = mode != .blocking;35pub const is_async = mode != .blocking;
3636
37fn getStdOutHandle() os.fd_t {37fn getStdOutHandle() os.fd_t {
38 if (builtin.os == .windows) {38 if (builtin.os.tag == .windows) {
39 return os.windows.peb().ProcessParameters.hStdOutput;39 return os.windows.peb().ProcessParameters.hStdOutput;
40 }40 }
4141
...@@ -54,7 +54,7 @@ pub fn getStdOut() File {...@@ -54,7 +54,7 @@ pub fn getStdOut() File {
54}54}
5555
56fn getStdErrHandle() os.fd_t {56fn getStdErrHandle() os.fd_t {
57 if (builtin.os == .windows) {57 if (builtin.os.tag == .windows) {
58 return os.windows.peb().ProcessParameters.hStdError;58 return os.windows.peb().ProcessParameters.hStdError;
59 }59 }
6060
...@@ -74,7 +74,7 @@ pub fn getStdErr() File {...@@ -74,7 +74,7 @@ pub fn getStdErr() File {
74}74}
7575
76fn getStdInHandle() os.fd_t {76fn getStdInHandle() os.fd_t {
77 if (builtin.os == .windows) {77 if (builtin.os.tag == .windows) {
78 return os.windows.peb().ProcessParameters.hStdInput;78 return os.windows.peb().ProcessParameters.hStdInput;
79 }79 }
8080
...@@ -348,11 +348,11 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {...@@ -348,11 +348,11 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
348 const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;348 const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
349 const shift = u7_bit_count - n;349 const shift = u7_bit_count - n;
350 switch (endian) {350 switch (endian) {
351 builtin.Endian.Big => {351 .Big => {
352 out_buffer = @as(Buf, self.bit_buffer >> shift);352 out_buffer = @as(Buf, self.bit_buffer >> shift);
353 self.bit_buffer <<= n;353 self.bit_buffer <<= n;
354 },354 },
355 builtin.Endian.Little => {355 .Little => {
356 const value = (self.bit_buffer << shift) >> shift;356 const value = (self.bit_buffer << shift) >> shift;
357 out_buffer = @as(Buf, value);357 out_buffer = @as(Buf, value);
358 self.bit_buffer >>= n;358 self.bit_buffer >>= n;
...@@ -376,7 +376,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {...@@ -376,7 +376,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
376 };376 };
377377
378 switch (endian) {378 switch (endian) {
379 builtin.Endian.Big => {379 .Big => {
380 if (n >= u8_bit_count) {380 if (n >= u8_bit_count) {
381 out_buffer <<= @intCast(u3, u8_bit_count - 1);381 out_buffer <<= @intCast(u3, u8_bit_count - 1);
382 out_buffer <<= 1;382 out_buffer <<= 1;
...@@ -392,7 +392,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {...@@ -392,7 +392,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
392 self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));392 self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
393 self.bit_count = shift;393 self.bit_count = shift;
394 },394 },
395 builtin.Endian.Little => {395 .Little => {
396 if (n >= u8_bit_count) {396 if (n >= u8_bit_count) {
397 out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);397 out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
398 out_bits.* += u8_bit_count;398 out_bits.* += u8_bit_count;
...@@ -666,8 +666,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -666,8 +666,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
666666
667 const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);667 const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
668 var in_buffer = switch (endian) {668 var in_buffer = switch (endian) {
669 builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),669 .Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
670 builtin.Endian.Little => buf_value,670 .Little => buf_value,
671 };671 };
672 var in_bits = bits;672 var in_bits = bits;
673673
...@@ -675,13 +675,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -675,13 +675,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
675 const bits_remaining = u8_bit_count - self.bit_count;675 const bits_remaining = u8_bit_count - self.bit_count;
676 const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);676 const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
677 switch (endian) {677 switch (endian) {
678 builtin.Endian.Big => {678 .Big => {
679 const shift = @intCast(BufShift, high_byte_shift + self.bit_count);679 const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
680 const v = @intCast(u8, in_buffer >> shift);680 const v = @intCast(u8, in_buffer >> shift);
681 self.bit_buffer |= v;681 self.bit_buffer |= v;
682 in_buffer <<= n;682 in_buffer <<= n;
683 },683 },
684 builtin.Endian.Little => {684 .Little => {
685 const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);685 const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
686 self.bit_buffer |= v;686 self.bit_buffer |= v;
687 in_buffer >>= n;687 in_buffer >>= n;
...@@ -701,13 +701,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -701,13 +701,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
701 //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer701 //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
702 while (in_bits >= u8_bit_count) {702 while (in_bits >= u8_bit_count) {
703 switch (endian) {703 switch (endian) {
704 builtin.Endian.Big => {704 .Big => {
705 const v = @intCast(u8, in_buffer >> high_byte_shift);705 const v = @intCast(u8, in_buffer >> high_byte_shift);
706 try self.out_stream.writeByte(v);706 try self.out_stream.writeByte(v);
707 in_buffer <<= @intCast(u3, u8_bit_count - 1);707 in_buffer <<= @intCast(u3, u8_bit_count - 1);
708 in_buffer <<= 1;708 in_buffer <<= 1;
709 },709 },
710 builtin.Endian.Little => {710 .Little => {
711 const v = @truncate(u8, in_buffer);711 const v = @truncate(u8, in_buffer);
712 try self.out_stream.writeByte(v);712 try self.out_stream.writeByte(v);
713 in_buffer >>= @intCast(u3, u8_bit_count - 1);713 in_buffer >>= @intCast(u3, u8_bit_count - 1);
...@@ -720,8 +720,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -720,8 +720,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
720 if (in_bits > 0) {720 if (in_bits > 0) {
721 self.bit_count = @intCast(u4, in_bits);721 self.bit_count = @intCast(u4, in_bits);
722 self.bit_buffer = switch (endian) {722 self.bit_buffer = switch (endian) {
723 builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift),723 .Big => @truncate(u8, in_buffer >> high_byte_shift),
724 builtin.Endian.Little => @truncate(u8, in_buffer),724 .Little => @truncate(u8, in_buffer),
725 };725 };
726 }726 }
727 }727 }
...@@ -858,10 +858,10 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,...@@ -858,10 +858,10 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,
858 var result = @as(U, 0);858 var result = @as(U, 0);
859 for (buffer) |byte, i| {859 for (buffer) |byte, i| {
860 switch (endian) {860 switch (endian) {
861 builtin.Endian.Big => {861 .Big => {
862 result = (result << u8_bit_count) | byte;862 result = (result << u8_bit_count) | byte;
863 },863 },
864 builtin.Endian.Little => {864 .Little => {
865 result |= @as(U, byte) << @intCast(Log2U, u8_bit_count * i);865 result |= @as(U, byte) << @intCast(Log2U, u8_bit_count * i);
866 },866 },
867 }867 }
lib/std/io/seekable_stream.zig+2-2
...@@ -73,7 +73,7 @@ pub const SliceSeekableInStream = struct {...@@ -73,7 +73,7 @@ pub const SliceSeekableInStream = struct {
73 fn seekToFn(in_stream: *SeekableInStream, pos: u64) SeekError!void {73 fn seekToFn(in_stream: *SeekableInStream, pos: u64) SeekError!void {
74 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);74 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
75 const usize_pos = @intCast(usize, pos);75 const usize_pos = @intCast(usize, pos);
76 if (usize_pos >= self.slice.len) return error.EndOfStream;76 if (usize_pos > self.slice.len) return error.EndOfStream;
77 self.pos = usize_pos;77 self.pos = usize_pos;
78 }78 }
7979
...@@ -86,7 +86,7 @@ pub const SliceSeekableInStream = struct {...@@ -86,7 +86,7 @@ pub const SliceSeekableInStream = struct {
86 self.pos -= abs_amt;86 self.pos -= abs_amt;
87 } else {87 } else {
88 const usize_amt = @intCast(usize, amt);88 const usize_amt = @intCast(usize, amt);
89 if (self.pos + usize_amt >= self.slice.len) return error.EndOfStream;89 if (self.pos + usize_amt > self.slice.len) return error.EndOfStream;
90 self.pos += usize_amt;90 self.pos += usize_amt;
91 }91 }
92 }92 }
lib/std/macho.zig+11
...@@ -24,6 +24,17 @@ pub const load_command = extern struct {...@@ -24,6 +24,17 @@ pub const load_command = extern struct {
24 cmdsize: u32,24 cmdsize: u32,
25};25};
2626
27pub const uuid_command = extern struct {
28 /// LC_UUID
29 cmd: u32,
30
31 /// sizeof(struct uuid_command)
32 cmdsize: u32,
33
34 /// the 128-bit uuid
35 uuid: [16]u8,
36};
37
27/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD38/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
28/// "stab" style symbol table information as described in the header files39/// "stab" style symbol table information as described in the header files
29/// <nlist.h> and <stab.h>.40/// <nlist.h> and <stab.h>.
lib/std/math/pow.zig+1-1
...@@ -32,7 +32,7 @@ const expect = std.testing.expect;...@@ -32,7 +32,7 @@ const expect = std.testing.expect;
32/// - pow(-inf, y) = pow(-0, -y)32/// - pow(-inf, y) = pow(-0, -y)
33/// - pow(x, y) = nan for finite x < 0 and finite non-integer y33/// - pow(x, y) = nan for finite x < 0 and finite non-integer y
34pub fn pow(comptime T: type, x: T, y: T) T {34pub fn pow(comptime T: type, x: T, y: T) T {
35 if (@typeInfo(T) == builtin.TypeId.Int) {35 if (@typeInfo(T) == .Int) {
36 return math.powi(T, x, y) catch unreachable;36 return math.powi(T, x, y) catch unreachable;
37 }37 }
3838
lib/std/math/powi.zig+1-1
...@@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{...@@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
25}!T) {25}!T) {
26 const info = @typeInfo(T);26 const info = @typeInfo(T);
2727
28 comptime assert(@typeInfo(T) == builtin.TypeId.Int);28 comptime assert(@typeInfo(T) == .Int);
2929
30 // powi(x, +-0) = 1 for any x30 // powi(x, +-0) = 1 for any x
31 if (y == 0 or y == -0) {31 if (y == 0 or y == -0) {
lib/std/mem.zig+174-60
...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
333 }333 }
334 return array;334 return array;
335 },335 },
336 .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {336 .Vector,
337 @compileError("Can't set a "++ @typeName(T) ++" to zero.");337 .ErrorUnion,
338 .ErrorSet,
339 .Union,
340 .Fn,
341 .BoundFn,
342 .Type,
343 .NoReturn,
344 .Undefined,
345 .Opaque,
346 .Frame,
347 .AnyFrame,
348 => {
349 @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
338 },350 },
339 }351 }
340}352}
...@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
470 return true;482 return true;
471}483}
472484
473pub fn len(comptime T: type, ptr: [*:0]const T) usize {485/// Deprecated. Use `span`.
474 var count: usize = 0;
475 while (ptr[count] != 0) : (count += 1) {}
476 return count;
477}
478
479pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {486pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
480 return ptr[0..len(T, ptr) :0];487 return ptr[0..len(ptr) :0];
481}488}
482489
490/// Deprecated. Use `span`.
483pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {491pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
484 return ptr[0..len(T, ptr) :0];492 return ptr[0..len(ptr) :0];
493}
494
495/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
496/// returns a slice. If there is a sentinel on the input type, there will be a
497/// sentinel on the output type. The constness of the output type matches
498/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated,
499/// and assumed to not allow null.
500pub fn Span(comptime T: type) type {
501 var ptr_info = @typeInfo(T).Pointer;
502 switch (ptr_info.size) {
503 .One => switch (@typeInfo(ptr_info.child)) {
504 .Array => |info| {
505 ptr_info.child = info.child;
506 ptr_info.sentinel = info.sentinel;
507 },
508 else => @compileError("invalid type given to std.mem.Span"),
509 },
510 .C => {
511 ptr_info.sentinel = 0;
512 ptr_info.is_allowzero = false;
513 },
514 .Many, .Slice => {},
515 }
516 ptr_info.size = .Slice;
517 return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
518}
519
520test "Span" {
521 testing.expect(Span(*[5]u16) == []u16);
522 testing.expect(Span(*const [5]u16) == []const u16);
523 testing.expect(Span([]u16) == []u16);
524 testing.expect(Span([]const u8) == []const u8);
525 testing.expect(Span([:1]u16) == [:1]u16);
526 testing.expect(Span([:1]const u8) == [:1]const u8);
527 testing.expect(Span([*:1]u16) == [:1]u16);
528 testing.expect(Span([*:1]const u8) == [:1]const u8);
529 testing.expect(Span([*c]u16) == [:0]u16);
530 testing.expect(Span([*c]const u8) == [:0]const u8);
531}
532
533/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
534/// returns a slice. If there is a sentinel on the input type, there will be a
535/// sentinel on the output type. The constness of the output type matches
536/// the constness of the input type.
537pub fn span(ptr: var) Span(@TypeOf(ptr)) {
538 const Result = Span(@TypeOf(ptr));
539 const l = len(ptr);
540 if (@typeInfo(Result).Pointer.sentinel) |s| {
541 return ptr[0..l :s];
542 } else {
543 return ptr[0..l];
544 }
545}
546
547test "span" {
548 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
549 const ptr = array[0..2 :3].ptr;
550 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
551 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
552}
553
554/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
555/// or a slice, and returns the length.
556pub fn len(ptr: var) usize {
557 return switch (@typeInfo(@TypeOf(ptr))) {
558 .Array => |info| info.len,
559 .Pointer => |info| switch (info.size) {
560 .One => switch (@typeInfo(info.child)) {
561 .Array => |x| x.len,
562 else => @compileError("invalid type given to std.mem.length"),
563 },
564 .Many => if (info.sentinel) |sentinel|
565 indexOfSentinel(info.child, sentinel, ptr)
566 else
567 @compileError("length of pointer with no sentinel"),
568 .C => indexOfSentinel(info.child, 0, ptr),
569 .Slice => ptr.len,
570 },
571 else => @compileError("invalid type given to std.mem.length"),
572 };
573}
574
575test "len" {
576 testing.expect(len("aoeu") == 4);
577
578 {
579 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
580 testing.expect(len(&array) == 5);
581 testing.expect(len(array[0..3]) == 3);
582 array[2] = 0;
583 const ptr = array[0..2 :0].ptr;
584 testing.expect(len(ptr) == 2);
585 }
586}
587
588pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
589 var i: usize = 0;
590 while (ptr[i] != sentinel) {
591 i += 1;
592 }
593 return i;
485}594}
486595
487/// Returns true if all elements in a slice are equal to the scalar value provided596/// Returns true if all elements in a slice are equal to the scalar value provided
...@@ -637,12 +746,12 @@ test "mem.indexOf" {...@@ -637,12 +746,12 @@ test "mem.indexOf" {
637pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType {746pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType {
638 var result: ReturnType = 0;747 var result: ReturnType = 0;
639 switch (endian) {748 switch (endian) {
640 builtin.Endian.Big => {749 .Big => {
641 for (bytes) |b| {750 for (bytes) |b| {
642 result = (result << 8) | b;751 result = (result << 8) | b;
643 }752 }
644 },753 },
645 builtin.Endian.Little => {754 .Little => {
646 const ShiftType = math.Log2Int(ReturnType);755 const ShiftType = math.Log2Int(ReturnType);
647 for (bytes) |b, index| {756 for (bytes) |b, index| {
648 result = result | (@as(ReturnType, b) << @intCast(ShiftType, index * 8));757 result = result | (@as(ReturnType, b) << @intCast(ShiftType, index * 8));
...@@ -670,13 +779,13 @@ pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)...@@ -670,13 +779,13 @@ pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)
670}779}
671780
672pub const readIntLittle = switch (builtin.endian) {781pub const readIntLittle = switch (builtin.endian) {
673 builtin.Endian.Little => readIntNative,782 .Little => readIntNative,
674 builtin.Endian.Big => readIntForeign,783 .Big => readIntForeign,
675};784};
676785
677pub const readIntBig = switch (builtin.endian) {786pub const readIntBig = switch (builtin.endian) {
678 builtin.Endian.Little => readIntForeign,787 .Little => readIntForeign,
679 builtin.Endian.Big => readIntNative,788 .Big => readIntNative,
680};789};
681790
682/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0791/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
...@@ -700,13 +809,13 @@ pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {...@@ -700,13 +809,13 @@ pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
700}809}
701810
702pub const readIntSliceLittle = switch (builtin.endian) {811pub const readIntSliceLittle = switch (builtin.endian) {
703 builtin.Endian.Little => readIntSliceNative,812 .Little => readIntSliceNative,
704 builtin.Endian.Big => readIntSliceForeign,813 .Big => readIntSliceForeign,
705};814};
706815
707pub const readIntSliceBig = switch (builtin.endian) {816pub const readIntSliceBig = switch (builtin.endian) {
708 builtin.Endian.Little => readIntSliceForeign,817 .Little => readIntSliceForeign,
709 builtin.Endian.Big => readIntSliceNative,818 .Big => readIntSliceNative,
710};819};
711820
712/// Reads an integer from memory with bit count specified by T.821/// Reads an integer from memory with bit count specified by T.
...@@ -783,13 +892,13 @@ pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, va...@@ -783,13 +892,13 @@ pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, va
783}892}
784893
785pub const writeIntLittle = switch (builtin.endian) {894pub const writeIntLittle = switch (builtin.endian) {
786 builtin.Endian.Little => writeIntNative,895 .Little => writeIntNative,
787 builtin.Endian.Big => writeIntForeign,896 .Big => writeIntForeign,
788};897};
789898
790pub const writeIntBig = switch (builtin.endian) {899pub const writeIntBig = switch (builtin.endian) {
791 builtin.Endian.Little => writeIntForeign,900 .Little => writeIntForeign,
792 builtin.Endian.Big => writeIntNative,901 .Big => writeIntNative,
793};902};
794903
795/// Writes an integer to memory, storing it in twos-complement.904/// Writes an integer to memory, storing it in twos-complement.
...@@ -841,13 +950,13 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {...@@ -841,13 +950,13 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
841}950}
842951
843pub const writeIntSliceNative = switch (builtin.endian) {952pub const writeIntSliceNative = switch (builtin.endian) {
844 builtin.Endian.Little => writeIntSliceLittle,953 .Little => writeIntSliceLittle,
845 builtin.Endian.Big => writeIntSliceBig,954 .Big => writeIntSliceBig,
846};955};
847956
848pub const writeIntSliceForeign = switch (builtin.endian) {957pub const writeIntSliceForeign = switch (builtin.endian) {
849 builtin.Endian.Little => writeIntSliceBig,958 .Little => writeIntSliceBig,
850 builtin.Endian.Big => writeIntSliceLittle,959 .Big => writeIntSliceLittle,
851};960};
852961
853/// Writes a twos-complement integer to memory, with the specified endianness.962/// Writes a twos-complement integer to memory, with the specified endianness.
...@@ -858,10 +967,10 @@ pub const writeIntSliceForeign = switch (builtin.endian) {...@@ -858,10 +967,10 @@ pub const writeIntSliceForeign = switch (builtin.endian) {
858/// use writeInt instead.967/// use writeInt instead.
859pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void {968pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void {
860 comptime assert(T.bit_count % 8 == 0);969 comptime assert(T.bit_count % 8 == 0);
861 switch (endian) {970 return switch (endian) {
862 builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value),971 .Little => writeIntSliceLittle(T, buffer, value),
863 builtin.Endian.Big => return writeIntSliceBig(T, buffer, value),972 .Big => writeIntSliceBig(T, buffer, value),
864 }973 };
865}974}
866975
867test "writeIntBig and writeIntLittle" {976test "writeIntBig and writeIntLittle" {
...@@ -1397,54 +1506,54 @@ test "rotate" {...@@ -1397,54 +1506,54 @@ test "rotate" {
1397/// Converts a little-endian integer to host endianness.1506/// Converts a little-endian integer to host endianness.
1398pub fn littleToNative(comptime T: type, x: T) T {1507pub fn littleToNative(comptime T: type, x: T) T {
1399 return switch (builtin.endian) {1508 return switch (builtin.endian) {
1400 builtin.Endian.Little => x,1509 .Little => x,
1401 builtin.Endian.Big => @byteSwap(T, x),1510 .Big => @byteSwap(T, x),
1402 };1511 };
1403}1512}
14041513
1405/// Converts a big-endian integer to host endianness.1514/// Converts a big-endian integer to host endianness.
1406pub fn bigToNative(comptime T: type, x: T) T {1515pub fn bigToNative(comptime T: type, x: T) T {
1407 return switch (builtin.endian) {1516 return switch (builtin.endian) {
1408 builtin.Endian.Little => @byteSwap(T, x),1517 .Little => @byteSwap(T, x),
1409 builtin.Endian.Big => x,1518 .Big => x,
1410 };1519 };
1411}1520}
14121521
1413/// Converts an integer from specified endianness to host endianness.1522/// Converts an integer from specified endianness to host endianness.
1414pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T {1523pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T {
1415 return switch (endianness_of_x) {1524 return switch (endianness_of_x) {
1416 builtin.Endian.Little => littleToNative(T, x),1525 .Little => littleToNative(T, x),
1417 builtin.Endian.Big => bigToNative(T, x),1526 .Big => bigToNative(T, x),
1418 };1527 };
1419}1528}
14201529
1421/// Converts an integer which has host endianness to the desired endianness.1530/// Converts an integer which has host endianness to the desired endianness.
1422pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T {1531pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T {
1423 return switch (desired_endianness) {1532 return switch (desired_endianness) {
1424 builtin.Endian.Little => nativeToLittle(T, x),1533 .Little => nativeToLittle(T, x),
1425 builtin.Endian.Big => nativeToBig(T, x),1534 .Big => nativeToBig(T, x),
1426 };1535 };
1427}1536}
14281537
1429/// Converts an integer which has host endianness to little endian.1538/// Converts an integer which has host endianness to little endian.
1430pub fn nativeToLittle(comptime T: type, x: T) T {1539pub fn nativeToLittle(comptime T: type, x: T) T {
1431 return switch (builtin.endian) {1540 return switch (builtin.endian) {
1432 builtin.Endian.Little => x,1541 .Little => x,
1433 builtin.Endian.Big => @byteSwap(T, x),1542 .Big => @byteSwap(T, x),
1434 };1543 };
1435}1544}
14361545
1437/// Converts an integer which has host endianness to big endian.1546/// Converts an integer which has host endianness to big endian.
1438pub fn nativeToBig(comptime T: type, x: T) T {1547pub fn nativeToBig(comptime T: type, x: T) T {
1439 return switch (builtin.endian) {1548 return switch (builtin.endian) {
1440 builtin.Endian.Little => @byteSwap(T, x),1549 .Little => @byteSwap(T, x),
1441 builtin.Endian.Big => x,1550 .Big => x,
1442 };1551 };
1443}1552}
14441553
1445fn AsBytesReturnType(comptime P: type) type {1554fn AsBytesReturnType(comptime P: type) type {
1446 if (comptime !trait.isSingleItemPtr(P))1555 if (comptime !trait.isSingleItemPtr(P))
1447 @compileError("expected single item " ++ "pointer, passed " ++ @typeName(P));1556 @compileError("expected single item pointer, passed " ++ @typeName(P));
14481557
1449 const size = @as(usize, @sizeOf(meta.Child(P)));1558 const size = @as(usize, @sizeOf(meta.Child(P)));
1450 const alignment = comptime meta.alignment(P);1559 const alignment = comptime meta.alignment(P);
...@@ -1469,8 +1578,8 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {...@@ -1469,8 +1578,8 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {
1469test "asBytes" {1578test "asBytes" {
1470 const deadbeef = @as(u32, 0xDEADBEEF);1579 const deadbeef = @as(u32, 0xDEADBEEF);
1471 const deadbeef_bytes = switch (builtin.endian) {1580 const deadbeef_bytes = switch (builtin.endian) {
1472 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1581 .Big => "\xDE\xAD\xBE\xEF",
1473 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",1582 .Little => "\xEF\xBE\xAD\xDE",
1474 };1583 };
14751584
1476 testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));1585 testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));
...@@ -1508,21 +1617,21 @@ pub fn toBytes(value: var) [@sizeOf(@TypeOf(value))]u8 {...@@ -1508,21 +1617,21 @@ pub fn toBytes(value: var) [@sizeOf(@TypeOf(value))]u8 {
1508test "toBytes" {1617test "toBytes" {
1509 var my_bytes = toBytes(@as(u32, 0x12345678));1618 var my_bytes = toBytes(@as(u32, 0x12345678));
1510 switch (builtin.endian) {1619 switch (builtin.endian) {
1511 builtin.Endian.Big => testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")),1620 .Big => testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")),
1512 builtin.Endian.Little => testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")),1621 .Little => testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")),
1513 }1622 }
15141623
1515 my_bytes[0] = '\x99';1624 my_bytes[0] = '\x99';
1516 switch (builtin.endian) {1625 switch (builtin.endian) {
1517 builtin.Endian.Big => testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")),1626 .Big => testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")),
1518 builtin.Endian.Little => testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")),1627 .Little => testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")),
1519 }1628 }
1520}1629}
15211630
1522fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {1631fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
1523 const size = @as(usize, @sizeOf(T));1632 const size = @as(usize, @sizeOf(T));
15241633
1525 if (comptime !trait.is(builtin.TypeId.Pointer)(B) or1634 if (comptime !trait.is(.Pointer)(B) or
1526 (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))1635 (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))
1527 {1636 {
1528 @compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));1637 @compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));
...@@ -1542,15 +1651,15 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @Typ...@@ -1542,15 +1651,15 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @Typ
1542test "bytesAsValue" {1651test "bytesAsValue" {
1543 const deadbeef = @as(u32, 0xDEADBEEF);1652 const deadbeef = @as(u32, 0xDEADBEEF);
1544 const deadbeef_bytes = switch (builtin.endian) {1653 const deadbeef_bytes = switch (builtin.endian) {
1545 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1654 .Big => "\xDE\xAD\xBE\xEF",
1546 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",1655 .Little => "\xEF\xBE\xAD\xDE",
1547 };1656 };
15481657
1549 testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*);1658 testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*);
15501659
1551 var codeface_bytes: [4]u8 = switch (builtin.endian) {1660 var codeface_bytes: [4]u8 = switch (builtin.endian) {
1552 builtin.Endian.Big => "\xC0\xDE\xFA\xCE",1661 .Big => "\xC0\xDE\xFA\xCE",
1553 builtin.Endian.Little => "\xCE\xFA\xDE\xC0",1662 .Little => "\xCE\xFA\xDE\xC0",
1554 }.*;1663 }.*;
1555 var codeface = bytesAsValue(u32, &codeface_bytes);1664 var codeface = bytesAsValue(u32, &codeface_bytes);
1556 testing.expect(codeface.* == 0xC0DEFACE);1665 testing.expect(codeface.* == 0xC0DEFACE);
...@@ -1583,8 +1692,8 @@ pub fn bytesToValue(comptime T: type, bytes: var) T {...@@ -1583,8 +1692,8 @@ pub fn bytesToValue(comptime T: type, bytes: var) T {
1583}1692}
1584test "bytesToValue" {1693test "bytesToValue" {
1585 const deadbeef_bytes = switch (builtin.endian) {1694 const deadbeef_bytes = switch (builtin.endian) {
1586 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1695 .Big => "\xDE\xAD\xBE\xEF",
1587 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",1696 .Little => "\xEF\xBE\xAD\xDE",
1588 };1697 };
15891698
1590 const deadbeef = bytesToValue(u32, deadbeef_bytes);1699 const deadbeef = bytesToValue(u32, deadbeef_bytes);
...@@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {...@@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
1753 return *[length]meta.Child(meta.Child(T));1862 return *[length]meta.Child(meta.Child(T));
1754}1863}
17551864
1756///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.1865/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1757pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) {1866/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
1867pub fn subArrayPtr(
1868 ptr: var,
1869 comptime start: usize,
1870 comptime length: usize,
1871) SubArrayPtrReturnType(@TypeOf(ptr), length) {
1758 assert(start + length <= ptr.*.len);1872 assert(start + length <= ptr.*.len);
17591873
1760 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);1874 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
lib/std/meta.zig+26
...@@ -115,6 +115,32 @@ test "std.meta.Child" {...@@ -115,6 +115,32 @@ test "std.meta.Child" {
115 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
116}116}
117117
118/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
119pub fn Sentinel(comptime T: type) Child(T) {
120 // comptime asserts that ptr has a sentinel
121 switch (@typeInfo(T)) {
122 .Array => |arrayInfo| {
123 return comptime arrayInfo.sentinel.?;
124 },
125 .Pointer => |ptrInfo| {
126 switch (ptrInfo.size) {
127 .Many, .Slice => {
128 return comptime ptrInfo.sentinel.?;
129 },
130 else => {},
131 }
132 },
133 else => {},
134 }
135 @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
136}
137
138test "std.meta.Sentinel" {
139 testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
140 testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
141 testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
142}
143
118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
119 return switch (@typeInfo(T)) {145 return switch (@typeInfo(T)) {
120 .Struct => |info| info.layout,146 .Struct => |info| info.layout,
lib/std/mutex.zig+2-2
...@@ -73,7 +73,7 @@ pub const Mutex = if (builtin.single_threaded)...@@ -73,7 +73,7 @@ pub const Mutex = if (builtin.single_threaded)
73 return self.tryAcquire() orelse @panic("deadlock detected");73 return self.tryAcquire() orelse @panic("deadlock detected");
74 }74 }
75 }75 }
76else if (builtin.os == .windows)76else if (builtin.os.tag == .windows)
77// https://locklessinc.com/articles/keyed_events/77// https://locklessinc.com/articles/keyed_events/
78 extern union {78 extern union {
79 locked: u8,79 locked: u8,
...@@ -161,7 +161,7 @@ else if (builtin.os == .windows)...@@ -161,7 +161,7 @@ else if (builtin.os == .windows)
161 }161 }
162 };162 };
163 }163 }
164else if (builtin.link_libc or builtin.os == .linux)164else if (builtin.link_libc or builtin.os.tag == .linux)
165// stack-based version of https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs165// stack-based version of https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs
166 struct {166 struct {
167 state: usize,167 state: usize,
lib/std/net.zig+2-2
...@@ -352,7 +352,7 @@ pub const Address = extern union {...@@ -352,7 +352,7 @@ pub const Address = extern union {
352 unreachable;352 unreachable;
353 }353 }
354354
355 const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path));355 const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path));
356 return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);356 return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
357 },357 },
358 else => unreachable,358 else => unreachable,
...@@ -501,7 +501,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*...@@ -501,7 +501,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
501501
502 return result;502 return result;
503 }503 }
504 if (builtin.os == .linux) {504 if (builtin.os.tag == .linux) {
505 const flags = std.c.AI_NUMERICSERV;505 const flags = std.c.AI_NUMERICSERV;
506 const family = os.AF_UNSPEC;506 const family = os.AF_UNSPEC;
507 var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);507 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" {...@@ -63,7 +63,7 @@ test "parse and render IPv4 addresses" {
63}63}
6464
65test "resolve DNS" {65test "resolve DNS" {
66 if (std.builtin.os == .windows) {66 if (std.builtin.os.tag == .windows) {
67 // DNS resolution not implemented on Windows yet.67 // DNS resolution not implemented on Windows yet.
68 return error.SkipZigTest;68 return error.SkipZigTest;
69 }69 }
...@@ -81,7 +81,7 @@ test "resolve DNS" {...@@ -81,7 +81,7 @@ test "resolve DNS" {
81test "listen on a port, send bytes, receive bytes" {81test "listen on a port, send bytes, receive bytes" {
82 if (!std.io.is_async) return error.SkipZigTest;82 if (!std.io.is_async) return error.SkipZigTest;
8383
84 if (std.builtin.os != .linux) {84 if (std.builtin.os.tag != .linux) {
85 // TODO build abstractions for other operating systems85 // TODO build abstractions for other operating systems
86 return error.SkipZigTest;86 return error.SkipZigTest;
87 }87 }
lib/std/os.zig+88-83
...@@ -56,7 +56,7 @@ pub const system = if (@hasDecl(root, "os") and root.os != @This())...@@ -56,7 +56,7 @@ pub const system = if (@hasDecl(root, "os") and root.os != @This())
56 root.os.system56 root.os.system
57else if (builtin.link_libc)57else if (builtin.link_libc)
58 std.c58 std.c
59else switch (builtin.os) {59else switch (builtin.os.tag) {
60 .macosx, .ios, .watchos, .tvos => darwin,60 .macosx, .ios, .watchos, .tvos => darwin,
61 .freebsd => freebsd,61 .freebsd => freebsd,
62 .linux => linux,62 .linux => linux,
...@@ -93,10 +93,10 @@ pub const errno = system.getErrno;...@@ -93,10 +93,10 @@ pub const errno = system.getErrno;
93/// must call `fsync` before `close`.93/// must call `fsync` before `close`.
94/// Note: The Zig standard library does not support POSIX thread cancellation.94/// Note: The Zig standard library does not support POSIX thread cancellation.
95pub fn close(fd: fd_t) void {95pub fn close(fd: fd_t) void {
96 if (builtin.os == .windows) {96 if (builtin.os.tag == .windows) {
97 return windows.CloseHandle(fd);97 return windows.CloseHandle(fd);
98 }98 }
99 if (builtin.os == .wasi) {99 if (builtin.os.tag == .wasi) {
100 _ = wasi.fd_close(fd);100 _ = wasi.fd_close(fd);
101 }101 }
102 if (comptime std.Target.current.isDarwin()) {102 if (comptime std.Target.current.isDarwin()) {
...@@ -121,12 +121,12 @@ pub const GetRandomError = OpenError;...@@ -121,12 +121,12 @@ pub const GetRandomError = OpenError;
121/// appropriate OS-specific library call. Otherwise it uses the zig standard121/// appropriate OS-specific library call. Otherwise it uses the zig standard
122/// library implementation.122/// library implementation.
123pub fn getrandom(buffer: []u8) GetRandomError!void {123pub fn getrandom(buffer: []u8) GetRandomError!void {
124 if (builtin.os == .windows) {124 if (builtin.os.tag == .windows) {
125 return windows.RtlGenRandom(buffer);125 return windows.RtlGenRandom(buffer);
126 }126 }
127 if (builtin.os == .linux or builtin.os == .freebsd) {127 if (builtin.os.tag == .linux or builtin.os.tag == .freebsd) {
128 var buf = buffer;128 var buf = buffer;
129 const use_c = builtin.os != .linux or129 const use_c = builtin.os.tag != .linux or
130 std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok;130 std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok;
131131
132 while (buf.len != 0) {132 while (buf.len != 0) {
...@@ -153,7 +153,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {...@@ -153,7 +153,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
153 }153 }
154 return;154 return;
155 }155 }
156 if (builtin.os == .wasi) {156 if (builtin.os.tag == .wasi) {
157 switch (wasi.random_get(buffer.ptr, buffer.len)) {157 switch (wasi.random_get(buffer.ptr, buffer.len)) {
158 0 => return,158 0 => return,
159 else => |err| return unexpectedErrno(err),159 else => |err| return unexpectedErrno(err),
...@@ -188,13 +188,13 @@ pub fn abort() noreturn {...@@ -188,13 +188,13 @@ pub fn abort() noreturn {
188 // MSVCRT abort() sometimes opens a popup window which is undesirable, so188 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
189 // even when linking libc on Windows we use our own abort implementation.189 // even when linking libc on Windows we use our own abort implementation.
190 // See https://github.com/ziglang/zig/issues/2071 for more details.190 // See https://github.com/ziglang/zig/issues/2071 for more details.
191 if (builtin.os == .windows) {191 if (builtin.os.tag == .windows) {
192 if (builtin.mode == .Debug) {192 if (builtin.mode == .Debug) {
193 @breakpoint();193 @breakpoint();
194 }194 }
195 windows.kernel32.ExitProcess(3);195 windows.kernel32.ExitProcess(3);
196 }196 }
197 if (!builtin.link_libc and builtin.os == .linux) {197 if (!builtin.link_libc and builtin.os.tag == .linux) {
198 raise(SIGABRT) catch {};198 raise(SIGABRT) catch {};
199199
200 // TODO the rest of the implementation of abort() from musl libc here200 // TODO the rest of the implementation of abort() from musl libc here
...@@ -202,10 +202,10 @@ pub fn abort() noreturn {...@@ -202,10 +202,10 @@ pub fn abort() noreturn {
202 raise(SIGKILL) catch {};202 raise(SIGKILL) catch {};
203 exit(127);203 exit(127);
204 }204 }
205 if (builtin.os == .uefi) {205 if (builtin.os.tag == .uefi) {
206 exit(0); // TODO choose appropriate exit code206 exit(0); // TODO choose appropriate exit code
207 }207 }
208 if (builtin.os == .wasi) {208 if (builtin.os.tag == .wasi) {
209 @breakpoint();209 @breakpoint();
210 exit(1);210 exit(1);
211 }211 }
...@@ -223,7 +223,7 @@ pub fn raise(sig: u8) RaiseError!void {...@@ -223,7 +223,7 @@ pub fn raise(sig: u8) RaiseError!void {
223 }223 }
224 }224 }
225225
226 if (builtin.os == .linux) {226 if (builtin.os.tag == .linux) {
227 var set: linux.sigset_t = undefined;227 var set: linux.sigset_t = undefined;
228 // block application signals228 // block application signals
229 _ = linux.sigprocmask(SIG_BLOCK, &linux.app_mask, &set);229 _ = linux.sigprocmask(SIG_BLOCK, &linux.app_mask, &set);
...@@ -260,16 +260,16 @@ pub fn exit(status: u8) noreturn {...@@ -260,16 +260,16 @@ pub fn exit(status: u8) noreturn {
260 if (builtin.link_libc) {260 if (builtin.link_libc) {
261 system.exit(status);261 system.exit(status);
262 }262 }
263 if (builtin.os == .windows) {263 if (builtin.os.tag == .windows) {
264 windows.kernel32.ExitProcess(status);264 windows.kernel32.ExitProcess(status);
265 }265 }
266 if (builtin.os == .wasi) {266 if (builtin.os.tag == .wasi) {
267 wasi.proc_exit(status);267 wasi.proc_exit(status);
268 }268 }
269 if (builtin.os == .linux and !builtin.single_threaded) {269 if (builtin.os.tag == .linux and !builtin.single_threaded) {
270 linux.exit_group(status);270 linux.exit_group(status);
271 }271 }
272 if (builtin.os == .uefi) {272 if (builtin.os.tag == .uefi) {
273 // exit() is only avaliable if exitBootServices() has not been called yet.273 // exit() is only avaliable if exitBootServices() has not been called yet.
274 // This call to exit should not fail, so we don't care about its return value.274 // This call to exit should not fail, so we don't care about its return value.
275 if (uefi.system_table.boot_services) |bs| {275 if (uefi.system_table.boot_services) |bs| {
...@@ -299,11 +299,11 @@ pub const ReadError = error{...@@ -299,11 +299,11 @@ pub const ReadError = error{
299/// If the application has a global event loop enabled, EAGAIN is handled299/// If the application has a global event loop enabled, EAGAIN is handled
300/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.300/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
301pub fn read(fd: fd_t, buf: []u8) ReadError!usize {301pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
302 if (builtin.os == .windows) {302 if (builtin.os.tag == .windows) {
303 return windows.ReadFile(fd, buf, null);303 return windows.ReadFile(fd, buf, null);
304 }304 }
305305
306 if (builtin.os == .wasi and !builtin.link_libc) {306 if (builtin.os.tag == .wasi and !builtin.link_libc) {
307 const iovs = [1]iovec{iovec{307 const iovs = [1]iovec{iovec{
308 .iov_base = buf.ptr,308 .iov_base = buf.ptr,
309 .iov_len = buf.len,309 .iov_len = buf.len,
...@@ -352,7 +352,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -352,7 +352,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
352/// * Windows352/// * Windows
353/// On these systems, the read races with concurrent writes to the same file descriptor.353/// On these systems, the read races with concurrent writes to the same file descriptor.
354pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {354pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
355 if (builtin.os == .windows) {355 if (builtin.os.tag == .windows) {
356 // TODO batch these into parallel requests356 // TODO batch these into parallel requests
357 var off: usize = 0;357 var off: usize = 0;
358 var iov_i: usize = 0;358 var iov_i: usize = 0;
...@@ -406,7 +406,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -406,7 +406,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
406/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are406/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
407/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.407/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
408pub fn pread(fd: fd_t, buf: []u8, offset: u64) ReadError!usize {408pub fn pread(fd: fd_t, buf: []u8, offset: u64) ReadError!usize {
409 if (builtin.os == .windows) {409 if (builtin.os.tag == .windows) {
410 return windows.ReadFile(fd, buf, offset);410 return windows.ReadFile(fd, buf, offset);
411 }411 }
412412
...@@ -493,7 +493,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {...@@ -493,7 +493,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
493 }493 }
494 }494 }
495495
496 if (builtin.os == .windows) {496 if (builtin.os.tag == .windows) {
497 // TODO batch these into parallel requests497 // TODO batch these into parallel requests
498 var off: usize = 0;498 var off: usize = 0;
499 var iov_i: usize = 0;499 var iov_i: usize = 0;
...@@ -557,11 +557,11 @@ pub const WriteError = error{...@@ -557,11 +557,11 @@ pub const WriteError = error{
557/// If the application has a global event loop enabled, EAGAIN is handled557/// If the application has a global event loop enabled, EAGAIN is handled
558/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.558/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
559pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {559pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
560 if (builtin.os == .windows) {560 if (builtin.os.tag == .windows) {
561 return windows.WriteFile(fd, bytes, null);561 return windows.WriteFile(fd, bytes, null);
562 }562 }
563563
564 if (builtin.os == .wasi and !builtin.link_libc) {564 if (builtin.os.tag == .wasi and !builtin.link_libc) {
565 const ciovs = [1]iovec_const{iovec_const{565 const ciovs = [1]iovec_const{iovec_const{
566 .iov_base = bytes.ptr,566 .iov_base = bytes.ptr,
567 .iov_len = bytes.len,567 .iov_len = bytes.len,
...@@ -650,7 +650,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {...@@ -650,7 +650,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
650/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are650/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
651/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.651/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
652pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) WriteError!void {652pub 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) {
654 return windows.WriteFile(fd, bytes, offset);654 return windows.WriteFile(fd, bytes, offset);
655 }655 }
656656
...@@ -739,7 +739,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void...@@ -739,7 +739,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void
739 }739 }
740 }740 }
741741
742 if (comptime std.Target.current.isWindows()) {742 if (std.Target.current.os.tag == .windows) {
743 var off = offset;743 var off = offset;
744 for (iov) |item| {744 for (iov) |item| {
745 try pwrite(fd, item.iov_base[0..item.iov_len], off);745 try pwrite(fd, item.iov_base[0..item.iov_len], off);
...@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std....@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
10951095
1096pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {1096pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
1097 for (envp_buf) |env| {1097 for (envp_buf) |env| {
1098 const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;1098 const env_buf = if (env) |ptr| ptr[0 .. mem.len(ptr) + 1] else break;
1099 allocator.free(env_buf);1099 allocator.free(env_buf);
1100 }1100 }
1101 allocator.free(envp_buf);1101 allocator.free(envp_buf);
...@@ -1129,7 +1129,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {...@@ -1129,7 +1129,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {
1129 }1129 }
1130 return null;1130 return null;
1131 }1131 }
1132 if (builtin.os == .windows) {1132 if (builtin.os.tag == .windows) {
1133 @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.");1133 @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.");
1134 }1134 }
1135 // TODO see https://github.com/ziglang/zig/issues/45241135 // TODO see https://github.com/ziglang/zig/issues/4524
...@@ -1158,7 +1158,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {...@@ -1158,7 +1158,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
1158 const value = system.getenv(key) orelse return null;1158 const value = system.getenv(key) orelse return null;
1159 return mem.toSliceConst(u8, value);1159 return mem.toSliceConst(u8, value);
1160 }1160 }
1161 if (builtin.os == .windows) {1161 if (builtin.os.tag == .windows) {
1162 @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.");1162 @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.");
1163 }1163 }
1164 return getenv(mem.toSliceConst(u8, key));1164 return getenv(mem.toSliceConst(u8, key));
...@@ -1167,7 +1167,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {...@@ -1167,7 +1167,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
1167/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.1167/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
1168/// See also `getenv`.1168/// See also `getenv`.
1169pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {1169pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
1170 if (builtin.os != .windows) {1170 if (builtin.os.tag != .windows) {
1171 @compileError("std.os.getenvW is a Windows-only API");1171 @compileError("std.os.getenvW is a Windows-only API");
1172 }1172 }
1173 const key_slice = mem.toSliceConst(u16, key);1173 const key_slice = mem.toSliceConst(u16, key);
...@@ -1199,7 +1199,7 @@ pub const GetCwdError = error{...@@ -1199,7 +1199,7 @@ pub const GetCwdError = error{
11991199
1200/// The result is a slice of out_buffer, indexed from 0.1200/// The result is a slice of out_buffer, indexed from 0.
1201pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {1201pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
1202 if (builtin.os == .windows) {1202 if (builtin.os.tag == .windows) {
1203 return windows.GetCurrentDirectory(out_buffer);1203 return windows.GetCurrentDirectory(out_buffer);
1204 }1204 }
12051205
...@@ -1240,7 +1240,7 @@ pub const SymLinkError = error{...@@ -1240,7 +1240,7 @@ pub const SymLinkError = error{
1240/// If `sym_link_path` exists, it will not be overwritten.1240/// If `sym_link_path` exists, it will not be overwritten.
1241/// See also `symlinkC` and `symlinkW`.1241/// See also `symlinkC` and `symlinkW`.
1242pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {1242pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
1243 if (builtin.os == .windows) {1243 if (builtin.os.tag == .windows) {
1244 const target_path_w = try windows.sliceToPrefixedFileW(target_path);1244 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
1245 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);1245 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
1246 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);1246 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!...@@ -1254,7 +1254,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
1254/// This is the same as `symlink` except the parameters are null-terminated pointers.1254/// This is the same as `symlink` except the parameters are null-terminated pointers.
1255/// See also `symlink`.1255/// See also `symlink`.
1256pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {1256pub 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) {
1258 const target_path_w = try windows.cStrToPrefixedFileW(target_path);1258 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
1259 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);1259 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
1260 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);1260 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
...@@ -1329,7 +1329,7 @@ pub const UnlinkError = error{...@@ -1329,7 +1329,7 @@ pub const UnlinkError = error{
1329/// Delete a name and possibly the file it refers to.1329/// Delete a name and possibly the file it refers to.
1330/// See also `unlinkC`.1330/// See also `unlinkC`.
1331pub fn unlink(file_path: []const u8) UnlinkError!void {1331pub fn unlink(file_path: []const u8) UnlinkError!void {
1332 if (builtin.os == .windows) {1332 if (builtin.os.tag == .windows) {
1333 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1333 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1334 return windows.DeleteFileW(&file_path_w);1334 return windows.DeleteFileW(&file_path_w);
1335 } else {1335 } else {
...@@ -1340,7 +1340,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {...@@ -1340,7 +1340,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
13401340
1341/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.1341/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
1342pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void {1342pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void {
1343 if (builtin.os == .windows) {1343 if (builtin.os.tag == .windows) {
1344 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1344 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1345 return windows.DeleteFileW(&file_path_w);1345 return windows.DeleteFileW(&file_path_w);
1346 }1346 }
...@@ -1372,7 +1372,7 @@ pub const UnlinkatError = UnlinkError || error{...@@ -1372,7 +1372,7 @@ pub const UnlinkatError = UnlinkError || error{
1372/// Asserts that the path parameter has no null bytes.1372/// Asserts that the path parameter has no null bytes.
1373pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {1373pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
1374 if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0);1374 if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0);
1375 if (builtin.os == .windows) {1375 if (builtin.os.tag == .windows) {
1376 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1376 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1377 return unlinkatW(dirfd, &file_path_w, flags);1377 return unlinkatW(dirfd, &file_path_w, flags);
1378 }1378 }
...@@ -1382,7 +1382,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo...@@ -1382,7 +1382,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
13821382
1383/// Same as `unlinkat` but `file_path` is a null-terminated string.1383/// Same as `unlinkat` but `file_path` is a null-terminated string.
1384pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {1384pub 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) {
1386 const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);1386 const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);
1387 return unlinkatW(dirfd, &file_path_w, flags);1387 return unlinkatW(dirfd, &file_path_w, flags);
1388 }1388 }
...@@ -1438,7 +1438,7 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr...@@ -1438,7 +1438,7 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr
14381438
1439 var attr = w.OBJECT_ATTRIBUTES{1439 var attr = w.OBJECT_ATTRIBUTES{
1440 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),1440 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
1441 .RootDirectory = dirfd,1441 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd,
1442 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.1442 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
1443 .ObjectName = &nt_name,1443 .ObjectName = &nt_name,
1444 .SecurityDescriptor = null,1444 .SecurityDescriptor = null,
...@@ -1493,7 +1493,7 @@ const RenameError = error{...@@ -1493,7 +1493,7 @@ const RenameError = error{
14931493
1494/// Change the name or location of a file.1494/// Change the name or location of a file.
1495pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {1495pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
1496 if (builtin.os == .windows) {1496 if (builtin.os.tag == .windows) {
1497 const old_path_w = try windows.sliceToPrefixedFileW(old_path);1497 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
1498 const new_path_w = try windows.sliceToPrefixedFileW(new_path);1498 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
1499 return renameW(&old_path_w, &new_path_w);1499 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 {...@@ -1506,7 +1506,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
15061506
1507/// Same as `rename` except the parameters are null-terminated byte arrays.1507/// Same as `rename` except the parameters are null-terminated byte arrays.
1508pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {1508pub 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) {
1510 const old_path_w = try windows.cStrToPrefixedFileW(old_path);1510 const old_path_w = try windows.cStrToPrefixedFileW(old_path);
1511 const new_path_w = try windows.cStrToPrefixedFileW(new_path);1511 const new_path_w = try windows.cStrToPrefixedFileW(new_path);
1512 return renameW(&old_path_w, &new_path_w);1512 return renameW(&old_path_w, &new_path_w);
...@@ -1561,7 +1561,7 @@ pub const MakeDirError = error{...@@ -1561,7 +1561,7 @@ pub const MakeDirError = error{
1561/// Create a directory.1561/// Create a directory.
1562/// `mode` is ignored on Windows.1562/// `mode` is ignored on Windows.
1563pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {1563pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
1564 if (builtin.os == .windows) {1564 if (builtin.os.tag == .windows) {
1565 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);1565 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1566 return windows.CreateDirectoryW(&dir_path_w, null);1566 return windows.CreateDirectoryW(&dir_path_w, null);
1567 } else {1567 } else {
...@@ -1572,7 +1572,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {...@@ -1572,7 +1572,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
15721572
1573/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.1573/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
1574pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {1574pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
1575 if (builtin.os == .windows) {1575 if (builtin.os.tag == .windows) {
1576 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);1576 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1577 return windows.CreateDirectoryW(&dir_path_w, null);1577 return windows.CreateDirectoryW(&dir_path_w, null);
1578 }1578 }
...@@ -1611,7 +1611,7 @@ pub const DeleteDirError = error{...@@ -1611,7 +1611,7 @@ pub const DeleteDirError = error{
16111611
1612/// Deletes an empty directory.1612/// Deletes an empty directory.
1613pub fn rmdir(dir_path: []const u8) DeleteDirError!void {1613pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
1614 if (builtin.os == .windows) {1614 if (builtin.os.tag == .windows) {
1615 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);1615 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1616 return windows.RemoveDirectoryW(&dir_path_w);1616 return windows.RemoveDirectoryW(&dir_path_w);
1617 } else {1617 } else {
...@@ -1622,7 +1622,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {...@@ -1622,7 +1622,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
16221622
1623/// Same as `rmdir` except the parameter is null-terminated.1623/// Same as `rmdir` except the parameter is null-terminated.
1624pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void {1624pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void {
1625 if (builtin.os == .windows) {1625 if (builtin.os.tag == .windows) {
1626 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);1626 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1627 return windows.RemoveDirectoryW(&dir_path_w);1627 return windows.RemoveDirectoryW(&dir_path_w);
1628 }1628 }
...@@ -1658,7 +1658,7 @@ pub const ChangeCurDirError = error{...@@ -1658,7 +1658,7 @@ pub const ChangeCurDirError = error{
1658/// Changes the current working directory of the calling process.1658/// Changes the current working directory of the calling process.
1659/// `dir_path` is recommended to be a UTF-8 encoded string.1659/// `dir_path` is recommended to be a UTF-8 encoded string.
1660pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {1660pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
1661 if (builtin.os == .windows) {1661 if (builtin.os.tag == .windows) {
1662 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);1662 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1663 @compileError("TODO implement chdir for Windows");1663 @compileError("TODO implement chdir for Windows");
1664 } else {1664 } else {
...@@ -1669,7 +1669,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {...@@ -1669,7 +1669,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
16691669
1670/// Same as `chdir` except the parameter is null-terminated.1670/// Same as `chdir` except the parameter is null-terminated.
1671pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void {1671pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void {
1672 if (builtin.os == .windows) {1672 if (builtin.os.tag == .windows) {
1673 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);1673 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1674 @compileError("TODO implement chdir for Windows");1674 @compileError("TODO implement chdir for Windows");
1675 }1675 }
...@@ -1700,7 +1700,7 @@ pub const ReadLinkError = error{...@@ -1700,7 +1700,7 @@ pub const ReadLinkError = error{
1700/// Read value of a symbolic link.1700/// Read value of a symbolic link.
1701/// The return value is a slice of `out_buffer` from index 0.1701/// The return value is a slice of `out_buffer` from index 0.
1702pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {1702pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
1703 if (builtin.os == .windows) {1703 if (builtin.os.tag == .windows) {
1704 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1704 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1705 @compileError("TODO implement readlink for Windows");1705 @compileError("TODO implement readlink for Windows");
1706 } else {1706 } else {
...@@ -1711,7 +1711,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {...@@ -1711,7 +1711,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
17111711
1712/// Same as `readlink` except `file_path` is null-terminated.1712/// Same as `readlink` except `file_path` is null-terminated.
1713pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {1713pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
1714 if (builtin.os == .windows) {1714 if (builtin.os.tag == .windows) {
1715 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1715 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1716 @compileError("TODO implement readlink for Windows");1716 @compileError("TODO implement readlink for Windows");
1717 }1717 }
...@@ -1732,7 +1732,7 @@ pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8...@@ -1732,7 +1732,7 @@ pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
1732}1732}
17331733
1734pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {1734pub 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) {
1736 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1736 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1737 @compileError("TODO implement readlink for Windows");1737 @compileError("TODO implement readlink for Windows");
1738 }1738 }
...@@ -1800,7 +1800,7 @@ pub fn setregid(rgid: u32, egid: u32) SetIdError!void {...@@ -1800,7 +1800,7 @@ pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
18001800
1801/// Test whether a file descriptor refers to a terminal.1801/// Test whether a file descriptor refers to a terminal.
1802pub fn isatty(handle: fd_t) bool {1802pub fn isatty(handle: fd_t) bool {
1803 if (builtin.os == .windows) {1803 if (builtin.os.tag == .windows) {
1804 if (isCygwinPty(handle))1804 if (isCygwinPty(handle))
1805 return true;1805 return true;
18061806
...@@ -1810,7 +1810,7 @@ pub fn isatty(handle: fd_t) bool {...@@ -1810,7 +1810,7 @@ pub fn isatty(handle: fd_t) bool {
1810 if (builtin.link_libc) {1810 if (builtin.link_libc) {
1811 return system.isatty(handle) != 0;1811 return system.isatty(handle) != 0;
1812 }1812 }
1813 if (builtin.os == .wasi) {1813 if (builtin.os.tag == .wasi) {
1814 var statbuf: fdstat_t = undefined;1814 var statbuf: fdstat_t = undefined;
1815 const err = system.fd_fdstat_get(handle, &statbuf);1815 const err = system.fd_fdstat_get(handle, &statbuf);
1816 if (err != 0) {1816 if (err != 0) {
...@@ -1828,7 +1828,7 @@ pub fn isatty(handle: fd_t) bool {...@@ -1828,7 +1828,7 @@ pub fn isatty(handle: fd_t) bool {
18281828
1829 return true;1829 return true;
1830 }1830 }
1831 if (builtin.os == .linux) {1831 if (builtin.os.tag == .linux) {
1832 var wsz: linux.winsize = undefined;1832 var wsz: linux.winsize = undefined;
1833 return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, @as(isize, handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;1833 return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, @as(isize, handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
1834 }1834 }
...@@ -1836,7 +1836,7 @@ pub fn isatty(handle: fd_t) bool {...@@ -1836,7 +1836,7 @@ pub fn isatty(handle: fd_t) bool {
1836}1836}
18371837
1838pub fn isCygwinPty(handle: fd_t) bool {1838pub fn isCygwinPty(handle: fd_t) bool {
1839 if (builtin.os != .windows) return false;1839 if (builtin.os.tag != .windows) return false;
18401840
1841 const size = @sizeOf(windows.FILE_NAME_INFO);1841 const size = @sizeOf(windows.FILE_NAME_INFO);
1842 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);1842 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);
...@@ -2589,7 +2589,7 @@ pub const AccessError = error{...@@ -2589,7 +2589,7 @@ pub const AccessError = error{
2589/// check user's permissions for a file2589/// check user's permissions for a file
2590/// TODO currently this assumes `mode` is `F_OK` on Windows.2590/// TODO currently this assumes `mode` is `F_OK` on Windows.
2591pub fn access(path: []const u8, mode: u32) AccessError!void {2591pub fn access(path: []const u8, mode: u32) AccessError!void {
2592 if (builtin.os == .windows) {2592 if (builtin.os.tag == .windows) {
2593 const path_w = try windows.sliceToPrefixedFileW(path);2593 const path_w = try windows.sliceToPrefixedFileW(path);
2594 _ = try windows.GetFileAttributesW(&path_w);2594 _ = try windows.GetFileAttributesW(&path_w);
2595 return;2595 return;
...@@ -2603,7 +2603,7 @@ pub const accessC = accessZ;...@@ -2603,7 +2603,7 @@ pub const accessC = accessZ;
26032603
2604/// Same as `access` except `path` is null-terminated.2604/// Same as `access` except `path` is null-terminated.
2605pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {2605pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
2606 if (builtin.os == .windows) {2606 if (builtin.os.tag == .windows) {
2607 const path_w = try windows.cStrToPrefixedFileW(path);2607 const path_w = try windows.cStrToPrefixedFileW(path);
2608 _ = try windows.GetFileAttributesW(&path_w);2608 _ = try windows.GetFileAttributesW(&path_w);
2609 return;2609 return;
...@@ -2644,7 +2644,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v...@@ -2644,7 +2644,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v
2644/// Check user's permissions for a file, based on an open directory handle.2644/// Check user's permissions for a file, based on an open directory handle.
2645/// TODO currently this ignores `mode` and `flags` on Windows.2645/// TODO currently this ignores `mode` and `flags` on Windows.
2646pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {2646pub 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) {
2648 const path_w = try windows.sliceToPrefixedFileW(path);2648 const path_w = try windows.sliceToPrefixedFileW(path);
2649 return faccessatW(dirfd, &path_w, mode, flags);2649 return faccessatW(dirfd, &path_w, mode, flags);
2650 }2650 }
...@@ -2654,7 +2654,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr...@@ -2654,7 +2654,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
26542654
2655/// Same as `faccessat` except the path parameter is null-terminated.2655/// Same as `faccessat` except the path parameter is null-terminated.
2656pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {2656pub 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) {
2658 const path_w = try windows.cStrToPrefixedFileW(path);2658 const path_w = try windows.cStrToPrefixedFileW(path);
2659 return faccessatW(dirfd, &path_w, mode, flags);2659 return faccessatW(dirfd, &path_w, mode, flags);
2660 }2660 }
...@@ -2764,6 +2764,7 @@ pub const SysCtlError = error{...@@ -2764,6 +2764,7 @@ pub const SysCtlError = error{
2764 PermissionDenied,2764 PermissionDenied,
2765 SystemResources,2765 SystemResources,
2766 NameTooLong,2766 NameTooLong,
2767 UnknownName,
2767} || UnexpectedError;2768} || UnexpectedError;
27682769
2769pub fn sysctl(2770pub fn sysctl(
...@@ -2779,6 +2780,7 @@ pub fn sysctl(...@@ -2779,6 +2780,7 @@ pub fn sysctl(
2779 EFAULT => unreachable,2780 EFAULT => unreachable,
2780 EPERM => return error.PermissionDenied,2781 EPERM => return error.PermissionDenied,
2781 ENOMEM => return error.SystemResources,2782 ENOMEM => return error.SystemResources,
2783 ENOENT => return error.UnknownName,
2782 else => |err| return unexpectedErrno(err),2784 else => |err| return unexpectedErrno(err),
2783 }2785 }
2784}2786}
...@@ -2795,6 +2797,7 @@ pub fn sysctlbynameC(...@@ -2795,6 +2797,7 @@ pub fn sysctlbynameC(
2795 EFAULT => unreachable,2797 EFAULT => unreachable,
2796 EPERM => return error.PermissionDenied,2798 EPERM => return error.PermissionDenied,
2797 ENOMEM => return error.SystemResources,2799 ENOMEM => return error.SystemResources,
2800 ENOENT => return error.UnknownName,
2798 else => |err| return unexpectedErrno(err),2801 else => |err| return unexpectedErrno(err),
2799 }2802 }
2800}2803}
...@@ -2811,7 +2814,7 @@ pub const SeekError = error{Unseekable} || UnexpectedError;...@@ -2811,7 +2814,7 @@ pub const SeekError = error{Unseekable} || UnexpectedError;
28112814
2812/// Repositions read/write file offset relative to the beginning.2815/// Repositions read/write file offset relative to the beginning.
2813pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {2816pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
2814 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {2817 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2815 var result: u64 = undefined;2818 var result: u64 = undefined;
2816 switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) {2819 switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) {
2817 0 => return,2820 0 => return,
...@@ -2823,7 +2826,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {...@@ -2823,7 +2826,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
2823 else => |err| return unexpectedErrno(err),2826 else => |err| return unexpectedErrno(err),
2824 }2827 }
2825 }2828 }
2826 if (builtin.os == .windows) {2829 if (builtin.os.tag == .windows) {
2827 return windows.SetFilePointerEx_BEGIN(fd, offset);2830 return windows.SetFilePointerEx_BEGIN(fd, offset);
2828 }2831 }
2829 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned2832 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned
...@@ -2840,7 +2843,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {...@@ -2840,7 +2843,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
28402843
2841/// Repositions read/write file offset relative to the current offset.2844/// Repositions read/write file offset relative to the current offset.
2842pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {2845pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
2843 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {2846 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2844 var result: u64 = undefined;2847 var result: u64 = undefined;
2845 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_CUR))) {2848 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_CUR))) {
2846 0 => return,2849 0 => return,
...@@ -2852,7 +2855,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {...@@ -2852,7 +2855,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
2852 else => |err| return unexpectedErrno(err),2855 else => |err| return unexpectedErrno(err),
2853 }2856 }
2854 }2857 }
2855 if (builtin.os == .windows) {2858 if (builtin.os.tag == .windows) {
2856 return windows.SetFilePointerEx_CURRENT(fd, offset);2859 return windows.SetFilePointerEx_CURRENT(fd, offset);
2857 }2860 }
2858 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {2861 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
...@@ -2868,7 +2871,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {...@@ -2868,7 +2871,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
28682871
2869/// Repositions read/write file offset relative to the end.2872/// Repositions read/write file offset relative to the end.
2870pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {2873pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
2871 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {2874 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2872 var result: u64 = undefined;2875 var result: u64 = undefined;
2873 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_END))) {2876 switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_END))) {
2874 0 => return,2877 0 => return,
...@@ -2880,7 +2883,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {...@@ -2880,7 +2883,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
2880 else => |err| return unexpectedErrno(err),2883 else => |err| return unexpectedErrno(err),
2881 }2884 }
2882 }2885 }
2883 if (builtin.os == .windows) {2886 if (builtin.os.tag == .windows) {
2884 return windows.SetFilePointerEx_END(fd, offset);2887 return windows.SetFilePointerEx_END(fd, offset);
2885 }2888 }
2886 switch (errno(system.lseek(fd, offset, SEEK_END))) {2889 switch (errno(system.lseek(fd, offset, SEEK_END))) {
...@@ -2896,7 +2899,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {...@@ -2896,7 +2899,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
28962899
2897/// Returns the read/write file offset relative to the beginning.2900/// Returns the read/write file offset relative to the beginning.
2898pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {2901pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
2899 if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {2902 if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2900 var result: u64 = undefined;2903 var result: u64 = undefined;
2901 switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {2904 switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {
2902 0 => return result,2905 0 => return result,
...@@ -2908,7 +2911,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {...@@ -2908,7 +2911,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
2908 else => |err| return unexpectedErrno(err),2911 else => |err| return unexpectedErrno(err),
2909 }2912 }
2910 }2913 }
2911 if (builtin.os == .windows) {2914 if (builtin.os.tag == .windows) {
2912 return windows.SetFilePointerEx_CURRENT_get(fd);2915 return windows.SetFilePointerEx_CURRENT_get(fd);
2913 }2916 }
2914 const rc = system.lseek(fd, 0, SEEK_CUR);2917 const rc = system.lseek(fd, 0, SEEK_CUR);
...@@ -2957,7 +2960,7 @@ pub const RealPathError = error{...@@ -2957,7 +2960,7 @@ pub const RealPathError = error{
2957/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.2960/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
2958/// See also `realpathC` and `realpathW`.2961/// See also `realpathC` and `realpathW`.
2959pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {2962pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2960 if (builtin.os == .windows) {2963 if (builtin.os.tag == .windows) {
2961 const pathname_w = try windows.sliceToPrefixedFileW(pathname);2964 const pathname_w = try windows.sliceToPrefixedFileW(pathname);
2962 return realpathW(&pathname_w, out_buffer);2965 return realpathW(&pathname_w, out_buffer);
2963 }2966 }
...@@ -2967,11 +2970,11 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE...@@ -2967,11 +2970,11 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
29672970
2968/// Same as `realpath` except `pathname` is null-terminated.2971/// Same as `realpath` except `pathname` is null-terminated.
2969pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {2972pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2970 if (builtin.os == .windows) {2973 if (builtin.os.tag == .windows) {
2971 const pathname_w = try windows.cStrToPrefixedFileW(pathname);2974 const pathname_w = try windows.cStrToPrefixedFileW(pathname);
2972 return realpathW(&pathname_w, out_buffer);2975 return realpathW(&pathname_w, out_buffer);
2973 }2976 }
2974 if (builtin.os == .linux and !builtin.link_libc) {2977 if (builtin.os.tag == .linux and !builtin.link_libc) {
2975 const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);2978 const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
2976 defer close(fd);2979 defer close(fd);
29772980
...@@ -3121,7 +3124,7 @@ pub fn dl_iterate_phdr(...@@ -3121,7 +3124,7 @@ pub fn dl_iterate_phdr(
3121pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;3124pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
31223125
3123pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {3126pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
3124 if (comptime std.Target.current.getOs() == .wasi) {3127 if (std.Target.current.os.tag == .wasi) {
3125 var ts: timestamp_t = undefined;3128 var ts: timestamp_t = undefined;
3126 switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {3129 switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {
3127 0 => {3130 0 => {
...@@ -3144,7 +3147,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {...@@ -3144,7 +3147,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
3144}3147}
31453148
3146pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {3149pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
3147 if (comptime std.Target.current.getOs() == .wasi) {3150 if (std.Target.current.os.tag == .wasi) {
3148 var ts: timestamp_t = undefined;3151 var ts: timestamp_t = undefined;
3149 switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {3152 switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {
3150 0 => res.* = .{3153 0 => res.* = .{
...@@ -3222,7 +3225,7 @@ pub const SigaltstackError = error{...@@ -3222,7 +3225,7 @@ pub const SigaltstackError = error{
3222} || UnexpectedError;3225} || UnexpectedError;
32233226
3224pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {3227pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
3225 if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi)3228 if (builtin.os.tag == .windows or builtin.os.tag == .uefi or builtin.os.tag == .wasi)
3226 @compileError("std.os.sigaltstack not available for this target");3229 @compileError("std.os.sigaltstack not available for this target");
32273230
3228 switch (errno(system.sigaltstack(ss, old_ss))) {3231 switch (errno(system.sigaltstack(ss, old_ss))) {
...@@ -3294,23 +3297,25 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {...@@ -3294,23 +3297,25 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
3294 else => |err| return unexpectedErrno(err),3297 else => |err| return unexpectedErrno(err),
3295 }3298 }
3296 }3299 }
3297 if (builtin.os == .linux) {3300 if (builtin.os.tag == .linux) {
3298 var uts: utsname = undefined;3301 const uts = uname();
3299 switch (errno(system.uname(&uts))) {3302 const hostname = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.nodename));
3300 0 => {3303 mem.copy(u8, name_buffer, hostname);
3301 const hostname = mem.toSlice(u8, @ptrCast([*:0]u8, &uts.nodename));3304 return name_buffer[0..hostname.len];
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 }
3309 }3305 }
33103306
3311 @compileError("TODO implement gethostname for this OS");3307 @compileError("TODO implement gethostname for this OS");
3312}3308}
33133309
3310pub fn uname() utsname {
3311 var uts: utsname = undefined;
3312 switch (errno(system.uname(&uts))) {
3313 0 => return uts,
3314 EFAULT => unreachable,
3315 else => unreachable,
3316 }
3317}
3318
3314pub fn res_mkquery(3319pub fn res_mkquery(
3315 op: u4,3320 op: u4,
3316 dname: []const u8,3321 dname: []const u8,
...@@ -3611,7 +3616,7 @@ pub const SchedYieldError = error{...@@ -3611,7 +3616,7 @@ pub const SchedYieldError = error{
3611};3616};
36123617
3613pub fn sched_yield() SchedYieldError!void {3618pub fn sched_yield() SchedYieldError!void {
3614 if (builtin.os == .windows) {3619 if (builtin.os.tag == .windows) {
3615 // The return value has to do with how many other threads there are; it is not3620 // The return value has to do with how many other threads there are; it is not
3616 // an error condition on Windows.3621 // an error condition on Windows.
3617 _ = windows.kernel32.SwitchToThread();3622 _ = windows.kernel32.SwitchToThread();
lib/std/os/bits.zig+2-2
...@@ -3,10 +3,10 @@...@@ -3,10 +3,10 @@
3//! Root source files can define `os.bits` and these will additionally be added3//! Root source files can define `os.bits` and these will additionally be added
4//! to the namespace.4//! to the namespace.
55
6const builtin = @import("builtin");6const std = @import("std");
7const root = @import("root");7const root = @import("root");
88
9pub usingnamespace switch (builtin.os) {9pub usingnamespace switch (std.Target.current.os.tag) {
10 .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),10 .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),
11 .dragonfly => @import("bits/dragonfly.zig"),11 .dragonfly => @import("bits/dragonfly.zig"),
12 .freebsd => @import("bits/freebsd.zig"),12 .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...@@ -1070,7 +1070,7 @@ pub fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) usi
1070}1070}
10711071
1072test "" {1072test "" {
1073 if (builtin.os == .linux) {1073 if (builtin.os.tag == .linux) {
1074 _ = @import("linux/test.zig");1074 _ = @import("linux/test.zig");
1075 }1075 }
1076}1076}
lib/std/os/linux/vdso.zig+7-3
...@@ -22,7 +22,11 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -22,7 +22,11 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
22 }) {22 }) {
23 const this_ph = @intToPtr(*elf.Phdr, ph_addr);23 const this_ph = @intToPtr(*elf.Phdr, ph_addr);
24 switch (this_ph.p_type) {24 switch (this_ph.p_type) {
25 elf.PT_LOAD => base = vdso_addr + this_ph.p_offset - this_ph.p_vaddr,25 // On WSL1 as well as older kernels, the VDSO ELF image is pre-linked in the upper half
26 // of the memory space (e.g. p_vaddr = 0xffffffffff700000 on WSL1).
27 // Wrapping operations are used on this line as well as subsequent calculations relative to base
28 // (lines 47, 78) to ensure no overflow check is tripped.
29 elf.PT_LOAD => base = vdso_addr +% this_ph.p_offset -% this_ph.p_vaddr,
26 elf.PT_DYNAMIC => maybe_dynv = @intToPtr([*]usize, vdso_addr + this_ph.p_offset),30 elf.PT_DYNAMIC => maybe_dynv = @intToPtr([*]usize, vdso_addr + this_ph.p_offset),
27 else => {},31 else => {},
28 }32 }
...@@ -40,7 +44,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -40,7 +44,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
40 {44 {
41 var i: usize = 0;45 var i: usize = 0;
42 while (dynv[i] != 0) : (i += 2) {46 while (dynv[i] != 0) : (i += 2) {
43 const p = base + dynv[i + 1];47 const p = base +% dynv[i + 1];
44 switch (dynv[i]) {48 switch (dynv[i]) {
45 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),49 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
46 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),50 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
...@@ -71,7 +75,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -71,7 +75,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
71 if (!checkver(maybe_verdef.?, versym[i], vername, strings))75 if (!checkver(maybe_verdef.?, versym[i], vername, strings))
72 continue;76 continue;
73 }77 }
74 return base + syms[i].st_value;78 return base +% syms[i].st_value;
75 }79 }
7680
77 return 0;81 return 0;
lib/std/os/test.zig+8-8
...@@ -53,7 +53,7 @@ test "std.Thread.getCurrentId" {...@@ -53,7 +53,7 @@ test "std.Thread.getCurrentId" {
53 thread.wait();53 thread.wait();
54 if (Thread.use_pthreads) {54 if (Thread.use_pthreads) {
55 expect(thread_current_id == thread_id);55 expect(thread_current_id == thread_id);
56 } else if (builtin.os == .windows) {56 } else if (builtin.os.tag == .windows) {
57 expect(Thread.getCurrentId() != thread_current_id);57 expect(Thread.getCurrentId() != thread_current_id);
58 } else {58 } else {
59 // If the thread completes very quickly, then thread_id can be 0. See the59 // If the thread completes very quickly, then thread_id can be 0. See the
...@@ -151,7 +151,7 @@ test "realpath" {...@@ -151,7 +151,7 @@ test "realpath" {
151}151}
152152
153test "sigaltstack" {153test "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
156 var st: os.stack_t = undefined;156 var st: os.stack_t = undefined;
157 try os.sigaltstack(null, &st);157 try os.sigaltstack(null, &st);
...@@ -204,7 +204,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {...@@ -204,7 +204,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
204}204}
205205
206test "dl_iterate_phdr" {206test "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)
208 return error.SkipZigTest;208 return error.SkipZigTest;
209209
210 var counter: usize = 0;210 var counter: usize = 0;
...@@ -213,7 +213,7 @@ test "dl_iterate_phdr" {...@@ -213,7 +213,7 @@ test "dl_iterate_phdr" {
213}213}
214214
215test "gethostname" {215test "gethostname" {
216 if (builtin.os == .windows)216 if (builtin.os.tag == .windows)
217 return error.SkipZigTest;217 return error.SkipZigTest;
218218
219 var buf: [os.HOST_NAME_MAX]u8 = undefined;219 var buf: [os.HOST_NAME_MAX]u8 = undefined;
...@@ -222,7 +222,7 @@ test "gethostname" {...@@ -222,7 +222,7 @@ test "gethostname" {
222}222}
223223
224test "pipe" {224test "pipe" {
225 if (builtin.os == .windows)225 if (builtin.os.tag == .windows)
226 return error.SkipZigTest;226 return error.SkipZigTest;
227227
228 var fds = try os.pipe();228 var fds = try os.pipe();
...@@ -241,7 +241,7 @@ test "argsAlloc" {...@@ -241,7 +241,7 @@ test "argsAlloc" {
241241
242test "memfd_create" {242test "memfd_create" {
243 // memfd_create is linux specific.243 // memfd_create is linux specific.
244 if (builtin.os != .linux) return error.SkipZigTest;244 if (builtin.os.tag != .linux) return error.SkipZigTest;
245 const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {245 const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
246 // Related: https://github.com/ziglang/zig/issues/4019246 // Related: https://github.com/ziglang/zig/issues/4019
247 error.SystemOutdated => return error.SkipZigTest,247 error.SystemOutdated => return error.SkipZigTest,
...@@ -258,7 +258,7 @@ test "memfd_create" {...@@ -258,7 +258,7 @@ test "memfd_create" {
258}258}
259259
260test "mmap" {260test "mmap" {
261 if (builtin.os == .windows)261 if (builtin.os.tag == .windows)
262 return error.SkipZigTest;262 return error.SkipZigTest;
263263
264 // Simple mmap() call with non page-aligned size264 // Simple mmap() call with non page-aligned size
...@@ -353,7 +353,7 @@ test "mmap" {...@@ -353,7 +353,7 @@ test "mmap" {
353}353}
354354
355test "getenv" {355test "getenv" {
356 if (builtin.os == .windows) {356 if (builtin.os.tag == .windows) {
357 expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);357 expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
358 } else {358 } else {
359 expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);359 expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
lib/std/os/windows/bits.zig+201-16
...@@ -23,6 +23,7 @@ pub const BOOL = c_int;...@@ -23,6 +23,7 @@ pub const BOOL = c_int;
23pub const BOOLEAN = BYTE;23pub const BOOLEAN = BYTE;
24pub const BYTE = u8;24pub const BYTE = u8;
25pub const CHAR = u8;25pub const CHAR = u8;
26pub const UCHAR = u8;
26pub const FLOAT = f32;27pub const FLOAT = f32;
27pub const HANDLE = *c_void;28pub const HANDLE = *c_void;
28pub const HCRYPTPROV = ULONG_PTR;29pub const HCRYPTPROV = ULONG_PTR;
...@@ -54,6 +55,7 @@ pub const WORD = u16;...@@ -54,6 +55,7 @@ pub const WORD = u16;
54pub const DWORD = u32;55pub const DWORD = u32;
55pub const DWORD64 = u64;56pub const DWORD64 = u64;
56pub const LARGE_INTEGER = i64;57pub const LARGE_INTEGER = i64;
58pub const ULARGE_INTEGER = u64;
57pub const USHORT = u16;59pub const USHORT = u16;
58pub const SHORT = i16;60pub const SHORT = i16;
59pub const ULONG = u32;61pub const ULONG = u32;
...@@ -1145,32 +1147,202 @@ pub const UNICODE_STRING = extern struct {...@@ -1145,32 +1147,202 @@ pub const UNICODE_STRING = extern struct {
1145 Buffer: [*]WCHAR,1147 Buffer: [*]WCHAR,
1146};1148};
11471149
1150const ACTIVATION_CONTEXT_DATA = @OpaqueType();
1151const ASSEMBLY_STORAGE_MAP = @OpaqueType();
1152const FLS_CALLBACK_INFO = @OpaqueType();
1153const RTL_BITMAP = @OpaqueType();
1154pub const PRTL_BITMAP = *RTL_BITMAP;
1155const KAFFINITY = usize;
1156
1157/// Process Environment Block
1158/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
1159/// - https://github.com/wine-mirror/wine/blob/1aff1e6a370ee8c0213a0fd4b220d121da8527aa/include/winternl.h#L269
1160/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/index.htm
1148pub const PEB = extern struct {1161pub const PEB = extern struct {
1149 Reserved1: [2]BYTE,1162 // Versions: All
1150 BeingDebugged: BYTE,1163 InheritedAddressSpace: BOOLEAN,
1151 Reserved2: [1]BYTE,1164
1152 Reserved3: [2]PVOID,1165 // Versions: 3.51+
1166 ReadImageFileExecOptions: BOOLEAN,
1167 BeingDebugged: BOOLEAN,
1168
1169 // Versions: 5.2+ (previously was padding)
1170 BitField: UCHAR,
1171
1172 // Versions: all
1173 Mutant: HANDLE,
1174 ImageBaseAddress: HMODULE,
1153 Ldr: *PEB_LDR_DATA,1175 Ldr: *PEB_LDR_DATA,
1154 ProcessParameters: *RTL_USER_PROCESS_PARAMETERS,1176 ProcessParameters: *RTL_USER_PROCESS_PARAMETERS,
1155 Reserved4: [3]PVOID,1177 SubSystemData: PVOID,
1178 ProcessHeap: HANDLE,
1179
1180 // Versions: 5.1+
1181 FastPebLock: *RTL_CRITICAL_SECTION,
1182
1183 // Versions: 5.2+
1156 AtlThunkSListPtr: PVOID,1184 AtlThunkSListPtr: PVOID,
1157 Reserved5: PVOID,1185 IFEOKey: PVOID,
1158 Reserved6: ULONG,1186
1159 Reserved7: PVOID,1187 // Versions: 6.0+
1160 Reserved8: ULONG,1188
1189 /// https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/crossprocessflags.htm
1190 CrossProcessFlags: ULONG,
1191
1192 // Versions: 6.0+
1193 union1: extern union {
1194 KernelCallbackTable: PVOID,
1195 UserSharedInfoPtr: PVOID,
1196 },
1197
1198 // Versions: 5.1+
1199 SystemReserved: ULONG,
1200
1201 // Versions: 5.1, (not 5.2, not 6.0), 6.1+
1161 AtlThunkSListPtr32: ULONG,1202 AtlThunkSListPtr32: ULONG,
1162 Reserved9: [45]PVOID,1203
1163 Reserved10: [96]BYTE,1204 // Versions: 6.1+
1164 PostProcessInitRoutine: PPS_POST_PROCESS_INIT_ROUTINE,1205 ApiSetMap: PVOID,
1165 Reserved11: [128]BYTE,1206
1166 Reserved12: [1]PVOID,1207 // Versions: all
1208 TlsExpansionCounter: ULONG,
1209 // note: there is padding here on 64 bit
1210 TlsBitmap: PRTL_BITMAP,
1211 TlsBitmapBits: [2]ULONG,
1212 ReadOnlySharedMemoryBase: PVOID,
1213
1214 // Versions: 1703+
1215 SharedData: PVOID,
1216
1217 // Versions: all
1218 ReadOnlyStaticServerData: *PVOID,
1219 AnsiCodePageData: PVOID,
1220 OemCodePageData: PVOID,
1221 UnicodeCaseTableData: PVOID,
1222
1223 // Versions: 3.51+
1224 NumberOfProcessors: ULONG,
1225 NtGlobalFlag: ULONG,
1226
1227 // Versions: all
1228 CriticalSectionTimeout: LARGE_INTEGER,
1229
1230 // End of Original PEB size
1231
1232 // Fields appended in 3.51:
1233 HeapSegmentReserve: ULONG_PTR,
1234 HeapSegmentCommit: ULONG_PTR,
1235 HeapDeCommitTotalFreeThreshold: ULONG_PTR,
1236 HeapDeCommitFreeBlockThreshold: ULONG_PTR,
1237 NumberOfHeaps: ULONG,
1238 MaximumNumberOfHeaps: ULONG,
1239 ProcessHeaps: *PVOID,
1240
1241 // Fields appended in 4.0:
1242 GdiSharedHandleTable: PVOID,
1243 ProcessStarterHelper: PVOID,
1244 GdiDCAttributeList: ULONG,
1245 // note: there is padding here on 64 bit
1246 LoaderLock: *RTL_CRITICAL_SECTION,
1247 OSMajorVersion: ULONG,
1248 OSMinorVersion: ULONG,
1249 OSBuildNumber: USHORT,
1250 OSCSDVersion: USHORT,
1251 OSPlatformId: ULONG,
1252 ImageSubSystem: ULONG,
1253 ImageSubSystemMajorVersion: ULONG,
1254 ImageSubSystemMinorVersion: ULONG,
1255 // note: there is padding here on 64 bit
1256 ActiveProcessAffinityMask: KAFFINITY,
1257 GdiHandleBuffer: [switch (@sizeOf(usize)) {
1258 4 => 0x22,
1259 8 => 0x3C,
1260 else => unreachable,
1261 }]ULONG,
1262
1263 // Fields appended in 5.0 (Windows 2000):
1264 PostProcessInitRoutine: PVOID,
1265 TlsExpansionBitmap: PRTL_BITMAP,
1266 TlsExpansionBitmapBits: [32]ULONG,
1167 SessionId: ULONG,1267 SessionId: ULONG,
1268 // note: there is padding here on 64 bit
1269 // Versions: 5.1+
1270 AppCompatFlags: ULARGE_INTEGER,
1271 AppCompatFlagsUser: ULARGE_INTEGER,
1272 ShimData: PVOID,
1273 // Versions: 5.0+
1274 AppCompatInfo: PVOID,
1275 CSDVersion: UNICODE_STRING,
1276
1277 // Fields appended in 5.1 (Windows XP):
1278 ActivationContextData: *const ACTIVATION_CONTEXT_DATA,
1279 ProcessAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
1280 SystemDefaultActivationData: *const ACTIVATION_CONTEXT_DATA,
1281 SystemAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
1282 MinimumStackCommit: ULONG_PTR,
1283
1284 // Fields appended in 5.2 (Windows Server 2003):
1285 FlsCallback: *FLS_CALLBACK_INFO,
1286 FlsListHead: LIST_ENTRY,
1287 FlsBitmap: PRTL_BITMAP,
1288 FlsBitmapBits: [4]ULONG,
1289 FlsHighIndex: ULONG,
1290
1291 // Fields appended in 6.0 (Windows Vista):
1292 WerRegistrationData: PVOID,
1293 WerShipAssertPtr: PVOID,
1294
1295 // Fields appended in 6.1 (Windows 7):
1296 pUnused: PVOID, // previously pContextData
1297 pImageHeaderHash: PVOID,
1298
1299 /// TODO: https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/tracingflags.htm
1300 TracingFlags: ULONG,
1301
1302 // Fields appended in 6.2 (Windows 8):
1303 CsrServerReadOnlySharedMemoryBase: ULONGLONG,
1304
1305 // Fields appended in 1511:
1306 TppWorkerpListLock: ULONG,
1307 TppWorkerpList: LIST_ENTRY,
1308 WaitOnAddressHashTable: [0x80]PVOID,
1309
1310 // Fields appended in 1709:
1311 TelemetryCoverageHeader: PVOID,
1312 CloudFileFlags: ULONG,
1168};1313};
11691314
1315/// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.
1316/// It is essentially the head of three double-linked lists of `LDR_DATA_TABLE_ENTRY` structures which each represent one loaded module.
1317///
1318/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
1319/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm
1170pub const PEB_LDR_DATA = extern struct {1320pub const PEB_LDR_DATA = extern struct {
1171 Reserved1: [8]BYTE,1321 // Versions: 3.51 and higher
1172 Reserved2: [3]PVOID,1322 /// The size in bytes of the structure
1323 Length: ULONG,
1324
1325 /// TRUE if the structure is prepared.
1326 Initialized: BOOLEAN,
1327
1328 SsHandle: PVOID,
1329 InLoadOrderModuleList: LIST_ENTRY,
1173 InMemoryOrderModuleList: LIST_ENTRY,1330 InMemoryOrderModuleList: LIST_ENTRY,
1331 InInitializationOrderModuleList: LIST_ENTRY,
1332
1333 // Versions: 5.1 and higher
1334
1335 /// No known use of this field is known in Windows 8 and higher.
1336 EntryInProgress: PVOID,
1337
1338 // Versions: 6.0 from Windows Vista SP1, and higher
1339 ShutdownInProgress: BOOLEAN,
1340
1341 /// Though ShutdownThreadId is declared as a HANDLE,
1342 /// it is indeed the thread ID as suggested by its name.
1343 /// It is picked up from the UniqueThread member of the CLIENT_ID in the
1344 /// TEB of the thread that asks to terminate the process.
1345 ShutdownThreadId: HANDLE,
1174};1346};
11751347
1176pub const RTL_USER_PROCESS_PARAMETERS = extern struct {1348pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
...@@ -1321,3 +1493,16 @@ pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {...@@ -1321,3 +1493,16 @@ pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {
1321 Flags: ULONG_PTR,1493 Flags: ULONG_PTR,
1322};1494};
1323pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX;1495pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX;
1496
1497pub const OSVERSIONINFOW = extern struct {
1498 dwOSVersionInfoSize: ULONG,
1499 dwMajorVersion: ULONG,
1500 dwMinorVersion: ULONG,
1501 dwBuildNumber: ULONG,
1502 dwPlatformId: ULONG,
1503 szCSDVersion: [128]WCHAR,
1504};
1505pub const POSVERSIONINFOW = *OSVERSIONINFOW;
1506pub const LPOSVERSIONINFOW = *OSVERSIONINFOW;
1507pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW;
1508pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW;
lib/std/os/windows/ntdll.zig+9-1
...@@ -1,6 +1,14 @@...@@ -1,6 +1,14 @@
1usingnamespace @import("bits.zig");1usingnamespace @import("bits.zig");
22
3pub extern "NtDll" fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) callconv(.Stdcall) WORD;3pub extern "NtDll" fn RtlGetVersion(
4 lpVersionInformation: PRTL_OSVERSIONINFOW,
5) callconv(.Stdcall) NTSTATUS;
6pub extern "NtDll" fn RtlCaptureStackBackTrace(
7 FramesToSkip: DWORD,
8 FramesToCapture: DWORD,
9 BackTrace: **c_void,
10 BackTraceHash: ?*DWORD,
11) callconv(.Stdcall) WORD;
4pub extern "NtDll" fn NtQueryInformationFile(12pub extern "NtDll" fn NtQueryInformationFile(
5 FileHandle: HANDLE,13 FileHandle: HANDLE,
6 IoStatusBlock: *IO_STATUS_BLOCK,14 IoStatusBlock: *IO_STATUS_BLOCK,
lib/std/packed_int_array.zig+2-2
...@@ -593,7 +593,7 @@ test "PackedInt(Array/Slice)Endian" {...@@ -593,7 +593,7 @@ test "PackedInt(Array/Slice)Endian" {
593// after this one is not mapped and will cause a segfault if we593// after this one is not mapped and will cause a segfault if we
594// don't account for the bounds.594// don't account for the bounds.
595test "PackedIntArray at end of available memory" {595test "PackedIntArray at end of available memory" {
596 switch (builtin.os) {596 switch (builtin.os.tag) {
597 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},597 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
598 else => return,598 else => return,
599 }599 }
...@@ -612,7 +612,7 @@ test "PackedIntArray at end of available memory" {...@@ -612,7 +612,7 @@ test "PackedIntArray at end of available memory" {
612}612}
613613
614test "PackedIntSlice at end of available memory" {614test "PackedIntSlice at end of available memory" {
615 switch (builtin.os) {615 switch (builtin.os.tag) {
616 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},616 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
617 else => return,617 else => return,
618 }618 }
lib/std/process.zig+15-11
...@@ -36,7 +36,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {...@@ -36,7 +36,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
36 var result = BufMap.init(allocator);36 var result = BufMap.init(allocator);
37 errdefer result.deinit();37 errdefer result.deinit();
3838
39 if (builtin.os == .windows) {39 if (builtin.os.tag == .windows) {
40 const ptr = os.windows.peb().ProcessParameters.Environment;40 const ptr = os.windows.peb().ProcessParameters.Environment;
4141
42 var i: usize = 0;42 var i: usize = 0;
...@@ -61,7 +61,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {...@@ -61,7 +61,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
61 try result.setMove(key, value);61 try result.setMove(key, value);
62 }62 }
63 return result;63 return result;
64 } else if (builtin.os == .wasi) {64 } else if (builtin.os.tag == .wasi) {
65 var environ_count: usize = undefined;65 var environ_count: usize = undefined;
66 var environ_buf_size: usize = undefined;66 var environ_buf_size: usize = undefined;
6767
...@@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{...@@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{
137137
138/// Caller must free returned memory.138/// Caller must free returned memory.
139pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {139pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
140 if (builtin.os == .windows) {140 if (builtin.os.tag == .windows) {
141 const result_w = blk: {141 const result_w = blk: {
142 const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);142 const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
143 defer allocator.free(key_w);143 defer allocator.free(key_w);
...@@ -338,12 +338,12 @@ pub const ArgIteratorWindows = struct {...@@ -338,12 +338,12 @@ pub const ArgIteratorWindows = struct {
338};338};
339339
340pub const ArgIterator = struct {340pub 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
343 inner: InnerType,343 inner: InnerType,
344344
345 pub fn init() ArgIterator {345 pub fn init() ArgIterator {
346 if (builtin.os == .wasi) {346 if (builtin.os.tag == .wasi) {
347 // TODO: Figure out a compatible interface accomodating WASI347 // TODO: Figure out a compatible interface accomodating WASI
348 @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");348 @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
349 }349 }
...@@ -355,7 +355,7 @@ pub const ArgIterator = struct {...@@ -355,7 +355,7 @@ pub const ArgIterator = struct {
355355
356 /// You must free the returned memory when done.356 /// You must free the returned memory when done.
357 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {357 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
358 if (builtin.os == .windows) {358 if (builtin.os.tag == .windows) {
359 return self.inner.next(allocator);359 return self.inner.next(allocator);
360 } else {360 } else {
361 return mem.dupe(allocator, u8, self.inner.next() orelse return null);361 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
...@@ -380,7 +380,7 @@ pub fn args() ArgIterator {...@@ -380,7 +380,7 @@ pub fn args() ArgIterator {
380380
381/// Caller must call argsFree on result.381/// Caller must call argsFree on result.
382pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {382pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
383 if (builtin.os == .wasi) {383 if (builtin.os.tag == .wasi) {
384 var count: usize = undefined;384 var count: usize = undefined;
385 var buf_size: usize = undefined;385 var buf_size: usize = undefined;
386386
...@@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {...@@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
445}445}
446446
447pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {447pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
448 if (builtin.os == .wasi) {448 if (builtin.os.tag == .wasi) {
449 const last_item = args_alloc[args_alloc.len - 1];449 const last_item = args_alloc[args_alloc.len - 1];
450 const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated450 const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
451 const first_item_ptr = args_alloc[0].ptr;451 const first_item_ptr = args_alloc[0].ptr;
...@@ -498,7 +498,7 @@ pub const UserInfo = struct {...@@ -498,7 +498,7 @@ pub const UserInfo = struct {
498498
499/// POSIX function which gets a uid from username.499/// POSIX function which gets a uid from username.
500pub fn getUserInfo(name: []const u8) !UserInfo {500pub fn getUserInfo(name: []const u8) !UserInfo {
501 return switch (builtin.os) {501 return switch (builtin.os.tag) {
502 .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),502 .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),
503 else => @compileError("Unsupported OS"),503 else => @compileError("Unsupported OS"),
504 };504 };
...@@ -591,7 +591,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {...@@ -591,7 +591,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
591}591}
592592
593pub fn getBaseAddress() usize {593pub fn getBaseAddress() usize {
594 switch (builtin.os) {594 switch (builtin.os.tag) {
595 .linux => {595 .linux => {
596 const base = os.system.getauxval(std.elf.AT_BASE);596 const base = os.system.getauxval(std.elf.AT_BASE);
597 if (base != 0) {597 if (base != 0) {
...@@ -609,13 +609,17 @@ pub fn getBaseAddress() usize {...@@ -609,13 +609,17 @@ pub fn getBaseAddress() usize {
609}609}
610610
611/// Caller owns the result value and each inner slice.611/// 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.
612pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {616pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
613 switch (builtin.link_mode) {617 switch (builtin.link_mode) {
614 .Static => return &[_][:0]u8{},618 .Static => return &[_][:0]u8{},
615 .Dynamic => {},619 .Dynamic => {},
616 }620 }
617 const List = std.ArrayList([:0]u8);621 const List = std.ArrayList([:0]u8);
618 switch (builtin.os) {622 switch (builtin.os.tag) {
619 .linux,623 .linux,
620 .freebsd,624 .freebsd,
621 .netbsd,625 .netbsd,
lib/std/reset_event.zig+3-3
...@@ -16,7 +16,7 @@ pub const ResetEvent = struct {...@@ -16,7 +16,7 @@ pub const ResetEvent = struct {
1616
17 pub const OsEvent = if (builtin.single_threaded)17 pub const OsEvent = if (builtin.single_threaded)
18 DebugEvent18 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)
20 PosixEvent20 PosixEvent
21 else21 else
22 AtomicEvent;22 AtomicEvent;
...@@ -106,7 +106,7 @@ const PosixEvent = struct {...@@ -106,7 +106,7 @@ const PosixEvent = struct {
106 fn deinit(self: *PosixEvent) void {106 fn deinit(self: *PosixEvent) void {
107 // on dragonfly, *destroy() functions can return EINVAL107 // on dragonfly, *destroy() functions can return EINVAL
108 // for statically initialized pthread structures108 // 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
111 const retm = c.pthread_mutex_destroy(&self.mutex);111 const retm = c.pthread_mutex_destroy(&self.mutex);
112 assert(retm == 0 or retm == err);112 assert(retm == 0 or retm == err);
...@@ -215,7 +215,7 @@ const AtomicEvent = struct {...@@ -215,7 +215,7 @@ const AtomicEvent = struct {
215 }215 }
216 }216 }
217217
218 pub const Futex = switch (builtin.os) {218 pub const Futex = switch (builtin.os.tag) {
219 .windows => WindowsFutex,219 .windows => WindowsFutex,
220 .linux => LinuxFutex,220 .linux => LinuxFutex,
221 else => SpinFutex,221 else => SpinFutex,
lib/std/special/c.zig+5-5
...@@ -17,7 +17,7 @@ const is_msvc = switch (builtin.abi) {...@@ -17,7 +17,7 @@ const is_msvc = switch (builtin.abi) {
17 .msvc => true,17 .msvc => true,
18 else => false,18 else => false,
19};19};
20const is_freestanding = switch (builtin.os) {20const is_freestanding = switch (builtin.os.tag) {
21 .freestanding => true,21 .freestanding => true,
22 else => false,22 else => false,
23};23};
...@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {...@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
47}47}
4848
49fn strlen(s: [*:0]const u8) callconv(.C) usize {49fn strlen(s: [*:0]const u8) callconv(.C) usize {
50 return std.mem.len(u8, s);50 return std.mem.len(s);
51}51}
5252
53fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {53fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {
...@@ -81,7 +81,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn...@@ -81,7 +81,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
81 @setCold(true);81 @setCold(true);
82 std.debug.panic("{}", .{msg});82 std.debug.panic("{}", .{msg});
83 }83 }
84 if (builtin.os != .freestanding and builtin.os != .other) {84 if (builtin.os.tag != .freestanding and builtin.os.tag != .other) {
85 std.os.abort();85 std.os.abort();
86 }86 }
87 while (true) {}87 while (true) {}
...@@ -178,11 +178,11 @@ test "test_bcmp" {...@@ -178,11 +178,11 @@ test "test_bcmp" {
178comptime {178comptime {
179 if (builtin.mode != builtin.Mode.ReleaseFast and179 if (builtin.mode != builtin.Mode.ReleaseFast and
180 builtin.mode != builtin.Mode.ReleaseSmall and180 builtin.mode != builtin.Mode.ReleaseSmall and
181 builtin.os != builtin.Os.windows)181 builtin.os.tag != .windows)
182 {182 {
183 @export(__stack_chk_fail, .{ .name = "__stack_chk_fail" });183 @export(__stack_chk_fail, .{ .name = "__stack_chk_fail" });
184 }184 }
185 if (builtin.os == builtin.Os.linux) {185 if (builtin.os.tag == .linux) {
186 @export(clone, .{ .name = "clone" });186 @export(clone, .{ .name = "clone" });
187 }187 }
188}188}
lib/std/special/compiler_rt.zig+8-10
...@@ -1,11 +1,9 @@...@@ -1,11 +1,9 @@
1const builtin = @import("builtin");1const std = @import("std");
2const builtin = std.builtin;
2const is_test = builtin.is_test;3const is_test = builtin.is_test;
34
4const is_gnu = switch (builtin.abi) {5const is_gnu = std.Target.current.abi.isGnu();
5 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,6const is_mingw = builtin.os.tag == .windows and is_gnu;
6 else => false,
7};
8const is_mingw = builtin.os == .windows and is_gnu;
97
10comptime {8comptime {
11 const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;9 const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
...@@ -180,7 +178,7 @@ comptime {...@@ -180,7 +178,7 @@ comptime {
180 @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });178 @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
181 @export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });179 @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) {
184 @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });182 @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
185 }183 }
186184
...@@ -250,7 +248,7 @@ comptime {...@@ -250,7 +248,7 @@ comptime {
250 @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });248 @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
251 }249 }
252250
253 if (builtin.os == .windows) {251 if (builtin.os.tag == .windows) {
254 // Default stack-probe functions emitted by LLVM252 // Default stack-probe functions emitted by LLVM
255 if (is_mingw) {253 if (is_mingw) {
256 @export(@import("compiler_rt/stack_probe.zig")._chkstk, .{ .name = "_alloca", .linkage = strong_linkage });254 @export(@import("compiler_rt/stack_probe.zig")._chkstk, .{ .name = "_alloca", .linkage = strong_linkage });
...@@ -288,7 +286,7 @@ comptime {...@@ -288,7 +286,7 @@ comptime {
288 else => {},286 else => {},
289 }287 }
290 } else {288 } else {
291 if (builtin.glibc_version != null) {289 if (std.Target.current.isGnuLibC() and builtin.link_libc) {
292 @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });290 @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });
293 }291 }
294 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });292 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
...@@ -307,7 +305,7 @@ comptime {...@@ -307,7 +305,7 @@ comptime {
307pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {305pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
308 @setCold(true);306 @setCold(true);
309 if (is_test) {307 if (is_test) {
310 @import("std").debug.panic("{}", .{msg});308 std.debug.panic("{}", .{msg});
311 } else {309 } else {
312 unreachable;310 unreachable;
313 }311 }
lib/std/special/compiler_rt/ashlti3.zig+1-1
...@@ -24,7 +24,7 @@ const twords = extern union {...@@ -24,7 +24,7 @@ const twords = extern union {
24 all: i128,24 all: i128,
25 s: S,25 s: S,
2626
27 const S = if (builtin.endian == builtin.Endian.Little)27 const S = if (builtin.endian == .Little)
28 struct {28 struct {
29 low: u64,29 low: u64,
30 high: u64,30 high: u64,
lib/std/special/compiler_rt/ashrti3.zig+1-1
...@@ -25,7 +25,7 @@ const twords = extern union {...@@ -25,7 +25,7 @@ const twords = extern union {
25 all: i128,25 all: i128,
26 s: S,26 s: S,
2727
28 const S = if (builtin.endian == builtin.Endian.Little)28 const S = if (builtin.endian == .Little)
29 struct {29 struct {
30 low: i64,30 low: i64,
31 high: i64,31 high: i64,
lib/std/special/compiler_rt/extendXfYf2_test.zig+1-1
...@@ -90,7 +90,7 @@ test "extendhfsf2" {...@@ -90,7 +90,7 @@ test "extendhfsf2" {
90 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN90 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
91 // On x86 the NaN becomes quiet because the return is pushed on the x8791 // On x86 the NaN becomes quiet because the return is pushed on the x87
92 // stack due to ABI requirements92 // stack due to ABI requirements
93 if (builtin.arch != .i386 and builtin.os == .windows)93 if (builtin.arch != .i386 and builtin.os.tag == .windows)
94 test__extendhfsf2(0x7c01, 0x7f802000); // sNaN94 test__extendhfsf2(0x7c01, 0x7f802000); // sNaN
9595
96 test__extendhfsf2(0, 0); // 096 test__extendhfsf2(0, 0); // 0
lib/std/special/compiler_rt/lshrti3.zig+1-1
...@@ -24,7 +24,7 @@ const twords = extern union {...@@ -24,7 +24,7 @@ const twords = extern union {
24 all: i128,24 all: i128,
25 s: S,25 s: S,
2626
27 const S = if (builtin.endian == builtin.Endian.Little)27 const S = if (builtin.endian == .Little)
28 struct {28 struct {
29 low: u64,29 low: u64,
30 high: u64,30 high: u64,
lib/std/special/compiler_rt/multi3.zig+1-1
...@@ -45,7 +45,7 @@ const twords = extern union {...@@ -45,7 +45,7 @@ const twords = extern union {
45 all: i128,45 all: i128,
46 s: S,46 s: S,
4747
48 const S = if (builtin.endian == builtin.Endian.Little)48 const S = if (builtin.endian == .Little)
49 struct {49 struct {
50 low: u64,50 low: u64,
51 high: u64,51 high: u64,
lib/std/special/compiler_rt/truncXfYf2.zig+6-6
...@@ -1,23 +1,23 @@...@@ -1,23 +1,23 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn __truncsfhf2(a: f32) callconv(.C) u16 {3pub 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 }));
5}5}
66
7pub fn __truncdfhf2(a: f64) callconv(.C) u16 {7pub 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 }));
9}9}
1010
11pub fn __trunctfsf2(a: f128) callconv(.C) f32 {11pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
12 return truncXfYf2(f32, f128, a);12 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a });
13}13}
1414
15pub fn __trunctfdf2(a: f128) callconv(.C) f64 {15pub fn __trunctfdf2(a: f128) callconv(.C) f64 {
16 return truncXfYf2(f64, f128, a);16 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f64, f128, a });
17}17}
1818
19pub fn __truncdfsf2(a: f64) callconv(.C) f32 {19pub fn __truncdfsf2(a: f64) callconv(.C) f32 {
20 return truncXfYf2(f32, f64, a);20 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f64, a });
21}21}
2222
23pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 {23pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 {
...@@ -35,7 +35,7 @@ pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {...@@ -35,7 +35,7 @@ pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
35 return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a});35 return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a});
36}36}
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 {
39 const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits);39 const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits);
40 const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits);40 const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits);
41 const srcSigBits = std.math.floatMantissaBits(src_t);41 const srcSigBits = std.math.floatMantissaBits(src_t);
lib/std/special/compiler_rt/udivmod.zig+2-2
...@@ -2,8 +2,8 @@ const builtin = @import("builtin");...@@ -2,8 +2,8 @@ const builtin = @import("builtin");
2const is_test = builtin.is_test;2const is_test = builtin.is_test;
33
4const low = switch (builtin.endian) {4const low = switch (builtin.endian) {
5 builtin.Endian.Big => 1,5 .Big => 1,
6 builtin.Endian.Little => 0,6 .Little => 0,
7};7};
8const high = 1 - low;8const high = 1 - low;
99
lib/std/special/init-exe/build.zig+10
...@@ -1,8 +1,18 @@...@@ -1,8 +1,18 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: *Builder) void {3pub 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.
4 const mode = b.standardReleaseOptions();12 const mode = b.standardReleaseOptions();
13
5 const exe = b.addExecutable("$", "src/main.zig");14 const exe = b.addExecutable("$", "src/main.zig");
15 exe.setTarget(target);
6 exe.setBuildMode(mode);16 exe.setBuildMode(mode);
7 exe.install();17 exe.install();
818
lib/std/special/init-exe/src/main.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() anyerror!void {3pub 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", .{});
5}5}
lib/std/spinlock.zig+1-1
...@@ -46,7 +46,7 @@ pub const SpinLock = struct {...@@ -46,7 +46,7 @@ pub const SpinLock = struct {
46 // and yielding for 380-410 iterations was found to be46 // and yielding for 380-410 iterations was found to be
47 // a nice sweet spot. Posix systems on the other hand,47 // a nice sweet spot. Posix systems on the other hand,
48 // especially linux, perform better by yielding the thread.48 // especially linux, perform better by yielding the thread.
49 switch (builtin.os) {49 switch (builtin.os.tag) {
50 .windows => loopHint(400),50 .windows => loopHint(400),
51 else => std.os.sched_yield() catch loopHint(1),51 else => std.os.sched_yield() catch loopHint(1),
52 }52 }
lib/std/start.zig+8-8
...@@ -12,7 +12,7 @@ const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";...@@ -12,7 +12,7 @@ const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1212
13comptime {13comptime {
14 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {14 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")) {
16 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });16 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
17 }17 }
18 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {18 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
...@@ -20,17 +20,17 @@ comptime {...@@ -20,17 +20,17 @@ comptime {
20 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {20 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
21 @export(main, .{ .name = "main", .linkage = .Weak });21 @export(main, .{ .name = "main", .linkage = .Weak });
22 }22 }
23 } else if (builtin.os == .windows) {23 } else if (builtin.os.tag == .windows) {
24 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and24 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
25 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))25 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
26 {26 {
27 @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" });27 @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" });
28 }28 }
29 } else if (builtin.os == .uefi) {29 } else if (builtin.os.tag == .uefi) {
30 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });30 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) {
32 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });32 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) {
34 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });34 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
35 }35 }
36 }36 }
...@@ -78,7 +78,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv...@@ -78,7 +78,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
78}78}
7979
80fn _start() callconv(.Naked) noreturn {80fn _start() callconv(.Naked) noreturn {
81 if (builtin.os == builtin.Os.wasi) {81 if (builtin.os.tag == .wasi) {
82 // This is marked inline because for some reason LLVM in release mode fails to inline it,82 // This is marked inline because for some reason LLVM in release mode fails to inline it,
83 // and we want fewer call frames in stack traces.83 // and we want fewer call frames in stack traces.
84 std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{}));84 std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{}));
...@@ -133,7 +133,7 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {...@@ -133,7 +133,7 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
133133
134// TODO https://github.com/ziglang/zig/issues/265134// TODO https://github.com/ziglang/zig/issues/265
135fn posixCallMainAndExit() noreturn {135fn posixCallMainAndExit() noreturn {
136 if (builtin.os == builtin.Os.freebsd) {136 if (builtin.os.tag == .freebsd) {
137 @setAlignStack(16);137 @setAlignStack(16);
138 }138 }
139 const argc = starting_stack_ptr[0];139 const argc = starting_stack_ptr[0];
...@@ -144,7 +144,7 @@ fn posixCallMainAndExit() noreturn {...@@ -144,7 +144,7 @@ fn posixCallMainAndExit() noreturn {
144 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}144 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
145 const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count];145 const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count];
146146
147 if (builtin.os == .linux) {147 if (builtin.os.tag == .linux) {
148 // Find the beginning of the auxiliary vector148 // Find the beginning of the auxiliary vector
149 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));149 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
150 std.os.linux.elf_aux_maybe = auxv;150 std.os.linux.elf_aux_maybe = auxv;
lib/std/target.zig+603-620
...@@ -1,61 +1,291 @@...@@ -1,61 +1,291 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const mem = std.mem;2const mem = std.mem;
3const builtin = std.builtin;3const builtin = std.builtin;
4const Version = std.builtin.Version;
45
5/// TODO Nearly all the functions in this namespace would be6/// TODO Nearly all the functions in this namespace would be
6/// better off if https://github.com/ziglang/zig/issues/4257/// better off if https://github.com/ziglang/zig/issues/425
7/// was solved.8/// was solved.
8pub const Target = union(enum) {9pub const Target = struct {
9 Native: void,10 cpu: Cpu,
10 Cross: Cross,11 os: Os,
1112 abi: Abi,
12 pub const Os = enum {13
13 freestanding,14 pub const Os = struct {
14 ananas,15 tag: Tag,
15 cloudabi,16 version_range: VersionRange,
16 dragonfly,17
17 freebsd,18 pub const Tag = enum {
18 fuchsia,19 freestanding,
19 ios,20 ananas,
20 kfreebsd,21 cloudabi,
21 linux,22 dragonfly,
22 lv2,23 freebsd,
23 macosx,24 fuchsia,
24 netbsd,25 ios,
25 openbsd,26 kfreebsd,
26 solaris,27 linux,
27 windows,28 lv2,
28 haiku,29 macosx,
29 minix,30 netbsd,
30 rtems,31 openbsd,
31 nacl,32 solaris,
32 cnk,33 windows,
33 aix,34 haiku,
34 cuda,35 minix,
35 nvcl,36 rtems,
36 amdhsa,37 nacl,
37 ps4,38 cnk,
38 elfiamcu,39 aix,
39 tvos,40 cuda,
40 watchos,41 nvcl,
41 mesa3d,42 amdhsa,
42 contiki,43 ps4,
43 amdpal,44 elfiamcu,
44 hermit,45 tvos,
45 hurd,46 watchos,
46 wasi,47 mesa3d,
47 emscripten,48 contiki,
48 uefi,49 amdpal,
49 other,50 hermit,
5051 hurd,
51 pub fn parse(text: []const u8) !Os {52 wasi,
52 const info = @typeInfo(Os);53 emscripten,
53 inline for (info.Enum.fields) |field| {54 uefi,
54 if (mem.eql(u8, text, field.name)) {55 other,
55 return @field(Os, field.name);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);
56 }102 }
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);
57 }112 }
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 };
59 }289 }
60 };290 };
61291
...@@ -98,11 +328,10 @@ pub const Target = union(enum) {...@@ -98,11 +328,10 @@ pub const Target = union(enum) {
98 macabi,328 macabi,
99329
100 pub fn default(arch: Cpu.Arch, target_os: Os) Abi {330 pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
101 switch (arch) {331 if (arch.isWasm()) {
102 .wasm32, .wasm64 => return .musl,332 return .musl;
103 else => {},
104 }333 }
105 switch (target_os) {334 switch (target_os.tag) {
106 .freestanding,335 .freestanding,
107 .ananas,336 .ananas,
108 .cloudabi,337 .cloudabi,
...@@ -147,14 +376,25 @@ pub const Target = union(enum) {...@@ -147,14 +376,25 @@ pub const Target = union(enum) {
147 }376 }
148 }377 }
149378
150 pub fn parse(text: []const u8) !Abi {379 pub fn isGnu(abi: Abi) bool {
151 const info = @typeInfo(Abi);380 return switch (abi) {
152 inline for (info.Enum.fields) |field| {381 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
153 if (mem.eql(u8, text, field.name)) {382 else => false,
154 return @field(Abi, field.name);383 };
155 }384 }
156 }385
157 return error.UnknownApplicationBinaryInterface;386 pub fn isMusl(abi: Abi) bool {
387 return switch (abi) {
388 .musl, .musleabi, .musleabihf => true,
389 else => false,
390 };
391 }
392
393 pub fn oFileExt(abi: Abi) [:0]const u8 {
394 return switch (abi) {
395 .msvc => ".obj",
396 else => ".o",
397 };
158 }398 }
159 };399 };
160400
...@@ -177,12 +417,6 @@ pub const Target = union(enum) {...@@ -177,12 +417,6 @@ pub const Target = union(enum) {
177 EfiRuntimeDriver,417 EfiRuntimeDriver,
178 };418 };
179419
180 pub const Cross = struct {
181 cpu: Cpu,
182 os: Os,
183 abi: Abi,
184 };
185
186 pub const Cpu = struct {420 pub const Cpu = struct {
187 /// Architecture421 /// Architecture
188 arch: Arch,422 arch: Arch,
...@@ -228,6 +462,12 @@ pub const Target = union(enum) {...@@ -228,6 +462,12 @@ pub const Target = union(enum) {
228 return Set{ .ints = [1]usize{0} ** usize_count };462 return Set{ .ints = [1]usize{0} ** usize_count };
229 }463 }
230464
465 pub fn isEmpty(set: Set) bool {
466 return for (set.ints) |x| {
467 if (x != 0) break false;
468 } else true;
469 }
470
231 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {471 pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
232 const usize_index = arch_feature_index / @bitSizeOf(usize);472 const usize_index = arch_feature_index / @bitSizeOf(usize);
233 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));473 const bit_index = @intCast(ShiftInt, arch_feature_index % @bitSizeOf(usize));
...@@ -254,6 +494,15 @@ pub const Target = union(enum) {...@@ -254,6 +494,15 @@ pub const Target = union(enum) {
254 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);494 set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
255 }495 }
256496
497 /// Removes the specified feature but not its dependents.
498 pub fn removeFeatureSet(set: *Set, other_set: Set) void {
499 // TODO should be able to use binary not on @Vector type.
500 // https://github.com/ziglang/zig/issues/903
501 for (set.ints) |*int, i| {
502 int.* &= ~other_set.ints[i];
503 }
504 }
505
257 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {506 pub fn populateDependencies(set: *Set, all_features_list: []const Cpu.Feature) void {
258 @setEvalBranchQuota(1000000);507 @setEvalBranchQuota(1000000);
259508
...@@ -392,7 +641,7 @@ pub const Target = union(enum) {...@@ -392,7 +641,7 @@ pub const Target = union(enum) {
392 return cpu;641 return cpu;
393 }642 }
394 }643 }
395 return error.UnknownCpu;644 return error.UnknownCpuModel;
396 }645 }
397646
398 pub fn toElfMachine(arch: Arch) std.elf.EM {647 pub fn toElfMachine(arch: Arch) std.elf.EM {
...@@ -508,6 +757,67 @@ pub const Target = union(enum) {...@@ -508,6 +757,67 @@ pub const Target = union(enum) {
508 };757 };
509 }758 }
510759
760 pub fn ptrBitWidth(arch: Arch) u32 {
761 switch (arch) {
762 .avr,
763 .msp430,
764 => return 16,
765
766 .arc,
767 .arm,
768 .armeb,
769 .hexagon,
770 .le32,
771 .mips,
772 .mipsel,
773 .powerpc,
774 .r600,
775 .riscv32,
776 .sparc,
777 .sparcel,
778 .tce,
779 .tcele,
780 .thumb,
781 .thumbeb,
782 .i386,
783 .xcore,
784 .nvptx,
785 .amdil,
786 .hsail,
787 .spir,
788 .kalimba,
789 .shave,
790 .lanai,
791 .wasm32,
792 .renderscript32,
793 .aarch64_32,
794 => return 32,
795
796 .aarch64,
797 .aarch64_be,
798 .mips64,
799 .mips64el,
800 .powerpc64,
801 .powerpc64le,
802 .riscv64,
803 .x86_64,
804 .nvptx64,
805 .le64,
806 .amdil64,
807 .hsail64,
808 .spir64,
809 .wasm64,
810 .renderscript64,
811 .amdgcn,
812 .bpfel,
813 .bpfeb,
814 .sparcv9,
815 .s390x,
816 .ve,
817 => return 64,
818 }
819 }
820
511 /// Returns a name that matches the lib/std/target/* directory name.821 /// Returns a name that matches the lib/std/target/* directory name.
512 pub fn genericName(arch: Arch) []const u8 {822 pub fn genericName(arch: Arch) []const u8 {
513 return switch (arch) {823 return switch (arch) {
...@@ -575,16 +885,6 @@ pub const Target = union(enum) {...@@ -575,16 +885,6 @@ pub const Target = union(enum) {
575 else => &[0]*const Model{},885 else => &[0]*const Model{},
576 };886 };
577 }887 }
578
579 pub fn parse(text: []const u8) !Arch {
580 const info = @typeInfo(Arch);
581 inline for (info.Enum.fields) |field| {
582 if (mem.eql(u8, text, field.name)) {
583 return @as(Arch, @field(Arch, field.name));
584 }
585 }
586 return error.UnknownArchitecture;
587 }
588 };888 };
589889
590 pub const Model = struct {890 pub const Model = struct {
...@@ -601,525 +901,172 @@ pub const Target = union(enum) {...@@ -601,525 +901,172 @@ pub const Target = union(enum) {
601 .features = features,901 .features = features,
602 };902 };
603 }903 }
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 }
604 };936 };
605937
606 /// The "default" set of CPU features for cross-compiling. A conservative set938 /// The "default" set of CPU features for cross-compiling. A conservative set
607 /// of features that is expected to be supported on most available hardware.939 /// of features that is expected to be supported on most available hardware.
608 pub fn baseline(arch: Arch) Cpu {940 pub fn baseline(arch: Arch) Cpu {
609 const S = struct {941 return Model.baseline(arch).toCpu(arch);
610 const generic_model = Model{
611 .name = "generic",
612 .llvm_name = null,
613 .features = Cpu.Feature.Set.empty,
614 };
615 };
616 const model = switch (arch) {
617 .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline,
618 .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic,
619 .avr => &avr.cpu.avr1,
620 .bpfel, .bpfeb => &bpf.cpu.generic,
621 .hexagon => &hexagon.cpu.generic,
622 .mips, .mipsel => &mips.cpu.mips32,
623 .mips64, .mips64el => &mips.cpu.mips64,
624 .msp430 => &msp430.cpu.generic,
625 .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic,
626 .amdgcn => &amdgpu.cpu.generic,
627 .riscv32 => &riscv.cpu.baseline_rv32,
628 .riscv64 => &riscv.cpu.baseline_rv64,
629 .sparc, .sparcv9, .sparcel => &sparc.cpu.generic,
630 .s390x => &systemz.cpu.generic,
631 .i386 => &x86.cpu.pentium4,
632 .x86_64 => &x86.cpu.x86_64,
633 .nvptx, .nvptx64 => &nvptx.cpu.sm_20,
634 .wasm32, .wasm64 => &wasm.cpu.generic,
635
636 else => &S.generic_model,
637 };
638 return model.toCpu(arch);
639 }942 }
640 };943 };
641944
642 pub const current = Target{945 pub const current = Target{
643 .Cross = Cross{946 .cpu = builtin.cpu,
644 .cpu = builtin.cpu,947 .os = builtin.os,
645 .os = builtin.os,948 .abi = builtin.abi,
646 .abi = builtin.abi,
647 },
648 };949 };
649950
650 pub const stack_align = 16;951 pub const stack_align = 16;
651952
652 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 {953 pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
653 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{954 return std.zig.CrossTarget.fromTarget(self).zigTriple(allocator);
654 @tagName(self.getArch()),
655 @tagName(self.getOs()),
656 @tagName(self.getAbi()),
657 });
658 }
659
660 /// Returned slice must be freed by the caller.
661 pub fn vcpkgTriplet(allocator: *mem.Allocator, target: Target, linkage: std.build.VcpkgLinkage) ![]const u8 {
662 const arch = switch (target.getArch()) {
663 .i386 => "x86",
664 .x86_64 => "x64",
665
666 .arm,
667 .armeb,
668 .thumb,
669 .thumbeb,
670 .aarch64_32,
671 => "arm",
672
673 .aarch64,
674 .aarch64_be,
675 => "arm64",
676
677 else => return error.VcpkgNoSuchArchitecture,
678 };
679
680 const os = switch (target.getOs()) {
681 .windows => "windows",
682 .linux => "linux",
683 .macosx => "macos",
684 else => return error.VcpkgNoSuchOs,
685 };
686
687 if (linkage == .Static) {
688 return try mem.join(allocator, "-", &[_][]const u8{ arch, os, "static" });
689 } else {
690 return try mem.join(allocator, "-", &[_][]const u8{ arch, os });
691 }
692 }955 }
693956
694 pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 {957 pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
695 // TODO is there anything else worthy of the description that is not958 return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
696 // already captured in the triple?
697 return self.zigTriple(allocator);
698 }959 }
699960
700 pub fn zigTripleNoSubArch(self: Target, allocator: *mem.Allocator) ![]u8 {961 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
701 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{962 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
702 @tagName(self.getArch()),
703 @tagName(self.getOs()),
704 @tagName(self.getAbi()),
705 });
706 }963 }
707964
708 pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {965 pub fn oFileExt(self: Target) [:0]const u8 {
709 return std.fmt.allocPrint(allocator, "{}-{}-{}", .{966 return self.abi.oFileExt();
710 @tagName(self.getArch()),
711 @tagName(self.getOs()),
712 @tagName(self.getAbi()),
713 });
714 }967 }
715968
716 pub const ParseOptions = struct {969 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
717 /// This is sometimes called a "triple". It looks roughly like this:970 switch (os_tag) {
718 /// riscv64-linux-gnu971 .windows => return ".exe",
719 /// The fields are, respectively:972 .uefi => return ".efi",
720 /// * CPU Architecture973 else => if (cpu_arch.isWasm()) {
721 /// * Operating System974 return ".wasm";
722 /// * C ABI (optional)975 } else {
723 arch_os_abi: []const u8,976 return "";
724977 },
725 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
726 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
727 /// to remove from the set.
728 cpu_features: []const u8 = "baseline",
729
730 /// If this is provided, the function will populate some information about parsing failures,
731 /// so that user-friendly error messages can be delivered.
732 diagnostics: ?*Diagnostics = null,
733
734 pub const Diagnostics = struct {
735 /// If the architecture was determined, this will be populated.
736 arch: ?Cpu.Arch = null,
737
738 /// If the OS was determined, this will be populated.
739 os: ?Os = null,
740
741 /// If the ABI was determined, this will be populated.
742 abi: ?Abi = null,
743
744 /// If the CPU name was determined, this will be populated.
745 cpu_name: ?[]const u8 = null,
746
747 /// If error.UnknownCpuFeature is returned, this will be populated.
748 unknown_feature_name: ?[]const u8 = null,
749 };
750 };
751
752 pub fn parse(args: ParseOptions) !Target {
753 var dummy_diags: ParseOptions.Diagnostics = undefined;
754 var diags = args.diagnostics orelse &dummy_diags;
755
756 var it = mem.separate(args.arch_os_abi, "-");
757 const arch_name = it.next() orelse return error.MissingArchitecture;
758 const arch = try Cpu.Arch.parse(arch_name);
759 diags.arch = arch;
760
761 const os_name = it.next() orelse return error.MissingOperatingSystem;
762 const os = try Os.parse(os_name);
763 diags.os = os;
764
765 const abi_name = it.next();
766 const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os);
767 diags.abi = abi;
768
769 if (it.next() != null) return error.UnexpectedExtraField;
770
771 const all_features = arch.allFeaturesList();
772 var index: usize = 0;
773 while (index < args.cpu_features.len and
774 args.cpu_features[index] != '+' and
775 args.cpu_features[index] != '-')
776 {
777 index += 1;
778 }978 }
779 const cpu_name = args.cpu_features[0..index];
780 diags.cpu_name = cpu_name;
781
782 const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: {
783 const cpu_model = try arch.parseCpuModel(cpu_name);
784
785 var set = cpu_model.features;
786 while (index < args.cpu_features.len) {
787 const op = args.cpu_features[index];
788 index += 1;
789 const start = index;
790 while (index < args.cpu_features.len and
791 args.cpu_features[index] != '+' and
792 args.cpu_features[index] != '-')
793 {
794 index += 1;
795 }
796 const feature_name = args.cpu_features[start..index];
797 for (all_features) |feature, feat_index_usize| {
798 const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize);
799 if (mem.eql(u8, feature_name, feature.name)) {
800 switch (op) {
801 '+' => set.addFeature(feat_index),
802 '-' => set.removeFeature(feat_index),
803 else => unreachable,
804 }
805 break;
806 }
807 } else {
808 diags.unknown_feature_name = feature_name;
809 return error.UnknownCpuFeature;
810 }
811 }
812 set.populateDependencies(all_features);
813 break :blk .{
814 .arch = arch,
815 .model = cpu_model,
816 .features = set,
817 };
818 };
819 var cross = Cross{
820 .cpu = cpu,
821 .os = os,
822 .abi = abi,
823 };
824 return Target{ .Cross = cross };
825 }979 }
826980
827 pub fn oFileExt(self: Target) []const u8 {981 pub fn exeFileExt(self: Target) [:0]const u8 {
828 return switch (self.getAbi()) {982 return exeFileExtSimple(self.cpu.arch, self.os.tag);
829 .msvc => ".obj",
830 else => ".o",
831 };
832 }983 }
833984
834 pub fn exeFileExt(self: Target) []const u8 {985 pub fn staticLibSuffix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
835 if (self.isWindows()) {986 if (cpu_arch.isWasm()) {
836 return ".exe";
837 } else if (self.isUefi()) {
838 return ".efi";
839 } else if (self.isWasm()) {
840 return ".wasm";987 return ".wasm";
841 } else {
842 return "";
843 }988 }
844 }989 switch (abi) {
845
846 pub fn staticLibSuffix(self: Target) []const u8 {
847 if (self.isWasm()) {
848 return ".wasm";
849 }
850 switch (self.getAbi()) {
851 .msvc => return ".lib",990 .msvc => return ".lib",
852 else => return ".a",991 else => return ".a",
853 }992 }
854 }993 }
855994
856 pub fn dynamicLibSuffix(self: Target) []const u8 {995 pub fn staticLibSuffix(self: Target) [:0]const u8 {
857 if (self.isDarwin()) {996 return staticLibSuffix_cpu_arch_abi(self.cpu.arch, self.abi);
858 return ".dylib";
859 }
860 switch (self.getOs()) {
861 .windows => return ".dll",
862 else => return ".so",
863 }
864 }997 }
865998
866 pub fn libPrefix(self: Target) []const u8 {999 pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
867 if (self.isWasm()) {1000 return self.os.tag.dynamicLibSuffix();
1001 }
1002
1003 pub fn libPrefix_cpu_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) [:0]const u8 {
1004 if (cpu_arch.isWasm()) {
868 return "";1005 return "";
869 }1006 }
870 switch (self.getAbi()) {1007 switch (abi) {
871 .msvc => return "",1008 .msvc => return "",
872 else => return "lib",1009 else => return "lib",
873 }1010 }
874 }1011 }
8751012
876 pub fn getOs(self: Target) Os {1013 pub fn libPrefix(self: Target) [:0]const u8 {
877 return switch (self) {1014 return libPrefix_cpu_arch_abi(self.cpu.arch, self.abi);
878 .Native => builtin.os,
879 .Cross => |t| t.os,
880 };
881 }1015 }
8821016
883 pub fn getCpu(self: Target) Cpu {1017 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
884 return switch (self) {1018 if (os_tag == .windows or os_tag == .uefi) {
885 .Native => builtin.cpu,1019 return .coff;
886 .Cross => |cross| cross.cpu,1020 } else if (os_tag.isDarwin()) {
887 };1021 return .macho;
888 }1022 }
8891023 if (cpu_arch.isWasm()) {
890 pub fn getArch(self: Target) Cpu.Arch {1024 return .wasm;
891 return self.getCpu().arch;
892 }
893
894 pub fn getAbi(self: Target) Abi {
895 switch (self) {
896 .Native => return builtin.abi,
897 .Cross => |t| return t.abi,
898 }1025 }
1026 return .elf;
899 }1027 }
9001028
901 pub fn getObjectFormat(self: Target) ObjectFormat {1029 pub fn getObjectFormat(self: Target) ObjectFormat {
902 switch (self) {1030 return getObjectFormatSimple(self.os.tag, self.cpu.arch);
903 .Native => return @import("builtin").object_format,
904 .Cross => blk: {
905 if (self.isWindows() or self.isUefi()) {
906 return .coff;
907 } else if (self.isDarwin()) {
908 return .macho;
909 }
910 if (self.isWasm()) {
911 return .wasm;
912 }
913 return .elf;
914 },
915 }
916 }1031 }
9171032
918 pub fn isMinGW(self: Target) bool {1033 pub fn isMinGW(self: Target) bool {
919 return self.isWindows() and self.isGnu();1034 return self.os.tag == .windows and self.isGnu();
920 }1035 }
9211036
922 pub fn isGnu(self: Target) bool {1037 pub fn isGnu(self: Target) bool {
923 return switch (self.getAbi()) {1038 return self.abi.isGnu();
924 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
925 else => false,
926 };
927 }1039 }
9281040
929 pub fn isMusl(self: Target) bool {1041 pub fn isMusl(self: Target) bool {
930 return switch (self.getAbi()) {1042 return self.abi.isMusl();
931 .musl, .musleabi, .musleabihf => true,
932 else => false,
933 };
934 }
935
936 pub fn isDarwin(self: Target) bool {
937 return switch (self.getOs()) {
938 .ios, .macosx, .watchos, .tvos => true,
939 else => false,
940 };
941 }
942
943 pub fn isWindows(self: Target) bool {
944 return switch (self.getOs()) {
945 .windows => true,
946 else => false,
947 };
948 }
949
950 pub fn isLinux(self: Target) bool {
951 return switch (self.getOs()) {
952 .linux => true,
953 else => false,
954 };
955 }1043 }
9561044
957 pub fn isAndroid(self: Target) bool {1045 pub fn isAndroid(self: Target) bool {
958 return switch (self.getAbi()) {1046 return switch (self.abi) {
959 .android => true,1047 .android => true,
960 else => false,1048 else => false,
961 };1049 };
962 }1050 }
9631051
964 pub fn isDragonFlyBSD(self: Target) bool {
965 return switch (self.getOs()) {
966 .dragonfly => true,
967 else => false,
968 };
969 }
970
971 pub fn isUefi(self: Target) bool {
972 return switch (self.getOs()) {
973 .uefi => true,
974 else => false,
975 };
976 }
977
978 pub fn isWasm(self: Target) bool {1052 pub fn isWasm(self: Target) bool {
979 return switch (self.getArch()) {1053 return self.cpu.arch.isWasm();
980 .wasm32, .wasm64 => true,
981 else => false,
982 };
983 }
984
985 pub fn isFreeBSD(self: Target) bool {
986 return switch (self.getOs()) {
987 .freebsd => true,
988 else => false,
989 };
990 }1054 }
9911055
992 pub fn isNetBSD(self: Target) bool {1056 pub fn isDarwin(self: Target) bool {
993 return switch (self.getOs()) {1057 return self.os.tag.isDarwin();
994 .netbsd => true,
995 else => false,
996 };
997 }1058 }
9981059
999 pub fn wantSharedLibSymLinks(self: Target) bool {1060 pub fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
1000 return !self.isWindows();1061 return os_tag == .linux and abi.isGnu();
1001 }1062 }
10021063
1003 pub fn osRequiresLibC(self: Target) bool {1064 pub fn isGnuLibC(self: Target) bool {
1004 return self.isDarwin() or self.isFreeBSD() or self.isNetBSD();1065 return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
1005 }
1006
1007 pub fn getArchPtrBitWidth(self: Target) u32 {
1008 switch (self.getArch()) {
1009 .avr,
1010 .msp430,
1011 => return 16,
1012
1013 .arc,
1014 .arm,
1015 .armeb,
1016 .hexagon,
1017 .le32,
1018 .mips,
1019 .mipsel,
1020 .powerpc,
1021 .r600,
1022 .riscv32,
1023 .sparc,
1024 .sparcel,
1025 .tce,
1026 .tcele,
1027 .thumb,
1028 .thumbeb,
1029 .i386,
1030 .xcore,
1031 .nvptx,
1032 .amdil,
1033 .hsail,
1034 .spir,
1035 .kalimba,
1036 .shave,
1037 .lanai,
1038 .wasm32,
1039 .renderscript32,
1040 .aarch64_32,
1041 => return 32,
1042
1043 .aarch64,
1044 .aarch64_be,
1045 .mips64,
1046 .mips64el,
1047 .powerpc64,
1048 .powerpc64le,
1049 .riscv64,
1050 .x86_64,
1051 .nvptx64,
1052 .le64,
1053 .amdil64,
1054 .hsail64,
1055 .spir64,
1056 .wasm64,
1057 .renderscript64,
1058 .amdgcn,
1059 .bpfel,
1060 .bpfeb,
1061 .sparcv9,
1062 .s390x,
1063 .ve,
1064 => return 64,
1065 }
1066 }1066 }
10671067
1068 pub fn supportsNewStackCall(self: Target) bool {1068 pub fn supportsNewStackCall(self: Target) bool {
1069 return !self.isWasm();1069 return !self.cpu.arch.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;
1123 }1070 }
11241071
1125 pub const FloatAbi = enum {1072 pub const FloatAbi = enum {
...@@ -1129,7 +1076,7 @@ pub const Target = union(enum) {...@@ -1129,7 +1076,7 @@ pub const Target = union(enum) {
1129 };1076 };
11301077
1131 pub fn getFloatAbi(self: Target) FloatAbi {1078 pub fn getFloatAbi(self: Target) FloatAbi {
1132 return switch (self.getAbi()) {1079 return switch (self.abi) {
1133 .gnueabihf,1080 .gnueabihf,
1134 .eabihf,1081 .eabihf,
1135 .musleabihf,1082 .musleabihf,
...@@ -1139,13 +1086,10 @@ pub const Target = union(enum) {...@@ -1139,13 +1086,10 @@ pub const Target = union(enum) {
1139 }1086 }
11401087
1141 pub fn hasDynamicLinker(self: Target) bool {1088 pub fn hasDynamicLinker(self: Target) bool {
1142 switch (self.getArch()) {1089 if (self.cpu.arch.isWasm()) {
1143 .wasm32,1090 return false;
1144 .wasm64,
1145 => return false,
1146 else => {},
1147 }1091 }
1148 switch (self.getOs()) {1092 switch (self.os.tag) {
1149 .freestanding,1093 .freestanding,
1150 .ios,1094 .ios,
1151 .tvos,1095 .tvos,
...@@ -1160,65 +1104,93 @@ pub const Target = union(enum) {...@@ -1160,65 +1104,93 @@ pub const Target = union(enum) {
1160 }1104 }
1161 }1105 }
11621106
1163 /// Caller owns returned memory.1107 pub const DynamicLinker = struct {
1164 pub fn getStandardDynamicLinkerPath(1108 /// Contains the memory used to store the dynamic linker path. This field should
1165 self: Target,1109 /// not be used directly. See `get` and `set`. This field exists so that this API requires no allocator.
1166 allocator: *mem.Allocator,1110 buffer: [255]u8 = undefined,
1167 ) error{1111
1168 OutOfMemory,1112 /// Used to construct the dynamic linker path. This field should not be used
1169 UnknownDynamicLinkerPath,1113 /// directly. See `get` and `set`.
1170 TargetHasNoDynamicLinker,1114 max_byte: ?u8 = null,
1171 }![:0]u8 {1115
1172 const a = allocator;1116 /// Asserts that the length is less than or equal to 255 bytes.
1173 if (self.isAndroid()) {1117 pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
1174 return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)1118 var result: DynamicLinker = undefined;
1175 "/system/bin/linker64"1119 result.set(dl_or_null);
1176 else1120 return result;
1177 "/system/bin/linker");
1178 }1121 }
11791122
1180 if (self.isMusl()) {1123 /// The returned memory has the same lifetime as the `DynamicLinker`.
1181 var result = try std.Buffer.init(allocator, "/lib/ld-musl-");1124 pub fn get(self: *const DynamicLinker) ?[]const u8 {
1182 defer result.deinit();1125 const m: usize = self.max_byte orelse return null;
11831126 return self.buffer[0 .. m + 1];
1184 var is_arm = false;1127 }
1185 switch (self.getArch()) {1128
1186 .arm, .thumb => {1129 /// Asserts that the length is less than or equal to 255 bytes.
1187 try result.append("arm");1130 pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
1188 is_arm = true;1131 if (dl_or_null) |dl| {
1189 },1132 mem.copy(u8, &self.buffer, dl);
1190 .armeb, .thumbeb => {1133 self.max_byte = @intCast(u8, dl.len - 1);
1191 try result.append("armeb");1134 } else {
1192 is_arm = true;1135 self.max_byte = null;
1193 },1136 }
1194 else => |arch| try result.append(@tagName(arch)),1137 }
1138 };
1139
1140 pub fn standardDynamicLinkerPath(self: Target) DynamicLinker {
1141 var result: DynamicLinker = .{};
1142 const S = struct {
1143 fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker {
1144 r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
1145 return r.*;
1195 }1146 }
1196 if (is_arm and self.getFloatAbi() == .hard) {1147 fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
1197 try result.append("hf");1148 mem.copy(u8, &r.buffer, s);
1149 r.max_byte = @intCast(u8, s.len - 1);
1150 return r.*;
1198 }1151 }
1199 try result.append(".so.1");1152 };
1200 return result.toOwnedSlice();1153 const print = S.print;
1154 const copy = S.copy;
1155
1156 if (self.isAndroid()) {
1157 const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
1158 return print(&result, "/system/bin/linker{}", .{suffix});
1201 }1159 }
12021160
1203 switch (self.getOs()) {1161 if (self.isMusl()) {
1204 .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),1162 const is_arm = switch (self.cpu.arch) {
1205 .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),1163 .arm, .armeb, .thumb, .thumbeb => true,
1206 .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),1164 else => false,
1207 .linux => switch (self.getArch()) {1165 };
1166 const arch_part = switch (self.cpu.arch) {
1167 .arm, .thumb => "arm",
1168 .armeb, .thumbeb => "armeb",
1169 else => |arch| @tagName(arch),
1170 };
1171 const arch_suffix = if (is_arm and self.getFloatAbi() == .hard) "hf" else "";
1172 return print(&result, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
1173 }
1174
1175 switch (self.os.tag) {
1176 .freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
1177 .netbsd => return copy(&result, "/libexec/ld.elf_so"),
1178 .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
1179 .linux => switch (self.cpu.arch) {
1208 .i386,1180 .i386,
1209 .sparc,1181 .sparc,
1210 .sparcel,1182 .sparcel,
1211 => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),1183 => return copy(&result, "/lib/ld-linux.so.2"),
12121184
1213 .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),1185 .aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
1214 .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),1186 .aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
1215 .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),1187 .aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
12161188
1217 .arm,1189 .arm,
1218 .armeb,1190 .armeb,
1219 .thumb,1191 .thumb,
1220 .thumbeb,1192 .thumbeb,
1221 => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {1193 => return copy(&result, switch (self.getFloatAbi()) {
1222 .hard => "/lib/ld-linux-armhf.so.3",1194 .hard => "/lib/ld-linux-armhf.so.3",
1223 else => "/lib/ld-linux.so.3",1195 else => "/lib/ld-linux.so.3",
1224 }),1196 }),
...@@ -1227,28 +1199,43 @@ pub const Target = union(enum) {...@@ -1227,28 +1199,43 @@ pub const Target = union(enum) {
1227 .mipsel,1199 .mipsel,
1228 .mips64,1200 .mips64,
1229 .mips64el,1201 .mips64el,
1230 => return error.UnknownDynamicLinkerPath,1202 => {
1203 const lib_suffix = switch (self.abi) {
1204 .gnuabin32, .gnux32 => "32",
1205 .gnuabi64 => "64",
1206 else => "",
1207 };
1208 const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
1209 const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
1210 return print(&result, "/lib{}/{}", .{ lib_suffix, loader });
1211 },
12311212
1232 .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),1213 .powerpc => return copy(&result, "/lib/ld.so.1"),
1233 .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),1214 .powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
1234 .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),1215 .s390x => return copy(&result, "/lib64/ld64.so.1"),
1235 .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),1216 .sparcv9 => return copy(&result, "/lib64/ld-linux.so.2"),
1236 .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {1217 .x86_64 => return copy(&result, switch (self.abi) {
1237 .gnux32 => "/libx32/ld-linux-x32.so.2",1218 .gnux32 => "/libx32/ld-linux-x32.so.2",
1238 else => "/lib64/ld-linux-x86-64.so.2",1219 else => "/lib64/ld-linux-x86-64.so.2",
1239 }),1220 }),
12401221
1241 .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),1222 .riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
1242 .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),1223 .riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
12431224
1225 // Architectures in this list have been verified as not having a standard
1226 // dynamic linker path.
1244 .wasm32,1227 .wasm32,
1245 .wasm64,1228 .wasm64,
1246 => return error.TargetHasNoDynamicLinker,1229 .bpfel,
1230 .bpfeb,
1231 .nvptx,
1232 .nvptx64,
1233 => return result,
12471234
1235 // TODO go over each item in this list and either move it to the above list, or
1236 // implement the standard dynamic linker path code for it.
1248 .arc,1237 .arc,
1249 .avr,1238 .avr,
1250 .bpfel,
1251 .bpfeb,
1252 .hexagon,1239 .hexagon,
1253 .msp430,1240 .msp430,
1254 .r600,1241 .r600,
...@@ -1256,8 +1243,6 @@ pub const Target = union(enum) {...@@ -1256,8 +1243,6 @@ pub const Target = union(enum) {
1256 .tce,1243 .tce,
1257 .tcele,1244 .tcele,
1258 .xcore,1245 .xcore,
1259 .nvptx,
1260 .nvptx64,
1261 .le32,1246 .le32,
1262 .le64,1247 .le64,
1263 .amdil,1248 .amdil,
...@@ -1272,9 +1257,11 @@ pub const Target = union(enum) {...@@ -1272,9 +1257,11 @@ pub const Target = union(enum) {
1272 .renderscript32,1257 .renderscript32,
1273 .renderscript64,1258 .renderscript64,
1274 .ve,1259 .ve,
1275 => return error.UnknownDynamicLinkerPath,1260 => return result,
1276 },1261 },
12771262
1263 // Operating systems in this list have been verified as not having a standard
1264 // dynamic linker path.
1278 .freestanding,1265 .freestanding,
1279 .ios,1266 .ios,
1280 .tvos,1267 .tvos,
...@@ -1283,40 +1270,36 @@ pub const Target = union(enum) {...@@ -1283,40 +1270,36 @@ pub const Target = union(enum) {
1283 .uefi,1270 .uefi,
1284 .windows,1271 .windows,
1285 .emscripten,1272 .emscripten,
1273 .wasi,
1286 .other,1274 .other,
1287 => return error.TargetHasNoDynamicLinker,1275 => return result,
12881276
1289 else => return error.UnknownDynamicLinkerPath,1277 // TODO go over each item in this list and either move it to the above list, or
1278 // implement the standard dynamic linker path code for it.
1279 .ananas,
1280 .cloudabi,
1281 .fuchsia,
1282 .kfreebsd,
1283 .lv2,
1284 .openbsd,
1285 .solaris,
1286 .haiku,
1287 .minix,
1288 .rtems,
1289 .nacl,
1290 .cnk,
1291 .aix,
1292 .cuda,
1293 .nvcl,
1294 .amdhsa,
1295 .ps4,
1296 .elfiamcu,
1297 .mesa3d,
1298 .contiki,
1299 .amdpal,
1300 .hermit,
1301 .hurd,
1302 => return result,
1290 }1303 }
1291 }1304 }
1292};1305};
1293
1294test "Target.parse" {
1295 {
1296 const target = (try Target.parse(.{
1297 .arch_os_abi = "x86_64-linux-gnu",
1298 .cpu_features = "x86_64-sse-sse2-avx-cx8",
1299 })).Cross;
1300
1301 std.testing.expect(target.os == .linux);
1302 std.testing.expect(target.abi == .gnu);
1303 std.testing.expect(target.cpu.arch == .x86_64);
1304 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
1305 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
1306 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
1307 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
1308 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
1309 }
1310 {
1311 const target = (try Target.parse(.{
1312 .arch_os_abi = "arm-linux-musleabihf",
1313 .cpu_features = "generic+v8a",
1314 })).Cross;
1315
1316 std.testing.expect(target.os == .linux);
1317 std.testing.expect(target.abi == .musleabihf);
1318 std.testing.expect(target.cpu.arch == .arm);
1319 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
1320 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
1321 }
1322}
lib/std/target/arm.zig+1-1
...@@ -1510,7 +1510,7 @@ pub const cpu = struct {...@@ -1510,7 +1510,7 @@ pub const cpu = struct {
1510 .name = "baseline",1510 .name = "baseline",
1511 .llvm_name = "generic",1511 .llvm_name = "generic",
1512 .features = featureSet(&[_]Feature{1512 .features = featureSet(&[_]Feature{
1513 .v6m,1513 .v7a,
1514 }),1514 }),
1515 };1515 };
1516 pub const cortex_a12 = CpuModel{1516 pub const cortex_a12 = CpuModel{
lib/std/testing.zig+2-8
...@@ -1,5 +1,3 @@...@@ -1,5 +1,3 @@
1const builtin = @import("builtin");
2const TypeId = builtin.TypeId;
3const std = @import("std.zig");1const std = @import("std.zig");
42
5pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;3pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
...@@ -65,16 +63,12 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {...@@ -65,16 +63,12 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
6563
66 .Pointer => |pointer| {64 .Pointer => |pointer| {
67 switch (pointer.size) {65 switch (pointer.size) {
68 builtin.TypeInfo.Pointer.Size.One,66 .One, .Many, .C => {
69 builtin.TypeInfo.Pointer.Size.Many,
70 builtin.TypeInfo.Pointer.Size.C,
71 => {
72 if (actual != expected) {67 if (actual != expected) {
73 std.debug.panic("expected {*}, found {*}", .{ expected, actual });68 std.debug.panic("expected {*}, found {*}", .{ expected, actual });
74 }69 }
75 },70 },
7671 .Slice => {
77 builtin.TypeInfo.Pointer.Size.Slice => {
78 if (actual.ptr != expected.ptr) {72 if (actual.ptr != expected.ptr) {
79 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });73 std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
80 }74 }
lib/std/thread.zig+15-18
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = std.builtin;
3const os = std.os;3const os = std.os;
4const mem = std.mem;4const mem = std.mem;
5const windows = std.os.windows;5const windows = std.os.windows;
...@@ -9,14 +9,14 @@ const assert = std.debug.assert;...@@ -9,14 +9,14 @@ const assert = std.debug.assert;
9pub const Thread = struct {9pub const Thread = struct {
10 data: Data,10 data: Data,
1111
12 pub const use_pthreads = builtin.os != .windows and builtin.link_libc;12 pub const use_pthreads = std.Target.current.os.tag != .windows and builtin.link_libc;
1313
14 /// Represents a kernel thread handle.14 /// Represents a kernel thread handle.
15 /// May be an integer or a pointer depending on the platform.15 /// May be an integer or a pointer depending on the platform.
16 /// On Linux and POSIX, this is the same as Id.16 /// On Linux and POSIX, this is the same as Id.
17 pub const Handle = if (use_pthreads)17 pub const Handle = if (use_pthreads)
18 c.pthread_t18 c.pthread_t
19 else switch (builtin.os) {19 else switch (std.Target.current.os.tag) {
20 .linux => i32,20 .linux => i32,
21 .windows => windows.HANDLE,21 .windows => windows.HANDLE,
22 else => void,22 else => void,
...@@ -25,7 +25,7 @@ pub const Thread = struct {...@@ -25,7 +25,7 @@ pub const Thread = struct {
25 /// Represents a unique ID per thread.25 /// Represents a unique ID per thread.
26 /// May be an integer or pointer depending on the platform.26 /// May be an integer or pointer depending on the platform.
27 /// On Linux and POSIX, this is the same as Handle.27 /// On Linux and POSIX, this is the same as Handle.
28 pub const Id = switch (builtin.os) {28 pub const Id = switch (std.Target.current.os.tag) {
29 .windows => windows.DWORD,29 .windows => windows.DWORD,
30 else => Handle,30 else => Handle,
31 };31 };
...@@ -35,7 +35,7 @@ pub const Thread = struct {...@@ -35,7 +35,7 @@ pub const Thread = struct {
35 handle: Thread.Handle,35 handle: Thread.Handle,
36 memory: []align(mem.page_size) u8,36 memory: []align(mem.page_size) u8,
37 }37 }
38 else switch (builtin.os) {38 else switch (std.Target.current.os.tag) {
39 .linux => struct {39 .linux => struct {
40 handle: Thread.Handle,40 handle: Thread.Handle,
41 memory: []align(mem.page_size) u8,41 memory: []align(mem.page_size) u8,
...@@ -55,7 +55,7 @@ pub const Thread = struct {...@@ -55,7 +55,7 @@ pub const Thread = struct {
55 if (use_pthreads) {55 if (use_pthreads) {
56 return c.pthread_self();56 return c.pthread_self();
57 } else57 } else
58 return switch (builtin.os) {58 return switch (std.Target.current.os.tag) {
59 .linux => os.linux.gettid(),59 .linux => os.linux.gettid(),
60 .windows => windows.kernel32.GetCurrentThreadId(),60 .windows => windows.kernel32.GetCurrentThreadId(),
61 else => @compileError("Unsupported OS"),61 else => @compileError("Unsupported OS"),
...@@ -83,7 +83,7 @@ pub const Thread = struct {...@@ -83,7 +83,7 @@ pub const Thread = struct {
83 else => unreachable,83 else => unreachable,
84 }84 }
85 os.munmap(self.data.memory);85 os.munmap(self.data.memory);
86 } else switch (builtin.os) {86 } else switch (std.Target.current.os.tag) {
87 .linux => {87 .linux => {
88 while (true) {88 while (true) {
89 const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);89 const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
...@@ -150,7 +150,7 @@ pub const Thread = struct {...@@ -150,7 +150,7 @@ pub const Thread = struct {
150 const Context = @TypeOf(context);150 const Context = @TypeOf(context);
151 comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);151 comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
152152
153 if (builtin.os == builtin.Os.windows) {153 if (std.Target.current.os.tag == .windows) {
154 const WinThread = struct {154 const WinThread = struct {
155 const OuterContext = struct {155 const OuterContext = struct {
156 thread: Thread,156 thread: Thread,
...@@ -309,16 +309,16 @@ pub const Thread = struct {...@@ -309,16 +309,16 @@ pub const Thread = struct {
309 os.EINVAL => unreachable,309 os.EINVAL => unreachable,
310 else => return os.unexpectedErrno(@intCast(usize, err)),310 else => return os.unexpectedErrno(@intCast(usize, err)),
311 }311 }
312 } else if (builtin.os == .linux) {312 } else if (std.Target.current.os.tag == .linux) {
313 var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |313 var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |
314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
315 os.CLONE_DETACHED;315 os.CLONE_DETACHED;
316 var newtls: usize = undefined;316 var newtls: usize = undefined;
317 // This structure is only needed when targeting i386317 // This structure is only needed when targeting i386
318 var user_desc: if (builtin.arch == .i386) os.linux.user_desc else void = undefined;318 var user_desc: if (std.Target.current.cpu.arch == .i386) os.linux.user_desc else void = undefined;
319319
320 if (os.linux.tls.tls_image) |tls_img| {320 if (os.linux.tls.tls_image) |tls_img| {
321 if (builtin.arch == .i386) {321 if (std.Target.current.cpu.arch == .i386) {
322 user_desc = os.linux.user_desc{322 user_desc = os.linux.user_desc{
323 .entry_number = tls_img.gdt_entry_number,323 .entry_number = tls_img.gdt_entry_number,
324 .base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset),324 .base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset),
...@@ -362,27 +362,24 @@ pub const Thread = struct {...@@ -362,27 +362,24 @@ pub const Thread = struct {
362 }362 }
363363
364 pub const CpuCountError = error{364 pub const CpuCountError = error{
365 OutOfMemory,
366 PermissionDenied,365 PermissionDenied,
367 SystemResources,366 SystemResources,
368 Unexpected,367 Unexpected,
369 };368 };
370369
371 pub fn cpuCount() CpuCountError!usize {370 pub fn cpuCount() CpuCountError!usize {
372 if (builtin.os == .linux) {371 if (std.Target.current.os.tag == .linux) {
373 const cpu_set = try os.sched_getaffinity(0);372 const cpu_set = try os.sched_getaffinity(0);
374 return @as(usize, os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast373 return @as(usize, os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast
375 }374 }
376 if (builtin.os == .windows) {375 if (std.Target.current.os.tag == .windows) {
377 var system_info: windows.SYSTEM_INFO = undefined;376 return os.windows.peb().NumberOfProcessors;
378 windows.kernel32.GetSystemInfo(&system_info);
379 return @intCast(usize, system_info.dwNumberOfProcessors);
380 }377 }
381 var count: c_int = undefined;378 var count: c_int = undefined;
382 var count_len: usize = @sizeOf(c_int);379 var count_len: usize = @sizeOf(c_int);
383 const name = if (comptime std.Target.current.isDarwin()) "hw.logicalcpu" else "hw.ncpu";380 const name = if (comptime std.Target.current.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
384 os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {381 os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {
385 error.NameTooLong => unreachable,382 error.NameTooLong, error.UnknownName => unreachable,
386 else => |e| return e,383 else => |e| return e,
387 };384 };
388 return @intCast(usize, count);385 return @intCast(usize, count);
lib/std/time.zig+10-8
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = std.builtin;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const os = std.os;5const os = std.os;
...@@ -7,10 +7,12 @@ const math = std.math;...@@ -7,10 +7,12 @@ const math = std.math;
77
8pub const epoch = @import("time/epoch.zig");8pub const epoch = @import("time/epoch.zig");
99
10const is_windows = std.Target.current.os.tag == .windows;
11
10/// Spurious wakeups are possible and no precision of timing is guaranteed.12/// Spurious wakeups are possible and no precision of timing is guaranteed.
11/// TODO integrate with evented I/O13/// TODO integrate with evented I/O
12pub fn sleep(nanoseconds: u64) void {14pub fn sleep(nanoseconds: u64) void {
13 if (builtin.os == .windows) {15 if (is_windows) {
14 const ns_per_ms = ns_per_s / ms_per_s;16 const ns_per_ms = ns_per_s / ms_per_s;
15 const big_ms_from_ns = nanoseconds / ns_per_ms;17 const big_ms_from_ns = nanoseconds / ns_per_ms;
16 const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD);18 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 {...@@ -31,7 +33,7 @@ pub fn timestamp() u64 {
31/// Get the posix timestamp, UTC, in milliseconds33/// Get the posix timestamp, UTC, in milliseconds
32/// TODO audit this function. is it possible to return an error?34/// TODO audit this function. is it possible to return an error?
33pub fn milliTimestamp() u64 {35pub fn milliTimestamp() u64 {
34 if (builtin.os == .windows) {36 if (is_windows) {
35 //FileTime has a granularity of 100 nanoseconds37 //FileTime has a granularity of 100 nanoseconds
36 // and uses the NTFS/Windows epoch38 // and uses the NTFS/Windows epoch
37 var ft: os.windows.FILETIME = undefined;39 var ft: os.windows.FILETIME = undefined;
...@@ -42,7 +44,7 @@ pub fn milliTimestamp() u64 {...@@ -42,7 +44,7 @@ pub fn milliTimestamp() u64 {
42 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;44 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
43 return @divFloor(ft64, hns_per_ms) - -epoch_adj;45 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
44 }46 }
45 if (builtin.os == .wasi and !builtin.link_libc) {47 if (builtin.os.tag == .wasi and !builtin.link_libc) {
46 var ns: os.wasi.timestamp_t = undefined;48 var ns: os.wasi.timestamp_t = undefined;
4749
48 // TODO: Verify that precision is ignored50 // TODO: Verify that precision is ignored
...@@ -102,7 +104,7 @@ pub const Timer = struct {...@@ -102,7 +104,7 @@ pub const Timer = struct {
102 ///if we used resolution's value when performing the104 ///if we used resolution's value when performing the
103 /// performance counter calc on windows/darwin, it would105 /// performance counter calc on windows/darwin, it would
104 /// be less precise106 /// be less precise
105 frequency: switch (builtin.os) {107 frequency: switch (builtin.os.tag) {
106 .windows => u64,108 .windows => u64,
107 .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,109 .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,
108 else => void,110 else => void,
...@@ -127,7 +129,7 @@ pub const Timer = struct {...@@ -127,7 +129,7 @@ pub const Timer = struct {
127 pub fn start() Error!Timer {129 pub fn start() Error!Timer {
128 var self: Timer = undefined;130 var self: Timer = undefined;
129131
130 if (builtin.os == .windows) {132 if (is_windows) {
131 self.frequency = os.windows.QueryPerformanceFrequency();133 self.frequency = os.windows.QueryPerformanceFrequency();
132 self.resolution = @divFloor(ns_per_s, self.frequency);134 self.resolution = @divFloor(ns_per_s, self.frequency);
133 self.start_time = os.windows.QueryPerformanceCounter();135 self.start_time = os.windows.QueryPerformanceCounter();
...@@ -172,7 +174,7 @@ pub const Timer = struct {...@@ -172,7 +174,7 @@ pub const Timer = struct {
172 }174 }
173175
174 fn clockNative() u64 {176 fn clockNative() u64 {
175 if (builtin.os == .windows) {177 if (is_windows) {
176 return os.windows.QueryPerformanceCounter();178 return os.windows.QueryPerformanceCounter();
177 }179 }
178 if (comptime std.Target.current.isDarwin()) {180 if (comptime std.Target.current.isDarwin()) {
...@@ -184,7 +186,7 @@ pub const Timer = struct {...@@ -184,7 +186,7 @@ pub const Timer = struct {
184 }186 }
185187
186 fn nativeDurationToNanos(self: Timer, duration: u64) u64 {188 fn nativeDurationToNanos(self: Timer, duration: u64) u64 {
187 if (builtin.os == .windows) {189 if (is_windows) {
188 return @divFloor(duration * ns_per_s, self.frequency);190 return @divFloor(duration * ns_per_s, self.frequency);
189 }191 }
190 if (comptime std.Target.current.isDarwin()) {192 if (comptime std.Target.current.isDarwin()) {
lib/std/valgrind.zig+2-2
...@@ -8,7 +8,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:...@@ -8,7 +8,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:
8 }8 }
99
10 switch (builtin.arch) {10 switch (builtin.arch) {
11 builtin.Arch.i386 => {11 .i386 => {
12 return asm volatile (12 return asm volatile (
13 \\ roll $3, %%edi ; roll $13, %%edi13 \\ roll $3, %%edi ; roll $13, %%edi
14 \\ roll $29, %%edi ; roll $19, %%edi14 \\ roll $29, %%edi ; roll $19, %%edi
...@@ -19,7 +19,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:...@@ -19,7 +19,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:
19 : "cc", "memory"19 : "cc", "memory"
20 );20 );
21 },21 },
22 builtin.Arch.x86_64 => {22 .x86_64 => {
23 return asm volatile (23 return asm volatile (
24 \\ rolq $3, %%rdi ; rolq $13, %%rdi24 \\ rolq $3, %%rdi ; rolq $13, %%rdi
25 \\ rolq $61, %%rdi ; rolq $51, %%rdi25 \\ rolq $61, %%rdi ; rolq $51, %%rdi
lib/std/zig.zig+3-6
...@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri...@@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri
6pub const render = @import("zig/render.zig").render;6pub const render = @import("zig/render.zig").render;
7pub const ast = @import("zig/ast.zig");7pub const ast = @import("zig/ast.zig");
8pub const system = @import("zig/system.zig");8pub const system = @import("zig/system.zig");
9pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
910
10test "std.zig tests" {11test "" {
11 _ = @import("zig/ast.zig");12 @import("std").meta.refAllDecls(@This());
12 _ = @import("zig/parse.zig");
13 _ = @import("zig/render.zig");
14 _ = @import("zig/tokenizer.zig");
15 _ = @import("zig/parse_string_literal.zig");
16}13}
lib/std/zig/cross_target.zig created+839
...@@ -0,0 +1,839 @@
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 pub fn getObjectFormat(self: CrossTarget) ObjectFormat {
649 return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());
650 }
651
652 fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
653 set.removeFeatureSet(self.cpu_features_sub);
654 set.addFeatureSet(self.cpu_features_add);
655 set.populateDependencies(self.getCpuArch().allFeaturesList());
656 set.removeFeatureSet(self.cpu_features_sub);
657 }
658
659 fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
660 var it = mem.separate(text, ".");
661 const os_name = it.next().?;
662 diags.os_name = os_name;
663 const os_is_native = mem.eql(u8, os_name, "native");
664 if (!os_is_native) {
665 result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse
666 return error.UnknownOperatingSystem;
667 }
668 const tag = result.getOsTag();
669 diags.os_tag = tag;
670
671 const version_text = it.rest();
672 if (it.next() == null) return;
673
674 switch (tag) {
675 .freestanding,
676 .ananas,
677 .cloudabi,
678 .dragonfly,
679 .fuchsia,
680 .ios,
681 .kfreebsd,
682 .lv2,
683 .solaris,
684 .haiku,
685 .minix,
686 .rtems,
687 .nacl,
688 .cnk,
689 .aix,
690 .cuda,
691 .nvcl,
692 .amdhsa,
693 .ps4,
694 .elfiamcu,
695 .tvos,
696 .watchos,
697 .mesa3d,
698 .contiki,
699 .amdpal,
700 .hermit,
701 .hurd,
702 .wasi,
703 .emscripten,
704 .uefi,
705 .other,
706 => return error.InvalidOperatingSystemVersion,
707
708 .freebsd,
709 .macosx,
710 .netbsd,
711 .openbsd,
712 .linux,
713 => {
714 var range_it = mem.separate(version_text, "...");
715
716 const min_text = range_it.next().?;
717 const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
718 error.Overflow => return error.InvalidOperatingSystemVersion,
719 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
720 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
721 };
722 result.os_version_min = .{ .semver = min_ver };
723
724 const max_text = range_it.next() orelse return;
725 const max_ver = SemVer.parse(max_text) catch |err| switch (err) {
726 error.Overflow => return error.InvalidOperatingSystemVersion,
727 error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
728 error.InvalidVersion => return error.InvalidOperatingSystemVersion,
729 };
730 result.os_version_max = .{ .semver = max_ver };
731 },
732
733 .windows => {
734 var range_it = mem.separate(version_text, "...");
735
736 const min_text = range_it.next().?;
737 const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
738 return error.InvalidOperatingSystemVersion;
739 result.os_version_min = .{ .windows = min_ver };
740
741 const max_text = range_it.next() orelse return;
742 const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
743 return error.InvalidOperatingSystemVersion;
744 result.os_version_max = .{ .windows = max_ver };
745 },
746 }
747 }
748};
749
750test "CrossTarget.parse" {
751 if (Target.current.isGnuLibC()) {
752 var cross_target = try CrossTarget.parse(.{});
753 cross_target.setGnuLibCVersion(2, 1, 1);
754
755 const text = try cross_target.zigTriple(std.testing.allocator);
756 defer std.testing.allocator.free(text);
757 std.testing.expectEqualSlices(u8, "native-native-gnu.2.1.1", text);
758 }
759 {
760 const cross_target = try CrossTarget.parse(.{
761 .arch_os_abi = "aarch64-linux",
762 .cpu_features = "native",
763 });
764
765 std.testing.expect(cross_target.cpu_arch.? == .aarch64);
766 std.testing.expect(cross_target.cpu_model == .native);
767 }
768 {
769 const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
770
771 std.testing.expect(cross_target.cpu_arch == null);
772 std.testing.expect(cross_target.isNative());
773
774 const text = try cross_target.zigTriple(std.testing.allocator);
775 defer std.testing.allocator.free(text);
776 std.testing.expectEqualSlices(u8, "native", text);
777 }
778 {
779 const cross_target = try CrossTarget.parse(.{
780 .arch_os_abi = "x86_64-linux-gnu",
781 .cpu_features = "x86_64-sse-sse2-avx-cx8",
782 });
783 const target = cross_target.toTarget();
784
785 std.testing.expect(target.os.tag == .linux);
786 std.testing.expect(target.abi == .gnu);
787 std.testing.expect(target.cpu.arch == .x86_64);
788 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
789 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
790 std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
791 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
792 std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
793
794 const text = try cross_target.zigTriple(std.testing.allocator);
795 defer std.testing.allocator.free(text);
796 std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text);
797 }
798 {
799 const cross_target = try CrossTarget.parse(.{
800 .arch_os_abi = "arm-linux-musleabihf",
801 .cpu_features = "generic+v8a",
802 });
803 const target = cross_target.toTarget();
804
805 std.testing.expect(target.os.tag == .linux);
806 std.testing.expect(target.abi == .musleabihf);
807 std.testing.expect(target.cpu.arch == .arm);
808 std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
809 std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
810
811 const text = try cross_target.zigTriple(std.testing.allocator);
812 defer std.testing.allocator.free(text);
813 std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text);
814 }
815 {
816 const cross_target = try CrossTarget.parse(.{
817 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
818 .cpu_features = "generic+v8a",
819 });
820 const target = cross_target.toTarget();
821
822 std.testing.expect(target.cpu.arch == .aarch64);
823 std.testing.expect(target.os.tag == .linux);
824 std.testing.expect(target.os.version_range.linux.range.min.major == 3);
825 std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
826 std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
827 std.testing.expect(target.os.version_range.linux.range.max.major == 4);
828 std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
829 std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
830 std.testing.expect(target.os.version_range.linux.glibc.major == 2);
831 std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
832 std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
833 std.testing.expect(target.abi == .gnu);
834
835 const text = try cross_target.zigTriple(std.testing.allocator);
836 defer std.testing.allocator.free(text);
837 std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text);
838 }
839}
lib/std/zig/system.zig+694-2
...@@ -1,11 +1,15 @@...@@ -1,11 +1,15 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const elf = std.elf;
2const mem = std.mem;3const mem = std.mem;
4const fs = std.fs;
3const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
4const ArrayList = std.ArrayList;6const ArrayList = std.ArrayList;
5const assert = std.debug.assert;7const assert = std.debug.assert;
6const process = std.process;8const 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
10pub const NativePaths = struct {14pub const NativePaths = struct {
11 include_dirs: ArrayList([:0]u8),15 include_dirs: ArrayList([:0]u8),
...@@ -77,7 +81,7 @@ pub const NativePaths = struct {...@@ -77,7 +81,7 @@ pub const NativePaths = struct {
77 }81 }
7882
79 if (!is_windows) {83 if (!is_windows) {
80 const triple = try std.Target.current.linuxTriple(allocator);84 const triple = try Target.current.linuxTriple(allocator);
8185
82 // TODO: $ ld --verbose | grep SEARCH_DIR86 // TODO: $ ld --verbose | grep SEARCH_DIR
83 // the output contains some paths that end with lib64, maybe include them too?87 // the output contains some paths that end with lib64, maybe include them too?
...@@ -161,3 +165,691 @@ pub const NativePaths = struct {...@@ -161,3 +165,691 @@ pub const NativePaths = struct {
161 try array.append(item);165 try array.append(item);
162 }166 }
163};167};
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 var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined;
225 version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info));
226
227 switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) {
228 .SUCCESS => {},
229 else => unreachable,
230 }
231
232 // Starting from the system infos build a NTDDI-like version
233 // constant whose format is:
234 // B0 B1 B2 B3
235 // `---` `` ``--> Sub-version (Starting from Windows 10 onwards)
236 // \ `--> Service pack (Always zero in the constants defined)
237 // `--> OS version (Major & minor)
238 const os_ver: u16 = //
239 @intCast(u16, version_info.dwMajorVersion & 0xff) << 8 |
240 @intCast(u16, version_info.dwMinorVersion & 0xff);
241 const sp_ver: u8 = 0;
242 const sub_ver: u8 = if (os_ver >= 0x0A00) subver: {
243 // There's no other way to obtain this info beside
244 // checking the build number against a known set of
245 // values
246 const known_build_numbers = [_]u32{
247 10240, 10586, 14393, 15063, 16299, 17134, 17763,
248 18362, 18363,
249 };
250 var last_idx: usize = 0;
251 for (known_build_numbers) |build, i| {
252 if (version_info.dwBuildNumber >= build)
253 last_idx = i;
254 }
255 break :subver @truncate(u8, last_idx);
256 } else 0;
257
258 const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver;
259
260 os.version_range.windows.max = @intToEnum(Target.Os.WindowsVersion, version);
261 os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version);
262 },
263 .macosx => {
264 var product_version: [32]u8 = undefined;
265 var size: usize = product_version.len;
266
267 // The osproductversion sysctl was introduced first with
268 // High Sierra, thankfully that's also the baseline that Zig
269 // supports
270 std.os.sysctlbynameC(
271 "kern.osproductversion",
272 &product_version,
273 &size,
274 null,
275 0,
276 ) catch |err| switch (err) {
277 error.UnknownName => unreachable,
278 else => unreachable,
279 };
280
281 const string_version = product_version[0 .. size - 1 :0];
282 if (std.builtin.Version.parse(string_version)) |ver| {
283 os.version_range.semver.min = ver;
284 os.version_range.semver.max = ver;
285 } else |err| switch (err) {
286 error.Overflow => {},
287 error.InvalidCharacter => {},
288 error.InvalidVersion => {},
289 }
290 },
291 .freebsd => {
292 // TODO Detect native operating system version.
293 },
294 else => {},
295 }
296 }
297
298 if (cross_target.os_version_min) |min| switch (min) {
299 .none => {},
300 .semver => |semver| switch (cross_target.getOsTag()) {
301 .linux => os.version_range.linux.range.min = semver,
302 else => os.version_range.semver.min = semver,
303 },
304 .windows => |win_ver| os.version_range.windows.min = win_ver,
305 };
306
307 if (cross_target.os_version_max) |max| switch (max) {
308 .none => {},
309 .semver => |semver| switch (cross_target.getOsTag()) {
310 .linux => os.version_range.linux.range.max = semver,
311 else => os.version_range.semver.max = semver,
312 },
313 .windows => |win_ver| os.version_range.windows.max = win_ver,
314 };
315
316 if (cross_target.glibc_version) |glibc| {
317 assert(cross_target.isGnuLibC());
318 os.version_range.linux.glibc = glibc;
319 }
320
321 return detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
322 }
323
324 /// First we attempt to use the executable's own binary. If it is dynamically
325 /// linked, then it should answer both the C ABI question and the dynamic linker question.
326 /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then
327 /// we fall back to the defaults.
328 /// TODO Remove the Allocator requirement from this function.
329 fn detectAbiAndDynamicLinker(
330 allocator: *Allocator,
331 cpu: Target.Cpu,
332 os: Target.Os,
333 cross_target: CrossTarget,
334 ) DetectError!NativeTargetInfo {
335 const native_target_has_ld = comptime Target.current.hasDynamicLinker();
336 const is_linux = Target.current.os.tag == .linux;
337 const have_all_info = cross_target.dynamic_linker.get() != null and
338 cross_target.abi != null and (!is_linux or cross_target.abi.?.isGnu());
339 const os_is_non_native = cross_target.os_tag != null;
340 if (!native_target_has_ld or have_all_info or os_is_non_native) {
341 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
342 }
343 // The current target's ABI cannot be relied on for this. For example, we may build the zig
344 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
345 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
346 // and supported by Zig. But that means that we must detect the system ABI here rather than
347 // relying on `Target.current`.
348 const all_abis = comptime blk: {
349 assert(@enumToInt(Target.Abi.none) == 0);
350 const fields = std.meta.fields(Target.Abi)[1..];
351 var array: [fields.len]Target.Abi = undefined;
352 inline for (fields) |field, i| {
353 array[i] = @field(Target.Abi, field.name);
354 }
355 break :blk array;
356 };
357 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
358 var ld_info_list_len: usize = 0;
359
360 for (all_abis) |abi| {
361 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
362 // skip adding it to `ld_info_list`.
363 const target: Target = .{
364 .cpu = cpu,
365 .os = os,
366 .abi = abi,
367 };
368 const ld = target.standardDynamicLinkerPath();
369 if (ld.get() == null) continue;
370
371 ld_info_list_buffer[ld_info_list_len] = .{
372 .ld = ld,
373 .abi = abi,
374 };
375 ld_info_list_len += 1;
376 }
377 const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
378
379 if (cross_target.dynamic_linker.get()) |explicit_ld| {
380 const explicit_ld_basename = fs.path.basename(explicit_ld);
381 for (ld_info_list) |ld_info| {
382 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
383 }
384 }
385
386 // Best case scenario: the executable is dynamically linked, and we can iterate
387 // over our own shared objects and find a dynamic linker.
388 self_exe: {
389 const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
390 defer allocator.free(lib_paths);
391
392 var found_ld_info: LdInfo = undefined;
393 var found_ld_path: [:0]const u8 = undefined;
394
395 // Look for dynamic linker.
396 // This is O(N^M) but typical case here is N=2 and M=10.
397 find_ld: for (lib_paths) |lib_path| {
398 for (ld_info_list) |ld_info| {
399 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
400 if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
401 found_ld_info = ld_info;
402 found_ld_path = lib_path;
403 break :find_ld;
404 }
405 }
406 } else break :self_exe;
407
408 // Look for glibc version.
409 var os_adjusted = os;
410 if (Target.current.os.tag == .linux and found_ld_info.abi.isGnu() and
411 cross_target.glibc_version == null)
412 {
413 for (lib_paths) |lib_path| {
414 if (std.mem.endsWith(u8, lib_path, glibc_so_basename)) {
415 os_adjusted.version_range.linux.glibc = glibcVerFromSO(lib_path) catch |err| switch (err) {
416 error.UnrecognizedGnuLibCFileName => continue,
417 error.InvalidGnuLibCVersion => continue,
418 error.GnuLibCVersionUnavailable => continue,
419 else => |e| return e,
420 };
421 break;
422 }
423 }
424 }
425
426 var result: NativeTargetInfo = .{
427 .target = .{
428 .cpu = cpu,
429 .os = os_adjusted,
430 .abi = cross_target.abi orelse found_ld_info.abi,
431 },
432 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
433 DynamicLinker.init(found_ld_path)
434 else
435 cross_target.dynamic_linker,
436 };
437 return result;
438 }
439
440 const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
441 error.NoSpaceLeft => unreachable,
442 error.NameTooLong => unreachable,
443 error.PathAlreadyExists => unreachable,
444 error.SharingViolation => unreachable,
445 error.InvalidUtf8 => unreachable,
446 error.BadPathName => unreachable,
447 error.PipeBusy => unreachable,
448
449 error.IsDir,
450 error.NotDir,
451 error.AccessDenied,
452 error.NoDevice,
453 error.FileNotFound,
454 error.FileTooBig,
455 error.Unexpected,
456 => return defaultAbiAndDynamicLinker(cpu, os, cross_target),
457
458 else => |e| return e,
459 };
460 defer env_file.close();
461
462 // If Zig is statically linked, such as via distributed binary static builds, the above
463 // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.
464 // Since that path is hard-coded into the shebang line of many portable scripts, it's a
465 // reasonably reliable path to check for.
466 return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
467 error.FileSystem,
468 error.SystemResources,
469 error.SymLinkLoop,
470 error.ProcessFdQuotaExceeded,
471 error.SystemFdQuotaExceeded,
472 => |e| return e,
473
474 error.UnableToReadElfFile,
475 error.InvalidElfClass,
476 error.InvalidElfVersion,
477 error.InvalidElfEndian,
478 error.InvalidElfFile,
479 error.InvalidElfMagic,
480 error.Unexpected,
481 error.UnexpectedEndOfFile,
482 error.NameTooLong,
483 // Finally, we fall back on the standard path.
484 => defaultAbiAndDynamicLinker(cpu, os, cross_target),
485 };
486 }
487
488 const glibc_so_basename = "libc.so.6";
489
490 fn glibcVerFromSO(so_path: [:0]const u8) !std.builtin.Version {
491 var link_buf: [std.os.PATH_MAX]u8 = undefined;
492 const link_name = std.os.readlinkC(so_path.ptr, &link_buf) catch |err| switch (err) {
493 error.AccessDenied => return error.GnuLibCVersionUnavailable,
494 error.FileSystem => return error.FileSystem,
495 error.SymLinkLoop => return error.SymLinkLoop,
496 error.NameTooLong => unreachable,
497 error.FileNotFound => return error.GnuLibCVersionUnavailable,
498 error.SystemResources => return error.SystemResources,
499 error.NotDir => return error.GnuLibCVersionUnavailable,
500 error.Unexpected => return error.GnuLibCVersionUnavailable,
501 };
502 return glibcVerFromLinkName(link_name);
503 }
504
505 fn glibcVerFromLinkName(link_name: []const u8) !std.builtin.Version {
506 // example: "libc-2.3.4.so"
507 // example: "libc-2.27.so"
508 const prefix = "libc-";
509 const suffix = ".so";
510 if (!mem.startsWith(u8, link_name, prefix) or !mem.endsWith(u8, link_name, suffix)) {
511 return error.UnrecognizedGnuLibCFileName;
512 }
513 // chop off "libc-" and ".so"
514 const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
515 return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) {
516 error.Overflow => return error.InvalidGnuLibCVersion,
517 error.InvalidCharacter => return error.InvalidGnuLibCVersion,
518 error.InvalidVersion => return error.InvalidGnuLibCVersion,
519 };
520 }
521
522 pub const AbiAndDynamicLinkerFromFileError = error{
523 FileSystem,
524 SystemResources,
525 SymLinkLoop,
526 ProcessFdQuotaExceeded,
527 SystemFdQuotaExceeded,
528 UnableToReadElfFile,
529 InvalidElfClass,
530 InvalidElfVersion,
531 InvalidElfEndian,
532 InvalidElfFile,
533 InvalidElfMagic,
534 Unexpected,
535 UnexpectedEndOfFile,
536 NameTooLong,
537 };
538
539 pub fn abiAndDynamicLinkerFromFile(
540 file: fs.File,
541 cpu: Target.Cpu,
542 os: Target.Os,
543 ld_info_list: []const LdInfo,
544 cross_target: CrossTarget,
545 ) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {
546 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
547 _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len);
548 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
549 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
550 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
551 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
552 elf.ELFDATA2LSB => .Little,
553 elf.ELFDATA2MSB => .Big,
554 else => return error.InvalidElfEndian,
555 };
556 const need_bswap = elf_endian != std.builtin.endian;
557 if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
558
559 const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) {
560 elf.ELFCLASS32 => false,
561 elf.ELFCLASS64 => true,
562 else => return error.InvalidElfClass,
563 };
564 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
565 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
566 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
567
568 var result: NativeTargetInfo = .{
569 .target = .{
570 .cpu = cpu,
571 .os = os,
572 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
573 },
574 .dynamic_linker = cross_target.dynamic_linker,
575 };
576 var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
577 const look_for_ld = cross_target.dynamic_linker.get() == null;
578
579 var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;
580 if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
581
582 var ph_i: u16 = 0;
583 while (ph_i < phnum) {
584 // Reserve some bytes so that we can deref the 64-bit struct fields
585 // even when the ELF file is 32-bits.
586 const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
587 const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
588 var ph_buf_i: usize = 0;
589 while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
590 ph_i += 1;
591 phoff += phentsize;
592 ph_buf_i += phentsize;
593 }) {
594 const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[ph_buf_i]));
595 const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[ph_buf_i]));
596 const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
597 switch (p_type) {
598 elf.PT_INTERP => if (look_for_ld) {
599 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
600 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
601 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
602 _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
603 // PT_INTERP includes a null byte in p_filesz.
604 const len = p_filesz - 1;
605 // dynamic_linker.max_byte is "max", not "len".
606 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
607 result.dynamic_linker.max_byte = @intCast(u8, len - 1);
608
609 // Use it to determine ABI.
610 const full_ld_path = result.dynamic_linker.buffer[0..len];
611 for (ld_info_list) |ld_info| {
612 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
613 if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
614 result.target.abi = ld_info.abi;
615 break;
616 }
617 }
618 },
619 // We only need this for detecting glibc version.
620 elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC() and
621 cross_target.glibc_version == null)
622 {
623 var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
624 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
625 const dyn_size: u64 = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
626 const dyn_num = p_filesz / dyn_size;
627 var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
628 var dyn_i: usize = 0;
629 dyn: while (dyn_i < dyn_num) {
630 // Reserve some bytes so that we can deref the 64-bit struct fields
631 // even when the ELF file is 32-bits.
632 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
633 const dyn_read_byte_len = try preadFull(
634 file,
635 dyn_buf[0 .. dyn_buf.len - dyn_reserve],
636 dyn_off,
637 dyn_size,
638 );
639 var dyn_buf_i: usize = 0;
640 while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
641 dyn_i += 1;
642 dyn_off += dyn_size;
643 dyn_buf_i += dyn_size;
644 }) {
645 const dyn32 = @ptrCast(
646 *elf.Elf32_Dyn,
647 @alignCast(@alignOf(elf.Elf32_Dyn), &dyn_buf[dyn_buf_i]),
648 );
649 const dyn64 = @ptrCast(
650 *elf.Elf64_Dyn,
651 @alignCast(@alignOf(elf.Elf64_Dyn), &dyn_buf[dyn_buf_i]),
652 );
653 const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
654 const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
655 if (tag == elf.DT_RUNPATH) {
656 rpath_offset = val;
657 break :dyn;
658 }
659 }
660 }
661 },
662 else => continue,
663 }
664 }
665 }
666
667 if (Target.current.os.tag == .linux and result.target.isGnuLibC() and cross_target.glibc_version == null) {
668 if (rpath_offset) |rpoff| {
669 const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
670
671 var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff);
672 const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize);
673 const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx);
674
675 var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
676 if (sh_buf.len < shentsize) return error.InvalidElfFile;
677
678 _ = try preadFull(file, &sh_buf, str_section_off, shentsize);
679 const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
680 const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
681 const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
682 const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
683 var strtab_buf: [4096:0]u8 = undefined;
684 const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
685 const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len);
686 const shstrtab = strtab_buf[0..shstrtab_read_len];
687
688 const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
689 var sh_i: u16 = 0;
690 const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) {
691 // Reserve some bytes so that we can deref the 64-bit struct fields
692 // even when the ELF file is 32-bits.
693 const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
694 const sh_read_byte_len = try preadFull(
695 file,
696 sh_buf[0 .. sh_buf.len - sh_reserve],
697 shoff,
698 shentsize,
699 );
700 var sh_buf_i: usize = 0;
701 while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({
702 sh_i += 1;
703 shoff += shentsize;
704 sh_buf_i += shentsize;
705 }) {
706 const sh32 = @ptrCast(
707 *elf.Elf32_Shdr,
708 @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf[sh_buf_i]),
709 );
710 const sh64 = @ptrCast(
711 *elf.Elf64_Shdr,
712 @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf[sh_buf_i]),
713 );
714 const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name);
715 // TODO this pointer cast should not be necessary
716 const sh_name = mem.toSliceConst(u8, @ptrCast([*:0]u8, shstrtab[sh_name_off..].ptr));
717 if (mem.eql(u8, sh_name, ".dynstr")) {
718 break :find_dyn_str .{
719 .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset),
720 .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size),
721 };
722 }
723 }
724 } else null;
725
726 if (dynstr) |ds| {
727 const strtab_len = std.math.min(ds.size, strtab_buf.len);
728 const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len);
729 const strtab = strtab_buf[0..strtab_read_len];
730 // TODO this pointer cast should not be necessary
731 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
732 var it = mem.tokenize(rpath_list, ":");
733 while (it.next()) |rpath| {
734 var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) {
735 error.NameTooLong => unreachable,
736 error.InvalidUtf8 => unreachable,
737 error.BadPathName => unreachable,
738 error.DeviceBusy => unreachable,
739
740 error.FileNotFound,
741 error.NotDir,
742 error.AccessDenied,
743 error.NoDevice,
744 => continue,
745
746 error.ProcessFdQuotaExceeded,
747 error.SystemFdQuotaExceeded,
748 error.SystemResources,
749 error.SymLinkLoop,
750 error.Unexpected,
751 => |e| return e,
752 };
753 defer dir.close();
754
755 var link_buf: [std.os.PATH_MAX]u8 = undefined;
756 const link_name = std.os.readlinkatC(
757 dir.fd,
758 glibc_so_basename,
759 &link_buf,
760 ) catch |err| switch (err) {
761 error.NameTooLong => unreachable,
762
763 error.AccessDenied,
764 error.FileNotFound,
765 error.NotDir,
766 => continue,
767
768 error.SystemResources,
769 error.FileSystem,
770 error.SymLinkLoop,
771 error.Unexpected,
772 => |e| return e,
773 };
774 result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
775 link_name,
776 ) catch |err| switch (err) {
777 error.UnrecognizedGnuLibCFileName,
778 error.InvalidGnuLibCVersion,
779 => continue,
780 };
781 break;
782 }
783 }
784 }
785 }
786
787 return result;
788 }
789
790 fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
791 var i: u64 = 0;
792 while (i < min_read_len) {
793 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
794 error.OperationAborted => unreachable, // Windows-only
795 error.WouldBlock => unreachable, // Did not request blocking mode
796 error.SystemResources => return error.SystemResources,
797 error.IsDir => return error.UnableToReadElfFile,
798 error.BrokenPipe => return error.UnableToReadElfFile,
799 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
800 error.Unexpected => return error.Unexpected,
801 error.InputOutput => return error.FileSystem,
802 };
803 if (len == 0) return error.UnexpectedEndOfFile;
804 i += len;
805 }
806 return i;
807 }
808
809 fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: CrossTarget) !NativeTargetInfo {
810 const target: Target = .{
811 .cpu = cpu,
812 .os = os,
813 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
814 };
815 return NativeTargetInfo{
816 .target = target,
817 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
818 target.standardDynamicLinkerPath()
819 else
820 cross_target.dynamic_linker,
821 };
822 }
823
824 pub const LdInfo = struct {
825 ld: DynamicLinker,
826 abi: Target.Abi,
827 };
828
829 fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
830 if (is_64) {
831 if (need_bswap) {
832 return @byteSwap(@TypeOf(int_64), int_64);
833 } else {
834 return int_64;
835 }
836 } else {
837 if (need_bswap) {
838 return @byteSwap(@TypeOf(int_32), int_32);
839 } else {
840 return int_32;
841 }
842 }
843 }
844
845 fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
846 // TODO Detect native CPU model & features. Until that is implemented we use baseline.
847 return baselineCpuAndFeatures(cross_target);
848 }
849
850 fn baselineCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
851 var adjusted_baseline = Target.Cpu.baseline(cross_target.getCpuArch());
852 cross_target.updateCpuFeatures(&adjusted_baseline.features);
853 return adjusted_baseline;
854 }
855};
src-self-hosted/c_int.zig+1-1
...@@ -70,7 +70,7 @@ pub const CInt = struct {...@@ -70,7 +70,7 @@ pub const CInt = struct {
7070
71 pub fn sizeInBits(cint: CInt, self: Target) u32 {71 pub fn sizeInBits(cint: CInt, self: Target) u32 {
72 const arch = self.getArch();72 const arch = self.getArch();
73 switch (self.getOs()) {73 switch (self.os.tag) {
74 .freestanding, .other => switch (self.getArch()) {74 .freestanding, .other => switch (self.getArch()) {
75 .msp430 => switch (cint.id) {75 .msp430 => switch (cint.id) {
76 .Short,76 .Short,
src-self-hosted/clang.zig+1-1
...@@ -1072,7 +1072,7 @@ pub const struct_ZigClangExprEvalResult = extern struct {...@@ -1072,7 +1072,7 @@ pub const struct_ZigClangExprEvalResult = extern struct {
10721072
1073pub const struct_ZigClangAPValue = extern struct {1073pub const struct_ZigClangAPValue = extern struct {
1074 Kind: ZigClangAPValueKind,1074 Kind: ZigClangAPValueKind,
1075 Data: if (builtin.os == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,1075 Data: if (builtin.os.tag == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,
1076};1076};
1077pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType;1077pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType;
10781078
src-self-hosted/introspect.zig+1-9
...@@ -1,4 +1,4 @@...@@ -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
3const std = @import("std");3const std = @import("std");
4const mem = std.mem;4const mem = std.mem;
...@@ -6,14 +6,6 @@ const fs = std.fs;...@@ -6,14 +6,6 @@ const fs = std.fs;
66
7const warn = std.debug.warn;7const 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
17/// Caller must free result9/// Caller must free result
18pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {10pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
19 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });11 const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
src-self-hosted/ir.zig+1-1
...@@ -1803,7 +1803,7 @@ pub const Builder = struct {...@@ -1803,7 +1803,7 @@ pub const Builder = struct {
18031803
1804 // Look at the params and ref() other instructions1804 // Look at the params and ref() other instructions
1805 inline for (@typeInfo(I.Params).Struct.fields) |f| {1805 inline for (@typeInfo(I.Params).Struct.fields) |f| {
1806 switch (f.fiedl_type) {1806 switch (f.field_type) {
1807 *Inst => @field(inst.params, f.name).ref(self),1807 *Inst => @field(inst.params, f.name).ref(self),
1808 *BasicBlock => @field(inst.params, f.name).ref(self),1808 *BasicBlock => @field(inst.params, f.name).ref(self),
1809 ?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),1809 ?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),
src-self-hosted/libc_installation.zig+12-114
...@@ -7,11 +7,7 @@ const Allocator = std.mem.Allocator;...@@ -7,11 +7,7 @@ const Allocator = std.mem.Allocator;
7const Batch = std.event.Batch;7const Batch = std.event.Batch;
88
9const is_darwin = Target.current.isDarwin();9const is_darwin = Target.current.isDarwin();
10const is_windows = Target.current.isWindows();10const is_windows = Target.current.os.tag == .windows;
11const is_freebsd = Target.current.isFreeBSD();
12const is_netbsd = Target.current.isNetBSD();
13const is_linux = Target.current.isLinux();
14const is_dragonfly = Target.current.isDragonFlyBSD();
15const is_gnu = Target.current.isGnu();11const is_gnu = Target.current.isGnu();
1612
17usingnamespace @import("windows_sdk.zig");13usingnamespace @import("windows_sdk.zig");
...@@ -99,27 +95,27 @@ pub const LibCInstallation = struct {...@@ -99,27 +95,27 @@ pub const LibCInstallation = struct {
99 return error.ParseError;95 return error.ParseError;
100 }96 }
101 if (self.crt_dir == null and !is_darwin) {97 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)});
103 return error.ParseError;99 return error.ParseError;
104 }100 }
105 if (self.static_crt_dir == null and is_windows and is_gnu) {101 if (self.static_crt_dir == null and is_windows and is_gnu) {
106 try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{102 try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{
107 @tagName(Target.current.getOs()),103 @tagName(Target.current.os.tag),
108 @tagName(Target.current.getAbi()),104 @tagName(Target.current.abi),
109 });105 });
110 return error.ParseError;106 return error.ParseError;
111 }107 }
112 if (self.msvc_lib_dir == null and is_windows and !is_gnu) {108 if (self.msvc_lib_dir == null and is_windows and !is_gnu) {
113 try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{109 try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{
114 @tagName(Target.current.getOs()),110 @tagName(Target.current.os.tag),
115 @tagName(Target.current.getAbi()),111 @tagName(Target.current.abi),
116 });112 });
117 return error.ParseError;113 return error.ParseError;
118 }114 }
119 if (self.kernel32_lib_dir == null and is_windows and !is_gnu) {115 if (self.kernel32_lib_dir == null and is_windows and !is_gnu) {
120 try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{116 try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{
121 @tagName(Target.current.getOs()),117 @tagName(Target.current.os.tag),
122 @tagName(Target.current.getAbi()),118 @tagName(Target.current.abi),
123 });119 });
124 return error.ParseError;120 return error.ParseError;
125 }121 }
...@@ -216,10 +212,10 @@ pub const LibCInstallation = struct {...@@ -216,10 +212,10 @@ pub const LibCInstallation = struct {
216 var batch = Batch(FindError!void, 2, .auto_async).init();212 var batch = Batch(FindError!void, 2, .auto_async).init();
217 errdefer batch.wait() catch {};213 errdefer batch.wait() catch {};
218 batch.add(&async self.findNativeIncludeDirPosix(args));214 batch.add(&async self.findNativeIncludeDirPosix(args));
219 if (is_freebsd or is_netbsd) {215 switch (Target.current.os.tag) {
220 self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib");216 .freebsd, .netbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"),
221 } else if (is_linux or is_dragonfly) {217 .linux, .dragonfly => batch.add(&async self.findNativeCrtDirPosix(args)),
222 batch.add(&async self.findNativeCrtDirPosix(args));218 else => {},
223 }219 }
224 break :blk batch.wait();220 break :blk batch.wait();
225 };221 };
...@@ -616,104 +612,6 @@ fn printVerboseInvocation(...@@ -616,104 +612,6 @@ fn printVerboseInvocation(
616 }612 }
617}613}
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
717const Search = struct {615const Search = struct {
718 path: []const u8,616 path: []const u8,
719 version: []const u8,617 version: []const u8,
src-self-hosted/link.zig+2-2
...@@ -515,7 +515,7 @@ const DarwinPlatform = struct {...@@ -515,7 +515,7 @@ const DarwinPlatform = struct {
515 break :blk ver;515 break :blk ver;
516 },516 },
517 .None => blk: {517 .None => blk: {
518 assert(comp.target.getOs() == .macosx);518 assert(comp.target.os.tag == .macosx);
519 result.kind = .MacOS;519 result.kind = .MacOS;
520 break :blk "10.14";520 break :blk "10.14";
521 },521 },
...@@ -534,7 +534,7 @@ const DarwinPlatform = struct {...@@ -534,7 +534,7 @@ const DarwinPlatform = struct {
534 }534 }
535535
536 if (result.kind == .IPhoneOS) {536 if (result.kind == .IPhoneOS) {
537 switch (comp.target.getArch()) {537 switch (comp.target.cpu.arch) {
538 .i386,538 .i386,
539 .x86_64,539 .x86_64,
540 => result.kind = .IPhoneOSSimulator,540 => result.kind = .IPhoneOSSimulator,
src-self-hosted/main.zig+10-10
...@@ -79,9 +79,9 @@ pub fn main() !void {...@@ -79,9 +79,9 @@ pub fn main() !void {
79 } else if (mem.eql(u8, cmd, "libc")) {79 } else if (mem.eql(u8, cmd, "libc")) {
80 return cmdLibC(allocator, cmd_args);80 return cmdLibC(allocator, cmd_args);
81 } else if (mem.eql(u8, cmd, "targets")) {81 } else if (mem.eql(u8, cmd, "targets")) {
82 // TODO figure out the current target rather than using the target that was specified when82 const info = try std.zig.system.NativeTargetInfo.detect(allocator);
83 // compiling the compiler83 defer info.deinit(allocator);
84 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, Target.current);84 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);
85 } else if (mem.eql(u8, cmd, "version")) {85 } else if (mem.eql(u8, cmd, "version")) {
86 return cmdVersion(allocator, cmd_args);86 return cmdVersion(allocator, cmd_args);
87 } else if (mem.eql(u8, cmd, "zen")) {87 } else if (mem.eql(u8, cmd, "zen")) {
...@@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
792}792}
793793
794fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {794fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
795 try stdout.print("{}\n", .{std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)});795 try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
796}796}
797797
798fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {798fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
...@@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {...@@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
863 \\ZIG_DIA_GUIDS_LIB {}863 \\ZIG_DIA_GUIDS_LIB {}
864 \\864 \\
865 , .{865 , .{
866 std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),866 c.ZIG_CMAKE_BINARY_DIR,
867 std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),867 c.ZIG_CXX_COMPILER,
868 std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),868 c.ZIG_LLD_INCLUDE_PATH,
869 std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),869 c.ZIG_LLD_LIBRARIES,
870 std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),870 c.ZIG_LLVM_CONFIG_EXE,
871 std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),871 c.ZIG_DIA_GUIDS_LIB,
872 });872 });
873}873}
874874
src-self-hosted/print_targets.zig+6-6
...@@ -124,7 +124,7 @@ pub fn cmdTargets(...@@ -124,7 +124,7 @@ pub fn cmdTargets(
124124
125 try jws.objectField("os");125 try jws.objectField("os");
126 try jws.beginArray();126 try jws.beginArray();
127 inline for (@typeInfo(Target.Os).Enum.fields) |field| {127 inline for (@typeInfo(Target.Os.Tag).Enum.fields) |field| {
128 try jws.arrayElem();128 try jws.arrayElem();
129 try jws.emitString(field.name);129 try jws.emitString(field.name);
130 }130 }
...@@ -201,16 +201,16 @@ pub fn cmdTargets(...@@ -201,16 +201,16 @@ pub fn cmdTargets(
201 try jws.objectField("cpu");201 try jws.objectField("cpu");
202 try jws.beginObject();202 try jws.beginObject();
203 try jws.objectField("arch");203 try jws.objectField("arch");
204 try jws.emitString(@tagName(native_target.getArch()));204 try jws.emitString(@tagName(native_target.cpu.arch));
205205
206 try jws.objectField("name");206 try jws.objectField("name");
207 const cpu = native_target.getCpu();207 const cpu = native_target.cpu;
208 try jws.emitString(cpu.model.name);208 try jws.emitString(cpu.model.name);
209209
210 {210 {
211 try jws.objectField("features");211 try jws.objectField("features");
212 try jws.beginArray();212 try jws.beginArray();
213 for (native_target.getArch().allFeaturesList()) |feature, i_usize| {213 for (native_target.cpu.arch.allFeaturesList()) |feature, i_usize| {
214 const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize);214 const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
215 if (cpu.features.isEnabled(index)) {215 if (cpu.features.isEnabled(index)) {
216 try jws.arrayElem();216 try jws.arrayElem();
...@@ -222,9 +222,9 @@ pub fn cmdTargets(...@@ -222,9 +222,9 @@ pub fn cmdTargets(
222 try jws.endObject();222 try jws.endObject();
223 }223 }
224 try jws.objectField("os");224 try jws.objectField("os");
225 try jws.emitString(@tagName(native_target.getOs()));225 try jws.emitString(@tagName(native_target.os.tag));
226 try jws.objectField("abi");226 try jws.objectField("abi");
227 try jws.emitString(@tagName(native_target.getAbi()));227 try jws.emitString(@tagName(native_target.abi));
228 // TODO implement native glibc version detection in self-hosted228 // TODO implement native glibc version detection in self-hosted
229 try jws.endObject();229 try jws.endObject();
230230
src-self-hosted/stage2.zig+279-124
...@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;...@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
10const ArrayList = std.ArrayList;10const ArrayList = std.ArrayList;
11const Buffer = std.Buffer;11const Buffer = std.Buffer;
12const Target = std.Target;12const Target = std.Target;
13const CrossTarget = std.zig.CrossTarget;
13const self_hosted_main = @import("main.zig");14const self_hosted_main = @import("main.zig");
14const errmsg = @import("errmsg.zig");15const errmsg = @import("errmsg.zig");
15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;16const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
...@@ -87,7 +88,7 @@ const Error = extern enum {...@@ -87,7 +88,7 @@ const Error = extern enum {
87 NotLazy,88 NotLazy,
88 IsAsync,89 IsAsync,
89 ImportOutsidePkgPath,90 ImportOutsidePkgPath,
90 UnknownCpu,91 UnknownCpuModel,
91 UnknownCpuFeature,92 UnknownCpuFeature,
92 InvalidCpuFeatures,93 InvalidCpuFeatures,
93 InvalidLlvmCpuFeaturesFormat,94 InvalidLlvmCpuFeaturesFormat,
...@@ -110,6 +111,8 @@ const Error = extern enum {...@@ -110,6 +111,8 @@ const Error = extern enum {
110 WindowsSdkNotFound,111 WindowsSdkNotFound,
111 UnknownDynamicLinkerPath,112 UnknownDynamicLinkerPath,
112 TargetHasNoDynamicLinker,113 TargetHasNoDynamicLinker,
114 InvalidAbiVersion,
115 InvalidOperatingSystemVersion,
113};116};
114117
115const FILE = std.c.FILE;118const FILE = std.c.FILE;
...@@ -632,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {...@@ -632,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
632}635}
633636
634fn cmdTargets(zig_triple: [*:0]const u8) !void {637fn cmdTargets(zig_triple: [*:0]const u8) !void {
635 var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });638 var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
636 target.Cross.cpu = blk: {639 var dynamic_linker: ?[*:0]u8 = null;
637 const llvm = @import("llvm.zig");640 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
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 };
642 return @import("print_targets.zig").cmdTargets(641 return @import("print_targets.zig").cmdTargets(
643 std.heap.c_allocator,642 std.heap.c_allocator,
644 &[0][]u8{},643 &[0][]u8{},
...@@ -652,16 +651,24 @@ export fn stage2_target_parse(...@@ -652,16 +651,24 @@ export fn stage2_target_parse(
652 target: *Stage2Target,651 target: *Stage2Target,
653 zig_triple: ?[*:0]const u8,652 zig_triple: ?[*:0]const u8,
654 mcpu: ?[*:0]const u8,653 mcpu: ?[*:0]const u8,
654 dynamic_linker: ?[*:0]const u8,
655) Error {655) Error {
656 stage2TargetParse(target, zig_triple, mcpu) catch |err| switch (err) {656 stage2TargetParse(target, zig_triple, mcpu, dynamic_linker) catch |err| switch (err) {
657 error.OutOfMemory => return .OutOfMemory,657 error.OutOfMemory => return .OutOfMemory,
658 error.UnknownArchitecture => return .UnknownArchitecture,658 error.UnknownArchitecture => return .UnknownArchitecture,
659 error.UnknownOperatingSystem => return .UnknownOperatingSystem,659 error.UnknownOperatingSystem => return .UnknownOperatingSystem,
660 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,660 error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
661 error.MissingOperatingSystem => return .MissingOperatingSystem,661 error.MissingOperatingSystem => return .MissingOperatingSystem,
662 error.MissingArchitecture => return .MissingArchitecture,
663 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,662 error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
664 error.UnexpectedExtraField => return .SemanticAnalyzeFail,663 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,
665 };672 };
666 return .None;673 return .None;
667}674}
...@@ -670,17 +677,20 @@ fn stage2TargetParse(...@@ -670,17 +677,20 @@ fn stage2TargetParse(
670 stage1_target: *Stage2Target,677 stage1_target: *Stage2Target,
671 zig_triple_oz: ?[*:0]const u8,678 zig_triple_oz: ?[*:0]const u8,
672 mcpu_oz: ?[*:0]const u8,679 mcpu_oz: ?[*:0]const u8,
680 dynamic_linker_oz: ?[*:0]const u8,
673) !void {681) !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: {
675 const zig_triple = mem.toSliceConst(u8, zig_triple_z);683 const zig_triple = mem.toSliceConst(u8, zig_triple_z);
676 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";684 const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
677 var diags: std.Target.ParseOptions.Diagnostics = .{};685 const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
678 break :blk Target.parse(.{686 var diags: CrossTarget.ParseOptions.Diagnostics = .{};
687 break :blk CrossTarget.parse(.{
679 .arch_os_abi = zig_triple,688 .arch_os_abi = zig_triple,
680 .cpu_features = mcpu,689 .cpu_features = mcpu,
690 .dynamic_linker = dynamic_linker,
681 .diagnostics = &diags,691 .diagnostics = &diags,
682 }) catch |err| switch (err) {692 }) catch |err| switch (err) {
683 error.UnknownCpu => {693 error.UnknownCpuModel => {
684 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{694 std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
685 diags.cpu_name.?,695 diags.cpu_name.?,
686 @tagName(diags.arch.?),696 @tagName(diags.arch.?),
...@@ -706,73 +716,11 @@ fn stage2TargetParse(...@@ -706,73 +716,11 @@ fn stage2TargetParse(
706 },716 },
707 else => |e| return e,717 else => |e| return e,
708 };718 };
709 } else Target.Native;719 } else .{};
710720
711 try stage1_target.fromTarget(target);721 try stage1_target.fromTarget(target);
712}722}
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
776// ABI warning724// ABI warning
777const Stage2LibCInstallation = extern struct {725const Stage2LibCInstallation = extern struct {
778 include_dir: [*:0]const u8,726 include_dir: [*:0]const u8,
...@@ -948,15 +896,18 @@ const Stage2Target = extern struct {...@@ -948,15 +896,18 @@ const Stage2Target = extern struct {
948896
949 is_native: bool,897 is_native: bool,
950898
951 glibc_version: ?*Stage2GLibCVersion, // null means default899 glibc_or_darwin_version: ?*Stage2SemVer,
952900
953 llvm_cpu_name: ?[*:0]const u8,901 llvm_cpu_name: ?[*:0]const u8,
954 llvm_cpu_features: ?[*:0]const u8,902 llvm_cpu_features: ?[*:0]const u8,
955 builtin_str: ?[*:0]const u8,903 cpu_builtin_str: ?[*:0]const u8,
956 cache_hash: ?[*:0]const u8,904 cache_hash: ?[*:0]const u8,
905 os_builtin_str: ?[*:0]const u8,
957906
958 fn toTarget(in_target: Stage2Target) Target {907 dynamic_linker: ?[*:0]const u8,
959 if (in_target.is_native) return .Native;908
909 fn toTarget(in_target: Stage2Target) CrossTarget {
910 if (in_target.is_native) return .{};
960911
961 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch912 const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
962 const in_os = in_target.os;913 const in_os = in_target.os;
...@@ -965,66 +916,270 @@ const Stage2Target = extern struct {...@@ -965,66 +916,270 @@ const Stage2Target = extern struct {
965 return .{916 return .{
966 .Cross = .{917 .Cross = .{
967 .cpu = Target.Cpu.baseline(enumInt(Target.Cpu.Arch, in_arch)),918 .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)),
969 .abi = enumInt(Target.Abi, in_abi),920 .abi = enumInt(Target.Abi, in_abi),
970 },921 },
971 };922 };
972 }923 }
973924
974 fn fromTarget(self: *Stage2Target, target: Target) !void {925 fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
975 const cpu = switch (target) {926 const allocator = std.heap.c_allocator;
976 .Native => blk: {927
977 // TODO self-host CPU model and feature detection instead of relying on LLVM928 var dynamic_linker: ?[*:0]u8 = null;
978 const llvm = @import("llvm.zig");929 const target = try crossTargetToTarget(cross_target, &dynamic_linker);
979 const llvm_cpu_name = llvm.GetHostCPUName();930
980 const llvm_cpu_features = llvm.GetNativeFeatures();931 var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{
981 break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);932 target.cpu.model.name,
982 },933 target.cpu.features.asBytes(),
983 .Cross => target.getCpu(),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 }
984 };1132 };
1133
985 self.* = .{1134 self.* = .{
986 .arch = @enumToInt(target.getArch()) + 1, // skip over ZigLLVM_UnknownArch1135 .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
987 .vendor = 0,1136 .vendor = 0,
988 .os = @enumToInt(target.getOs()),1137 .os = @enumToInt(target.os.tag),
989 .abi = @enumToInt(target.getAbi()),1138 .abi = @enumToInt(target.abi),
990 .llvm_cpu_name = null,1139 .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
991 .llvm_cpu_features = null,1140 .llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
992 .builtin_str = null,1141 .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
993 .cache_hash = null,1142 .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
994 .is_native = target == .Native,1143 .cache_hash = cache_hash.toOwnedSlice().ptr,
995 .glibc_version = null,1144 .is_native = cross_target.isNative(),
1145 .glibc_or_darwin_version = glibc_or_darwin_version,
1146 .dynamic_linker = dynamic_linker,
996 };1147 };
997 try initStage1TargetCpuFeatures(self, cpu);
998 }1148 }
999};1149};
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
1001// ABI warning1176// ABI warning
1002const Stage2GLibCVersion = extern struct {1177const Stage2SemVer = extern struct {
1003 major: u32,1178 major: u32,
1004 minor: u32,1179 minor: u32,
1005 patch: u32,1180 patch: u32,
1006};1181};
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
1028// ABI warning1183// ABI warning
1029const Stage2NativePaths = extern struct {1184const Stage2NativePaths = extern struct {
1030 include_dirs_ptr: [*][*:0]u8,1185 include_dirs_ptr: [*][*:0]u8,
src-self-hosted/translate_c.zig+1-1
...@@ -4850,7 +4850,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4850,7 +4850,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4850 }4850 }
48514851
4852 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);4852 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
4853 const slice = begin_c[0..mem.len(u8, begin_c)];4853 const slice = begin_c[0..mem.len(begin_c)];
48544854
4855 tok_list.shrink(0);4855 tok_list.shrink(0);
4856 var tokenizer = std.c.Tokenizer{4856 var tokenizer = std.c.Tokenizer{
src-self-hosted/util.zig-22
...@@ -34,25 +34,3 @@ pub fn initializeAllTargets() void {...@@ -34,25 +34,3 @@ pub fn initializeAllTargets() void {
34 llvm.InitializeAllAsmPrinters();34 llvm.InitializeAllAsmPrinters();
35 llvm.InitializeAllAsmParsers();35 llvm.InitializeAllAsmParsers();
36}36}
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-4
...@@ -2249,14 +2249,11 @@ struct CodeGen {...@@ -2249,14 +2249,11 @@ struct CodeGen {
2249 bool test_is_evented;2249 bool test_is_evented;
2250 CodeModel code_model;2250 CodeModel code_model;
22512251
2252 Buf *mmacosx_version_min;
2253 Buf *mios_version_min;
2254 Buf *root_out_name;2252 Buf *root_out_name;
2255 Buf *test_filter;2253 Buf *test_filter;
2256 Buf *test_name_prefix;2254 Buf *test_name_prefix;
2257 Buf *zig_lib_dir;2255 Buf *zig_lib_dir;
2258 Buf *zig_std_dir;2256 Buf *zig_std_dir;
2259 Buf *dynamic_linker_path;
2260 Buf *version_script_path;2257 Buf *version_script_path;
22612258
2262 const char **llvm_argv;2259 const char **llvm_argv;
...@@ -3266,7 +3263,6 @@ struct IrInstSrcContainerInitList {...@@ -3266,7 +3263,6 @@ struct IrInstSrcContainerInitList {
3266struct IrInstSrcContainerInitFieldsField {3263struct IrInstSrcContainerInitFieldsField {
3267 Buf *name;3264 Buf *name;
3268 AstNode *source_node;3265 AstNode *source_node;
3269 TypeStructField *type_struct_field;
3270 IrInstSrc *result_loc;3266 IrInstSrc *result_loc;
3271};3267};
32723268
src/analyze.cpp+89-60
...@@ -1131,18 +1131,26 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent...@@ -1131,18 +1131,26 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
1131 Error err;1131 Error err;
1132 if (type_val->special != ConstValSpecialLazy) {1132 if (type_val->special != ConstValSpecialLazy) {
1133 assert(type_val->special == ConstValSpecialStatic);1133 assert(type_val->special == ConstValSpecialStatic);
1134 if ((type_val->data.x_type->id == ZigTypeIdStruct &&1134
1135 type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) ||1135 // Self-referencing types via pointers are allowed and have non-zero size
1136 (type_val->data.x_type->id == ZigTypeIdUnion &&1136 ZigType *ty = type_val->data.x_type;
1137 type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits) ||1137 while (ty->id == ZigTypeIdPointer &&
1138 type_val->data.x_type->id == ZigTypeIdPointer)1138 !ty->data.pointer.resolve_loop_flag_zero_bits)
1139 {
1140 ty = ty->data.pointer.child_type;
1141 }
1142
1143 if ((ty->id == ZigTypeIdStruct && ty->data.structure.resolve_loop_flag_zero_bits) ||
1144 (ty->id == ZigTypeIdUnion && ty->data.unionation.resolve_loop_flag_zero_bits) ||
1145 (ty->id == ZigTypeIdPointer && ty->data.pointer.resolve_loop_flag_zero_bits))
1139 {1146 {
1140 // Does a struct/union which contains a pointer field to itself have bits? Yes.
1141 *is_zero_bits = false;1147 *is_zero_bits = false;
1142 return ErrorNone;1148 return ErrorNone;
1143 }1149 }
1150
1144 if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))1151 if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))
1145 return err;1152 return err;
1153
1146 *is_zero_bits = (type_val->data.x_type->abi_size == 0);1154 *is_zero_bits = (type_val->data.x_type->abi_size == 0);
1147 return ErrorNone;1155 return ErrorNone;
1148 }1156 }
...@@ -3955,7 +3963,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {...@@ -3955,7 +3963,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
39553963
3956 // TODO more validation for types that can't be used for export/extern variables3964 // TODO more validation for types that can't be used for export/extern variables
3957 ZigType *implicit_type = nullptr;3965 ZigType *implicit_type = nullptr;
3958 if (explicit_type != nullptr && explicit_type->id == ZigTypeIdInvalid) {3966 if (explicit_type != nullptr && type_is_invalid(explicit_type)) {
3959 implicit_type = explicit_type;3967 implicit_type = explicit_type;
3960 } else if (var_decl->expr) {3968 } else if (var_decl->expr) {
3961 init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type,3969 init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type,
...@@ -4763,38 +4771,41 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {...@@ -4763,38 +4771,41 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
4763 if (return_err_set_type->data.error_set.infer_fn != nullptr &&4771 if (return_err_set_type->data.error_set.infer_fn != nullptr &&
4764 return_err_set_type->data.error_set.incomplete)4772 return_err_set_type->data.error_set.incomplete)
4765 {4773 {
4766 ZigType *inferred_err_set_type;4774 // The inferred error set type is null if the function doesn't
4775 // return any error
4776 ZigType *inferred_err_set_type = nullptr;
4777
4767 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {4778 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
4768 inferred_err_set_type = fn->src_implicit_return_type;4779 inferred_err_set_type = fn->src_implicit_return_type;
4769 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {4780 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
4770 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;4781 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
4771 } else {
4772 add_node_error(g, return_type_node,
4773 buf_sprintf("function with inferred error set must return at least one possible error"));
4774 fn->anal_state = FnAnalStateInvalid;
4775 return;
4776 }4782 }
47774783
4778 if (inferred_err_set_type->data.error_set.infer_fn != nullptr &&4784 if (inferred_err_set_type != nullptr) {
4779 inferred_err_set_type->data.error_set.incomplete)4785 if (inferred_err_set_type->data.error_set.infer_fn != nullptr &&
4780 {4786 inferred_err_set_type->data.error_set.incomplete)
4781 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {4787 {
4782 fn->anal_state = FnAnalStateInvalid;4788 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
4783 return;4789 fn->anal_state = FnAnalStateInvalid;
4790 return;
4791 }
4784 }4792 }
4785 }
47864793
4787 return_err_set_type->data.error_set.incomplete = false;4794 return_err_set_type->data.error_set.incomplete = false;
4788 if (type_is_global_error_set(inferred_err_set_type)) {4795 if (type_is_global_error_set(inferred_err_set_type)) {
4789 return_err_set_type->data.error_set.err_count = UINT32_MAX;4796 return_err_set_type->data.error_set.err_count = UINT32_MAX;
4790 } else {4797 } else {
4791 return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;4798 return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
4792 if (inferred_err_set_type->data.error_set.err_count > 0) {4799 if (inferred_err_set_type->data.error_set.err_count > 0) {
4793 return_err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);4800 return_err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);
4794 for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {4801 for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {
4795 return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];4802 return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];
4803 }
4796 }4804 }
4797 }4805 }
4806 } else {
4807 return_err_set_type->data.error_set.incomplete = false;
4808 return_err_set_type->data.error_set.err_count = 0;
4798 }4809 }
4799 }4810 }
4800 }4811 }
...@@ -5390,6 +5401,8 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {...@@ -5390,6 +5401,8 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
53905401
5391static bool can_mutate_comptime_var_state(ZigValue *value) {5402static bool can_mutate_comptime_var_state(ZigValue *value) {
5392 assert(value != nullptr);5403 assert(value != nullptr);
5404 if (value->special == ConstValSpecialUndef)
5405 return false;
5393 switch (value->type->id) {5406 switch (value->type->id) {
5394 case ZigTypeIdInvalid:5407 case ZigTypeIdInvalid:
5395 zig_unreachable();5408 zig_unreachable();
...@@ -5418,6 +5431,8 @@ static bool can_mutate_comptime_var_state(ZigValue *value) {...@@ -5418,6 +5431,8 @@ static bool can_mutate_comptime_var_state(ZigValue *value) {
5418 return value->data.x_ptr.mut == ConstPtrMutComptimeVar;5431 return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
54195432
5420 case ZigTypeIdArray:5433 case ZigTypeIdArray:
5434 if (value->special == ConstValSpecialUndef)
5435 return false;
5421 if (value->type->data.array.len == 0)5436 if (value->type->data.array.len == 0)
5422 return false;5437 return false;
5423 switch (value->data.x_array.special) {5438 switch (value->data.x_array.special) {
...@@ -6690,8 +6705,16 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {...@@ -6690,8 +6705,16 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
6690}6705}
66916706
6692static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) {6707static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) {
6693 assert(a->data.x_array.special != ConstArraySpecialUndef);6708 if (a->data.x_array.special == ConstArraySpecialUndef &&
6694 assert(b->data.x_array.special != ConstArraySpecialUndef);6709 b->data.x_array.special == ConstArraySpecialUndef)
6710 {
6711 return true;
6712 }
6713 if (a->data.x_array.special == ConstArraySpecialUndef ||
6714 b->data.x_array.special == ConstArraySpecialUndef)
6715 {
6716 return false;
6717 }
6695 if (a->data.x_array.special == ConstArraySpecialBuf &&6718 if (a->data.x_array.special == ConstArraySpecialBuf &&
6696 b->data.x_array.special == ConstArraySpecialBuf)6719 b->data.x_array.special == ConstArraySpecialBuf)
6697 {6720 {
...@@ -6713,8 +6736,6 @@ static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_...@@ -6713,8 +6736,6 @@ static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_
67136736
6714bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {6737bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
6715 if (a->type->id != b->type->id) return false;6738 if (a->type->id != b->type->id) return false;
6716 assert(a->special == ConstValSpecialStatic);
6717 assert(b->special == ConstValSpecialStatic);
6718 if (a->type == b->type) {6739 if (a->type == b->type) {
6719 switch (type_has_one_possible_value(g, a->type)) {6740 switch (type_has_one_possible_value(g, a->type)) {
6720 case OnePossibleValueInvalid:6741 case OnePossibleValueInvalid:
...@@ -6725,6 +6746,11 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {...@@ -6725,6 +6746,11 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
6725 return true;6746 return true;
6726 }6747 }
6727 }6748 }
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);
6728 switch (a->type->id) {6754 switch (a->type->id) {
6729 case ZigTypeIdOpaque:6755 case ZigTypeIdOpaque:
6730 zig_unreachable();6756 zig_unreachable();
...@@ -8708,7 +8734,6 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus...@@ -8708,7 +8734,6 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
8708 if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return;8734 if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return;
8709 }8735 }
87108736
8711 LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
8712 ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);8737 ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
8713 if (type->data.maybe.resolve_status >= wanted_resolve_status) return;8738 if (type->data.maybe.resolve_status >= wanted_resolve_status) return;
87148739
...@@ -8718,35 +8743,28 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus...@@ -8718,35 +8743,28 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
8718 };8743 };
8719 LLVMStructSetBody(type->llvm_type, elem_types, 2, false);8744 LLVMStructSetBody(type->llvm_type, elem_types, 2, false);
87208745
8721 uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type);8746 uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_child_index);
8722 uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type);8747 uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_null_index);
8723 uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
8724
8725 uint64_t maybe_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, bool_llvm_type);
8726 uint64_t maybe_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, bool_llvm_type);
8727 uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1);
87288748
8729 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);8749 ZigLLVMDIType *di_element_types[2];
8730 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);8750 di_element_types[maybe_child_index] =
8731
8732 ZigLLVMDIType *di_element_types[] = {
8733 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),8751 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
8734 "val", di_file, line,8752 "val", di_file, line,
8735 val_debug_size_in_bits,8753 8 * child_type->abi_size,
8736 val_debug_align_in_bits,8754 8 * child_type->abi_align,
8737 val_offset_in_bits,8755 val_offset_in_bits,
8738 ZigLLVM_DIFlags_Zero, child_llvm_di_type),8756 ZigLLVM_DIFlags_Zero, child_llvm_di_type);
8757 di_element_types[maybe_null_index] =
8739 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),8758 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
8740 "maybe", di_file, line,8759 "maybe", di_file, line,
8741 maybe_debug_size_in_bits,8760 8*g->builtin_types.entry_bool->abi_size,
8742 maybe_debug_align_in_bits,8761 8*g->builtin_types.entry_bool->abi_align,
8743 maybe_offset_in_bits,8762 maybe_offset_in_bits,
8744 ZigLLVM_DIFlags_Zero, bool_llvm_di_type),8763 ZigLLVM_DIFlags_Zero, bool_llvm_di_type);
8745 };
8746 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,8764 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
8747 compile_unit_scope,8765 compile_unit_scope,
8748 buf_ptr(&type->name),8766 buf_ptr(&type->name),
8749 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,
8750 nullptr, di_element_types, 2, 0, nullptr, "");8768 nullptr, di_element_types, 2, 0, nullptr, "");
87518769
8752 ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);8770 ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
...@@ -9387,13 +9405,24 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) {...@@ -9387,13 +9405,24 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) {
9387 dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i;9405 dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i;
9388 }9406 }
9389 } else if (dest->type->id == ZigTypeIdArray) {9407 } else if (dest->type->id == ZigTypeIdArray) {
9390 if (dest->data.x_array.special == ConstArraySpecialNone) {9408 switch (dest->data.x_array.special) {
9391 dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(dest->type->data.array.len);9409 case ConstArraySpecialNone: {
9392 for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) {9410 dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(dest->type->data.array.len);
9393 copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]);9411 for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) {
9394 dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray;9412 copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]);
9395 dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest;9413 dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray;
9396 dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i;9414 dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest;
9415 dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i;
9416 }
9417 break;
9418 }
9419 case ConstArraySpecialUndef: {
9420 // Nothing to copy; the above memcpy did everything we needed.
9421 break;
9422 }
9423 case ConstArraySpecialBuf: {
9424 dest->data.x_array.data.s_buf = buf_create_from_buf(src->data.x_array.data.s_buf);
9425 break;
9397 }9426 }
9398 }9427 }
9399 } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) {9428 } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) {
src/codegen.cpp+50-97
...@@ -32,31 +32,6 @@ enum ResumeId {...@@ -32,31 +32,6 @@ enum ResumeId {
32 ResumeIdCall,32 ResumeIdCall,
33};33};
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
60static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {35static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
61 ZigPackage *entry = heap::c_allocator.create<ZigPackage>();36 ZigPackage *entry = heap::c_allocator.create<ZigPackage>();
62 entry->package_table.init(4);37 entry->package_table.init(4);
...@@ -160,14 +135,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) {...@@ -160,14 +135,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) {
160 g->darwin_frameworks.append(buf_create_from_str(framework));135 g->darwin_frameworks.append(buf_create_from_str(framework));
161}136}
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
171void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {138void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
172 g->linker_rdynamic = rdynamic;139 g->linker_rdynamic = rdynamic;
173}140}
...@@ -972,7 +939,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -972,7 +939,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
972 case PanicMsgIdExactDivisionRemainder:939 case PanicMsgIdExactDivisionRemainder:
973 return buf_create_from_str("exact division produced remainder");940 return buf_create_from_str("exact division produced remainder");
974 case PanicMsgIdUnwrapOptionalFail:941 case PanicMsgIdUnwrapOptionalFail:
975 return buf_create_from_str("attempt to unwrap null");942 return buf_create_from_str("attempt to use null value");
976 case PanicMsgIdUnreachable:943 case PanicMsgIdUnreachable:
977 return buf_create_from_str("reached unreachable code");944 return buf_create_from_str("reached unreachable code");
978 case PanicMsgIdInvalidErrorCode:945 case PanicMsgIdInvalidErrorCode:
...@@ -3325,11 +3292,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl...@@ -3325,11 +3292,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
3325 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");3292 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
3326 size_t field_count = wanted_type->data.enumeration.src_field_count;3293 size_t field_count = wanted_type->data.enumeration.src_field_count;
3327 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);3294 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
3295
3296 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
3297 occupied_tag_values.init(field_count);
3298
3328 for (size_t field_i = 0; field_i < field_count; field_i += 1) {3299 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
3300 TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
3301
3302 Buf *name = type_enum_field->name;
3303 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
3304 if (entry != nullptr) {
3305 continue;
3306 }
3307
3329 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),3308 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
3330 &wanted_type->data.enumeration.fields[field_i].value);3309 &type_enum_field->value);
3331 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);3310 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
3332 }3311 }
3312 occupied_tag_values.deinit();
3333 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);3313 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
3334 gen_safety_crash(g, PanicMsgIdBadEnumValue);3314 gen_safety_crash(g, PanicMsgIdBadEnumValue);
33353315
...@@ -4466,7 +4446,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutableGen *execu...@@ -4466,7 +4446,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutableGen *execu
44664446
4467 if (!type_has_bits(field->type_entry)) {4447 if (!type_has_bits(field->type_entry)) {
4468 ZigType *tag_type = union_type->data.unionation.tag_type;4448 ZigType *tag_type = union_type->data.unionation.tag_type;
4469 if (!instruction->initializing || !type_has_bits(tag_type))4449 if (!instruction->initializing || tag_type == nullptr || !type_has_bits(tag_type))
4470 return nullptr;4450 return nullptr;
44714451
4472 // The field has no bits but we still have to change the discriminant4452 // The field has no bits but we still have to change the discriminant
...@@ -5026,8 +5006,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -5026,8 +5006,18 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
5026 LLVMConstNull(usize->llvm_type),5006 LLVMConstNull(usize->llvm_type),
5027 };5007 };
50285008
5009 HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
5010 occupied_tag_values.init(field_count);
5011
5029 for (size_t field_i = 0; field_i < field_count; field_i += 1) {5012 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
5030 Buf *name = enum_type->data.enumeration.fields[field_i].name;5013 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
5014
5015 Buf *name = type_enum_field->name;
5016 auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
5017 if (entry != nullptr) {
5018 continue;
5019 }
5020
5031 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);5021 LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
5032 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");5022 LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
5033 LLVMSetInitializer(str_global, str_init);5023 LLVMSetInitializer(str_global, str_init);
...@@ -5057,6 +5047,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -5057,6 +5047,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
5057 LLVMPositionBuilderAtEnd(g->builder, return_block);5047 LLVMPositionBuilderAtEnd(g->builder, return_block);
5058 LLVMBuildRet(g->builder, slice_global);5048 LLVMBuildRet(g->builder, slice_global);
5059 }5049 }
5050 occupied_tag_values.deinit();
50605051
5061 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);5052 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
5062 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {5053 if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
...@@ -5081,11 +5072,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa...@@ -5081,11 +5072,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
5081{5072{
5082 ZigType *enum_type = instruction->target->value->type;5073 ZigType *enum_type = instruction->target->value->type;
5083 assert(enum_type->id == ZigTypeIdEnum);5074 assert(enum_type->id == ZigTypeIdEnum);
5084 if (enum_type->data.enumeration.non_exhaustive) {
5085 add_node_error(g, instruction->base.base.source_node,
5086 buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
5087 codegen_report_errors_and_exit(g);
5088 }
50895075
5090 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);5076 LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
50915077
...@@ -8518,25 +8504,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -8518,25 +8504,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
8518 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);8504 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
8519 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));8505 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
8520 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));8506 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
8521 buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);8507 buf_append_str(contents, "/// Deprecated: use `std.Target.cpu.arch`\n");
8522 buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);8508 buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
8523 buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);8509 buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
8524 {8510 {
8525 buf_append_str(contents, "pub const cpu: Cpu = ");8511 buf_append_str(contents, "pub const cpu: Cpu = ");
8526 if (g->zig_target->builtin_str != nullptr) {8512 if (g->zig_target->cpu_builtin_str != nullptr) {
8527 buf_append_str(contents, g->zig_target->builtin_str);8513 buf_append_str(contents, g->zig_target->cpu_builtin_str);
8528 } else {8514 } else {
8529 buf_append_str(contents, "Target.Cpu.baseline(arch);\n");8515 buf_appendf(contents, "Target.Cpu.baseline(.%s);\n", cur_arch);
8530 }8516 }
8531 }8517 }
8532 if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {8518 {
8533 buf_appendf(contents,8519 buf_append_str(contents, "pub const os = ");
8534 "pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n",8520 if (g->zig_target->os_builtin_str != nullptr) {
8535 g->zig_target->glibc_version->major,8521 buf_append_str(contents, g->zig_target->os_builtin_str);
8536 g->zig_target->glibc_version->minor,8522 } else {
8537 g->zig_target->glibc_version->patch);8523 buf_appendf(contents, "Target.Os.defaultVersionRange(.%s);\n", cur_os);
8538 } else {8524 }
8539 buf_appendf(contents, "pub const glibc_version: ?Version = null;\n");
8540 }8525 }
8541 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);8526 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
8542 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));8527 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
...@@ -8631,10 +8616,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {...@@ -8631,10 +8616,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {
8631 if (g->zig_target->cache_hash != nullptr) {8616 if (g->zig_target->cache_hash != nullptr) {
8632 cache_str(&cache_hash, g->zig_target->cache_hash);8617 cache_str(&cache_hash, g->zig_target->cache_hash);
8633 }8618 }
8634 if (g->zig_target->glibc_version != nullptr) {8619 if (g->zig_target->glibc_or_darwin_version != nullptr) {
8635 cache_int(&cache_hash, g->zig_target->glibc_version->major);8620 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->major);
8636 cache_int(&cache_hash, g->zig_target->glibc_version->minor);8621 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->minor);
8637 cache_int(&cache_hash, g->zig_target->glibc_version->patch);8622 cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->patch);
8638 }8623 }
8639 cache_bool(&cache_hash, g->have_err_ret_tracing);8624 cache_bool(&cache_hash, g->have_err_ret_tracing);
8640 cache_bool(&cache_hash, g->libc_link_lib != nullptr);8625 cache_bool(&cache_hash, g->libc_link_lib != nullptr);
...@@ -8841,28 +8826,6 @@ static void init(CodeGen *g) {...@@ -8841,28 +8826,6 @@ static void init(CodeGen *g) {
8841 }8826 }
8842}8827}
88438828
8844static void detect_dynamic_linker(CodeGen *g) {
8845 Error err;
8846
8847 if (g->dynamic_linker_path != nullptr)
8848 return;
8849 if (!g->have_dynamic_link)
8850 return;
8851 if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
8852 return;
8853
8854 char *dynamic_linker_ptr;
8855 size_t dynamic_linker_len;
8856 if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
8857 if (err == ErrorTargetHasNoDynamicLinker) return;
8858 fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
8859 exit(1);
8860 }
8861 g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
8862 // Skips heap::c_allocator because the memory is allocated by stage2 library.
8863 free(dynamic_linker_ptr);
8864}
8865
8866static void detect_libc(CodeGen *g) {8829static void detect_libc(CodeGen *g) {
8867 Error err;8830 Error err;
88688831
...@@ -10298,10 +10261,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10298,10 +10261,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10298 if (g->zig_target->cache_hash != nullptr) {10261 if (g->zig_target->cache_hash != nullptr) {
10299 cache_str(ch, g->zig_target->cache_hash);10262 cache_str(ch, g->zig_target->cache_hash);
10300 }10263 }
10301 if (g->zig_target->glibc_version != nullptr) {10264 if (g->zig_target->glibc_or_darwin_version != nullptr) {
10302 cache_int(ch, g->zig_target->glibc_version->major);10265 cache_int(ch, g->zig_target->glibc_or_darwin_version->major);
10303 cache_int(ch, g->zig_target->glibc_version->minor);10266 cache_int(ch, g->zig_target->glibc_or_darwin_version->minor);
10304 cache_int(ch, g->zig_target->glibc_version->patch);10267 cache_int(ch, g->zig_target->glibc_or_darwin_version->patch);
10268 }
10269 if (g->zig_target->dynamic_linker != nullptr) {
10270 cache_str(ch, g->zig_target->dynamic_linker);
10305 }10271 }
10306 cache_int(ch, detect_subsystem(g));10272 cache_int(ch, detect_subsystem(g));
10307 cache_bool(ch, g->strip_debug_symbols);10273 cache_bool(ch, g->strip_debug_symbols);
...@@ -10329,8 +10295,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10329,8 +10295,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10329 cache_bool(ch, g->emit_bin);10295 cache_bool(ch, g->emit_bin);
10330 cache_bool(ch, g->emit_llvm_ir);10296 cache_bool(ch, g->emit_llvm_ir);
10331 cache_bool(ch, g->emit_asm);10297 cache_bool(ch, g->emit_asm);
10332 cache_buf_opt(ch, g->mmacosx_version_min);
10333 cache_buf_opt(ch, g->mios_version_min);
10334 cache_usize(ch, g->version_major);10298 cache_usize(ch, g->version_major);
10335 cache_usize(ch, g->version_minor);10299 cache_usize(ch, g->version_minor);
10336 cache_usize(ch, g->version_patch);10300 cache_usize(ch, g->version_patch);
...@@ -10345,7 +10309,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10345,7 +10309,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10345 cache_str(ch, g->libc->msvc_lib_dir);10309 cache_str(ch, g->libc->msvc_lib_dir);
10346 cache_str(ch, g->libc->kernel32_lib_dir);10310 cache_str(ch, g->libc->kernel32_lib_dir);
10347 }10311 }
10348 cache_buf_opt(ch, g->dynamic_linker_path);
10349 cache_buf_opt(ch, g->version_script_path);10312 cache_buf_opt(ch, g->version_script_path);
1035010313
10351 // gen_c_objects appends objects to g->link_objects which we want to include in the hash10314 // gen_c_objects appends objects to g->link_objects which we want to include in the hash
...@@ -10442,7 +10405,6 @@ void codegen_build_and_link(CodeGen *g) {...@@ -10442,7 +10405,6 @@ void codegen_build_and_link(CodeGen *g) {
10442 g->have_err_ret_tracing = detect_err_ret_tracing(g);10405 g->have_err_ret_tracing = detect_err_ret_tracing(g);
10443 g->have_sanitize_c = detect_sanitize_c(g);10406 g->have_sanitize_c = detect_sanitize_c(g);
10444 detect_libc(g);10407 detect_libc(g);
10445 detect_dynamic_linker(g);
1044610408
10447 Buf digest = BUF_INIT;10409 Buf digest = BUF_INIT;
10448 if (g->enable_cache) {10410 if (g->enable_cache) {
...@@ -10639,7 +10601,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o...@@ -10639,7 +10601,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
10639 child_gen->verbose_cc = parent_gen->verbose_cc;10601 child_gen->verbose_cc = parent_gen->verbose_cc;
10640 child_gen->verbose_llvm_cpu_features = parent_gen->verbose_llvm_cpu_features;10602 child_gen->verbose_llvm_cpu_features = parent_gen->verbose_llvm_cpu_features;
10641 child_gen->llvm_argv = parent_gen->llvm_argv;10603 child_gen->llvm_argv = parent_gen->llvm_argv;
10642 child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path;
1064310604
10644 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);10605 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
10645 child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled;10606 child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled;
...@@ -10647,9 +10608,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o...@@ -10647,9 +10608,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
1064710608
10648 codegen_set_errmsg_color(child_gen, parent_gen->err_color);10609 codegen_set_errmsg_color(child_gen, parent_gen->err_color);
1064910610
10650 codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
10651 codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
10652
10653 child_gen->enable_cache = true;10611 child_gen->enable_cache = true;
1065410612
10655 return child_gen;10613 return child_gen;
...@@ -10757,11 +10715,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget...@@ -10757,11 +10715,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
10757 g->each_lib_rpath = false;10715 g->each_lib_rpath = false;
10758 } else {10716 } else {
10759 g->each_lib_rpath = true;10717 g->each_lib_rpath = true;
10760
10761 if (target_os_is_darwin(g->zig_target->os)) {
10762 init_darwin_native(g);
10763 }
10764
10765 }10718 }
1076610719
10767 if (target_os_requires_libc(g->zig_target->os)) {10720 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);...@@ -35,8 +35,6 @@ LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
35void codegen_add_framework(CodeGen *codegen, const char *name);35void codegen_add_framework(CodeGen *codegen, const char *name);
36void codegen_add_rpath(CodeGen *codegen, const char *name);36void codegen_add_rpath(CodeGen *codegen, const char *name);
37void codegen_set_rdynamic(CodeGen *g, bool rdynamic);37void 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);
40void codegen_set_linker_script(CodeGen *g, const char *linker_script);38void codegen_set_linker_script(CodeGen *g, const char *linker_script);
41void codegen_set_test_filter(CodeGen *g, Buf *filter);39void codegen_set_test_filter(CodeGen *g, Buf *filter);
42void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);40void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
src/compiler.cpp-25
...@@ -4,31 +4,6 @@...@@ -4,31 +4,6 @@
44
5#include <stdio.h>5#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
32Error get_compiler_id(Buf **result) {7Error get_compiler_id(Buf **result) {
33 static Buf saved_compiler_id = BUF_INIT;8 static Buf saved_compiler_id = BUF_INIT;
349
src/compiler.hpp-1
...@@ -12,7 +12,6 @@...@@ -12,7 +12,6 @@
12#include "error.hpp"12#include "error.hpp"
1313
14Error get_compiler_id(Buf **result);14Error get_compiler_id(Buf **result);
15Buf *get_self_libc_path(void);
1615
17Buf *get_zig_lib_dir(void);16Buf *get_zig_lib_dir(void);
18Buf *get_zig_special_dir(Buf *zig_lib_dir);17Buf *get_zig_special_dir(Buf *zig_lib_dir);
src/error.cpp+2
...@@ -81,6 +81,8 @@ const char *err_str(Error err) {...@@ -81,6 +81,8 @@ const char *err_str(Error err) {
81 case ErrorWindowsSdkNotFound: return "Windows SDK not found";81 case ErrorWindowsSdkNotFound: return "Windows SDK not found";
82 case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path";82 case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path";
83 case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker";83 case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker";
84 case ErrorInvalidAbiVersion: return "invalid C ABI version";
85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
84 }86 }
85 return "(invalid error)";87 return "(invalid error)";
86}88}
src/glibc.cpp+13-50
...@@ -55,7 +55,7 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo...@@ -55,7 +55,7 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
55 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);55 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
56 if (!opt_component.is_some) break;56 if (!opt_component.is_some) break;
57 Buf *ver_buf = buf_create_from_slice(opt_component.value);57 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();
59 if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {59 if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {
60 if (verbose) {60 if (verbose) {
61 fprintf(stderr, "Unable to parse glibc version '%s': %s\n", buf_ptr(ver_buf), err_str(err));61 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...@@ -186,9 +186,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
186 cache_buf(cache_hash, compiler_id);186 cache_buf(cache_hash, compiler_id);
187 cache_int(cache_hash, target->arch);187 cache_int(cache_hash, target->arch);
188 cache_int(cache_hash, target->abi);188 cache_int(cache_hash, target->abi);
189 cache_int(cache_hash, target->glibc_version->major);189 cache_int(cache_hash, target->glibc_or_darwin_version->major);
190 cache_int(cache_hash, target->glibc_version->minor);190 cache_int(cache_hash, target->glibc_or_darwin_version->minor);
191 cache_int(cache_hash, target->glibc_version->patch);191 cache_int(cache_hash, target->glibc_or_darwin_version->patch);
192192
193 Buf digest = BUF_INIT;193 Buf digest = BUF_INIT;
194 buf_resize(&digest, 0);194 buf_resize(&digest, 0);
...@@ -224,10 +224,10 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con...@@ -224,10 +224,10 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
224224
225 uint8_t target_ver_index = 0;225 uint8_t target_ver_index = 0;
226 for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) {226 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);227 const Stage2SemVer *this_ver = &glibc_abi->all_versions.at(target_ver_index);
228 if (this_ver->major == target->glibc_version->major &&228 if (this_ver->major == target->glibc_or_darwin_version->major &&
229 this_ver->minor == target->glibc_version->minor &&229 this_ver->minor == target->glibc_or_darwin_version->minor &&
230 this_ver->patch == target->glibc_version->patch)230 this_ver->patch == target->glibc_or_darwin_version->patch)
231 {231 {
232 break;232 break;
233 }233 }
...@@ -235,9 +235,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con...@@ -235,9 +235,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
235 if (target_ver_index == glibc_abi->all_versions.length) {235 if (target_ver_index == glibc_abi->all_versions.length) {
236 if (verbose) {236 if (verbose) {
237 fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",237 fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",
238 target->glibc_version->major,238 target->glibc_or_darwin_version->major,
239 target->glibc_version->minor,239 target->glibc_or_darwin_version->minor,
240 target->glibc_version->patch);240 target->glibc_or_darwin_version->patch);
241 }241 }
242 return ErrorUnknownABI;242 return ErrorUnknownABI;
243 }243 }
...@@ -246,7 +246,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con...@@ -246,7 +246,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
246 Buf *map_contents = buf_alloc();246 Buf *map_contents = buf_alloc();
247247
248 for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) {248 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);
250 if (ver->patch == 0) {250 if (ver->patch == 0) {
251 buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);251 buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);
252 } else {252 } else {
...@@ -294,7 +294,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con...@@ -294,7 +294,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
294 uint8_t ver_index = ver_list->versions[ver_i];294 uint8_t ver_index = ver_list->versions[ver_i];
295295
296 Buf *stub_name;296 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);
298 const char *sym_name = buf_ptr(libc_fn->name);298 const char *sym_name = buf_ptr(libc_fn->name);
299 if (ver->patch == 0) {299 if (ver->patch == 0) {
300 stub_name = buf_sprintf("%s_%d_%d", sym_name, ver->major, ver->minor);300 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) {...@@ -362,43 +362,6 @@ bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) {
362 a->abi == b->abi;362 a->abi == b->abi;
363}363}
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
402size_t glibc_lib_count(void) {365size_t glibc_lib_count(void) {
403 return array_length(glibc_libs);366 return array_length(glibc_libs);
404}367}
src/glibc.hpp+1-4
...@@ -32,7 +32,7 @@ struct ZigGLibCAbi {...@@ -32,7 +32,7 @@ struct ZigGLibCAbi {
32 Buf *abi_txt_path;32 Buf *abi_txt_path;
33 Buf *vers_txt_path;33 Buf *vers_txt_path;
34 Buf *fns_txt_path;34 Buf *fns_txt_path;
35 ZigList<ZigGLibCVersion> all_versions;35 ZigList<Stage2SemVer> all_versions;
36 ZigList<ZigGLibCFn> all_functions;36 ZigList<ZigGLibCFn> all_functions;
37 // The value is a pointer to all_functions.length items and each item is an index37 // The value is a pointer to all_functions.length items and each item is an index
38 // into all_functions.38 // into all_functions.
...@@ -43,9 +43,6 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo...@@ -43,9 +43,6 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
43Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,43Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
44 Buf **out_dir, bool verbose, Stage2ProgressNode *progress_node);44 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
49size_t glibc_lib_count(void);46size_t glibc_lib_count(void);
50const ZigGLibCLib *glibc_lib_enum(size_t index);47const ZigGLibCLib *glibc_lib_enum(size_t index);
51const ZigGLibCLib *glibc_lib_find(const char *name);48const ZigGLibCLib *glibc_lib_find(const char *name);
src/ir.cpp+81-25
...@@ -12555,13 +12555,22 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc...@@ -12555,13 +12555,22 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc
12555{12555{
12556 Error err;12556 Error err;
1255712557
12558 if ((err = type_resolve(ira->codegen, array_ptr->value->type->data.pointer.child_type,12558 assert(array_ptr->value->type->id == ZigTypeIdPointer);
12559 ResolveStatusAlignmentKnown)))12559
12560 {12560 if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {
12561 return ira->codegen->invalid_inst_gen;12561 return ira->codegen->invalid_inst_gen;
12562 }12562 }
1256312563
12564 wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, array_ptr->value->type));12564 assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
12565
12566 const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len;
12567
12568 // A zero-sized array can always be casted irregardless of the destination
12569 // alignment
12570 if (array_len != 0) {
12571 wanted_type = adjust_slice_align(ira->codegen, wanted_type,
12572 get_ptr_align(ira->codegen, array_ptr->value->type));
12573 }
1256512574
12566 if (instr_is_comptime(array_ptr)) {12575 if (instr_is_comptime(array_ptr)) {
12567 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);12576 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
...@@ -14833,19 +14842,19 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,...@@ -14833,19 +14842,19 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,
1483314842
14834 // cast from inferred struct type to array, union, or struct14843 // cast from inferred struct type to array, union, or struct
14835 if (is_anon_container(actual_type)) {14844 if (is_anon_container(actual_type)) {
14836 AstNode *decl_node = actual_type->data.structure.decl_node;14845 const bool is_array_init =
14837 ir_assert(decl_node->type == NodeTypeContainerInitExpr, source_instr);14846 actual_type->data.structure.special == StructSpecialInferredTuple;
14838 ContainerInitKind init_kind = decl_node->data.container_init_expr.kind;14847 const uint32_t field_count = actual_type->data.structure.src_field_count;
14839 uint32_t field_count = actual_type->data.structure.src_field_count;14848
14840 if (wanted_type->id == ZigTypeIdArray && (init_kind == ContainerInitKindArray || field_count == 0) &&14849 if (wanted_type->id == ZigTypeIdArray && (is_array_init || field_count == 0) &&
14841 wanted_type->data.array.len == field_count)14850 wanted_type->data.array.len == field_count)
14842 {14851 {
14843 return ir_analyze_struct_literal_to_array(ira, source_instr, value, wanted_type);14852 return ir_analyze_struct_literal_to_array(ira, source_instr, value, wanted_type);
14844 } else if (wanted_type->id == ZigTypeIdStruct &&14853 } else if (wanted_type->id == ZigTypeIdStruct &&
14845 (init_kind == ContainerInitKindStruct || field_count == 0))14854 (!is_array_init || field_count == 0))
14846 {14855 {
14847 return ir_analyze_struct_literal_to_struct(ira, source_instr, value, wanted_type);14856 return ir_analyze_struct_literal_to_struct(ira, source_instr, value, wanted_type);
14848 } else if (wanted_type->id == ZigTypeIdUnion && init_kind == ContainerInitKindStruct && field_count == 1) {14857 } else if (wanted_type->id == ZigTypeIdUnion && !is_array_init && field_count == 1) {
14849 return ir_analyze_struct_literal_to_union(ira, source_instr, value, wanted_type);14858 return ir_analyze_struct_literal_to_union(ira, source_instr, value, wanted_type);
14850 }14859 }
14851 }14860 }
...@@ -17799,6 +17808,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport...@@ -17799,6 +17808,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
17799 }17808 }
17800 } break;17809 } break;
17801 case ZigTypeIdInt:17810 case ZigTypeIdInt:
17811 want_var_export = true;
17802 break;17812 break;
17803 case ZigTypeIdVoid:17813 case ZigTypeIdVoid:
17804 case ZigTypeIdBool:17814 case ZigTypeIdBool:
...@@ -20369,6 +20379,17 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {...@@ -20369,6 +20379,17 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
20369 ptr_type->data.pointer.allow_zero);20379 ptr_type->data.pointer.allow_zero);
20370}20380}
2037120381
20382static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) {
20383 assert(ptr_type->id == ZigTypeIdPointer);
20384 return get_pointer_to_type_extra(g,
20385 ptr_type->data.pointer.child_type,
20386 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
20387 ptr_type->data.pointer.ptr_len,
20388 ptr_type->data.pointer.explicit_alignment,
20389 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
20390 allow_zero);
20391}
20392
20372static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {20393static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
20373 Error err;20394 Error err;
20374 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;20395 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
...@@ -23148,12 +23169,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc...@@ -23148,12 +23169,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
23148 if (instr_is_comptime(target)) {23169 if (instr_is_comptime(target)) {
23149 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))23170 if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
23150 return ira->codegen->invalid_inst_gen;23171 return ira->codegen->invalid_inst_gen;
23151 if (target->value->type->data.enumeration.non_exhaustive) {23172 TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
23152 ir_add_error(ira, &instruction->base.base,23173 if (field == nullptr) {
23153 buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));23174 Buf *int_buf = buf_alloc();
23175 bigint_append_buf(int_buf, &target->value->data.x_bigint, 10);
23176
23177 ir_add_error(ira, &target->base,
23178 buf_sprintf("no tag by value %s", buf_ptr(int_buf)));
23154 return ira->codegen->invalid_inst_gen;23179 return ira->codegen->invalid_inst_gen;
23155 }23180 }
23156 TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
23157 ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;23181 ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
23158 IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);23182 IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
23159 init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field->name), true);23183 init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field->name), true);
...@@ -25920,6 +25944,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -25920,6 +25944,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
25920 ZigType *non_sentinel_slice_ptr_type;25944 ZigType *non_sentinel_slice_ptr_type;
25921 ZigType *elem_type;25945 ZigType *elem_type;
2592225946
25947 bool generate_non_null_assert = false;
25948
25923 if (array_type->id == ZigTypeIdArray) {25949 if (array_type->id == ZigTypeIdArray) {
25924 elem_type = array_type->data.array.child_type;25950 elem_type = array_type->data.array.child_type;
25925 bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic &&25951 bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic &&
...@@ -25947,6 +25973,14 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -25947,6 +25973,14 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
25947 elem_type = array_type->data.pointer.child_type;25973 elem_type = array_type->data.pointer.child_type;
25948 if (array_type->data.pointer.ptr_len == PtrLenC) {25974 if (array_type->data.pointer.ptr_len == PtrLenC) {
25949 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);25975 array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
25976
25977 // C pointers are allowzero by default.
25978 // However, we want to be able to slice them without generating an allowzero slice (see issue #4401).
25979 // To achieve this, we generate a runtime safety check and make the slice type non-allowzero.
25980 if (array_type->data.pointer.allow_zero) {
25981 array_type = adjust_ptr_allow_zero(ira->codegen, array_type, false);
25982 generate_non_null_assert = true;
25983 }
25950 }25984 }
25951 ZigType *maybe_sentineled_slice_ptr_type = array_type;25985 ZigType *maybe_sentineled_slice_ptr_type = array_type;
25952 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);25986 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);
...@@ -26218,7 +26252,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26218,7 +26252,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
2621826252
26219 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,26253 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26220 return_type, nullptr, true, true);26254 return_type, nullptr, true, true);
26221
26222 if (result_loc != nullptr) {26255 if (result_loc != nullptr) {
26223 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {26256 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26224 return result_loc;26257 return result_loc;
...@@ -26231,8 +26264,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26231,8 +26264,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26231 return ira->codegen->invalid_inst_gen;26264 return ira->codegen->invalid_inst_gen;
26232 }26265 }
2623326266
26234 return ir_build_slice_gen(ira, &instruction->base.base, return_type,26267 if (generate_non_null_assert) {
26235 ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc);26268 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
26269
26270 if (type_is_invalid(ptr_val->value->type))
26271 return ira->codegen->invalid_inst_gen;
26272
26273 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
26274 }
26275
26276 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
26277 casted_start, end, instruction->safety_check_on, result_loc);
26236}26278}
2623726279
26238static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {26280static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {
...@@ -27818,9 +27860,15 @@ static IrInstGen *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInst* source_instr, Ir...@@ -27818,9 +27860,15 @@ static IrInstGen *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInst* source_instr, Ir
27818 }27860 }
2781927861
27820 IrInstGen *result = ir_const(ira, source_instr, ptr_type);27862 IrInstGen *result = ir_const(ira, source_instr, ptr_type);
27821 result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;27863 if (ptr_type->id == ZigTypeIdOptional && addr == 0) {
27822 result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar;27864 result->value->data.x_ptr.special = ConstPtrSpecialNull;
27823 result->value->data.x_ptr.data.hard_coded_addr.addr = addr;27865 result->value->data.x_ptr.mut = ConstPtrMutComptimeConst;
27866 } else {
27867 result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
27868 result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar;
27869 result->value->data.x_ptr.data.hard_coded_addr.addr = addr;
27870 }
27871
27824 return result;27872 return result;
27825 }27873 }
2782627874
...@@ -27878,15 +27926,15 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr...@@ -27878,15 +27926,15 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr
2787827926
27879 ZigType *usize = ira->codegen->builtin_types.entry_usize;27927 ZigType *usize = ira->codegen->builtin_types.entry_usize;
2788027928
27881 // We check size explicitly so we can use get_src_ptr_type here.27929 ZigType *src_ptr_type = get_src_ptr_type(target->value->type);
27882 if (get_src_ptr_type(target->value->type) == nullptr) {27930 if (src_ptr_type == nullptr) {
27883 ir_add_error(ira, &target->base,27931 ir_add_error(ira, &target->base,
27884 buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value->type->name)));27932 buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value->type->name)));
27885 return ira->codegen->invalid_inst_gen;27933 return ira->codegen->invalid_inst_gen;
27886 }27934 }
2788727935
27888 bool has_bits;27936 bool has_bits;
27889 if ((err = type_has_bits2(ira->codegen, target->value->type, &has_bits)))27937 if ((err = type_has_bits2(ira->codegen, src_ptr_type, &has_bits)))
27890 return ira->codegen->invalid_inst_gen;27938 return ira->codegen->invalid_inst_gen;
2789127939
27892 if (!has_bits) {27940 if (!has_bits) {
...@@ -27899,11 +27947,19 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr...@@ -27899,11 +27947,19 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr
27899 ZigValue *val = ir_resolve_const(ira, target, UndefBad);27947 ZigValue *val = ir_resolve_const(ira, target, UndefBad);
27900 if (!val)27948 if (!val)
27901 return ira->codegen->invalid_inst_gen;27949 return ira->codegen->invalid_inst_gen;
27902 if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {27950
27951 // Since we've already run this type trough get_codegen_ptr_type it is
27952 // safe to access the x_ptr fields
27953 if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
27903 IrInstGen *result = ir_const(ira, &instruction->base.base, usize);27954 IrInstGen *result = ir_const(ira, &instruction->base.base, usize);
27904 bigint_init_unsigned(&result->value->data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);27955 bigint_init_unsigned(&result->value->data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
27905 result->value->type = usize;27956 result->value->type = usize;
27906 return result;27957 return result;
27958 } else if (val->data.x_ptr.special == ConstPtrSpecialNull) {
27959 IrInstGen *result = ir_const(ira, &instruction->base.base, usize);
27960 bigint_init_unsigned(&result->value->data.x_bigint, 0);
27961 result->value->type = usize;
27962 return result;
27907 }27963 }
27908 }27964 }
2790927965
src/link.cpp+19-112
...@@ -1751,9 +1751,9 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1751,9 +1751,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
1751 }1751 }
17521752
1753 if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {1753 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);
1755 lj->args.append("-dynamic-linker");1755 lj->args.append("-dynamic-linker");
1756 lj->args.append(buf_ptr(g->dynamic_linker_path));1756 lj->args.append(g->zig_target->dynamic_linker);
1757 }1757 }
1758 }1758 }
17591759
...@@ -2376,99 +2376,6 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -2376,99 +2376,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
2376 }2376 }
2377}2377}
23782378
2379
2380// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
2381// grouped values as integers. Numbers which are not provided are set to 0.
2382// return true if the entire string was parsed (9.2), or all groups were
2383// parsed (10.3.5extrastuff).
2384static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
2385 *had_extra = false;
2386
2387 *major = 0;
2388 *minor = 0;
2389 *micro = 0;
2390
2391 if (*str == '\0')
2392 return false;
2393
2394 char *end;
2395 *major = (int)strtol(str, &end, 10);
2396 if (*str != '\0' && *end == '\0')
2397 return true;
2398 if (*end != '.')
2399 return false;
2400
2401 str = end + 1;
2402 *minor = (int)strtol(str, &end, 10);
2403 if (*str != '\0' && *end == '\0')
2404 return true;
2405 if (*end != '.')
2406 return false;
2407
2408 str = end + 1;
2409 *micro = (int)strtol(str, &end, 10);
2410 if (*str != '\0' && *end == '\0')
2411 return true;
2412 if (str == end)
2413 return false;
2414 *had_extra = true;
2415 return true;
2416}
2417
2418enum DarwinPlatformKind {
2419 MacOS,
2420 IPhoneOS,
2421 IPhoneOSSimulator,
2422};
2423
2424struct DarwinPlatform {
2425 DarwinPlatformKind kind;
2426 int major;
2427 int minor;
2428 int micro;
2429};
2430
2431static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
2432 CodeGen *g = lj->codegen;
2433
2434 if (g->mmacosx_version_min) {
2435 platform->kind = MacOS;
2436 } else if (g->mios_version_min) {
2437 platform->kind = IPhoneOS;
2438 } else if (g->zig_target->os == OsMacOSX) {
2439 platform->kind = MacOS;
2440 g->mmacosx_version_min = buf_create_from_str("10.14");
2441 } else {
2442 zig_panic("unable to infer -mmacosx-version-min or -mios-version-min");
2443 }
2444
2445 bool had_extra;
2446 if (platform->kind == MacOS) {
2447 if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
2448 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
2449 had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
2450 {
2451 zig_panic("invalid -mmacosx-version-min");
2452 }
2453 } else if (platform->kind == IPhoneOS) {
2454 if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
2455 &platform->major, &platform->minor, &platform->micro, &had_extra) ||
2456 had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
2457 {
2458 zig_panic("invalid -mios-version-min");
2459 }
2460 } else {
2461 zig_unreachable();
2462 }
2463
2464 if (platform->kind == IPhoneOS &&
2465 (g->zig_target->arch == ZigLLVM_x86 ||
2466 g->zig_target->arch == ZigLLVM_x86_64))
2467 {
2468 platform->kind = IPhoneOSSimulator;
2469 }
2470}
2471
2472static void construct_linker_job_macho(LinkJob *lj) {2379static void construct_linker_job_macho(LinkJob *lj) {
2473 CodeGen *g = lj->codegen;2380 CodeGen *g = lj->codegen;
24742381
...@@ -2512,25 +2419,25 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -2512,25 +2419,25 @@ static void construct_linker_job_macho(LinkJob *lj) {
2512 lj->args.append("-arch");2419 lj->args.append("-arch");
2513 lj->args.append(get_darwin_arch_string(g->zig_target));2420 lj->args.append(get_darwin_arch_string(g->zig_target));
25142421
2515 DarwinPlatform platform;2422 if (g->zig_target->glibc_or_darwin_version != nullptr) {
2516 get_darwin_platform(lj, &platform);2423 if (g->zig_target->os == OsMacOSX) {
2517 switch (platform.kind) {
2518 case MacOS:
2519 lj->args.append("-macosx_version_min");2424 lj->args.append("-macosx_version_min");
2520 break;2425 } else if (g->zig_target->os == OsIOS) {
2521 case IPhoneOS:2426 if (g->zig_target->arch == ZigLLVM_x86 || g->zig_target->arch == ZigLLVM_x86_64) {
2522 lj->args.append("-iphoneos_version_min");2427 lj->args.append("-ios_simulator_version_min");
2523 break;2428 } else {
2524 case IPhoneOSSimulator:2429 lj->args.append("-iphoneos_version_min");
2525 lj->args.append("-ios_simulator_version_min");2430 }
2526 break;2431 }
2527 }2432 Buf *version_string = buf_sprintf("%d.%d.%d",
2528 Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);2433 g->zig_target->glibc_or_darwin_version->major,
2529 lj->args.append(buf_ptr(version_string));2434 g->zig_target->glibc_or_darwin_version->minor,
25302435 g->zig_target->glibc_or_darwin_version->patch);
2531 lj->args.append("-sdk_version");2436 lj->args.append(buf_ptr(version_string));
2532 lj->args.append(buf_ptr(version_string));
25332437
2438 lj->args.append("-sdk_version");
2439 lj->args.append(buf_ptr(version_string));
2440 }
25342441
2535 if (g->out_type == OutTypeExe) {2442 if (g->out_type == OutTypeExe) {
2536 lj->args.append("-pie");2443 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) {...@@ -89,8 +89,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
89 " --single-threaded source may assume it is only used single-threaded\n"89 " --single-threaded source may assume it is only used single-threaded\n"
90 " -dynamic create a shared library (.so; .dll; .dylib)\n"90 " -dynamic create a shared library (.so; .dll; .dylib)\n"
91 " --strip exclude debug symbols\n"91 " --strip exclude debug symbols\n"
92 " -target [name] <arch><sub>-<os>-<abi> see the targets command\n"92 " -target [name] <arch>-<os>-<abi> see the targets command\n"
93 " -target-glibc [version] target a specific glibc version (default: 2.17)\n"
94 " --verbose-tokenize enable compiler debug output for tokenization\n"93 " --verbose-tokenize enable compiler debug output for tokenization\n"
95 " --verbose-ast enable compiler debug output for AST parsing\n"94 " --verbose-ast enable compiler debug output for AST parsing\n"
96 " --verbose-link enable compiler debug output for linking\n"95 " --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) {...@@ -128,8 +127,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
128 " --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"127 " --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
129 " -F[dir] (darwin) add search path for frameworks\n"128 " -F[dir] (darwin) add search path for frameworks\n"
130 " -framework [name] (darwin) link against framework\n"129 " -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"
133 " --ver-major [ver] dynamic library semver major version\n"130 " --ver-major [ver] dynamic library semver major version\n"
134 " --ver-minor [ver] dynamic library semver minor version\n"131 " --ver-minor [ver] dynamic library semver minor version\n"
135 " --ver-patch [ver] dynamic library semver patch version\n"132 " --ver-patch [ver] dynamic library semver patch version\n"
...@@ -405,7 +402,7 @@ static int main0(int argc, char **argv) {...@@ -405,7 +402,7 @@ static int main0(int argc, char **argv) {
405 bool link_eh_frame_hdr = false;402 bool link_eh_frame_hdr = false;
406 ErrColor color = ErrColorAuto;403 ErrColor color = ErrColorAuto;
407 CacheOpt enable_cache = CacheOptAuto;404 CacheOpt enable_cache = CacheOptAuto;
408 Buf *dynamic_linker = nullptr;405 const char *dynamic_linker = nullptr;
409 const char *libc_txt = nullptr;406 const char *libc_txt = nullptr;
410 ZigList<const char *> clang_argv = {0};407 ZigList<const char *> clang_argv = {0};
411 ZigList<const char *> lib_dirs = {0};408 ZigList<const char *> lib_dirs = {0};
...@@ -416,11 +413,8 @@ static int main0(int argc, char **argv) {...@@ -416,11 +413,8 @@ static int main0(int argc, char **argv) {
416 bool have_libc = false;413 bool have_libc = false;
417 const char *target_string = nullptr;414 const char *target_string = nullptr;
418 bool rdynamic = false;415 bool rdynamic = false;
419 const char *mmacosx_version_min = nullptr;
420 const char *mios_version_min = nullptr;
421 const char *linker_script = nullptr;416 const char *linker_script = nullptr;
422 Buf *version_script = nullptr;417 Buf *version_script = nullptr;
423 const char *target_glibc = nullptr;
424 ZigList<const char *> rpath_list = {0};418 ZigList<const char *> rpath_list = {0};
425 bool each_lib_rpath = false;419 bool each_lib_rpath = false;
426 ZigList<const char *> objects = {0};420 ZigList<const char *> objects = {0};
...@@ -503,7 +497,10 @@ static int main0(int argc, char **argv) {...@@ -503,7 +497,10 @@ static int main0(int argc, char **argv) {
503 os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("build_runner.zig"), build_runner_path);497 os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("build_runner.zig"), build_runner_path);
504498
505 ZigTarget target;499 ZigTarget target;
506 get_native_target(&target);500 if ((err = target_parse_triple(&target, "native", nullptr, nullptr))) {
501 fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
502 return EXIT_FAILURE;
503 }
507504
508 Buf *build_file_buf = buf_create_from_str((build_file != nullptr) ? build_file : "build.zig");505 Buf *build_file_buf = buf_create_from_str((build_file != nullptr) ? build_file : "build.zig");
509 Buf build_file_abs = os_path_resolve(&build_file_buf, 1);506 Buf build_file_abs = os_path_resolve(&build_file_buf, 1);
...@@ -770,7 +767,7 @@ static int main0(int argc, char **argv) {...@@ -770,7 +767,7 @@ static int main0(int argc, char **argv) {
770 } else if (strcmp(arg, "--name") == 0) {767 } else if (strcmp(arg, "--name") == 0) {
771 out_name = argv[i];768 out_name = argv[i];
772 } else if (strcmp(arg, "--dynamic-linker") == 0) {769 } else if (strcmp(arg, "--dynamic-linker") == 0) {
773 dynamic_linker = buf_create_from_str(argv[i]);770 dynamic_linker = argv[i];
774 } else if (strcmp(arg, "--libc") == 0) {771 } else if (strcmp(arg, "--libc") == 0) {
775 libc_txt = argv[i];772 libc_txt = argv[i];
776 } else if (strcmp(arg, "-D") == 0) {773 } else if (strcmp(arg, "-D") == 0) {
...@@ -844,18 +841,12 @@ static int main0(int argc, char **argv) {...@@ -844,18 +841,12 @@ static int main0(int argc, char **argv) {
844 cache_dir = argv[i];841 cache_dir = argv[i];
845 } else if (strcmp(arg, "-target") == 0) {842 } else if (strcmp(arg, "-target") == 0) {
846 target_string = argv[i];843 target_string = argv[i];
847 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
848 mmacosx_version_min = argv[i];
849 } else if (strcmp(arg, "-mios-version-min") == 0) {
850 mios_version_min = argv[i];
851 } else if (strcmp(arg, "-framework") == 0) {844 } else if (strcmp(arg, "-framework") == 0) {
852 frameworks.append(argv[i]);845 frameworks.append(argv[i]);
853 } else if (strcmp(arg, "--linker-script") == 0) {846 } else if (strcmp(arg, "--linker-script") == 0) {
854 linker_script = argv[i];847 linker_script = argv[i];
855 } else if (strcmp(arg, "--version-script") == 0) {848 } else if (strcmp(arg, "--version-script") == 0) {
856 version_script = buf_create_from_str(argv[i]); 849 version_script = buf_create_from_str(argv[i]);
857 } else if (strcmp(arg, "-target-glibc") == 0) {
858 target_glibc = argv[i];
859 } else if (strcmp(arg, "-rpath") == 0) {850 } else if (strcmp(arg, "-rpath") == 0) {
860 rpath_list.append(argv[i]);851 rpath_list.append(argv[i]);
861 } else if (strcmp(arg, "--test-filter") == 0) {852 } else if (strcmp(arg, "--test-filter") == 0) {
...@@ -978,34 +969,11 @@ static int main0(int argc, char **argv) {...@@ -978,34 +969,11 @@ static int main0(int argc, char **argv) {
978 init_all_targets();969 init_all_targets();
979970
980 ZigTarget target;971 ZigTarget target;
981 if ((err = target_parse_triple(&target, target_string, mcpu))) {972 if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) {
982 fprintf(stderr, "invalid target: %s\n"973 fprintf(stderr, "invalid target: %s\n"
983 "See `%s targets` to display valid targets.\n", err_str(err), arg0);974 "See `%s targets` to display valid targets.\n", err_str(err), arg0);
984 return print_error_usage(arg0);975 return print_error_usage(arg0);
985 }976 }
986 if (target_is_glibc(&target)) {
987 target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>();
988
989 if (target_glibc != nullptr) {
990 if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) {
991 fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err));
992 return print_error_usage(arg0);
993 }
994 } else {
995 target_init_default_glibc_version(&target);
996#if defined(ZIG_OS_LINUX)
997 if (target.is_native) {
998 // TODO self-host glibc version detection, and then this logic can go away
999 if ((err = glibc_detect_native_version(target.glibc_version))) {
1000 // Fall back to the default version.
1001 }
1002 }
1003#endif
1004 }
1005 } else if (target_glibc != nullptr) {
1006 fprintf(stderr, "'%s' is not a glibc-compatible target", target_string);
1007 return print_error_usage(arg0);
1008 }
1009977
1010 Buf zig_triple_buf = BUF_INIT;978 Buf zig_triple_buf = BUF_INIT;
1011 target_triple_zig(&zig_triple_buf, &target);979 target_triple_zig(&zig_triple_buf, &target);
...@@ -1226,7 +1194,6 @@ static int main0(int argc, char **argv) {...@@ -1226,7 +1194,6 @@ static int main0(int argc, char **argv) {
12261194
1227 codegen_set_strip(g, strip);1195 codegen_set_strip(g, strip);
1228 g->is_dynamic = is_dynamic;1196 g->is_dynamic = is_dynamic;
1229 g->dynamic_linker_path = dynamic_linker;
1230 g->verbose_tokenize = verbose_tokenize;1197 g->verbose_tokenize = verbose_tokenize;
1231 g->verbose_ast = verbose_ast;1198 g->verbose_ast = verbose_ast;
1232 g->verbose_link = verbose_link;1199 g->verbose_link = verbose_link;
...@@ -1265,18 +1232,6 @@ static int main0(int argc, char **argv) {...@@ -1265,18 +1232,6 @@ static int main0(int argc, char **argv) {
1265 }1232 }
12661233
1267 codegen_set_rdynamic(g, rdynamic);1234 codegen_set_rdynamic(g, rdynamic);
1268 if (mmacosx_version_min && mios_version_min) {
1269 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
1270 return main_exit(root_progress_node, EXIT_FAILURE);
1271 }
1272
1273 if (mmacosx_version_min) {
1274 codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
1275 }
1276
1277 if (mios_version_min) {
1278 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
1279 }
12801235
1281 if (test_filter) {1236 if (test_filter) {
1282 codegen_set_test_filter(g, buf_create_from_str(test_filter));1237 codegen_set_test_filter(g, buf_create_from_str(test_filter));
...@@ -1365,7 +1320,10 @@ static int main0(int argc, char **argv) {...@@ -1365,7 +1320,10 @@ static int main0(int argc, char **argv) {
1365 return main_exit(root_progress_node, EXIT_SUCCESS);1320 return main_exit(root_progress_node, EXIT_SUCCESS);
1366 } else if (cmd == CmdTest) {1321 } else if (cmd == CmdTest) {
1367 ZigTarget native;1322 ZigTarget native;
1368 get_native_target(&native);1323 if ((err = target_parse_triple(&native, "native", nullptr, nullptr))) {
1324 fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
1325 return EXIT_FAILURE;
1326 }
13691327
1370 g->enable_cache = get_cache_opt(enable_cache, output_dir == nullptr);1328 g->enable_cache = get_cache_opt(enable_cache, output_dir == nullptr);
1371 codegen_build_and_link(g);1329 codegen_build_and_link(g);
src/os.cpp+2-2
...@@ -1073,8 +1073,8 @@ static Error set_file_times(OsFile file, OsTimeStamp ts) {...@@ -1073,8 +1073,8 @@ static Error set_file_times(OsFile file, OsTimeStamp ts) {
1073 return ErrorNone;1073 return ErrorNone;
1074#else1074#else
1075 struct timespec times[2] = {1075 struct timespec times[2] = {
1076 { ts.sec, ts.nsec },1076 { (time_t)ts.sec, (time_t)ts.nsec },
1077 { ts.sec, ts.nsec },1077 { (time_t)ts.sec, (time_t)ts.nsec },
1078 };1078 };
1079 if (futimens(file, times) == -1) {1079 if (futimens(file, times) == -1) {
1080 switch (errno) {1080 switch (errno) {
src/stage2.cpp+106-9
...@@ -91,7 +91,109 @@ void stage2_progress_complete_one(Stage2ProgressNode *node) {}...@@ -91,7 +91,109 @@ void stage2_progress_complete_one(Stage2ProgressNode *node) {}
91void stage2_progress_disable_tty(Stage2Progress *progress) {}91void stage2_progress_disable_tty(Stage2Progress *progress) {}
92void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}92void 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{
95 Error err;197 Error err;
96198
97 if (zig_triple == nullptr) {199 if (zig_triple == nullptr) {
...@@ -100,13 +202,11 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons...@@ -100,13 +202,11 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
100 if (mcpu == nullptr) {202 if (mcpu == nullptr) {
101 target->llvm_cpu_name = ZigLLVMGetHostCPUName();203 target->llvm_cpu_name = ZigLLVMGetHostCPUName();
102 target->llvm_cpu_features = ZigLLVMGetNativeFeatures();204 target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
103 target->builtin_str = "Target.Cpu.baseline(arch);\n";
104 target->cache_hash = "native\n\n";205 target->cache_hash = "native\n\n";
105 } else if (strcmp(mcpu, "baseline") == 0) {206 } else if (strcmp(mcpu, "baseline") == 0) {
106 target->is_native = false;207 target->is_native = false;
107 target->llvm_cpu_name = "";208 target->llvm_cpu_name = "";
108 target->llvm_cpu_features = "";209 target->llvm_cpu_features = "";
109 target->builtin_str = "Target.Cpu.baseline(arch);\n";
110 target->cache_hash = "baseline\n\n";210 target->cache_hash = "baseline\n\n";
111 } else {211 } else {
112 const char *msg = "stage0 can't handle CPU/features in the target";212 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...@@ -148,10 +248,12 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
148 const char *msg = "stage0 can't handle CPU/features in the target";248 const char *msg = "stage0 can't handle CPU/features in the target";
149 stage2_panic(msg, strlen(msg));249 stage2_panic(msg, strlen(msg));
150 }250 }
151 target->builtin_str = "Target.Cpu.baseline(arch);\n";
152 target->cache_hash = "\n\n";251 target->cache_hash = "\n\n";
153 }252 }
154253
254 if (dynamic_linker != nullptr) {
255 target->dynamic_linker = dynamic_linker;
256 }
155 return ErrorNone;257 return ErrorNone;
156}258}
157259
...@@ -186,11 +288,6 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {...@@ -186,11 +288,6 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
186 stage2_panic(msg, strlen(msg));288 stage2_panic(msg, strlen(msg));
187}289}
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
194enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {291enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {
195 native_paths->include_dirs_ptr = nullptr;292 native_paths->include_dirs_ptr = nullptr;
196 native_paths->include_dirs_len = 0;293 native_paths->include_dirs_len = 0;
src/stage2.h+11-11
...@@ -103,6 +103,8 @@ enum Error {...@@ -103,6 +103,8 @@ enum Error {
103 ErrorWindowsSdkNotFound,103 ErrorWindowsSdkNotFound,
104 ErrorUnknownDynamicLinkerPath,104 ErrorUnknownDynamicLinkerPath,
105 ErrorTargetHasNoDynamicLinker,105 ErrorTargetHasNoDynamicLinker,
106 ErrorInvalidAbiVersion,
107 ErrorInvalidOperatingSystemVersion,
106};108};
107109
108// ABI warning110// ABI warning
...@@ -268,14 +270,12 @@ enum Os {...@@ -268,14 +270,12 @@ enum Os {
268};270};
269271
270// ABI warning272// ABI warning
271struct ZigGLibCVersion {273struct Stage2SemVer {
272 uint32_t major; // always 2274 uint32_t major;
273 uint32_t minor;275 uint32_t minor;
274 uint32_t patch;276 uint32_t patch;
275};277};
276278
277struct Stage2TargetData;
278
279// ABI warning279// ABI warning
280struct ZigTarget {280struct ZigTarget {
281 enum ZigLLVM_ArchType arch;281 enum ZigLLVM_ArchType arch;
...@@ -286,20 +286,20 @@ struct ZigTarget {...@@ -286,20 +286,20 @@ struct ZigTarget {
286286
287 bool is_native;287 bool is_native;
288288
289 struct ZigGLibCVersion *glibc_version; // null means default289 // null means default. this is double-purposed to be darwin min version
290 struct Stage2SemVer *glibc_or_darwin_version;
290291
291 const char *llvm_cpu_name;292 const char *llvm_cpu_name;
292 const char *llvm_cpu_features;293 const char *llvm_cpu_features;
293 const char *builtin_str;294 const char *cpu_builtin_str;
294 const char *cache_hash;295 const char *cache_hash;
296 const char *os_builtin_str;
297 const char *dynamic_linker;
295};298};
296299
297// ABI warning300// ABI warning
298ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,301ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
299 char **out_ptr, size_t *out_len);302 const char *dynamic_linker);
300
301// ABI warning
302ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu);
303303
304304
305// ABI warning305// ABI warning
src/target.cpp+4-104
...@@ -286,83 +286,6 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {...@@ -286,83 +286,6 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {
286 zig_unreachable();286 zig_unreachable();
287}287}
288288
289static Os get_zig_os_type(ZigLLVM_OSType os_type) {
290 switch (os_type) {
291 case ZigLLVM_UnknownOS:
292 return OsFreestanding;
293 case ZigLLVM_Ananas:
294 return OsAnanas;
295 case ZigLLVM_CloudABI:
296 return OsCloudABI;
297 case ZigLLVM_DragonFly:
298 return OsDragonFly;
299 case ZigLLVM_FreeBSD:
300 return OsFreeBSD;
301 case ZigLLVM_Fuchsia:
302 return OsFuchsia;
303 case ZigLLVM_IOS:
304 return OsIOS;
305 case ZigLLVM_KFreeBSD:
306 return OsKFreeBSD;
307 case ZigLLVM_Linux:
308 return OsLinux;
309 case ZigLLVM_Lv2:
310 return OsLv2;
311 case ZigLLVM_Darwin:
312 case ZigLLVM_MacOSX:
313 return OsMacOSX;
314 case ZigLLVM_NetBSD:
315 return OsNetBSD;
316 case ZigLLVM_OpenBSD:
317 return OsOpenBSD;
318 case ZigLLVM_Solaris:
319 return OsSolaris;
320 case ZigLLVM_Win32:
321 return OsWindows;
322 case ZigLLVM_Haiku:
323 return OsHaiku;
324 case ZigLLVM_Minix:
325 return OsMinix;
326 case ZigLLVM_RTEMS:
327 return OsRTEMS;
328 case ZigLLVM_NaCl:
329 return OsNaCl;
330 case ZigLLVM_CNK:
331 return OsCNK;
332 case ZigLLVM_AIX:
333 return OsAIX;
334 case ZigLLVM_CUDA:
335 return OsCUDA;
336 case ZigLLVM_NVCL:
337 return OsNVCL;
338 case ZigLLVM_AMDHSA:
339 return OsAMDHSA;
340 case ZigLLVM_PS4:
341 return OsPS4;
342 case ZigLLVM_ELFIAMCU:
343 return OsELFIAMCU;
344 case ZigLLVM_TvOS:
345 return OsTvOS;
346 case ZigLLVM_WatchOS:
347 return OsWatchOS;
348 case ZigLLVM_Mesa3D:
349 return OsMesa3D;
350 case ZigLLVM_Contiki:
351 return OsContiki;
352 case ZigLLVM_AMDPAL:
353 return OsAMDPAL;
354 case ZigLLVM_HermitCore:
355 return OsHermitCore;
356 case ZigLLVM_Hurd:
357 return OsHurd;
358 case ZigLLVM_WASI:
359 return OsWASI;
360 case ZigLLVM_Emscripten:
361 return OsEmscripten;
362 }
363 zig_unreachable();
364}
365
366const char *target_os_name(Os os_type) {289const char *target_os_name(Os os_type) {
367 switch (os_type) {290 switch (os_type) {
368 case OsFreestanding:291 case OsFreestanding:
...@@ -423,7 +346,7 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) {...@@ -423,7 +346,7 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) {
423 return ZigLLVMGetEnvironmentTypeName(abi);346 return ZigLLVMGetEnvironmentTypeName(abi);
424}347}
425348
426Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {349Error target_parse_glibc_version(Stage2SemVer *glibc_ver, const char *text) {
427 glibc_ver->major = 2;350 glibc_ver->major = 2;
428 glibc_ver->minor = 0;351 glibc_ver->minor = 0;
429 glibc_ver->patch = 0;352 glibc_ver->patch = 0;
...@@ -446,31 +369,8 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {...@@ -446,31 +369,8 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
446 return ErrorNone;369 return ErrorNone;
447}370}
448371
449void get_native_target(ZigTarget *target) {
450 // first zero initialize
451 *target = {};
452
453 ZigLLVM_OSType os_type;
454 ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
455 ZigLLVMGetNativeTarget(
456 &target->arch,
457 &target->vendor,
458 &os_type,
459 &target->abi,
460 &oformat);
461 target->os = get_zig_os_type(os_type);
462 target->is_native = true;
463 if (target->abi == ZigLLVM_UnknownEnvironment) {
464 target->abi = target_default_abi(target->arch, target->os);
465 }
466 if (target_is_glibc(target)) {
467 target->glibc_version = heap::c_allocator.create<ZigGLibCVersion>();
468 target_init_default_glibc_version(target);
469 }
470}
471
472void target_init_default_glibc_version(ZigTarget *target) {372void target_init_default_glibc_version(ZigTarget *target) {
473 *target->glibc_version = {2, 17, 0};373 *target->glibc_or_darwin_version = {2, 17, 0};
474}374}
475375
476Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) {376Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) {
...@@ -509,8 +409,8 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si...@@ -509,8 +409,8 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
509 return ErrorUnknownABI;409 return ErrorUnknownABI;
510}410}
511411
512Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu) {412Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker) {
513 return stage2_target_parse(target, triple, mcpu);413 return stage2_target_parse(target, triple, mcpu, dynamic_linker);
514}414}
515415
516const char *target_arch_name(ZigLLVM_ArchType arch) {416const char *target_arch_name(ZigLLVM_ArchType arch) {
src/target.hpp+2-3
...@@ -41,12 +41,12 @@ enum CIntType {...@@ -41,12 +41,12 @@ enum CIntType {
41 CIntTypeCount,41 CIntTypeCount,
42};42};
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);
45Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);45Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);
46Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);46Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
47Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);47Error 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);
50void target_init_default_glibc_version(ZigTarget *target);50void target_init_default_glibc_version(ZigTarget *target);
5151
52size_t target_arch_count(void);52size_t target_arch_count(void);
...@@ -73,7 +73,6 @@ ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);...@@ -73,7 +73,6 @@ ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
73const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);73const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
74ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);74ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
7575
76void get_native_target(ZigTarget *target);
77void target_triple_llvm(Buf *triple, const ZigTarget *target);76void target_triple_llvm(Buf *triple, const ZigTarget *target);
78void target_triple_zig(Buf *triple, const ZigTarget *target);77void target_triple_zig(Buf *triple, const ZigTarget *target);
7978
test/assemble_and_link.zig+2-2
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1const builtin = @import("builtin");1const std = @import("std");
2const tests = @import("tests.zig");2const tests = @import("tests.zig");
33
4pub fn addCases(cases: *tests.CompareOutputContext) void {4pub 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) {
6 cases.addAsm("hello world linux x86_64",6 cases.addAsm("hello world linux x86_64",
7 \\.text7 \\.text
8 \\.globl _start8 \\.globl _start
test/cli.zig+2-3
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
3const testing = std.testing;2const testing = std.testing;
4const process = std.process;3const process = std.process;
5const fs = std.fs;4const fs = std.fs;
...@@ -93,11 +92,11 @@ fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void {...@@ -93,11 +92,11 @@ fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void {
93fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {92fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
94 _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" });93 _ = try exec(dir_path, &[_][]const u8{ zig_exe, "init-exe" });
95 const run_result = try exec(dir_path, &[_][]const u8{ zig_exe, "build", "run" });94 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"));
97}96}
9897
99fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {98fn 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
102 const example_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.zig" });101 const example_zig_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.zig" });
103 const example_s_path = try fs.path.join(a, &[_][]const u8{ dir_path, "example.s" });102 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 @@...@@ -1,4 +1,3 @@
1const builtin = @import("builtin");
2const std = @import("std");1const std = @import("std");
3const os = std.os;2const os = std.os;
4const tests = @import("tests.zig");3const tests = @import("tests.zig");
...@@ -131,8 +130,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -131,8 +130,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
131 , "Hello, world!\n 12 12 a\n");130 , "Hello, world!\n 12 12 a\n");
132131
133 cases.addC("number literals",132 cases.addC("number literals",
134 \\const builtin = @import("builtin");133 \\const std = @import("std");
135 \\const is_windows = builtin.os == builtin.Os.windows;134 \\const is_windows = std.Target.current.os.tag == .windows;
136 \\const c = @cImport({135 \\const c = @cImport({
137 \\ if (is_windows) {136 \\ if (is_windows) {
138 \\ // See https://github.com/ziglang/zig/issues/515137 \\ // See https://github.com/ziglang/zig/issues/515
...@@ -306,8 +305,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -306,8 +305,8 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
306 , "");305 , "");
307306
308 cases.addC("casting between float and integer types",307 cases.addC("casting between float and integer types",
309 \\const builtin = @import("builtin");308 \\const std = @import("std");
310 \\const is_windows = builtin.os == builtin.Os.windows;309 \\const is_windows = std.Target.current.os.tag == .windows;
311 \\const c = @cImport({310 \\const c = @cImport({
312 \\ if (is_windows) {311 \\ if (is_windows) {
313 \\ // See https://github.com/ziglang/zig/issues/515312 \\ // See https://github.com/ziglang/zig/issues/515
test/compile_errors.zig+37-25
...@@ -1,8 +1,34 @@...@@ -1,8 +1,34 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
2const builtin = @import("builtin");2const std = @import("std");
3const Target = @import("std").Target;
43
5pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("type mismatch with tuple concatenation",
6 \\export fn entry() void {
7 \\ var x = .{};
8 \\ x = x ++ .{ 1, 2, 3 };
9 \\}
10 , &[_][]const u8{
11 "tmp.zig:3:11: error: expected type 'struct:2:14', found 'struct:3:11'",
12 });
13
14 cases.addTest("@tagName on invalid value of non-exhaustive enum",
15 \\test "enum" {
16 \\ const E = enum(u8) {A, B, _};
17 \\ _ = @tagName(@intToEnum(E, 5));
18 \\}
19 , &[_][]const u8{
20 "tmp.zig:3:18: error: no tag by value 5",
21 });
22
23 cases.addTest("@ptrToInt with pointer to zero-sized type",
24 \\export fn entry() void {
25 \\ var pointer: ?*u0 = null;
26 \\ var x = @ptrToInt(pointer);
27 \\}
28 , &[_][]const u8{
29 "tmp.zig:3:23: error: pointer to size 0 type has no address",
30 });
31
6 cases.addTest("slice to pointer conversion mismatch",32 cases.addTest("slice to pointer conversion mismatch",
7 \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 {33 \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 {
8 \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1];34 \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1];
...@@ -360,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -360,12 +386,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
360 , &[_][]const u8{386 , &[_][]const u8{
361 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",387 "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack",
362 });388 });
363 tc.target = Target{389 tc.target = std.zig.CrossTarget{
364 .Cross = .{390 .cpu_arch = .wasm32,
365 .cpu = Target.Cpu.baseline(.wasm32),391 .os_tag = .wasi,
366 .os = .wasi,392 .abi = .none,
367 .abi = .none,
368 },
369 };393 };
370 break :x tc;394 break :x tc;
371 });395 });
...@@ -761,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -761,12 +785,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
761 , &[_][]const u8{785 , &[_][]const u8{
762 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",786 "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs",
763 });787 });
764 tc.target = Target{788 tc.target = std.zig.CrossTarget{
765 .Cross = .{789 .cpu_arch = .x86_64,
766 .cpu = Target.Cpu.baseline(.x86_64),790 .os_tag = .linux,
767 .os = .linux,791 .abi = .gnu,
768 .abi = .gnu,
769 },
770 };792 };
771 break :x tc;793 break :x tc;
772 });794 });
...@@ -1426,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1426,7 +1448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1426 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",1448 "tmp.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
1427 });1449 });
14281450
1429 if (builtin.os == builtin.Os.linux) {1451 if (std.Target.current.os.tag == .linux) {
1430 cases.addTest("implicit dependency on libc",1452 cases.addTest("implicit dependency on libc",
1431 \\extern "c" fn exit(u8) void;1453 \\extern "c" fn exit(u8) void;
1432 \\export fn entry() void {1454 \\export fn entry() void {
...@@ -2716,16 +2738,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2716,16 +2738,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2716 "tmp.zig:5:5: error: else prong required when switching on type 'anyerror'",2738 "tmp.zig:5:5: error: else prong required when switching on type 'anyerror'",
2717 });2739 });
27182740
2719 cases.add("inferred error set with no returned error",
2720 \\export fn entry() void {
2721 \\ foo() catch unreachable;
2722 \\}
2723 \\fn foo() !void {
2724 \\}
2725 , &[_][]const u8{
2726 "tmp.zig:4:11: error: function with inferred error set must return at least one possible error",
2727 });
2728
2729 cases.add("error not handled in switch",2741 cases.add("error not handled in switch",
2730 \\export fn entry() void {2742 \\export fn entry() void {
2731 \\ foo(452) catch |err| switch (err) {2743 \\ foo(452) catch |err| switch (err) {
test/runtime_safety.zig+13
...@@ -745,4 +745,17 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -745,4 +745,17 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
745 \\ (await p) catch unreachable;745 \\ (await p) catch unreachable;
746 \\}746 \\}
747 );747 );
748
749 // Slicing a C pointer returns a non-allowzero slice, thus we need to emit
750 // a safety check to ensure the pointer is not null.
751 cases.addRuntimeSafety("slicing null C pointer",
752 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
753 \\ @import("std").os.exit(126);
754 \\}
755 \\
756 \\pub fn main() void {
757 \\ var ptr: [*c]const u32 = null;
758 \\ var slice = ptr[0..3];
759 \\}
760 );
748}761}
test/src/translate_c.zig+3-2
...@@ -7,6 +7,7 @@ const fmt = std.fmt;...@@ -7,6 +7,7 @@ const fmt = std.fmt;
7const mem = std.mem;7const mem = std.mem;
8const fs = std.fs;8const fs = std.fs;
9const warn = std.debug.warn;9const warn = std.debug.warn;
10const CrossTarget = std.zig.CrossTarget;
1011
11pub const TranslateCContext = struct {12pub const TranslateCContext = struct {
12 b: *build.Builder,13 b: *build.Builder,
...@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {...@@ -19,7 +20,7 @@ pub const TranslateCContext = struct {
19 sources: ArrayList(SourceFile),20 sources: ArrayList(SourceFile),
20 expected_lines: ArrayList([]const u8),21 expected_lines: ArrayList([]const u8),
21 allow_warnings: bool,22 allow_warnings: bool,
22 target: std.Target = .Native,23 target: CrossTarget = CrossTarget{},
2324
24 const SourceFile = struct {25 const SourceFile = struct {
25 filename: []const u8,26 filename: []const u8,
...@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {...@@ -75,7 +76,7 @@ pub const TranslateCContext = struct {
75 pub fn addWithTarget(76 pub fn addWithTarget(
76 self: *TranslateCContext,77 self: *TranslateCContext,
77 name: []const u8,78 name: []const u8,
78 target: std.Target,79 target: CrossTarget,
79 source: []const u8,80 source: []const u8,
80 expected_lines: []const []const u8,81 expected_lines: []const []const u8,
81 ) void {82 ) void {
test/stack_traces.zig+26-26
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1const builtin = @import("builtin");
2const std = @import("std");1const std = @import("std");
3const os = std.os;2const os = std.os;
4const tests = @import("tests.zig");3const tests = @import("tests.zig");
54
5// zig fmt: off
6pub fn addCases(cases: *tests.StackTracesContext) void {6pub fn addCases(cases: *tests.StackTracesContext) void {
7 const source_return =7 const source_return =
8 \\const std = @import("std");8 \\const std = @import("std");
...@@ -41,6 +41,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -41,6 +41,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
41 \\ try foo();41 \\ try foo();
42 \\}42 \\}
43 ;43 ;
44
44 const source_dumpCurrentStackTrace =45 const source_dumpCurrentStackTrace =
45 \\const std = @import("std");46 \\const std = @import("std");
46 \\47 \\
...@@ -56,8 +57,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -56,8 +57,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
56 \\}57 \\}
57 ;58 ;
5859
59 // zig fmt: off60 switch (std.Target.current.os.tag) {
60 switch (builtin.os) {
61 .freebsd => {61 .freebsd => {
62 cases.addCase(62 cases.addCase(
63 "return",63 "return",
...@@ -310,15 +310,15 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -310,15 +310,15 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
310 source_return,310 source_return,
311 [_][]const u8{311 [_][]const u8{
312 // debug312 // debug
313 \\error: TheSkyIsFalling313 \\error: TheSkyIsFalling
314 \\source.zig:4:5: [address] in _main.0 (test.o)314 \\source.zig:4:5: [address] in main (test)
315 \\ return error.TheSkyIsFalling;315 \\ return error.TheSkyIsFalling;
316 \\ ^316 \\ ^
317 \\317 \\
318 ,318 ,
319 // release-safe319 // release-safe
320 \\error: TheSkyIsFalling320 \\error: TheSkyIsFalling
321 \\source.zig:4:5: [address] in _main (test.o)321 \\source.zig:4:5: [address] in std.start.main (test)
322 \\ return error.TheSkyIsFalling;322 \\ return error.TheSkyIsFalling;
323 \\ ^323 \\ ^
324 \\324 \\
...@@ -337,21 +337,21 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -337,21 +337,21 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
337 source_try_return,337 source_try_return,
338 [_][]const u8{338 [_][]const u8{
339 // debug339 // debug
340 \\error: TheSkyIsFalling340 \\error: TheSkyIsFalling
341 \\source.zig:4:5: [address] in _foo (test.o)341 \\source.zig:4:5: [address] in foo (test)
342 \\ return error.TheSkyIsFalling;342 \\ return error.TheSkyIsFalling;
343 \\ ^343 \\ ^
344 \\source.zig:8:5: [address] in _main.0 (test.o)344 \\source.zig:8:5: [address] in main (test)
345 \\ try foo();345 \\ try foo();
346 \\ ^346 \\ ^
347 \\347 \\
348 ,348 ,
349 // release-safe349 // release-safe
350 \\error: TheSkyIsFalling350 \\error: TheSkyIsFalling
351 \\source.zig:4:5: [address] in _main (test.o)351 \\source.zig:4:5: [address] in std.start.main (test)
352 \\ return error.TheSkyIsFalling;352 \\ return error.TheSkyIsFalling;
353 \\ ^353 \\ ^
354 \\source.zig:8:5: [address] in _main (test.o)354 \\source.zig:8:5: [address] in std.start.main (test)
355 \\ try foo();355 \\ try foo();
356 \\ ^356 \\ ^
357 \\357 \\
...@@ -370,33 +370,33 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -370,33 +370,33 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
370 source_try_try_return_return,370 source_try_try_return_return,
371 [_][]const u8{371 [_][]const u8{
372 // debug372 // debug
373 \\error: TheSkyIsFalling373 \\error: TheSkyIsFalling
374 \\source.zig:12:5: [address] in _make_error (test.o)374 \\source.zig:12:5: [address] in make_error (test)
375 \\ return error.TheSkyIsFalling;375 \\ return error.TheSkyIsFalling;
376 \\ ^376 \\ ^
377 \\source.zig:8:5: [address] in _bar (test.o)377 \\source.zig:8:5: [address] in bar (test)
378 \\ return make_error();378 \\ return make_error();
379 \\ ^379 \\ ^
380 \\source.zig:4:5: [address] in _foo (test.o)380 \\source.zig:4:5: [address] in foo (test)
381 \\ try bar();381 \\ try bar();
382 \\ ^382 \\ ^
383 \\source.zig:16:5: [address] in _main.0 (test.o)383 \\source.zig:16:5: [address] in main (test)
384 \\ try foo();384 \\ try foo();
385 \\ ^385 \\ ^
386 \\386 \\
387 ,387 ,
388 // release-safe388 // release-safe
389 \\error: TheSkyIsFalling389 \\error: TheSkyIsFalling
390 \\source.zig:12:5: [address] in _main (test.o)390 \\source.zig:12:5: [address] in std.start.main (test)
391 \\ return error.TheSkyIsFalling;391 \\ return error.TheSkyIsFalling;
392 \\ ^392 \\ ^
393 \\source.zig:8:5: [address] in _main (test.o)393 \\source.zig:8:5: [address] in std.start.main (test)
394 \\ return make_error();394 \\ return make_error();
395 \\ ^395 \\ ^
396 \\source.zig:4:5: [address] in _main (test.o)396 \\source.zig:4:5: [address] in std.start.main (test)
397 \\ try bar();397 \\ try bar();
398 \\ ^398 \\ ^
399 \\source.zig:16:5: [address] in _main (test.o)399 \\source.zig:16:5: [address] in std.start.main (test)
400 \\ try foo();400 \\ try foo();
401 \\ ^401 \\ ^
402 \\402 \\
...@@ -440,7 +440,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -440,7 +440,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
440 source_try_return,440 source_try_return,
441 [_][]const u8{441 [_][]const u8{
442 // debug442 // debug
443 \\error: TheSkyIsFalling443 \\error: TheSkyIsFalling
444 \\source.zig:4:5: [address] in foo (test.obj)444 \\source.zig:4:5: [address] in foo (test.obj)
445 \\ return error.TheSkyIsFalling;445 \\ return error.TheSkyIsFalling;
446 \\ ^446 \\ ^
...@@ -466,7 +466,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -466,7 +466,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
466 source_try_try_return_return,466 source_try_try_return_return,
467 [_][]const u8{467 [_][]const u8{
468 // debug468 // debug
469 \\error: TheSkyIsFalling469 \\error: TheSkyIsFalling
470 \\source.zig:12:5: [address] in make_error (test.obj)470 \\source.zig:12:5: [address] in make_error (test.obj)
471 \\ return error.TheSkyIsFalling;471 \\ return error.TheSkyIsFalling;
472 \\ ^472 \\ ^
...@@ -496,5 +496,5 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -496,5 +496,5 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
496 },496 },
497 else => {},497 else => {},
498 }498 }
499 // zig fmt: off
500}499}
500// zig fmt: off
test/stage1/behavior.zig+1
...@@ -40,6 +40,7 @@ comptime {...@@ -40,6 +40,7 @@ comptime {
40 _ = @import("behavior/bugs/3384.zig");40 _ = @import("behavior/bugs/3384.zig");
41 _ = @import("behavior/bugs/3586.zig");41 _ = @import("behavior/bugs/3586.zig");
42 _ = @import("behavior/bugs/3742.zig");42 _ = @import("behavior/bugs/3742.zig");
43 _ = @import("behavior/bugs/4560.zig");
43 _ = @import("behavior/bugs/394.zig");44 _ = @import("behavior/bugs/394.zig");
44 _ = @import("behavior/bugs/421.zig");45 _ = @import("behavior/bugs/421.zig");
45 _ = @import("behavior/bugs/529.zig");46 _ = @import("behavior/bugs/529.zig");
test/stage1/behavior/asm.zig+4-3
...@@ -1,9 +1,10 @@...@@ -1,9 +1,10 @@
1const std = @import("std");1const std = @import("std");
2const config = @import("builtin");
3const expect = std.testing.expect;2const 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
5comptime {6comptime {
6 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {7 if (is_x86_64_linux) {
7 asm (8 asm (
8 \\.globl this_is_my_alias;9 \\.globl this_is_my_alias;
9 \\.type this_is_my_alias, @function;10 \\.type this_is_my_alias, @function;
...@@ -13,7 +14,7 @@ comptime {...@@ -13,7 +14,7 @@ comptime {
13}14}
1415
15test "module level assembly" {16test "module level assembly" {
16 if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {17 if (is_x86_64_linux) {
17 expect(this_is_my_alias() == 1234);18 expect(this_is_my_alias() == 1234);
18 }19 }
19}20}
test/stage1/behavior/bugs/4560.zig created+32
...@@ -0,0 +1,32 @@
1const std = @import("std");
2
3test "fixed" {
4 var s: S = .{
5 .a = 1,
6 .b = .{
7 .size = 123,
8 .max_distance_from_start_index = 456,
9 },
10 };
11 std.testing.expect(s.a == 1);
12 std.testing.expect(s.b.size == 123);
13 std.testing.expect(s.b.max_distance_from_start_index == 456);
14}
15
16const S = struct {
17 a: u32,
18 b: Map,
19
20 const Map = StringHashMap(*S);
21};
22
23pub fn StringHashMap(comptime V: type) type {
24 return HashMap([]const u8, V);
25}
26
27pub fn HashMap(comptime K: type, comptime V: type) type {
28 return struct {
29 size: usize,
30 max_distance_from_start_index: usize,
31 };
32}
test/stage1/behavior/byteswap.zig+2-3
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const builtin = @import("builtin");
43
5test "@byteSwap integers" {4test "@byteSwap integers" {
6 const ByteSwapIntTest = struct {5 const ByteSwapIntTest = struct {
...@@ -41,10 +40,10 @@ test "@byteSwap integers" {...@@ -41,10 +40,10 @@ test "@byteSwap integers" {
4140
42test "@byteSwap vectors" {41test "@byteSwap vectors" {
43 // https://github.com/ziglang/zig/issues/356342 // 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
46 // https://github.com/ziglang/zig/issues/331745 // 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
49 const ByteSwapVectorTest = struct {48 const ByteSwapVectorTest = struct {
50 fn run() void {49 fn run() void {
test/stage1/behavior/cast.zig+11
...@@ -487,6 +487,17 @@ test "@intToEnum passed a comptime_int to an enum with one item" {...@@ -487,6 +487,17 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
487 expect(x == E.A);487 expect(x == E.A);
488}488}
489489
490test "@intToEnum runtime to an extern enum with duplicate values" {
491 const E = extern enum(u8) {
492 A = 1,
493 B = 1,
494 };
495 var a: u8 = 1;
496 var x = @intToEnum(E, a);
497 expect(x == E.A);
498 expect(x == E.B);
499}
500
490test "@intCast to u0 and use the result" {501test "@intCast to u0 and use the result" {
491 const S = struct {502 const S = struct {
492 fn doTheTest(zero: u1, one: u1, bigzero: i32) void {503 fn doTheTest(zero: u1, one: u1, bigzero: i32) void {
test/stage1/behavior/enum.zig+22-1
...@@ -198,7 +198,17 @@ test "@tagName" {...@@ -198,7 +198,17 @@ test "@tagName" {
198 comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));198 comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
199}199}
200200
201fn testEnumTagNameBare(n: BareNumber) []const u8 {201test "@tagName extern enum with duplicates" {
202 expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A"));
203 comptime expect(mem.eql(u8, testEnumTagNameBare(ExternDuplicates.B), "A"));
204}
205
206test "@tagName non-exhaustive enum" {
207 expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
208 comptime expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
209}
210
211fn testEnumTagNameBare(n: var) []const u8 {
202 return @tagName(n);212 return @tagName(n);
203}213}
204214
...@@ -208,6 +218,17 @@ const BareNumber = enum {...@@ -208,6 +218,17 @@ const BareNumber = enum {
208 Three,218 Three,
209};219};
210220
221const ExternDuplicates = extern enum(u8) {
222 A = 1,
223 B = 1,
224};
225
226const NonExhaustive = enum(u8) {
227 A,
228 B,
229 _,
230};
231
211test "enum alignment" {232test "enum alignment" {
212 comptime {233 comptime {
213 expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));234 expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
test/stage1/behavior/eval.zig+25
...@@ -807,3 +807,28 @@ test "return 0 from function that has u0 return type" {...@@ -807,3 +807,28 @@ test "return 0 from function that has u0 return type" {
807 }807 }
808 }808 }
809}809}
810
811test "two comptime calls with array default initialized to undefined" {
812 const S = struct {
813 const CrossTarget = struct {
814 dynamic_linker: DynamicLinker = DynamicLinker{},
815
816 pub fn parse() void {
817 var result: CrossTarget = .{ };
818 result.getCpuArch();
819 }
820
821 pub fn getCpuArch(self: CrossTarget) void { }
822 };
823
824 const DynamicLinker = struct {
825 buffer: [255]u8 = undefined,
826 };
827
828 };
829
830 comptime {
831 S.CrossTarget.parse();
832 S.CrossTarget.parse();
833 }
834}
test/stage1/behavior/fn.zig+13-1
...@@ -1,4 +1,7 @@...@@ -1,4 +1,7 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const testing = std.testing;
3const expect = testing.expect;
4const expectEqual = testing.expectEqual;
25
3test "params" {6test "params" {
4 expect(testParamsAdd(22, 11) == 33);7 expect(testParamsAdd(22, 11) == 33);
...@@ -272,3 +275,12 @@ test "ability to give comptime types and non comptime types to same parameter" {...@@ -272,3 +275,12 @@ test "ability to give comptime types and non comptime types to same parameter" {
272 S.doTheTest();275 S.doTheTest();
273 comptime S.doTheTest();276 comptime S.doTheTest();
274}277}
278
279test "function with inferred error set but returning no error" {
280 const S = struct {
281 fn foo() !void {}
282 };
283
284 const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?;
285 expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len);
286}
test/stage1/behavior/math.zig+1-5
...@@ -525,7 +525,7 @@ test "comptime_int xor" {...@@ -525,7 +525,7 @@ test "comptime_int xor" {
525}525}
526526
527test "f128" {527test "f128" {
528 if (std.Target.current.isWindows()) {528 if (std.Target.current.os.tag == .windows) {
529 // TODO https://github.com/ziglang/zig/issues/508529 // TODO https://github.com/ziglang/zig/issues/508
530 return error.SkipZigTest;530 return error.SkipZigTest;
531 }531 }
...@@ -619,10 +619,6 @@ test "vector integer addition" {...@@ -619,10 +619,6 @@ test "vector integer addition" {
619}619}
620620
621test "NaN comparison" {621test "NaN comparison" {
622 if (std.Target.current.isWindows()) {
623 // TODO https://github.com/ziglang/zig/issues/508
624 return error.SkipZigTest;
625 }
626 testNanEqNan(f16);622 testNanEqNan(f16);
627 testNanEqNan(f32);623 testNanEqNan(f32);
628 testNanEqNan(f64);624 testNanEqNan(f64);
test/stage1/behavior/misc.zig+1-1
...@@ -335,7 +335,7 @@ test "string concatenation" {...@@ -335,7 +335,7 @@ test "string concatenation" {
335 comptime expect(@TypeOf(a) == *const [12:0]u8);335 comptime expect(@TypeOf(a) == *const [12:0]u8);
336 comptime expect(@TypeOf(b) == *const [12:0]u8);336 comptime expect(@TypeOf(b) == *const [12:0]u8);
337337
338 const len = mem.len(u8, b);338 const len = mem.len(b);
339 const len_with_null = len + 1;339 const len_with_null = len + 1;
340 {340 {
341 var i: u32 = 0;341 var i: u32 = 0;
test/stage1/behavior/namespace_depends_on_compile_var.zig+4-4
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const builtin = @import("builtin");1const std = @import("std");
2const expect = @import("std").testing.expect;2const expect = std.testing.expect;
33
4test "namespace depends on compile var" {4test "namespace depends on compile var" {
5 if (some_namespace.a_bool) {5 if (some_namespace.a_bool) {
...@@ -8,7 +8,7 @@ test "namespace depends on compile var" {...@@ -8,7 +8,7 @@ test "namespace depends on compile var" {
8 expect(!some_namespace.a_bool);8 expect(!some_namespace.a_bool);
9 }9 }
10}10}
11const some_namespace = switch (builtin.os) {11const some_namespace = switch (std.builtin.os.tag) {
12 builtin.Os.linux => @import("namespace_depends_on_compile_var/a.zig"),12 .linux => @import("namespace_depends_on_compile_var/a.zig"),
13 else => @import("namespace_depends_on_compile_var/b.zig"),13 else => @import("namespace_depends_on_compile_var/b.zig"),
14};14};
test/stage1/behavior/pointers.zig+12
...@@ -318,3 +318,15 @@ test "pointer arithmetic affects the alignment" {...@@ -318,3 +318,15 @@ test "pointer arithmetic affects the alignment" {
318 expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);318 expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4);
319 }319 }
320}320}
321
322test "@ptrToInt on null optional at comptime" {
323 {
324 const pointer = @intToPtr(?*u8, 0x000);
325 const x = @ptrToInt(pointer);
326 comptime expect(0 == @ptrToInt(pointer));
327 }
328 {
329 const pointer = @intToPtr(?*u8, 0xf00);
330 comptime expect(0xf00 == @ptrToInt(pointer));
331 }
332}
test/stage1/behavior/sizeof_and_typeof.zig+54-2
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1const builtin = @import("builtin");1const std = @import("std");
2const expect = @import("std").testing.expect;2const builtin = std.builtin;
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
35
4test "@sizeOf and @TypeOf" {6test "@sizeOf and @TypeOf" {
5 const y: @TypeOf(x) = 120;7 const y: @TypeOf(x) = 120;
...@@ -135,3 +137,53 @@ test "@bitSizeOf" {...@@ -135,3 +137,53 @@ test "@bitSizeOf" {
135 a: u2,137 a: u2,
136 }) == 2);138 }) == 2);
137}139}
140
141test "@sizeOf comparison against zero" {
142 const S0 = struct {
143 f: *@This(),
144 };
145 const U0 = union {
146 f: *@This(),
147 };
148 const S1 = struct {
149 fn H(comptime T: type) type {
150 return struct {
151 x: T,
152 };
153 }
154 f0: H(*@This()),
155 f1: H(**@This()),
156 f2: H(***@This()),
157 };
158 const U1 = union {
159 fn H(comptime T: type) type {
160 return struct {
161 x: T,
162 };
163 }
164 f0: H(*@This()),
165 f1: H(**@This()),
166 f2: H(***@This()),
167 };
168 const S = struct {
169 fn doTheTest(comptime T: type, comptime result: bool) void {
170 expectEqual(result, @sizeOf(T) > 0);
171 }
172 };
173 // Zero-sized type
174 S.doTheTest(u0, false);
175 S.doTheTest(*u0, false);
176 // Non byte-sized type
177 S.doTheTest(u1, true);
178 S.doTheTest(*u1, true);
179 // Regular type
180 S.doTheTest(u8, true);
181 S.doTheTest(*u8, true);
182 S.doTheTest(f32, true);
183 S.doTheTest(*f32, true);
184 // Container with ptr pointing to themselves
185 S.doTheTest(S0, true);
186 S.doTheTest(U0, true);
187 S.doTheTest(S1, true);
188 S.doTheTest(U1, true);
189}
test/stage1/behavior/slice.zig+29
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;3const expectEqualSlices = std.testing.expectEqualSlices;
4const expectEqual = std.testing.expectEqual;
4const mem = std.mem;5const mem = std.mem;
56
6const x = @intToPtr([*]i32, 0x1000)[0..0x500];7const x = @intToPtr([*]i32, 0x1000)[0..0x500];
...@@ -42,6 +43,17 @@ test "C pointer" {...@@ -42,6 +43,17 @@ test "C pointer" {
42 expectEqualSlices(u8, "kjdhfkjdhf", slice);43 expectEqualSlices(u8, "kjdhfkjdhf", slice);
43}44}
4445
46test "C pointer slice access" {
47 var buf: [10]u32 = [1]u32{42} ** 10;
48 const c_ptr = @ptrCast([*c]const u32, &buf);
49
50 comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));
51
52 for (c_ptr[0..5]) |*cl| {
53 expectEqual(@as(u32, 42), cl.*);
54 }
55}
56
45fn sliceSum(comptime q: []const u8) i32 {57fn sliceSum(comptime q: []const u8) i32 {
46 comptime var result = 0;58 comptime var result = 0;
47 inline for (q) |item| {59 inline for (q) |item| {
...@@ -97,3 +109,20 @@ test "obtaining a null terminated slice" {...@@ -97,3 +109,20 @@ test "obtaining a null terminated slice" {
97 comptime expect(@TypeOf(ptr2) == [:0]u8);109 comptime expect(@TypeOf(ptr2) == [:0]u8);
98 comptime expect(@TypeOf(ptr2[0..2]) == []u8);110 comptime expect(@TypeOf(ptr2[0..2]) == []u8);
99}111}
112
113test "empty array to slice" {
114 const S = struct {
115 fn doTheTest() void {
116 const empty: []align(16) u8 = &[_]u8{};
117 const align_1: []align(1) u8 = empty;
118 const align_4: []align(4) u8 = empty;
119 const align_16: []align(16) u8 = empty;
120 expectEqual(1, @typeInfo(@TypeOf(align_1)).Pointer.alignment);
121 expectEqual(4, @typeInfo(@TypeOf(align_4)).Pointer.alignment);
122 expectEqual(16, @typeInfo(@TypeOf(align_16)).Pointer.alignment);
123 }
124 };
125
126 S.doTheTest();
127 comptime S.doTheTest();
128}
test/stage1/behavior/vector.zig+1-2
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
5const builtin = @import("builtin");
65
7test "implicit cast vector to array - bool" {6test "implicit cast vector to array - bool" {
8 const S = struct {7 const S = struct {
...@@ -114,7 +113,7 @@ test "array to vector" {...@@ -114,7 +113,7 @@ test "array to vector" {
114113
115test "vector casts of sizes not divisable by 8" {114test "vector casts of sizes not divisable by 8" {
116 // https://github.com/ziglang/zig/issues/3563115 // 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
119 const S = struct {118 const S = struct {
120 fn doTheTest() void {119 fn doTheTest() void {
test/standalone.zig+2-2
...@@ -18,10 +18,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -18,10 +18,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
18 cases.addBuildFile("test/standalone/use_alias/build.zig");18 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
20 cases.addBuildFile("test/standalone/empty_env/build.zig");20 cases.addBuildFile("test/standalone/empty_env/build.zig");
21 if (std.Target.current.getOs() != .wasi) {21 if (std.Target.current.os.tag != .wasi) {
22 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");22 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
23 }23 }
24 if (std.Target.current.getArch() == .x86_64) { // TODO add C ABI support for other architectures24 if (std.Target.current.cpu.arch == .x86_64) { // TODO add C ABI support for other architectures
25 cases.addBuildFile("test/stage1/c_abi/build.zig");25 cases.addBuildFile("test/stage1/c_abi/build.zig");
26 }26 }
27}27}
test/standalone/global_linkage/build.zig created+23
...@@ -0,0 +1,23 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const mode = b.standardReleaseOptions();
5 const target = b.standardTargetOptions(null);
6
7 const obj1 = b.addStaticLibrary("obj1", "obj1.zig");
8 obj1.setBuildMode(mode);
9 obj1.setTheTarget(target);
10
11 const obj2 = b.addStaticLibrary("obj2", "obj2.zig");
12 obj2.setBuildMode(mode);
13 obj2.setTheTarget(target);
14
15 const main = b.addTest("main.zig");
16 main.setBuildMode(mode);
17 main.setTheTarget(target);
18 main.linkLibrary(obj1);
19 main.linkLibrary(obj2);
20
21 const test_step = b.step("test", "Test it");
22 test_step.dependOn(&main.step);
23}
test/standalone/global_linkage/main.zig created+9
...@@ -0,0 +1,9 @@
1const std = @import("std");
2
3extern var obj1_integer: usize;
4extern var obj2_integer: usize;
5
6test "access the external integers" {
7 std.testing.expect(obj1_integer == 421);
8 std.testing.expect(obj2_integer == 422);
9}
test/standalone/global_linkage/obj1.zig created+7
...@@ -0,0 +1,7 @@
1extern var internal_integer: usize = 1;
2extern var obj1_integer: usize = 421;
3
4comptime {
5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
6 @export(obj1_integer, .{ .name = "obj1_integer", .linkage = .Strong });
7}
test/standalone/global_linkage/obj2.zig created+7
...@@ -0,0 +1,7 @@
1extern var internal_integer: usize = 2;
2extern var obj2_integer: usize = 422;
3
4comptime {
5 @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal });
6 @export(obj2_integer, .{ .name = "obj2_integer", .linkage = .Strong });
7}
test/tests.zig+90-133
...@@ -1,16 +1,15 @@...@@ -1,16 +1,15 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;
2const debug = std.debug;3const debug = std.debug;
3const warn = debug.warn;4const warn = debug.warn;
4const build = std.build;5const build = std.build;
5pub const Target = build.Target;6const CrossTarget = std.zig.CrossTarget;
6pub const CrossTarget = build.CrossTarget;
7const Buffer = std.Buffer;7const Buffer = std.Buffer;
8const io = std.io;8const io = std.io;
9const fs = std.fs;9const fs = std.fs;
10const mem = std.mem;10const mem = std.mem;
11const fmt = std.fmt;11const fmt = std.fmt;
12const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
13const builtin = @import("builtin");
14const Mode = builtin.Mode;13const Mode = builtin.Mode;
15const LibExeObjStep = build.LibExeObjStep;14const LibExeObjStep = build.LibExeObjStep;
1615
...@@ -31,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla...@@ -31,7 +30,7 @@ pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTransla
31pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;30pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext;
3231
33const TestTarget = struct {32const TestTarget = struct {
34 target: Target = .Native,33 target: CrossTarget = @as(CrossTarget, .{}),
35 mode: builtin.Mode = .Debug,34 mode: builtin.Mode = .Debug,
36 link_libc: bool = false,35 link_libc: bool = false,
37 single_threaded: bool = false,36 single_threaded: bool = false,
...@@ -53,93 +52,77 @@ const test_targets = blk: {...@@ -53,93 +52,77 @@ const test_targets = blk: {
53 },52 },
5453
55 TestTarget{54 TestTarget{
56 .target = Target{55 .target = .{
57 .Cross = CrossTarget{56 .cpu_arch = .x86_64,
58 .cpu = Target.Cpu.baseline(.x86_64),57 .os_tag = .linux,
59 .os = .linux,58 .abi = .none,
60 .abi = .none,
61 },
62 },59 },
63 },60 },
64 TestTarget{61 TestTarget{
65 .target = Target{62 .target = .{
66 .Cross = CrossTarget{63 .cpu_arch = .x86_64,
67 .cpu = Target.Cpu.baseline(.x86_64),64 .os_tag = .linux,
68 .os = .linux,65 .abi = .gnu,
69 .abi = .gnu,
70 },
71 },66 },
72 .link_libc = true,67 .link_libc = true,
73 },68 },
74 TestTarget{69 TestTarget{
75 .target = Target{70 .target = .{
76 .Cross = CrossTarget{71 .cpu_arch = .x86_64,
77 .cpu = Target.Cpu.baseline(.x86_64),72 .os_tag = .linux,
78 .os = .linux,73 .abi = .musl,
79 .abi = .musl,
80 },
81 },74 },
82 .link_libc = true,75 .link_libc = true,
83 },76 },
8477
85 TestTarget{78 TestTarget{
86 .target = Target{79 .target = .{
87 .Cross = CrossTarget{80 .cpu_arch = .i386,
88 .cpu = Target.Cpu.baseline(.i386),81 .os_tag = .linux,
89 .os = .linux,82 .abi = .none,
90 .abi = .none,
91 },
92 },83 },
93 },84 },
94 TestTarget{85 TestTarget{
95 .target = Target{86 .target = .{
96 .Cross = CrossTarget{87 .cpu_arch = .i386,
97 .cpu = Target.Cpu.baseline(.i386),88 .os_tag = .linux,
98 .os = .linux,89 .abi = .musl,
99 .abi = .musl,
100 },
101 },90 },
102 .link_libc = true,91 .link_libc = true,
103 },92 },
10493
105 TestTarget{94 TestTarget{
106 .target = Target{95 .target = .{
107 .Cross = CrossTarget{96 .cpu_arch = .aarch64,
108 .cpu = Target.Cpu.baseline(.aarch64),97 .os_tag = .linux,
109 .os = .linux,98 .abi = .none,
110 .abi = .none,
111 },
112 },99 },
113 },100 },
114 TestTarget{101 TestTarget{
115 .target = Target{102 .target = .{
116 .Cross = CrossTarget{103 .cpu_arch = .aarch64,
117 .cpu = Target.Cpu.baseline(.aarch64),104 .os_tag = .linux,
118 .os = .linux,105 .abi = .musl,
119 .abi = .musl,
120 },
121 },106 },
122 .link_libc = true,107 .link_libc = true,
123 },108 },
124 TestTarget{109 TestTarget{
125 .target = Target{110 .target = .{
126 .Cross = CrossTarget{111 .cpu_arch = .aarch64,
127 .cpu = Target.Cpu.baseline(.aarch64),112 .os_tag = .linux,
128 .os = .linux,113 .abi = .gnu,
129 .abi = .gnu,
130 },
131 },114 },
132 .link_libc = true,115 .link_libc = true,
133 },116 },
134117
135 TestTarget{118 TestTarget{
136 .target = Target.parse(.{119 .target = CrossTarget.parse(.{
137 .arch_os_abi = "arm-linux-none",120 .arch_os_abi = "arm-linux-none",
138 .cpu_features = "generic+v8a",121 .cpu_features = "generic+v8a",
139 }) catch unreachable,122 }) catch unreachable,
140 },123 },
141 TestTarget{124 TestTarget{
142 .target = Target.parse(.{125 .target = CrossTarget.parse(.{
143 .arch_os_abi = "arm-linux-musleabihf",126 .arch_os_abi = "arm-linux-musleabihf",
144 .cpu_features = "generic+v8a",127 .cpu_features = "generic+v8a",
145 }) catch unreachable,128 }) catch unreachable,
...@@ -147,7 +130,7 @@ const test_targets = blk: {...@@ -147,7 +130,7 @@ const test_targets = blk: {
147 },130 },
148 // TODO https://github.com/ziglang/zig/issues/3287131 // TODO https://github.com/ziglang/zig/issues/3287
149 //TestTarget{132 //TestTarget{
150 // .target = Target.parse(.{133 // .target = CrossTarget.parse(.{
151 // .arch_os_abi = "arm-linux-gnueabihf",134 // .arch_os_abi = "arm-linux-gnueabihf",
152 // .cpu_features = "generic+v8a",135 // .cpu_features = "generic+v8a",
153 // }) catch unreachable,136 // }) catch unreachable,
...@@ -155,109 +138,89 @@ const test_targets = blk: {...@@ -155,109 +138,89 @@ const test_targets = blk: {
155 //},138 //},
156139
157 TestTarget{140 TestTarget{
158 .target = Target{141 .target = .{
159 .Cross = CrossTarget{142 .cpu_arch = .mipsel,
160 .cpu = Target.Cpu.baseline(.mipsel),143 .os_tag = .linux,
161 .os = .linux,144 .abi = .none,
162 .abi = .none,
163 },
164 },145 },
165 },146 },
166 TestTarget{147 TestTarget{
167 .target = Target{148 .target = .{
168 .Cross = CrossTarget{149 .cpu_arch = .mipsel,
169 .cpu = Target.Cpu.baseline(.mipsel),150 .os_tag = .linux,
170 .os = .linux,151 .abi = .musl,
171 .abi = .musl,
172 },
173 },152 },
174 .link_libc = true,153 .link_libc = true,
175 },154 },
176155
177 TestTarget{156 TestTarget{
178 .target = Target{157 .target = .{
179 .Cross = CrossTarget{158 .cpu_arch = .riscv64,
180 .cpu = Target.Cpu.baseline(.riscv64),159 .os_tag = .linux,
181 .os = .linux,160 .abi = .none,
182 .abi = .none,
183 },
184 },161 },
185 },162 },
186163
187 // https://github.com/ziglang/zig/issues/4485164 // https://github.com/ziglang/zig/issues/4485
188 //TestTarget{165 //TestTarget{
189 // .target = Target{166 // .target = .{
190 // .Cross = CrossTarget{167 // .cpu_arch = .riscv64,
191 // .cpu = Target.Cpu.baseline(.riscv64),168 // .os_tag = .linux,
192 // .os = .linux,169 // .abi = .musl,
193 // .abi = .musl,
194 // },
195 // },170 // },
196 // .link_libc = true,171 // .link_libc = true,
197 //},172 //},
198173
199 // https://github.com/ziglang/zig/issues/3340174 // https://github.com/ziglang/zig/issues/3340
200 //TestTarget{175 //TestTarget{
201 // .target = Target{176 // .target = .{
202 // .Cross = CrossTarget{177 // .cpu_arch = .riscv64,
203 // .cpu = Target.Cpu.baseline(.riscv64),178 // .os = .linux,
204 // .os = .linux,179 // .abi = .gnu,
205 // .abi = .gnu,
206 // },
207 // },180 // },
208 // .link_libc = true,181 // .link_libc = true,
209 //},182 //},
210183
211 TestTarget{184 TestTarget{
212 .target = Target{185 .target = .{
213 .Cross = CrossTarget{186 .cpu_arch = .x86_64,
214 .cpu = Target.Cpu.baseline(.x86_64),187 .os_tag = .macosx,
215 .os = .macosx,188 .abi = .gnu,
216 .abi = .gnu,
217 },
218 },189 },
219 // TODO https://github.com/ziglang/zig/issues/3295190 // TODO https://github.com/ziglang/zig/issues/3295
220 .disable_native = true,191 .disable_native = true,
221 },192 },
222193
223 TestTarget{194 TestTarget{
224 .target = Target{195 .target = .{
225 .Cross = CrossTarget{196 .cpu_arch = .i386,
226 .cpu = Target.Cpu.baseline(.i386),197 .os_tag = .windows,
227 .os = .windows,198 .abi = .msvc,
228 .abi = .msvc,
229 },
230 },199 },
231 },200 },
232201
233 TestTarget{202 TestTarget{
234 .target = Target{203 .target = .{
235 .Cross = CrossTarget{204 .cpu_arch = .x86_64,
236 .cpu = Target.Cpu.baseline(.x86_64),205 .os_tag = .windows,
237 .os = .windows,206 .abi = .msvc,
238 .abi = .msvc,
239 },
240 },207 },
241 },208 },
242209
243 TestTarget{210 TestTarget{
244 .target = Target{211 .target = .{
245 .Cross = CrossTarget{212 .cpu_arch = .i386,
246 .cpu = Target.Cpu.baseline(.i386),213 .os_tag = .windows,
247 .os = .windows,214 .abi = .gnu,
248 .abi = .gnu,
249 },
250 },215 },
251 .link_libc = true,216 .link_libc = true,
252 },217 },
253218
254 TestTarget{219 TestTarget{
255 .target = Target{220 .target = .{
256 .Cross = CrossTarget{221 .cpu_arch = .x86_64,
257 .cpu = Target.Cpu.baseline(.x86_64),222 .os_tag = .windows,
258 .os = .windows,223 .abi = .gnu,
259 .abi = .gnu,
260 },
261 },224 },
262 .link_libc = true,225 .link_libc = true,
263 },226 },
...@@ -466,13 +429,13 @@ pub fn addPkgTests(...@@ -466,13 +429,13 @@ pub fn addPkgTests(
466 const step = b.step(b.fmt("test-{}", .{name}), desc);429 const step = b.step(b.fmt("test-{}", .{name}), desc);
467430
468 for (test_targets) |test_target| {431 for (test_targets) |test_target| {
469 if (skip_non_native and test_target.target != .Native)432 if (skip_non_native and !test_target.target.isNative())
470 continue;433 continue;
471434
472 if (skip_libc and test_target.link_libc)435 if (skip_libc and test_target.link_libc)
473 continue;436 continue;
474437
475 if (test_target.link_libc and test_target.target.osRequiresLibC()) {438 if (test_target.link_libc and test_target.target.getOs().requiresLibC()) {
476 // This would be a redundant test.439 // This would be a redundant test.
477 continue;440 continue;
478 }441 }
...@@ -482,8 +445,8 @@ pub fn addPkgTests(...@@ -482,8 +445,8 @@ pub fn addPkgTests(
482445
483 const ArchTag = @TagType(builtin.Arch);446 const ArchTag = @TagType(builtin.Arch);
484 if (test_target.disable_native and447 if (test_target.disable_native and
485 test_target.target.getOs() == builtin.os and448 test_target.target.getOsTag() == std.Target.current.os.tag and
486 test_target.target.getArch() == builtin.arch)449 test_target.target.getCpuArch() == std.Target.current.cpu.arch)
487 {450 {
488 continue;451 continue;
489 }452 }
...@@ -493,17 +456,14 @@ pub fn addPkgTests(...@@ -493,17 +456,14 @@ pub fn addPkgTests(
493 } else false;456 } else false;
494 if (!want_this_mode) continue;457 if (!want_this_mode) continue;
495458
496 const libc_prefix = if (test_target.target.osRequiresLibC())459 const libc_prefix = if (test_target.target.getOs().requiresLibC())
497 ""460 ""
498 else if (test_target.link_libc)461 else if (test_target.link_libc)
499 "c"462 "c"
500 else463 else
501 "bare";464 "bare";
502465
503 const triple_prefix = if (test_target.target == .Native)466 const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
504 @as([]const u8, "native")
505 else
506 test_target.target.zigTripleNoSubArch(b.allocator) catch unreachable;
507467
508 const these_tests = b.addTest(root_src);468 const these_tests = b.addTest(root_src);
509 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";469 const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
...@@ -517,7 +477,7 @@ pub fn addPkgTests(...@@ -517,7 +477,7 @@ pub fn addPkgTests(
517 these_tests.single_threaded = test_target.single_threaded;477 these_tests.single_threaded = test_target.single_threaded;
518 these_tests.setFilter(test_filter);478 these_tests.setFilter(test_filter);
519 these_tests.setBuildMode(test_target.mode);479 these_tests.setBuildMode(test_target.mode);
520 these_tests.setTheTarget(test_target.target);480 these_tests.setTarget(test_target.target);
521 if (test_target.link_libc) {481 if (test_target.link_libc) {
522 these_tests.linkSystemLibrary("c");482 these_tests.linkSystemLibrary("c");
523 }483 }
...@@ -694,7 +654,7 @@ pub const StackTracesContext = struct {...@@ -694,7 +654,7 @@ pub const StackTracesContext = struct {
694 const delims = [_][]const u8{ ":", ":", ":", " in " };654 const delims = [_][]const u8{ ":", ":", ":", " in " };
695 var marks = [_]usize{0} ** 4;655 var marks = [_]usize{0} ** 4;
696 // offset search past `[drive]:` on windows656 // offset search past `[drive]:` on windows
697 var pos: usize = if (builtin.os == .windows) 2 else 0;657 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
698 for (delims) |delim, i| {658 for (delims) |delim, i| {
699 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {659 marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
700 try buf.append(line);660 try buf.append(line);
...@@ -747,7 +707,7 @@ pub const CompileErrorContext = struct {...@@ -747,7 +707,7 @@ pub const CompileErrorContext = struct {
747 link_libc: bool,707 link_libc: bool,
748 is_exe: bool,708 is_exe: bool,
749 is_test: bool,709 is_test: bool,
750 target: Target = .Native,710 target: CrossTarget = CrossTarget{},
751711
752 const SourceFile = struct {712 const SourceFile = struct {
753 filename: []const u8,713 filename: []const u8,
...@@ -839,12 +799,9 @@ pub const CompileErrorContext = struct {...@@ -839,12 +799,9 @@ pub const CompileErrorContext = struct {
839 zig_args.append("--output-dir") catch unreachable;799 zig_args.append("--output-dir") catch unreachable;
840 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;800 zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
841801
842 switch (self.case.target) {802 if (!self.case.target.isNative()) {
843 .Native => {},803 try zig_args.append("-target");
844 .Cross => {804 try zig_args.append(try self.case.target.zigTriple(b.allocator));
845 try zig_args.append("-target");
846 try zig_args.append(try self.case.target.zigTriple(b.allocator));
847 },
848 }805 }
849806
850 switch (self.build_mode) {807 switch (self.build_mode) {
test/translate_c.zig+11-13
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
2const builtin = @import("builtin");2const std = @import("std");
3const Target = @import("std").Target;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("macro line continuation",6 cases.add("macro line continuation",
...@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -665,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
665 \\}665 \\}
666 });666 });
667667
668 if (builtin.os != builtin.Os.windows) {668 if (std.Target.current.os.tag != .windows) {
669 // Windows treats this as an enum with type c_int669 // Windows treats this as an enum with type c_int
670 cases.add("big negative enum init values when C ABI supports long long enums",670 cases.add("big negative enum init values when C ABI supports long long enums",
671 \\enum EnumWithInits {671 \\enum EnumWithInits {
...@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1064,7 +1064,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1064 \\}1064 \\}
1065 });1065 });
10661066
1067 if (builtin.os != builtin.Os.windows) {1067 if (std.Target.current.os.tag != .windows) {
1068 // sysv_abi not currently supported on windows1068 // sysv_abi not currently supported on windows
1069 cases.add("Macro qualified functions",1069 cases.add("Macro qualified functions",
1070 \\void __attribute__((sysv_abi)) foo(void);1070 \\void __attribute__((sysv_abi)) foo(void);
...@@ -1093,12 +1093,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1093,12 +1093,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1093 \\pub const fn1 = ?fn (u8) callconv(.C) void;1093 \\pub const fn1 = ?fn (u8) callconv(.C) void;
1094 });1094 });
10951095
1096 cases.addWithTarget("Calling convention", tests.Target{1096 cases.addWithTarget("Calling convention", .{
1097 .Cross = .{1097 .cpu_arch = .i386,
1098 .cpu = Target.Cpu.baseline(.i386),1098 .os_tag = .linux,
1099 .os = .linux,1099 .abi = .none,
1100 .abi = .none,
1101 },
1102 },1100 },
1103 \\void __attribute__((fastcall)) foo1(float *a);1101 \\void __attribute__((fastcall)) foo1(float *a);
1104 \\void __attribute__((stdcall)) foo2(float *a);1102 \\void __attribute__((stdcall)) foo2(float *a);
...@@ -1113,7 +1111,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1113,7 +1111,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1113 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;1111 \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void;
1114 });1112 });
11151113
1116 cases.addWithTarget("Calling convention", Target.parse(.{1114 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1117 .arch_os_abi = "arm-linux-none",1115 .arch_os_abi = "arm-linux-none",
1118 .cpu_features = "generic+v8_5a",1116 .cpu_features = "generic+v8_5a",
1119 }) catch unreachable,1117 }) catch unreachable,
...@@ -1124,7 +1122,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1124,7 +1122,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1124 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;1122 \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void;
1125 });1123 });
11261124
1127 cases.addWithTarget("Calling convention", Target.parse(.{1125 cases.addWithTarget("Calling convention", CrossTarget.parse(.{
1128 .arch_os_abi = "aarch64-linux-none",1126 .arch_os_abi = "aarch64-linux-none",
1129 .cpu_features = "generic+v8_5a",1127 .cpu_features = "generic+v8_5a",
1130 }) catch unreachable,1128 }) catch unreachable,
...@@ -1596,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1596,7 +1594,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1596 \\}1594 \\}
1597 });1595 });
15981596
1599 if (builtin.os != .windows) {1597 if (std.Target.current.os.tag != .windows) {
1600 // When clang uses the <arch>-windows-none triple it behaves as MSVC and1598 // When clang uses the <arch>-windows-none triple it behaves as MSVC and
1601 // interprets the inner `struct Bar` as an anonymous structure1599 // interprets the inner `struct Bar` as an anonymous structure
1602 cases.add("type referenced struct",1600 cases.add("type referenced struct",