| author | |
| committer | |
| log | d1cb16aace5f5996cf2556d07fd3418a951b31df |
| tree | e154f475be8de6f0b0c486cf1baa1557c3f12b65 |
| parent | 3418a332ab3a120f21354d98579d7a3a2dcb523b |
| parent | 387418277a4964714ddaec3336a602ec87dde0f9 |
| signature |
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); |
| 307 | 307 | ||
| 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++.a | 310 | \\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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | ||
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fs = std.fs; | 4 | const fs = std.fs; |
| 5 | const process = std.process; | 5 | const process = std.process; |
| ... | @@ -10,8 +10,8 @@ const testing = std.testing; | ... | @@ -10,8 +10,8 @@ const testing = std.testing; |
| 10 | 10 | ||
| 11 | const max_doc_file_size = 10 * 1024 * 1024; | 11 | const max_doc_file_size = 10 * 1024 * 1024; |
| 12 | 12 | ||
| 13 | const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt(); | 13 | const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt(); |
| 14 | const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt(); | 14 | const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt(); |
| 15 | const tmp_dir_name = "docgen_tmp"; | 15 | const tmp_dir_name = "docgen_tmp"; |
| 16 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; | 16 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; |
| 17 | 17 | ||
| ... | @@ -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 | } |
| 523 | 523 | ||
| 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 |
| 1001 | 1001 | ||
| 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 }); |
| 1044 | 1044 | ||
| ... | @@ -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", .{}); | ||
| 1146 | 1147 | ||
| 1147 | if (code.target_str) |triple| { | 1148 | if (code.target_str) |triple| { |
| 1148 | if (mem.startsWith(u8, triple, "wasm32") or | 1149 | if (mem.startsWith(u8, triple, "wasm32") or |
| 1149 | mem.startsWith(u8, triple, "riscv64-linux") or | 1150 | mem.startsWith(u8, triple, "riscv64-linux") or |
| 1150 | mem.startsWith(u8, triple, "x86_64-linux") and | 1151 | (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 execution | 1154 | // 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 | } |
| 1387 | 1388 | ||
| 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#} |
| 968 | const builtin = @import("builtin"); | 968 | const std = @import("std"); |
| 969 | const builtin = std.builtin; | ||
| 969 | const big = @as(f64, 1 << 40); | 970 | const big = @as(f64, 1 << 40); |
| 970 | 971 | ||
| 971 | export fn foo_strict(x: f64) f64 { | 972 | export 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#} |
| 2066 | const assert = @import("std").debug.assert; | 2067 | const std = @import("std"); |
| 2067 | const builtin = @import("builtin"); | 2068 | const assert = std.debug.assert; |
| 2068 | 2069 | ||
| 2069 | test "variable alignment" { | 2070 | test "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#} |
| 2476 | const std = @import("std"); | 2477 | const std = @import("std"); |
| 2477 | const builtin = @import("builtin"); | 2478 | const builtin = std.builtin; |
| 2478 | const assert = std.debug.assert; | 2479 | const assert = std.debug.assert; |
| 2479 | 2480 | ||
| 2480 | const Full = packed struct { | 2481 | const Full = packed struct { |
| ... | @@ -3204,8 +3205,8 @@ test "separate scopes" { | ... | @@ -3204,8 +3205,8 @@ test "separate scopes" { |
| 3204 | 3205 | ||
| 3205 | {#header_open|switch#} | 3206 | {#header_open|switch#} |
| 3206 | {#code_begin|test|switch#} | 3207 | {#code_begin|test|switch#} |
| 3207 | const assert = @import("std").debug.assert; | 3208 | const std = @import("std"); |
| 3208 | const builtin = @import("builtin"); | 3209 | const assert = std.debug.assert; |
| 3209 | 3210 | ||
| 3210 | test "switch simple" { | 3211 | test "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 | } |
| 3250 | 3251 | ||
| 3251 | // Switch expressions can be used outside a function: | 3252 | // Switch expressions can be used outside a function: |
| 3252 | const os_msg = switch (builtin.os) { | 3253 | const 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 | }; |
| 3256 | 3257 | ||
| 3257 | // Inside a function, switch statements implicitly are compile-time | 3258 | // 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. |
| 3259 | test "switch inside function" { | 3260 | test "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#} |
| 7333 | const builtin = @import("builtin"); | ||
| 7334 | |||
| 7335 | comptime { | 7334 | comptime { |
| 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#} |
| 9365 | const std = @import("std"); | 9364 | const std = @import("std"); |
| 9366 | const builtin = @import("builtin"); | 9365 | const builtin = std.builtin; |
| 9367 | const assert = std.debug.assert; | 9366 | const assert = std.debug.assert; |
| 9368 | 9367 | ||
| 9369 | test "builtin.is_test" { | 9368 | test "builtin.is_test" { |
| ... | @@ -9681,7 +9680,8 @@ WebAssembly.instantiate(typedArray, { | ... | @@ -9681,7 +9680,8 @@ WebAssembly.instantiate(typedArray, { |
| 9681 | <pre><code>$ node test.js | 9680 | <pre><code>$ node test.js |
| 9682 | The result is 3</code></pre> | 9681 | The 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#} |
| 9687 | const std = @import("std"); | 9687 | const std = @import("std"); |
lib/std/build.zig+137-110| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = std.builtin; |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fs = std.fs; | 4 | const fs = std.fs; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| ... | @@ -15,6 +15,7 @@ const BufSet = std.BufSet; | ... | @@ -15,6 +15,7 @@ const BufSet = std.BufSet; |
| 15 | const BufMap = std.BufMap; | 15 | const BufMap = std.BufMap; |
| 16 | const fmt_lib = std.fmt; | 16 | const fmt_lib = std.fmt; |
| 17 | const File = std.fs.File; | 17 | const File = std.fs.File; |
| 18 | const CrossTarget = std.zig.CrossTarget; | ||
| 18 | 19 | ||
| 19 | pub const FmtStep = @import("build/fmt.zig").FmtStep; | 20 | pub const FmtStep = @import("build/fmt.zig").FmtStep; |
| 20 | pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep; | 21 | pub 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 | } |
| 523 | 524 | ||
| 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 message | 528 | default_target: CrossTarget = CrossTarget{}, |
| 528 | // there's probably a better way to collect the target | 529 | }; |
| 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 target | 600 | for (list) |t| { |
| 601 | const t_triple = t.zigTriple(self.allocator) catch unreachable; | ||
| 602 | std.debug.warn(" {}\n", .{t_triple}); | ||
| 603 | } | ||
| 604 | // TODO instead of process exit, return error and have a zig build flag implemented by | ||
| 605 | // the build runner that turns process exits into error return traces | ||
| 606 | process.exit(1); | ||
| 541 | } | 607 | } |
| 608 | |||
| 609 | return selected_target; | ||
| 542 | } | 610 | } |
| 543 | 611 | ||
| 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 { |
| 796 | 864 | ||
| 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 situations | 866 | // 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 | }; |
| 972 | 1040 | ||
| 973 | test "builder.findProgram compiles" { | 1041 | test "builder.findProgram compiles" { |
| 974 | // TODO: uncomment and fix the leak | 1042 | 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 | } |
| 980 | 1049 | ||
| 981 | /// Deprecated. Use `builtin.Version`. | 1050 | /// Deprecated. Use `std.builtin.Version`. |
| 982 | pub const Version = builtin.Version; | 1051 | pub const Version = builtin.Version; |
| 983 | 1052 | ||
| 984 | /// Deprecated. Use `std.Target.Cross`. | 1053 | /// Deprecated. Use `std.zig.CrossTarget`. |
| 985 | pub const CrossTarget = std.Target.Cross; | 1054 | pub const Target = std.zig.CrossTarget; |
| 986 | |||
| 987 | /// Deprecated. Use `std.Target`. | ||
| 988 | pub const Target = std.Target; | ||
| 989 | 1055 | ||
| 990 | pub const Pkg = struct { | 1056 | pub 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, |
| 1080 | 1146 | ||
| 1081 | object_src: []const u8, | 1147 | object_src: []const u8, |
| 1082 | 1148 | ||
| ... | @@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct { | ... | @@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct { |
| 1091 | install_step: ?*InstallArtifactStep, | 1157 | install_step: ?*InstallArtifactStep, |
| 1092 | 1158 | ||
| 1093 | libc_file: ?[]const u8 = null, | 1159 | libc_file: ?[]const u8 = null, |
| 1094 | target_glibc: ?Version = null, | ||
| 1095 | 1160 | ||
| 1096 | valgrind_support: ?bool = null, | 1161 | valgrind_support: ?bool = null, |
| 1097 | 1162 | ||
| ... | @@ -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, |
| 1114 | 1179 | ||
| 1115 | dynamic_linker: ?[]const u8 = null, | ||
| 1116 | |||
| 1117 | /// Position Independent Code | 1180 | /// Position Independent Code |
| 1118 | force_pic: ?bool = null, | 1181 | force_pic: ?bool = null, |
| 1119 | 1182 | ||
| ... | @@ -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 | } |
| 1284 | 1345 | ||
| 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 | } |
| 1306 | 1350 | ||
| 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); |
| 1697 | 1733 | ||
| 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 | } |
| 1863 | 1899 | ||
| 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 | } |
| 1870 | 1906 | ||
| 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 | } |
| 1907 | 1943 | ||
| 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); | ||
| 1913 | 1947 | ||
| 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); | ||
| 1917 | 1953 | ||
| 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); |
| 1928 | 1964 | ||
| 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 | } |
| 1945 | 1979 | ||
| 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 | } |
| 1950 | 1985 | ||
| 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 | } |
| 1955 | 1990 | ||
| 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 :qemu | 2010 | self.glibc_multi_install_dir orelse break :qemu |
| 1981 | else | 2011 | else |
| ... | @@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum { | ... | @@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum { |
| 2420 | Found, | 2450 | Found, |
| 2421 | }; | 2451 | }; |
| 2422 | 2452 | ||
| 2423 | pub const VcpkgLinkage = enum { | 2453 | pub const VcpkgLinkage = std.builtin.LinkMode; |
| 2424 | Static, | ||
| 2425 | Dynamic, | ||
| 2426 | }; | ||
| 2427 | 2454 | ||
| 2428 | pub const InstallDir = enum { | 2455 | pub 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 { |
| 82 | 82 | ||
| 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; |
| 7 | const CheckFileStep = build.CheckFileStep; | 7 | const CheckFileStep = build.CheckFileStep; |
| 8 | const fs = std.fs; | 8 | const fs = std.fs; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const CrossTarget = std.zig.CrossTarget; | ||
| 10 | 11 | ||
| 11 | pub const TranslateCStep = struct { | 12 | pub 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{}, |
| 18 | 19 | ||
| 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 | } |
| 41 | 42 | ||
| 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 | } |
| 45 | 46 | ||
| ... | @@ -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"); |
| 65 | 66 | ||
| 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 | } |
| 73 | 71 | ||
| 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, |
| 187 | 187 | ||
| 188 | /// This field is an optional type. | ||
| 188 | /// The type of the sentinel is the element type of the pointer, which is | 189 | /// 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 way | 190 | /// 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, |
| 208 | 209 | ||
| 210 | /// This field is an optional type. | ||
| 209 | /// The type of the sentinel is the element type of the array, which is | 211 | /// 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 way | 212 | /// 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 { |
| 398 | pub const Version = struct { | 400 | pub 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 | }; |
| 403 | 458 | ||
| 404 | /// This data structure is used by the Zig language code generation and | 459 | /// 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | ||
| 3 | const page_size = std.mem.page_size; | 3 | const page_size = std.mem.page_size; |
| 4 | 4 | ||
| 5 | pub const tokenizer = @import("c/tokenizer.zig"); | 5 | pub 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"); |
| 10 | 10 | ||
| 11 | pub usingnamespace @import("os/bits.zig"); | 11 | pub usingnamespace @import("os/bits.zig"); |
| 12 | 12 | ||
| 13 | pub usingnamespace switch (builtin.os) { | 13 | pub 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 |
| 109 | pub extern "c" fn dup(fd: fd_t) c_int; | 108 | pub extern "c" fn dup(fd: fd_t) c_int; |
| 110 | pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int; | 109 | pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int; |
| 111 | pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; | 110 | pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 111 | pub extern "c" fn readlinkat(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; | ||
| 112 | pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; | 112 | pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; |
| 113 | pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; | 113 | pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; |
| 114 | pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; | 114 | pub 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 |
| 125 | pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; | 125 | pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; |
| 126 | pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; | 126 | pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; |
| 127 | pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; | 127 | pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; |
| 128 | pub extern "c" fn uname(buf: *utsname) c_int; | ||
| 128 | 129 | ||
| 129 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; | 130 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; |
| 130 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; | 131 | pub 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 | }; |
| 96 | const __SIZEOF_PTHREAD_COND_T = 48; | 96 | const __SIZEOF_PTHREAD_COND_T = 48; |
| 97 | const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) { | 97 | const __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; |
| 17 | const maxInt = std.math.maxInt; | 17 | const maxInt = std.math.maxInt; |
| 18 | 18 | ||
| 19 | pub const ChildProcess = struct { | 19 | pub 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, |
| 23 | 23 | ||
| 24 | allocator: *mem.Allocator, | 24 | allocator: *mem.Allocator, |
| 25 | 25 | ||
| ... | @@ -39,15 +39,15 @@ pub const ChildProcess = struct { | ... | @@ -39,15 +39,15 @@ pub const ChildProcess = struct { |
| 39 | stderr_behavior: StdIo, | 39 | stderr_behavior: StdIo, |
| 40 | 40 | ||
| 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, |
| 43 | 43 | ||
| 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, |
| 46 | 46 | ||
| 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, |
| 49 | 49 | ||
| 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, |
| 51 | 51 | ||
| 52 | expand_arg0: Arg0Expand, | 52 | expand_arg0: Arg0Expand, |
| 53 | 53 | ||
| ... | @@ -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 { |
| 118 | 118 | ||
| 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 { |
| 132 | 132 | ||
| 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 { |
| 162 | 162 | ||
| 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); |
| 309 | 309 | ||
| 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 fork | 402 | // 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 writeable | 407 | // There's no distinction between the readable and the writeable |
| 408 | // end with eventfd | 408 | // 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 | } |
| 121 | 121 | ||
| 122 | fn mode(comptime x: comptime_int) comptime_int { | 122 | fn 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 | } |
| 125 | 125 | ||
| 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; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const testing = std.testing; | 5 | const testing = std.testing; |
| 6 | 6 | ||
| 7 | pub const line_sep = switch (builtin.os) { | 7 | pub 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 | }; |
| 11 | 11 | ||
| ... | @@ -28,7 +28,7 @@ test "cstr fns" { | ... | @@ -28,7 +28,7 @@ test "cstr fns" { |
| 28 | 28 | ||
| 29 | fn testCStrFnsImpl() void { | 29 | fn 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 | } |
| 33 | 33 | ||
| 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 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = std.builtin; | ||
| 2 | const math = std.math; | 3 | const math = std.math; |
| 3 | const mem = std.mem; | 4 | const mem = std.mem; |
| 4 | const io = std.io; | 5 | const io = std.io; |
| ... | @@ -11,7 +12,6 @@ const macho = std.macho; | ... | @@ -11,7 +12,6 @@ const macho = std.macho; |
| 11 | const coff = std.coff; | 12 | const coff = std.coff; |
| 12 | const pdb = std.pdb; | 13 | const pdb = std.pdb; |
| 13 | const ArrayList = std.ArrayList; | 14 | const ArrayList = std.ArrayList; |
| 14 | const builtin = @import("builtin"); | ||
| 15 | const root = @import("root"); | 15 | const root = @import("root"); |
| 16 | const maxInt = std.math.maxInt; | 16 | const maxInt = std.math.maxInt; |
| 17 | const File = std.fs.File; | 17 | const 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 | }; |
| 40 | 40 | ||
| 41 | pub 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. |
| 43 | var stderr_file: File = undefined; | 55 | var 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 pointer | 155 | /// 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. |
| 145 | pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { | 157 | pub 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 { |
| 219 | pub fn panic(comptime format: []const u8, args: var) noreturn { | 231 | pub 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_address | 233 | // 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 | } |
| 225 | 237 | ||
| ... | @@ -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 | } |
| 380 | 392 | ||
| 381 | /// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented, | ||
| 382 | /// make this `noasync fn` and remove the individual noasync calls. | ||
| 383 | pub 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 | ||
| 394 | fn 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 | |||
| 550 | pub const TTY = struct { | 393 | pub 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 | }; |
| 619 | 462 | ||
| 620 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 463 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 621 | fn populateModule(di: *DebugInfo, mod: *Module) !void { | 464 | fn 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); |
| 651 | 494 | ||
| 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 | } |
| 684 | 527 | ||
| 685 | fn 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(); | 529 | pub 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) { |
| 688 | 531 | 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, |
| 692 | 535 | 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 | ); |
| 698 | 541 | }, | |
| 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(); | ||
| 704 | 544 | ||
| 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 | } |
| 715 | 558 | ||
| 716 | pub 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 | |||
| 720 | fn printLineInfo( | 559 | fn 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/4353 | 611 | /// 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. |
| 775 | pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { | 614 | pub 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 | } |
| 789 | 629 | ||
| 790 | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { | 630 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 791 | const self_file = try fs.openSelfExe(); | 631 | fn 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(); | ||
| 793 | 634 | ||
| 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); |
| 796 | 637 | ||
| 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 | } |
| 960 | 802 | ||
| 961 | fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { | 803 | fn 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 | ||
| 973 | pub 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 | } |
| 980 | 808 | ||
| 981 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 809 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 982 | pub fn openElfDebugInfo( | 810 | pub 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(); |
| 993 | 820 | ||
| 994 | const debug_info = (try efile.findSection(".debug_info")) orelse | 821 | 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")) orelse | 823 | 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")) orelse | 825 | 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")) orelse | 827 | 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"); |
| 1003 | 830 | ||
| 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 | else | 839 | else |
| 1013 | null, | 840 | null, |
| 1014 | }; | 841 | }; |
| 1015 | 842 | ||
| 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 | } |
| 1019 | 851 | ||
| 1020 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 852 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 1021 | fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo { | 853 | fn 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(); | ||
| 1024 | 855 | ||
| 1025 | const exe_len = math.cast(usize, try exe_file.getEndPos()) catch | 856 | 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) |
| 1036 | 861 | return error.InvalidDebugInfo; | |
| 1037 | return openElfDebugInfo(allocator, exe_mmap); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | ||
| 1041 | fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ||
| 1042 | const hdr = &std.c._mh_execute_header; | ||
| 1043 | assert(hdr.magic == std.macho.MH_MAGIC_64); | ||
| 1044 | 862 | ||
| 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]; |
| 1060 | 878 | ||
| 1061 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); | 879 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); |
| 1062 | 880 | ||
| 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); |
| 1110 | 928 | ||
| 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 | } |
| 1149 | 969 | ||
| 1150 | const MachoSymbol = struct { | 970 | const 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, |
| 1154 | 974 | ||
| 1155 | /// Returns the address from the macho file | 975 | /// 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 | }; |
| 1164 | 984 | ||
| 1165 | pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); | 985 | fn mapWholeFile(path: []const u8) ![]const u8 { |
| 1166 | pub const DwarfInStream = io.InStream(anyerror); | 986 | const file = try noasync fs.openFileAbsolute(path, .{ .always_blocking = true }); |
| 1167 | 987 | defer noasync file.close(); | |
| 1168 | pub 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 | } | ||
| 1184 | 988 | ||
| 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) !void | 990 | 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 | }; | ||
| 1197 | 999 | ||
| 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 | } | ||
| 1216 | 1002 | ||
| 1217 | fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { | 1003 | pub 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 | } | ||
| 1225 | 1006 | ||
| 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 | } |
| 1228 | 1013 | ||
| 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 | } |
| 1331 | 1018 | ||
| 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) |
| 1335 | 1022 | 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)); | ||
| 1346 | 1027 | ||
| 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(); |
| 1349 | 1030 | ||
| 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); | ||
| 1351 | 1034 | ||
| 1352 | const address_size = try s.stream.readByte(); | 1035 | if (address < base_address) continue; |
| 1353 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; | ||
| 1354 | 1036 | ||
| 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)); | ||
| 1357 | 1040 | ||
| 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; | ||
| 1359 | 1049 | ||
| 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 | ); | ||
| 1362 | 1054 | ||
| 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; | ||
| 1364 | 1058 | ||
| 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 | }); | ||
| 1395 | 1063 | ||
| 1396 | this_unit_offset += next_offset; | 1064 | const obj_di = try self.allocator.create(ModuleDebugInfo); |
| 1397 | } | 1065 | errdefer self.allocator.destroy(obj_di); |
| 1398 | } | ||
| 1399 | 1066 | ||
| 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; | ||
| 1417 | 1073 | ||
| 1418 | try s.seekable_stream.seekTo(ranges_offset); | 1074 | try self.address_map.putNoClobber(base_address, obj_di); |
| 1419 | 1075 | ||
| 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; | ||
| 1492 | 1080 | ||
| 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 | } |
| 1507 | 1083 | ||
| 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(); |
| 1510 | 1086 | ||
| 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; |
| 1513 | 1089 | 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; | ||
| 1515 | 1097 | ||
| 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)); | ||
| 1522 | 1110 | ||
| 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 5 | 1112 | // 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; | ||
| 1526 | 1126 | ||
| 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; |
| 1529 | 1129 | ||
| 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 | } | ||
| 1532 | 1134 | ||
| 1533 | if (version >= 4) { | 1135 | var name_buffer: [windows.PATH_MAX_WIDE + 4:0]u16 = undefined; |
| 1534 | // maximum_operations_per_instruction | 1136 | // 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 | } |
| 1537 | 1160 | ||
| 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(); | ||
| 1545 | 1163 | ||
| 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; | ||
| 1547 | 1179 | ||
| 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 | } |
| 1554 | 1206 | ||
| 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 | } |
| 1562 | 1210 | ||
| 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 |
| 1565 | 1213 | 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 | } | ||
| 1579 | 1217 | ||
| 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); | ||
| 1581 | 1220 | ||
| 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; | ||
| 1583 | 1226 | ||
| 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(); | ||
| 1586 | 1228 | ||
| 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 | }; | ||
| 1675 | 1232 | ||
| 1676 | fn getString(di: *DwarfInfo, offset: u64) ![]u8 { | 1233 | const 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) catch | 1236 | line_info: ?LineInfo = null, |
| 1680 | return error.InvalidDebugInfo; | ||
| 1681 | 1237 | ||
| 1682 | // Valid strings always have a terminating zero byte | 1238 | 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 | }; |
| 1690 | 1244 | ||
| 1691 | pub const DebugInfo = switch (builtin.os) { | 1245 | pub 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, |
| 1696 | 1252 | ||
| 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 | ); | ||
| 1703 | 1254 | ||
| 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 | |||
| 1717 | const PcRange = struct { | ||
| 1718 | start: u64, | ||
| 1719 | end: u64, | ||
| 1720 | }; | ||
| 1721 | 1258 | ||
| 1722 | const 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 | |||
| 1729 | const AbbrevTable = ArrayList(AbbrevTableEntry); | ||
| 1730 | |||
| 1731 | const AbbrevTableHeader = struct { | ||
| 1732 | // offset from .debug_abbrev | ||
| 1733 | offset: u64, | ||
| 1734 | table: AbbrevTable, | ||
| 1735 | }; | ||
| 1736 | 1261 | ||
| 1737 | const 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; |
| 1743 | 1268 | ||
| 1744 | const 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 | }; | ||
| 1748 | 1287 | ||
| 1749 | const 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 | } | ||
| 1761 | 1318 | ||
| 1762 | const 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; | ||
| 1765 | 1327 | ||
| 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 | }; | ||
| 1771 | 1339 | ||
| 1772 | const Die = struct { | 1340 | try DW.openDwarfDebugInfo(&di, self.allocator()); |
| 1773 | tag_id: u64, | ||
| 1774 | has_children: bool, | ||
| 1775 | attrs: ArrayList(Attr), | ||
| 1776 | 1341 | ||
| 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 | }; | ||
| 1781 | 1344 | ||
| 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 | } | ||
| 1821 | 1347 | ||
| 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 | }; | ||
| 1831 | 1352 | ||
| 1832 | const 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 | }; | ||
| 1838 | 1356 | ||
| 1839 | pub 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, | ||
| 1844 | 1360 | ||
| 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 | }; | ||
| 1850 | 1363 | ||
| 1851 | const 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, |
| 1859 | 1372 | }); | |
| 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 | } | ||
| 1891 | 1373 | ||
| 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 | } | ||
| 1914 | 1377 | ||
| 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 | } else | 1384 | }, |
| 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 | } | ||
| 1923 | 1396 | ||
| 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, | ||
| 1937 | 1406 | ||
| 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 | }; | ||
| 1948 | 1410 | ||
| 1949 | // TODO the noasyncs here are workarounds | 1411 | fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { |
| 1950 | fn 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 | } | ||
| 1959 | 1414 | ||
| 1960 | // TODO the noasyncs here are workarounds | 1415 | var coff_section: *coff.Section = undefined; |
| 1961 | fn 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 | } | ||
| 1967 | 1420 | ||
| 1968 | fn 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 | }; | ||
| 1972 | 1430 | ||
| 1973 | // TODO the noasyncs here are workarounds | 1431 | const mod = &self.modules[mod_index]; |
| 1974 | fn 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 | } | ||
| 1978 | 1535 | ||
| 1979 | fn 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 | ||
| 2006 | fn 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 | ||
| 2011 | fn 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 | } | ||
| 2021 | 1544 | ||
| 2022 | // TODO the noasyncs here are workarounds | 1545 | if (sect_offset > subsect_info.len) |
| 2023 | fn 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 | ||
| 2037 | fn 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 | |||
| 2086 | fn 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 | } | ||
| 2092 | 1551 | ||
| 2093 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 1552 | return SymbolInfo{ |
| 2094 | fn 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 | }, |
| 2100 | 1559 | .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, |
| 2103 | 1562 | mapped_memory: []const u8, | |
| 2104 | const exe_len = math.cast(usize, try exe_file.getEndPos()) catch | 1563 | |
| 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, |
| 2115 | 1574 | }, | |
| 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 | }; |
| 2121 | 1580 | } 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 | }; | ||
| 2140 | 1586 | ||
| 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 | } |
| 2168 | 1589 | }, | |
| 2169 | var debug_line = opt_debug_line orelse | 1590 | 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 | |||
| 2199 | const Func = struct { | ||
| 2200 | pc_range: ?PcRange, | ||
| 2201 | name: ?[]u8, | ||
| 2202 | }; | 1591 | }; |
| 2203 | 1592 | ||
| 2204 | fn 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 awareness | 1593 | /// TODO multithreaded awareness |
| 2217 | var debug_info_allocator: ?*mem.Allocator = null; | 1594 | var debug_info_allocator: ?*mem.Allocator = null; |
| 2218 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; | 1595 | var 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 | } |
| 2226 | 1603 | ||
| 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. |
| 2228 | pub const have_segfault_handling_support = builtin.os == .linux or builtin.os == .windows; | 1605 | pub const have_segfault_handling_support = builtin.os.tag == .linux or builtin.os.tag == .windows; |
| 2229 | pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) | 1606 | pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) |
| 2230 | root.enable_segfault_handler | 1607 | root.enable_segfault_handler |
| 2231 | else | 1608 | else |
| ... | @@ -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 | } |
| 2261 | 1638 | ||
| 2262 | fn resetSegfaultHandler() void { | 1639 | fn 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 @@ |
| 1 | pub const TAG_padding = 0x00; | 1 | const std = @import("std.zig"); |
| 2 | pub const TAG_array_type = 0x01; | 2 | const builtin = @import("builtin"); |
| 3 | pub const TAG_class_type = 0x02; | 3 | const debug = std.debug; |
| 4 | pub const TAG_entry_point = 0x03; | 4 | const fs = std.fs; |
| 5 | pub const TAG_enumeration_type = 0x04; | 5 | const io = std.io; |
| 6 | pub const TAG_formal_parameter = 0x05; | 6 | const mem = std.mem; |
| 7 | pub const TAG_imported_declaration = 0x08; | 7 | const math = std.math; |
| 8 | pub const TAG_label = 0x0a; | 8 | const leb = @import("debug/leb128.zig"); |
| 9 | pub const TAG_lexical_block = 0x0b; | 9 | |
| 10 | pub const TAG_member = 0x0d; | 10 | const ArrayList = std.ArrayList; |
| 11 | pub const TAG_pointer_type = 0x0f; | 11 | |
| 12 | pub const TAG_reference_type = 0x10; | 12 | usingnamespace @import("dwarf_bits.zig"); |
| 13 | pub const TAG_compile_unit = 0x11; | 13 | |
| 14 | pub const TAG_string_type = 0x12; | 14 | pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); |
| 15 | pub const TAG_structure_type = 0x13; | 15 | pub const DwarfInStream = io.InStream(anyerror); |
| 16 | pub const TAG_subroutine = 0x14; | 16 | |
| 17 | pub const TAG_subroutine_type = 0x15; | 17 | const PcRange = struct { |
| 18 | pub const TAG_typedef = 0x16; | 18 | start: u64, |
| 19 | pub const TAG_union_type = 0x17; | 19 | end: u64, |
| 20 | pub const TAG_unspecified_parameters = 0x18; | 20 | }; |
| 21 | pub const TAG_variant = 0x19; | 21 | |
| 22 | pub const TAG_common_block = 0x1a; | 22 | const Func = struct { |
| 23 | pub const TAG_common_inclusion = 0x1b; | 23 | pc_range: ?PcRange, |
| 24 | pub const TAG_inheritance = 0x1c; | 24 | name: ?[]const u8, |
| 25 | pub const TAG_inlined_subroutine = 0x1d; | 25 | }; |
| 26 | pub const TAG_module = 0x1e; | 26 | |
| 27 | pub const TAG_ptr_to_member_type = 0x1f; | 27 | const CompileUnit = struct { |
| 28 | pub const TAG_set_type = 0x20; | 28 | version: u16, |
| 29 | pub const TAG_subrange_type = 0x21; | 29 | is_64: bool, |
| 30 | pub const TAG_with_stmt = 0x22; | 30 | die: *Die, |
| 31 | pub const TAG_access_declaration = 0x23; | 31 | pc_range: ?PcRange, |
| 32 | pub const TAG_base_type = 0x24; | 32 | }; |
| 33 | pub const TAG_catch_block = 0x25; | 33 | |
| 34 | pub const TAG_const_type = 0x26; | 34 | const AbbrevTable = ArrayList(AbbrevTableEntry); |
| 35 | pub const TAG_constant = 0x27; | 35 | |
| 36 | pub const TAG_enumerator = 0x28; | 36 | const AbbrevTableHeader = struct { |
| 37 | pub const TAG_file_type = 0x29; | 37 | // offset from .debug_abbrev |
| 38 | pub const TAG_friend = 0x2a; | 38 | offset: u64, |
| 39 | pub const TAG_namelist = 0x2b; | 39 | table: AbbrevTable, |
| 40 | pub const TAG_namelist_item = 0x2c; | 40 | }; |
| 41 | pub const TAG_packed_type = 0x2d; | 41 | |
| 42 | pub const TAG_subprogram = 0x2e; | 42 | const AbbrevTableEntry = struct { |
| 43 | pub const TAG_template_type_param = 0x2f; | 43 | has_children: bool, |
| 44 | pub const TAG_template_value_param = 0x30; | 44 | abbrev_code: u64, |
| 45 | pub const TAG_thrown_type = 0x31; | 45 | tag_id: u64, |
| 46 | pub const TAG_try_block = 0x32; | 46 | attrs: ArrayList(AbbrevAttr), |
| 47 | pub const TAG_variant_part = 0x33; | 47 | }; |
| 48 | pub const TAG_variable = 0x34; | 48 | |
| 49 | pub const TAG_volatile_type = 0x35; | 49 | const AbbrevAttr = struct { |
| 50 | 50 | attr_id: u64, | |
| 51 | // DWARF 3 | 51 | form_id: u64, |
| 52 | pub const TAG_dwarf_procedure = 0x36; | 52 | }; |
| 53 | pub const TAG_restrict_type = 0x37; | 53 | |
| 54 | pub const TAG_interface_type = 0x38; | 54 | const FormValue = union(enum) { |
| 55 | pub const TAG_namespace = 0x39; | 55 | Address: u64, |
| 56 | pub const TAG_imported_module = 0x3a; | 56 | Block: []u8, |
| 57 | pub const TAG_unspecified_type = 0x3b; | 57 | Const: Constant, |
| 58 | pub const TAG_partial_unit = 0x3c; | 58 | ExprLoc: []u8, |
| 59 | pub const TAG_imported_unit = 0x3d; | 59 | Flag: bool, |
| 60 | pub const TAG_condition = 0x3f; | 60 | SecOffset: u64, |
| 61 | pub const TAG_shared_type = 0x40; | 61 | Ref: u64, |
| 62 | 62 | RefAddr: u64, | |
| 63 | // DWARF 4 | 63 | String: []const u8, |
| 64 | pub const TAG_type_unit = 0x41; | 64 | StrPtr: u64, |
| 65 | pub const TAG_rvalue_reference_type = 0x42; | 65 | }; |
| 66 | pub const TAG_template_alias = 0x43; | 66 | |
| 67 | 67 | const Constant = struct { | |
| 68 | pub const TAG_lo_user = 0x4080; | 68 | payload: u64, |
| 69 | pub const TAG_hi_user = 0xffff; | 69 | signed: bool, |
| 70 | 70 | ||
| 71 | // SGI/MIPS Extensions. | 71 | fn asUnsignedLe(self: *const Constant) !u64 { |
| 72 | pub const DW_TAG_MIPS_loop = 0x4081; | 72 | if (self.signed) return error.InvalidDebugInfo; |
| 73 | 73 | return self.payload; | |
| 74 | // HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . | 74 | } |
| 75 | pub const TAG_HP_array_descriptor = 0x4090; | 75 | }; |
| 76 | pub const TAG_HP_Bliss_field = 0x4091; | 76 | |
| 77 | pub const TAG_HP_Bliss_field_set = 0x4092; | 77 | const Die = struct { |
| 78 | 78 | tag_id: u64, | |
| 79 | // GNU extensions. | 79 | has_children: bool, |
| 80 | pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90. | 80 | attrs: ArrayList(Attr), |
| 81 | pub const TAG_function_template = 0x4102; // For C++. | 81 | |
| 82 | pub const TAG_class_template = 0x4103; //For C++. | 82 | const Attr = struct { |
| 83 | pub const TAG_GNU_BINCL = 0x4104; | 83 | id: u64, |
| 84 | pub const TAG_GNU_EINCL = 0x4105; | 84 | value: FormValue, |
| 85 | 85 | }; | |
| 86 | // Template template parameter. | 86 | |
| 87 | // See http://gcc.gnu.org/wiki/TemplateParmsDwarf . | 87 | fn getAttr(self: *const Die, id: u64) ?*const FormValue { |
| 88 | pub const TAG_GNU_template_template_param = 0x4106; | 88 | for (self.attrs.toSliceConst()) |*attr| { |
| 89 | 89 | if (attr.id == id) return &attr.value; | |
| 90 | // Template parameter pack extension = specified at | 90 | } |
| 91 | // http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates | 91 | return null; |
| 92 | // The values of these two TAGS are in the DW_TAG_GNU_* space until the tags | 92 | } |
| 93 | // are properly part of DWARF 5. | 93 | |
| 94 | pub const TAG_GNU_template_parameter_pack = 0x4107; | 94 | fn getAttrAddr(self: *const Die, id: u64) !u64 { |
| 95 | pub 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 at | 96 | 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 tags | 98 | else => error.InvalidDebugInfo, |
| 99 | // are properly part of DWARF 5. | 99 | }; |
| 100 | pub const TAG_GNU_call_site = 0x4109; | 100 | } |
| 101 | pub 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 { |
| 103 | pub const TAG_upc_shared_type = 0x8765; | 103 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 104 | pub const TAG_upc_strict_type = 0x8766; | 104 | return switch (form_value.*) { |
| 105 | pub const TAG_upc_relaxed_type = 0x8767; | 105 | FormValue.Const => |value| value.asUnsignedLe(), |
| 106 | // PGI (STMicroelectronics; extensions. No documentation available. | 106 | FormValue.SecOffset => |value| value, |
| 107 | pub const TAG_PGI_kanji_type = 0xA000; | 107 | else => error.InvalidDebugInfo, |
| 108 | pub const TAG_PGI_interface_block = 0xA020; | 108 | }; |
| 109 | 109 | } | |
| 110 | pub const FORM_addr = 0x01; | 110 | |
| 111 | pub const FORM_block2 = 0x03; | 111 | fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 { |
| 112 | pub const FORM_block4 = 0x04; | 112 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 113 | pub const FORM_data2 = 0x05; | 113 | return switch (form_value.*) { |
| 114 | pub const FORM_data4 = 0x06; | 114 | FormValue.Const => |value| value.asUnsignedLe(), |
| 115 | pub const FORM_data8 = 0x07; | 115 | else => error.InvalidDebugInfo, |
| 116 | pub const FORM_string = 0x08; | 116 | }; |
| 117 | pub const FORM_block = 0x09; | 117 | } |
| 118 | pub const FORM_block1 = 0x0a; | 118 | |
| 119 | pub const FORM_data1 = 0x0b; | 119 | fn getAttrRef(self: *const Die, id: u64) !u64 { |
| 120 | pub const FORM_flag = 0x0c; | 120 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 121 | pub const FORM_sdata = 0x0d; | 121 | return switch (form_value.*) { |
| 122 | pub const FORM_strp = 0x0e; | 122 | FormValue.Ref => |value| value, |
| 123 | pub const FORM_udata = 0x0f; | 123 | else => error.InvalidDebugInfo, |
| 124 | pub const FORM_ref_addr = 0x10; | 124 | }; |
| 125 | pub const FORM_ref1 = 0x11; | 125 | } |
| 126 | pub const FORM_ref2 = 0x12; | 126 | |
| 127 | pub const FORM_ref4 = 0x13; | 127 | fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 { |
| 128 | pub const FORM_ref8 = 0x14; | 128 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 129 | pub const FORM_ref_udata = 0x15; | 129 | return switch (form_value.*) { |
| 130 | pub const FORM_indirect = 0x16; | 130 | FormValue.String => |value| value, |
| 131 | pub const FORM_sec_offset = 0x17; | 131 | FormValue.StrPtr => |offset| di.getString(offset), |
| 132 | pub const FORM_exprloc = 0x18; | 132 | else => error.InvalidDebugInfo, |
| 133 | pub const FORM_flag_present = 0x19; | 133 | }; |
| 134 | pub const FORM_ref_sig8 = 0x20; | 134 | } |
| 135 | 135 | }; | |
| 136 | // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. | 136 | |
| 137 | pub const FORM_GNU_addr_index = 0x1f01; | 137 | const FileEntry = struct { |
| 138 | pub const FORM_GNU_str_index = 0x1f02; | 138 | file_name: []const u8, |
| 139 | 139 | 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, |
| 142 | pub const FORM_GNU_ref_alt = 0x1f20; | 142 | }; |
| 143 | pub const FORM_GNU_strp_alt = 0x1f21; | 143 | |
| 144 | 144 | const LineNumberProgram = struct { | |
| 145 | pub const AT_sibling = 0x01; | 145 | address: usize, |
| 146 | pub const AT_location = 0x02; | 146 | file: usize, |
| 147 | pub const AT_name = 0x03; | 147 | line: i64, |
| 148 | pub const AT_ordering = 0x09; | 148 | column: u64, |
| 149 | pub const AT_subscr_data = 0x0a; | 149 | is_stmt: bool, |
| 150 | pub const AT_byte_size = 0x0b; | 150 | basic_block: bool, |
| 151 | pub const AT_bit_offset = 0x0c; | 151 | end_sequence: bool, |
| 152 | pub const AT_bit_size = 0x0d; | 152 | |
| 153 | pub const AT_element_list = 0x0f; | 153 | default_is_stmt: bool, |
| 154 | pub const AT_stmt_list = 0x10; | 154 | target_address: usize, |
| 155 | pub const AT_low_pc = 0x11; | 155 | include_dirs: []const []const u8, |
| 156 | pub const AT_high_pc = 0x12; | 156 | file_entries: *ArrayList(FileEntry), |
| 157 | pub const AT_language = 0x13; | 157 | |
| 158 | pub const AT_member = 0x14; | 158 | prev_address: usize, |
| 159 | pub const AT_discr = 0x15; | 159 | prev_file: usize, |
| 160 | pub const AT_discr_value = 0x16; | 160 | prev_line: i64, |
| 161 | pub const AT_visibility = 0x17; | 161 | prev_column: u64, |
| 162 | pub const AT_import = 0x18; | 162 | prev_is_stmt: bool, |
| 163 | pub const AT_string_length = 0x19; | 163 | prev_basic_block: bool, |
| 164 | pub const AT_common_reference = 0x1a; | 164 | prev_end_sequence: bool, |
| 165 | pub const AT_comp_dir = 0x1b; | 165 | |
| 166 | pub const AT_const_value = 0x1c; | 166 | // Reset the state machine following the DWARF specification |
| 167 | pub const AT_containing_type = 0x1d; | 167 | pub fn reset(self: *LineNumberProgram) void { |
| 168 | pub const AT_default_value = 0x1e; | 168 | self.address = 0; |
| 169 | pub const AT_inline = 0x20; | 169 | self.file = 1; |
| 170 | pub const AT_is_optional = 0x21; | 170 | self.line = 1; |
| 171 | pub const AT_lower_bound = 0x22; | 171 | self.column = 0; |
| 172 | pub const AT_producer = 0x25; | 172 | self.is_stmt = self.default_is_stmt; |
| 173 | pub const AT_prototyped = 0x27; | 173 | self.basic_block = false; |
| 174 | pub const AT_return_addr = 0x2a; | 174 | self.end_sequence = false; |
| 175 | pub const AT_start_scope = 0x2c; | 175 | // Invalidate all the remaining fields |
| 176 | pub const AT_bit_stride = 0x2e; | 176 | self.prev_address = 0; |
| 177 | pub const AT_upper_bound = 0x2f; | 177 | self.prev_file = undefined; |
| 178 | pub const AT_abstract_origin = 0x31; | 178 | self.prev_line = undefined; |
| 179 | pub const AT_accessibility = 0x32; | 179 | self.prev_column = undefined; |
| 180 | pub const AT_address_class = 0x33; | 180 | self.prev_is_stmt = undefined; |
| 181 | pub const AT_artificial = 0x34; | 181 | self.prev_basic_block = undefined; |
| 182 | pub const AT_base_types = 0x35; | 182 | self.prev_end_sequence = undefined; |
| 183 | pub const AT_calling_convention = 0x36; | 183 | } |
| 184 | pub const AT_count = 0x37; | 184 | |
| 185 | pub 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 { |
| 186 | pub const AT_decl_column = 0x39; | 186 | return LineNumberProgram{ |
| 187 | pub const AT_decl_file = 0x3a; | 187 | .address = 0, |
| 188 | pub const AT_decl_line = 0x3b; | 188 | .file = 1, |
| 189 | pub const AT_declaration = 0x3c; | 189 | .line = 1, |
| 190 | pub const AT_discr_list = 0x3d; | 190 | .column = 0, |
| 191 | pub const AT_encoding = 0x3e; | 191 | .is_stmt = is_stmt, |
| 192 | pub const AT_external = 0x3f; | 192 | .basic_block = false, |
| 193 | pub const AT_frame_base = 0x40; | 193 | .end_sequence = false, |
| 194 | pub const AT_friend = 0x41; | 194 | .include_dirs = include_dirs, |
| 195 | pub const AT_identifier_case = 0x42; | 195 | .file_entries = file_entries, |
| 196 | pub const AT_macro_info = 0x43; | 196 | .default_is_stmt = is_stmt, |
| 197 | pub const AT_namelist_items = 0x44; | 197 | .target_address = target_address, |
| 198 | pub const AT_priority = 0x45; | 198 | .prev_address = 0, |
| 199 | pub const AT_segment = 0x46; | 199 | .prev_file = undefined, |
| 200 | pub const AT_specification = 0x47; | 200 | .prev_line = undefined, |
| 201 | pub const AT_static_link = 0x48; | 201 | .prev_column = undefined, |
| 202 | pub const AT_type = 0x49; | 202 | .prev_is_stmt = undefined, |
| 203 | pub const AT_use_location = 0x4a; | 203 | .prev_basic_block = undefined, |
| 204 | pub const AT_variable_parameter = 0x4b; | 204 | .prev_end_sequence = undefined, |
| 205 | pub const AT_virtuality = 0x4c; | 205 | }; |
| 206 | pub const AT_vtable_elem_location = 0x4d; | 206 | } |
| 207 | 207 | ||
| 208 | // DWARF 3 values. | 208 | pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo { |
| 209 | pub const AT_allocated = 0x4e; | 209 | if (self.target_address >= self.prev_address and self.target_address < self.address) { |
| 210 | pub const AT_associated = 0x4f; | 210 | const file_entry = if (self.prev_file == 0) { |
| 211 | pub const AT_data_location = 0x50; | 211 | return error.MissingDebugInfo; |
| 212 | pub const AT_byte_stride = 0x51; | 212 | } else if (self.prev_file - 1 >= self.file_entries.len) { |
| 213 | pub const AT_entry_pc = 0x52; | 213 | return error.InvalidDebugInfo; |
| 214 | pub const AT_use_UTF8 = 0x53; | 214 | } else |
| 215 | pub const AT_extension = 0x54; | 215 | &self.file_entries.items[self.prev_file - 1]; |
| 216 | pub const AT_ranges = 0x55; | 216 | |
| 217 | pub const AT_trampoline = 0x56; | 217 | const dir_name = if (file_entry.dir_index >= self.include_dirs.len) { |
| 218 | pub const AT_call_column = 0x57; | 218 | return error.InvalidDebugInfo; |
| 219 | pub const AT_call_file = 0x58; | 219 | } else |
| 220 | pub const AT_call_line = 0x59; | 220 | self.include_dirs[file_entry.dir_index]; |
| 221 | pub const AT_description = 0x5a; | 221 | const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name }); |
| 222 | pub const AT_binary_scale = 0x5b; | 222 | errdefer self.file_entries.allocator.free(file_name); |
| 223 | pub const AT_decimal_scale = 0x5c; | 223 | return debug.LineInfo{ |
| 224 | pub const AT_small = 0x5d; | 224 | .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0, |
| 225 | pub const AT_decimal_sign = 0x5e; | 225 | .column = self.prev_column, |
| 226 | pub const AT_digit_count = 0x5f; | 226 | .file_name = file_name, |
| 227 | pub const AT_picture_string = 0x60; | 227 | .allocator = self.file_entries.allocator, |
| 228 | pub const AT_mutable = 0x61; | 228 | }; |
| 229 | pub const AT_threads_scaled = 0x62; | 229 | } |
| 230 | pub const AT_explicit = 0x63; | 230 | |
| 231 | pub const AT_object_pointer = 0x64; | 231 | self.prev_address = self.address; |
| 232 | pub const AT_endianity = 0x65; | 232 | self.prev_file = self.file; |
| 233 | pub const AT_elemental = 0x66; | 233 | self.prev_line = self.line; |
| 234 | pub const AT_pure = 0x67; | 234 | self.prev_column = self.column; |
| 235 | pub const AT_recursive = 0x68; | 235 | self.prev_is_stmt = self.is_stmt; |
| 236 | 236 | self.prev_basic_block = self.basic_block; | |
| 237 | // DWARF 4. | 237 | self.prev_end_sequence = self.end_sequence; |
| 238 | pub const AT_signature = 0x69; | 238 | return null; |
| 239 | pub const AT_main_subprogram = 0x6a; | 239 | } |
| 240 | pub const AT_data_bit_offset = 0x6b; | 240 | }; |
| 241 | pub const AT_const_expr = 0x6c; | 241 | |
| 242 | pub const AT_enum_class = 0x6d; | 242 | fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { |
| 243 | pub const AT_linkage_name = 0x6e; | 243 | const first_32_bits = try in_stream.readIntLittle(u32); |
| 244 | 244 | is_64.* = (first_32_bits == 0xffffffff); | |
| 245 | // DWARF 5 | 245 | if (is_64.*) { |
| 246 | pub const AT_alignment = 0x88; | 246 | return in_stream.readIntLittle(u64); |
| 247 | 247 | } else { | |
| 248 | pub const AT_lo_user = 0x2000; // Implementation-defined range start. | 248 | if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; |
| 249 | pub const AT_hi_user = 0x3fff; // Implementation-defined range end. | 249 | // TODO this cast should not be needed |
| 250 | 250 | return @as(u64, first_32_bits); | |
| 251 | // SGI/MIPS extensions. | 251 | } |
| 252 | pub const AT_MIPS_fde = 0x2001; | 252 | } |
| 253 | pub const AT_MIPS_loop_begin = 0x2002; | 253 | |
| 254 | pub const AT_MIPS_tail_loop_begin = 0x2003; | 254 | // TODO the noasyncs here are workarounds |
| 255 | pub const AT_MIPS_epilog_begin = 0x2004; | 255 | fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { |
| 256 | pub const AT_MIPS_loop_unroll_factor = 0x2005; | 256 | const buf = try allocator.alloc(u8, size); |
| 257 | pub const AT_MIPS_software_pipeline_depth = 0x2006; | 257 | errdefer allocator.free(buf); |
| 258 | pub const AT_MIPS_linkage_name = 0x2007; | 258 | if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile; |
| 259 | pub const AT_MIPS_stride = 0x2008; | 259 | return buf; |
| 260 | pub const AT_MIPS_abstract_name = 0x2009; | 260 | } |
| 261 | pub const AT_MIPS_clone_origin = 0x200a; | 261 | |
| 262 | pub const AT_MIPS_has_inlines = 0x200b; | 262 | fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 263 | 263 | const buf = try readAllocBytes(allocator, in_stream, size); | |
| 264 | // HP extensions. | 264 | return FormValue{ .Block = buf }; |
| 265 | pub const AT_HP_block_index = 0x2000; | 265 | } |
| 266 | pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde. | 266 | |
| 267 | pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll. | 267 | // TODO the noasyncs here are workarounds |
| 268 | pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride. | 268 | fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 269 | pub const AT_HP_actuals_stmt_list = 0x2010; | 269 | const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size); |
| 270 | pub const AT_HP_proc_per_section = 0x2011; | 270 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 271 | pub const AT_HP_raw_data_ptr = 0x2012; | 271 | } |
| 272 | pub const AT_HP_pass_by_reference = 0x2013; | 272 | |
| 273 | pub const AT_HP_opt_level = 0x2014; | 273 | fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue { |
| 274 | pub const AT_HP_prof_version_id = 0x2015; | 274 | // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here. |
| 275 | pub const AT_HP_opt_flags = 0x2016; | 275 | // `noasync` should be removed from all the function calls once it is fixed. |
| 276 | pub const AT_HP_cold_region_low_pc = 0x2017; | 276 | return FormValue{ |
| 277 | pub const AT_HP_cold_region_high_pc = 0x2018; | 277 | .Const = Constant{ |
| 278 | pub const AT_HP_all_variables_modifiable = 0x2019; | 278 | .signed = signed, |
| 279 | pub const AT_HP_linkage_name = 0x201a; | 279 | .payload = switch (size) { |
| 280 | pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g. | 280 | 1 => try noasync in_stream.readIntLittle(u8), |
| 281 | pub const AT_HP_unit_name = 0x201f; | 281 | 2 => try noasync in_stream.readIntLittle(u16), |
| 282 | pub const AT_HP_unit_size = 0x2020; | 282 | 4 => try noasync in_stream.readIntLittle(u32), |
| 283 | pub const AT_HP_widened_byte_size = 0x2021; | 283 | 8 => try noasync in_stream.readIntLittle(u64), |
| 284 | pub const AT_HP_definition_points = 0x2022; | 284 | -1 => blk: { |
| 285 | pub const AT_HP_default_location = 0x2023; | 285 | if (signed) { |
| 286 | pub const AT_HP_is_result_param = 0x2029; | 286 | const x = try noasync leb.readILEB128(i64, in_stream); |
| 287 | 287 | break :blk @bitCast(u64, x); | |
| 288 | // GNU extensions. | 288 | } else { |
| 289 | pub const AT_sf_names = 0x2101; | 289 | const x = try noasync leb.readULEB128(u64, in_stream); |
| 290 | pub const AT_src_info = 0x2102; | 290 | break :blk x; |
| 291 | pub const AT_mac_info = 0x2103; | 291 | } |
| 292 | pub const AT_src_coords = 0x2104; | 292 | }, |
| 293 | pub const AT_body_begin = 0x2105; | 293 | else => @compileError("Invalid size"), |
| 294 | pub const AT_body_end = 0x2106; | 294 | }, |
| 295 | pub const AT_GNU_vector = 0x2107; | 295 | }, |
| 296 | // Thread-safety annotations. | 296 | }; |
| 297 | // See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . | 297 | } |
| 298 | pub const AT_GNU_guarded_by = 0x2108; | 298 | |
| 299 | pub const AT_GNU_pt_guarded_by = 0x2109; | 299 | // TODO the noasyncs here are workarounds |
| 300 | pub const AT_GNU_guarded = 0x210a; | 300 | fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { |
| 301 | pub 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)); |
| 302 | pub const AT_GNU_locks_excluded = 0x210c; | 302 | } |
| 303 | pub const AT_GNU_exclusive_locks_required = 0x210d; | 303 | |
| 304 | pub const AT_GNU_shared_locks_required = 0x210e; | 304 | // TODO the noasyncs here are workarounds |
| 305 | // One-definition rule violation detection. | 305 | fn parseFormValueTargetAddrSize(in_stream: var) !u64 { |
| 306 | // See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo . | 306 | if (@sizeOf(usize) == 4) { |
| 307 | pub 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) { |
| 310 | pub 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; |
| 313 | pub const AT_GNU_call_site_value = 0x2111; | 313 | } |
| 314 | pub const AT_GNU_call_site_data_value = 0x2112; | 314 | } |
| 315 | pub const AT_GNU_call_site_target = 0x2113; | 315 | |
| 316 | pub const AT_GNU_call_site_target_clobbered = 0x2114; | 316 | // TODO the noasyncs here are workarounds |
| 317 | pub const AT_GNU_tail_call = 0x2115; | 317 | fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue { |
| 318 | pub const AT_GNU_all_tail_call_sites = 0x2116; | 318 | return FormValue{ |
| 319 | pub const AT_GNU_all_call_sites = 0x2117; | 319 | .Ref = switch (size) { |
| 320 | pub 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), |
| 322 | pub 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), |
| 324 | pub const AT_GNU_dwo_name = 0x2130; | 324 | -1 => try noasync leb.readULEB128(u64, in_stream), |
| 325 | pub const AT_GNU_dwo_id = 0x2131; | 325 | else => unreachable, |
| 326 | pub const AT_GNU_ranges_base = 0x2132; | 326 | }, |
| 327 | pub const AT_GNU_addr_base = 0x2133; | 327 | }; |
| 328 | pub const AT_GNU_pubnames = 0x2134; | 328 | } |
| 329 | pub const AT_GNU_pubtypes = 0x2135; | 329 | |
| 330 | // VMS extensions. | 330 | // TODO the noasyncs here are workarounds |
| 331 | pub const AT_VMS_rtnbeg_pd_address = 0x2201; | 331 | fn 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), |
| 335 | pub const AT_use_GNAT_descriptive_type = 0x2301; | 335 | FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), |
| 336 | pub const AT_GNAT_descriptive_type = 0x2302; | 336 | FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), |
| 337 | // UPC extension. | 337 | FORM_block => x: { |
| 338 | pub 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); |
| 340 | pub const AT_PGI_lbase = 0x3a00; | 340 | }, |
| 341 | pub const AT_PGI_soffset = 0x3a01; | 341 | FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), |
| 342 | pub const AT_PGI_lstride = 0x3a02; | 342 | FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2), |
| 343 | 343 | FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4), | |
| 344 | pub const OP_addr = 0x03; | 344 | FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8), |
| 345 | pub const OP_deref = 0x06; | 345 | FORM_udata, FORM_sdata => { |
| 346 | pub const OP_const1u = 0x08; | 346 | const signed = form_id == FORM_sdata; |
| 347 | pub const OP_const1s = 0x09; | 347 | return parseFormValueConstant(allocator, in_stream, signed, -1); |
| 348 | pub const OP_const2u = 0x0a; | 348 | }, |
| 349 | pub const OP_const2s = 0x0b; | 349 | FORM_exprloc => { |
| 350 | pub const OP_const4u = 0x0c; | 350 | const size = try noasync leb.readULEB128(usize, in_stream); |
| 351 | pub const OP_const4s = 0x0d; | 351 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 352 | pub const OP_const8u = 0x0e; | 352 | return FormValue{ .ExprLoc = buf }; |
| 353 | pub const OP_const8s = 0x0f; | 353 | }, |
| 354 | pub const OP_constu = 0x10; | 354 | FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 }, |
| 355 | pub const OP_consts = 0x11; | 355 | FORM_flag_present => FormValue{ .Flag = true }, |
| 356 | pub const OP_dup = 0x12; | 356 | FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, |
| 357 | pub const OP_drop = 0x13; | 357 | |
| 358 | pub const OP_over = 0x14; | 358 | FORM_ref1 => parseFormValueRef(allocator, in_stream, 1), |
| 359 | pub const OP_pick = 0x15; | 359 | FORM_ref2 => parseFormValueRef(allocator, in_stream, 2), |
| 360 | pub const OP_swap = 0x16; | 360 | FORM_ref4 => parseFormValueRef(allocator, in_stream, 4), |
| 361 | pub const OP_rot = 0x17; | 361 | FORM_ref8 => parseFormValueRef(allocator, in_stream, 8), |
| 362 | pub const OP_xderef = 0x18; | 362 | FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1), |
| 363 | pub const OP_abs = 0x19; | 363 | |
| 364 | pub const OP_and = 0x1a; | 364 | FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, |
| 365 | pub const OP_div = 0x1b; | 365 | FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) }, |
| 366 | pub const OP_minus = 0x1c; | 366 | |
| 367 | pub const OP_mod = 0x1d; | 367 | FORM_string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) }, |
| 368 | pub const OP_mul = 0x1e; | 368 | FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, |
| 369 | pub const OP_neg = 0x1f; | 369 | FORM_indirect => { |
| 370 | pub const OP_not = 0x20; | 370 | const child_form_id = try noasync leb.readULEB128(u64, in_stream); |
| 371 | pub const OP_or = 0x21; | 371 | const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64)); |
| 372 | pub const OP_plus = 0x22; | 372 | var frame = try allocator.create(F); |
| 373 | pub const OP_plus_uconst = 0x23; | 373 | defer allocator.destroy(frame); |
| 374 | pub const OP_shl = 0x24; | 374 | return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, is_64); |
| 375 | pub const OP_shr = 0x25; | 375 | }, |
| 376 | pub const OP_shra = 0x26; | 376 | else => error.InvalidDebugInfo, |
| 377 | pub const OP_xor = 0x27; | 377 | }; |
| 378 | pub const OP_bra = 0x28; | 378 | } |
| 379 | pub const OP_eq = 0x29; | 379 | |
| 380 | pub const OP_ge = 0x2a; | 380 | fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { |
| 381 | pub const OP_gt = 0x2b; | 381 | for (abbrev_table.toSliceConst()) |*table_entry| { |
| 382 | pub const OP_le = 0x2c; | 382 | if (table_entry.abbrev_code == abbrev_code) return table_entry; |
| 383 | pub const OP_lt = 0x2d; | 383 | } |
| 384 | pub const OP_ne = 0x2e; | 384 | return null; |
| 385 | pub const OP_skip = 0x2f; | 385 | } |
| 386 | pub const OP_lit0 = 0x30; | 386 | |
| 387 | pub const OP_lit1 = 0x31; | 387 | pub const DwarfInfo = struct { |
| 388 | pub const OP_lit2 = 0x32; | 388 | endian: builtin.Endian, |
| 389 | pub const OP_lit3 = 0x33; | 389 | // No memory is owned by the DwarfInfo |
| 390 | pub const OP_lit4 = 0x34; | 390 | debug_info: []const u8, |
| 391 | pub const OP_lit5 = 0x35; | 391 | debug_abbrev: []const u8, |
| 392 | pub const OP_lit6 = 0x36; | 392 | debug_str: []const u8, |
| 393 | pub const OP_lit7 = 0x37; | 393 | debug_line: []const u8, |
| 394 | pub const OP_lit8 = 0x38; | 394 | debug_ranges: ?[]const u8, |
| 395 | pub const OP_lit9 = 0x39; | 395 | // Filled later by the initializer |
| 396 | pub const OP_lit10 = 0x3a; | 396 | abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined, |
| 397 | pub const OP_lit11 = 0x3b; | 397 | compile_unit_list: ArrayList(CompileUnit) = undefined, |
| 398 | pub const OP_lit12 = 0x3c; | 398 | func_list: ArrayList(Func) = undefined, |
| 399 | pub const OP_lit13 = 0x3d; | 399 | |
| 400 | pub const OP_lit14 = 0x3e; | 400 | pub fn allocator(self: DwarfInfo) *mem.Allocator { |
| 401 | pub const OP_lit15 = 0x3f; | 401 | return self.abbrev_table_list.allocator; |
| 402 | pub const OP_lit16 = 0x40; | 402 | } |
| 403 | pub const OP_lit17 = 0x41; | 403 | |
| 404 | pub const OP_lit18 = 0x42; | 404 | fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { |
| 405 | pub const OP_lit19 = 0x43; | 405 | for (di.func_list.toSliceConst()) |*func| { |
| 406 | pub const OP_lit20 = 0x44; | 406 | if (func.pc_range) |range| { |
| 407 | pub const OP_lit21 = 0x45; | 407 | if (address >= range.start and address < range.end) { |
| 408 | pub const OP_lit22 = 0x46; | 408 | return func.name; |
| 409 | pub const OP_lit23 = 0x47; | 409 | } |
| 410 | pub const OP_lit24 = 0x48; | 410 | } |
| 411 | pub const OP_lit25 = 0x49; | 411 | } |
| 412 | pub const OP_lit26 = 0x4a; | 412 | |
| 413 | pub const OP_lit27 = 0x4b; | 413 | return null; |
| 414 | pub const OP_lit28 = 0x4c; | 414 | } |
| 415 | pub const OP_lit29 = 0x4d; | 415 | |
| 416 | pub const OP_lit30 = 0x4e; | 416 | fn scanAllFunctions(di: *DwarfInfo) !void { |
| 417 | pub const OP_lit31 = 0x4f; | 417 | var s = io.SliceSeekableInStream.init(di.debug_info); |
| 418 | pub const OP_reg0 = 0x50; | 418 | var this_unit_offset: u64 = 0; |
| 419 | pub const OP_reg1 = 0x51; | 419 | |
| 420 | pub const OP_reg2 = 0x52; | 420 | while (this_unit_offset < try s.seekable_stream.getEndPos()) { |
| 421 | pub const OP_reg3 = 0x53; | 421 | s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) { |
| 422 | pub const OP_reg4 = 0x54; | 422 | error.EndOfStream => unreachable, |
| 423 | pub const OP_reg5 = 0x55; | 423 | else => return err, |
| 424 | pub const OP_reg6 = 0x56; | 424 | }; |
| 425 | pub const OP_reg7 = 0x57; | 425 | |
| 426 | pub const OP_reg8 = 0x58; | 426 | var is_64: bool = undefined; |
| 427 | pub const OP_reg9 = 0x59; | 427 | const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64); |
| 428 | pub const OP_reg10 = 0x5a; | 428 | if (unit_length == 0) return; |
| 429 | pub const OP_reg11 = 0x5b; | 429 | const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); |
| 430 | pub const OP_reg12 = 0x5c; | 430 | |
| 431 | pub const OP_reg13 = 0x5d; | 431 | const version = try s.stream.readInt(u16, di.endian); |
| 432 | pub const OP_reg14 = 0x5e; | 432 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 433 | pub const OP_reg15 = 0x5f; | 433 | |
| 434 | pub 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); |
| 435 | pub const OP_reg17 = 0x61; | 435 | |
| 436 | pub const OP_reg18 = 0x62; | 436 | const address_size = try s.stream.readByte(); |
| 437 | pub const OP_reg19 = 0x63; | 437 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| 438 | pub const OP_reg20 = 0x64; | 438 | |
| 439 | pub const OP_reg21 = 0x65; | 439 | const compile_unit_pos = try s.seekable_stream.getPos(); |
| 440 | pub const OP_reg22 = 0x66; | 440 | const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); |
| 441 | pub const OP_reg23 = 0x67; | 441 | |
| 442 | pub const OP_reg24 = 0x68; | 442 | try s.seekable_stream.seekTo(compile_unit_pos); |
| 443 | pub const OP_reg25 = 0x69; | 443 | |
| 444 | pub const OP_reg26 = 0x6a; | 444 | const next_unit_pos = this_unit_offset + next_offset; |
| 445 | pub const OP_reg27 = 0x6b; | 445 | |
| 446 | pub const OP_reg28 = 0x6c; | 446 | while ((try s.seekable_stream.getPos()) < next_unit_pos) { |
| 447 | pub const OP_reg29 = 0x6d; | 447 | const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue; |
| 448 | pub const OP_reg30 = 0x6e; | 448 | defer die_obj.attrs.deinit(); |
| 449 | pub const OP_reg31 = 0x6f; | 449 | |
| 450 | pub const OP_breg0 = 0x70; | 450 | const after_die_offset = try s.seekable_stream.getPos(); |
| 451 | pub const OP_breg1 = 0x71; | 451 | |
| 452 | pub const OP_breg2 = 0x72; | 452 | switch (die_obj.tag_id) { |
| 453 | pub const OP_breg3 = 0x73; | 453 | TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => { |
| 454 | pub const OP_breg4 = 0x74; | 454 | const fn_name = x: { |
| 455 | pub const OP_breg5 = 0x75; | 455 | var depth: i32 = 3; |
| 456 | pub const OP_breg6 = 0x76; | 456 | var this_die_obj = die_obj; |
| 457 | pub const OP_breg7 = 0x77; | 457 | // Prenvent endless loops |
| 458 | pub const OP_breg8 = 0x78; | 458 | while (depth > 0) : (depth -= 1) { |
| 459 | pub const OP_breg9 = 0x79; | 459 | if (this_die_obj.getAttr(AT_name)) |_| { |
| 460 | pub const OP_breg10 = 0x7a; | 460 | const name = try this_die_obj.getAttrString(di, AT_name); |
| 461 | pub const OP_breg11 = 0x7b; | 461 | break :x name; |
| 462 | pub const OP_breg12 = 0x7c; | 462 | } else if (this_die_obj.getAttr(AT_abstract_origin)) |ref| { |
| 463 | pub const OP_breg13 = 0x7d; | 463 | // Follow the DIE it points to and repeat |
| 464 | pub const OP_breg14 = 0x7e; | 464 | const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin); |
| 465 | pub const OP_breg15 = 0x7f; | 465 | if (ref_offset > next_offset) return error.InvalidDebugInfo; |
| 466 | pub const OP_breg16 = 0x80; | 466 | try s.seekable_stream.seekTo(this_unit_offset + ref_offset); |
| 467 | pub const OP_breg17 = 0x81; | 467 | this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; |
| 468 | pub const OP_breg18 = 0x82; | 468 | } else if (this_die_obj.getAttr(AT_specification)) |ref| { |
| 469 | pub const OP_breg19 = 0x83; | 469 | // Follow the DIE it points to and repeat |
| 470 | pub const OP_breg20 = 0x84; | 470 | const ref_offset = try this_die_obj.getAttrRef(AT_specification); |
| 471 | pub const OP_breg21 = 0x85; | 471 | if (ref_offset > next_offset) return error.InvalidDebugInfo; |
| 472 | pub const OP_breg22 = 0x86; | 472 | try s.seekable_stream.seekTo(this_unit_offset + ref_offset); |
| 473 | pub const OP_breg23 = 0x87; | 473 | this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; |
| 474 | pub const OP_breg24 = 0x88; | 474 | } else { |
| 475 | pub const OP_breg25 = 0x89; | 475 | break :x null; |
| 476 | pub const OP_breg26 = 0x8a; | 476 | } |
| 477 | pub const OP_breg27 = 0x8b; | 477 | } |
| 478 | pub const OP_breg28 = 0x8c; | 478 | |
| 479 | pub const OP_breg29 = 0x8d; | 479 | break :x null; |
| 480 | pub const OP_breg30 = 0x8e; | 480 | }; |
| 481 | pub const OP_breg31 = 0x8f; | 481 | |
| 482 | pub const OP_regx = 0x90; | 482 | const pc_range = x: { |
| 483 | pub const OP_fbreg = 0x91; | 483 | if (die_obj.getAttrAddr(AT_low_pc)) |low_pc| { |
| 484 | pub const OP_bregx = 0x92; | 484 | if (die_obj.getAttr(AT_high_pc)) |high_pc_value| { |
| 485 | pub const OP_piece = 0x93; | 485 | const pc_end = switch (high_pc_value.*) { |
| 486 | pub const OP_deref_size = 0x94; | 486 | FormValue.Address => |value| value, |
| 487 | pub const OP_xderef_size = 0x95; | 487 | FormValue.Const => |value| b: { |
| 488 | pub const OP_nop = 0x96; | 488 | const offset = try value.asUnsignedLe(); |
| 489 | 489 | break :b (low_pc + offset); | |
| 490 | // DWARF 3 extensions. | 490 | }, |
| 491 | pub const OP_push_object_address = 0x97; | 491 | else => return error.InvalidDebugInfo, |
| 492 | pub const OP_call2 = 0x98; | 492 | }; |
| 493 | pub const OP_call4 = 0x99; | 493 | break :x PcRange{ |
| 494 | pub const OP_call_ref = 0x9a; | 494 | .start = low_pc, |
| 495 | pub const OP_form_tls_address = 0x9b; | 495 | .end = pc_end, |
| 496 | pub const OP_call_frame_cfa = 0x9c; | 496 | }; |
| 497 | pub const OP_bit_piece = 0x9d; | 497 | } else { |
| 498 | 498 | break :x null; | |
| 499 | // DWARF 4 extensions. | 499 | } |
| 500 | pub const OP_implicit_value = 0x9e; | 500 | } else |err| { |
| 501 | pub const OP_stack_value = 0x9f; | 501 | if (err != error.MissingDebugInfo) return err; |
| 502 | 502 | break :x null; | |
| 503 | pub const OP_lo_user = 0xe0; // Implementation-defined range start. | 503 | } |
| 504 | pub const OP_hi_user = 0xff; // Implementation-defined range end. | 504 | }; |
| 505 | 505 | ||
| 506 | // GNU extensions. | 506 | try di.func_list.append(Func{ |
| 507 | pub 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, |
| 509 | pub const OP_GNU_uninit = 0xf0; | 509 | }); |
| 510 | pub 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 | } |
| 513 | pub 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 | } |
| 516 | pub 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 | } |
| 519 | pub const OP_GNU_const_type = 0xf4; | 519 | } |
| 520 | pub const OP_GNU_regval_type = 0xf5; | 520 | |
| 521 | pub const OP_GNU_deref_type = 0xf6; | 521 | fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 522 | pub const OP_GNU_convert = 0xf7; | 522 | var s = io.SliceSeekableInStream.init(di.debug_info); |
| 523 | pub const OP_GNU_reinterpret = 0xf9; | 523 | var this_unit_offset: u64 = 0; |
| 524 | // The GNU parameter ref extension. | 524 | |
| 525 | pub 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) { |
| 527 | pub const OP_GNU_addr_index = 0xfb; | 527 | error.EndOfStream => unreachable, |
| 528 | pub const OP_GNU_const_index = 0xfc; | 528 | else => return err, |
| 529 | // HP extensions. | 529 | }; |
| 530 | pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address. | 530 | |
| 531 | pub const OP_HP_is_value = 0xe1; | 531 | var is_64: bool = undefined; |
| 532 | pub const OP_HP_fltconst4 = 0xe2; | 532 | const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64); |
| 533 | pub const OP_HP_fltconst8 = 0xe3; | 533 | if (unit_length == 0) return; |
| 534 | pub const OP_HP_mod_range = 0xe4; | 534 | const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); |
| 535 | pub const OP_HP_unmod_range = 0xe5; | 535 | |
| 536 | pub 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; |
| 538 | pub const OP_PGI_omp_thread_num = 0xf8; | 538 | |
| 539 | 539 | const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian); | |
| 540 | pub const ATE_void = 0x0; | 540 | |
| 541 | pub const ATE_address = 0x1; | 541 | const address_size = try s.stream.readByte(); |
| 542 | pub const ATE_boolean = 0x2; | 542 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| 543 | pub const ATE_complex_float = 0x3; | 543 | |
| 544 | pub const ATE_float = 0x4; | 544 | const compile_unit_pos = try s.seekable_stream.getPos(); |
| 545 | pub const ATE_signed = 0x5; | 545 | const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); |
| 546 | pub const ATE_signed_char = 0x6; | 546 | |
| 547 | pub const ATE_unsigned = 0x7; | 547 | try s.seekable_stream.seekTo(compile_unit_pos); |
| 548 | pub const ATE_unsigned_char = 0x8; | 548 | |
| 549 | 549 | 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; |
| 551 | pub const ATE_imaginary_float = 0x9; | 551 | |
| 552 | pub const ATE_packed_decimal = 0xa; | 552 | if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo; |
| 553 | pub const ATE_numeric_string = 0xb; | 553 | |
| 554 | pub const ATE_edited = 0xc; | 554 | const pc_range = x: { |
| 555 | pub const ATE_signed_fixed = 0xd; | 555 | if (compile_unit_die.getAttrAddr(AT_low_pc)) |low_pc| { |
| 556 | pub const ATE_unsigned_fixed = 0xe; | 556 | if (compile_unit_die.getAttr(AT_high_pc)) |high_pc_value| { |
| 557 | pub const ATE_decimal_float = 0xf; | 557 | const pc_end = switch (high_pc_value.*) { |
| 558 | 558 | FormValue.Address => |value| value, | |
| 559 | // DWARF 4. | 559 | FormValue.Const => |value| b: { |
| 560 | pub const ATE_UTF = 0x10; | 560 | const offset = try value.asUnsignedLe(); |
| 561 | 561 | break :b (low_pc + offset); | |
| 562 | pub const ATE_lo_user = 0x80; | 562 | }, |
| 563 | pub const ATE_hi_user = 0xff; | 563 | else => return error.InvalidDebugInfo, |
| 564 | 564 | }; | |
| 565 | // HP extensions. | 565 | break :x PcRange{ |
| 566 | pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit). | 566 | .start = low_pc, |
| 567 | pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit). | 567 | .end = pc_end, |
| 568 | pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit). | 568 | }; |
| 569 | pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit). | 569 | } else { |
| 570 | pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64). | 570 | break :x null; |
| 571 | pub const ATE_HP_imaginary_float80 = 0x85; | 571 | } |
| 572 | pub const ATE_HP_imaginary_float128 = 0x86; | 572 | } else |err| { |
| 573 | pub const ATE_HP_VAX_float = 0x88; // F or G floating. | 573 | if (err != error.MissingDebugInfo) return err; |
| 574 | pub const ATE_HP_VAX_float_d = 0x89; // D floating. | 574 | break :x null; |
| 575 | pub const ATE_HP_packed_decimal = 0x8a; // Cobol. | 575 | } |
| 576 | pub const ATE_HP_zoned_decimal = 0x8b; // Cobol. | 576 | }; |
| 577 | pub const ATE_HP_edited = 0x8c; // Cobol. | 577 | |
| 578 | pub const ATE_HP_signed_fixed = 0x8d; // Cobol. | 578 | try di.compile_unit_list.append(CompileUnit{ |
| 579 | pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol. | 579 | .version = version, |
| 580 | pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex. | 580 | .is_64 = is_64, |
| 581 | pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex. | 581 | .pc_range = pc_range, |
| 582 | 582 | .die = compile_unit_die, | |
| 583 | pub const CFA_advance_loc = 0x40; | 583 | }); |
| 584 | pub const CFA_offset = 0x80; | 584 | |
| 585 | pub const CFA_restore = 0xc0; | 585 | this_unit_offset += next_offset; |
| 586 | pub const CFA_nop = 0x00; | 586 | } |
| 587 | pub const CFA_set_loc = 0x01; | 587 | } |
| 588 | pub const CFA_advance_loc1 = 0x02; | 588 | |
| 589 | pub const CFA_advance_loc2 = 0x03; | 589 | fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { |
| 590 | pub const CFA_advance_loc4 = 0x04; | 590 | for (di.compile_unit_list.toSlice()) |*compile_unit| { |
| 591 | pub const CFA_offset_extended = 0x05; | 591 | if (compile_unit.pc_range) |range| { |
| 592 | pub const CFA_restore_extended = 0x06; | 592 | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 593 | pub const CFA_undefined = 0x07; | 593 | } |
| 594 | pub const CFA_same_value = 0x08; | 594 | if (di.debug_ranges) |debug_ranges| { |
| 595 | pub const CFA_register = 0x09; | 595 | if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| { |
| 596 | pub const CFA_remember_state = 0x0a; | 596 | var s = io.SliceSeekableInStream.init(debug_ranges); |
| 597 | pub const CFA_restore_state = 0x0b; | 597 | |
| 598 | pub const CFA_def_cfa = 0x0c; | 598 | // All the addresses in the list are relative to the value |
| 599 | pub const CFA_def_cfa_register = 0x0d; | 599 | // specified by DW_AT_low_pc or to some other value encoded |
| 600 | pub const CFA_def_cfa_offset = 0x0e; | 600 | // in the list itself. |
| 601 | 601 | // 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) { |
| 603 | pub const CFA_def_cfa_expression = 0x0f; | 603 | error.MissingDebugInfo => 0, |
| 604 | pub const CFA_expression = 0x10; | 604 | else => return err, |
| 605 | pub const CFA_offset_extended_sf = 0x11; | 605 | }; |
| 606 | pub const CFA_def_cfa_sf = 0x12; | 606 | |
| 607 | pub const CFA_def_cfa_offset_sf = 0x13; | 607 | try s.seekable_stream.seekTo(ranges_offset); |
| 608 | pub const CFA_val_offset = 0x14; | 608 | |
| 609 | pub const CFA_val_offset_sf = 0x15; | 609 | while (true) { |
| 610 | pub const CFA_val_expression = 0x16; | 610 | const begin_addr = try s.stream.readIntLittle(usize); |
| 611 | 611 | const end_addr = try s.stream.readIntLittle(usize); | |
| 612 | pub const CFA_lo_user = 0x1c; | 612 | if (begin_addr == 0 and end_addr == 0) { |
| 613 | pub const CFA_hi_user = 0x3f; | 613 | break; |
| 614 | 614 | } | |
| 615 | // SGI/MIPS specific. | 615 | // This entry selects a new value for the base address |
| 616 | pub const CFA_MIPS_advance_loc8 = 0x1d; | 616 | if (begin_addr == math.maxInt(usize)) { |
| 617 | 617 | base_address = end_addr; | |
| 618 | // GNU extensions. | 618 | continue; |
| 619 | pub const CFA_GNU_window_save = 0x2d; | 619 | } |
| 620 | pub const CFA_GNU_args_size = 0x2e; | 620 | if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { |
| 621 | pub const CFA_GNU_negative_offset_extended = 0x2f; | 621 | return compile_unit; |
| 622 | 622 | } | |
| 623 | pub const CHILDREN_no = 0x00; | 623 | } |
| 624 | pub const CHILDREN_yes = 0x01; | 624 | } else |err| { |
| 625 | 625 | if (err != error.MissingDebugInfo) return err; | |
| 626 | pub const LNS_extended_op = 0x00; | 626 | continue; |
| 627 | pub const LNS_copy = 0x01; | 627 | } |
| 628 | pub const LNS_advance_pc = 0x02; | 628 | } |
| 629 | pub const LNS_advance_line = 0x03; | 629 | } |
| 630 | pub const LNS_set_file = 0x04; | 630 | return error.MissingDebugInfo; |
| 631 | pub const LNS_set_column = 0x05; | 631 | } |
| 632 | pub const LNS_negate_stmt = 0x06; | 632 | |
| 633 | pub const LNS_set_basic_block = 0x07; | 633 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 634 | pub const LNS_const_add_pc = 0x08; | 634 | /// seeks in the stream and parses it. |
| 635 | pub const LNS_fixed_advance_pc = 0x09; | 635 | fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 636 | pub const LNS_set_prologue_end = 0x0a; | 636 | for (di.abbrev_table_list.toSlice()) |*header| { |
| 637 | pub const LNS_set_epilogue_begin = 0x0b; | 637 | if (header.offset == abbrev_offset) { |
| 638 | pub const LNS_set_isa = 0x0c; | 638 | return &header.table; |
| 639 | 639 | } | |
| 640 | pub const LNE_end_sequence = 0x01; | 640 | } |
| 641 | pub const LNE_set_address = 0x02; | 641 | try di.abbrev_table_list.append(AbbrevTableHeader{ |
| 642 | pub const LNE_define_file = 0x03; | 642 | .offset = abbrev_offset, |
| 643 | pub const LNE_set_discriminator = 0x04; | 643 | .table = try di.parseAbbrevTable(abbrev_offset), |
| 644 | pub const LNE_lo_user = 0x80; | 644 | }); |
| 645 | pub const LNE_hi_user = 0xff; | 645 | return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table; |
| 646 | 646 | } | |
| 647 | pub const LANG_C89 = 0x0001; | 647 | |
| 648 | pub const LANG_C = 0x0002; | 648 | fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable { |
| 649 | pub const LANG_Ada83 = 0x0003; | 649 | var s = io.SliceSeekableInStream.init(di.debug_abbrev); |
| 650 | pub const LANG_C_plus_plus = 0x0004; | 650 | |
| 651 | pub const LANG_Cobol74 = 0x0005; | 651 | try s.seekable_stream.seekTo(offset); |
| 652 | pub const LANG_Cobol85 = 0x0006; | 652 | var result = AbbrevTable.init(di.allocator()); |
| 653 | pub const LANG_Fortran77 = 0x0007; | 653 | errdefer result.deinit(); |
| 654 | pub const LANG_Fortran90 = 0x0008; | 654 | while (true) { |
| 655 | pub const LANG_Pascal83 = 0x0009; | 655 | const abbrev_code = try leb.readULEB128(u64, &s.stream); |
| 656 | pub const LANG_Modula2 = 0x000a; | 656 | if (abbrev_code == 0) return result; |
| 657 | pub const LANG_Java = 0x000b; | 657 | try result.append(AbbrevTableEntry{ |
| 658 | pub const LANG_C99 = 0x000c; | 658 | .abbrev_code = abbrev_code, |
| 659 | pub const LANG_Ada95 = 0x000d; | 659 | .tag_id = try leb.readULEB128(u64, &s.stream), |
| 660 | pub const LANG_Fortran95 = 0x000e; | 660 | .has_children = (try s.stream.readByte()) == CHILDREN_yes, |
| 661 | pub const LANG_PLI = 0x000f; | 661 | .attrs = ArrayList(AbbrevAttr).init(di.allocator()), |
| 662 | pub const LANG_ObjC = 0x0010; | 662 | }); |
| 663 | pub const LANG_ObjC_plus_plus = 0x0011; | 663 | const attrs = &result.items[result.len - 1].attrs; |
| 664 | pub const LANG_UPC = 0x0012; | 664 | |
| 665 | pub const LANG_D = 0x0013; | 665 | while (true) { |
| 666 | pub const LANG_Python = 0x0014; | 666 | const attr_id = try leb.readULEB128(u64, &s.stream); |
| 667 | pub const LANG_Go = 0x0016; | 667 | const form_id = try leb.readULEB128(u64, &s.stream); |
| 668 | pub const LANG_C_plus_plus_11 = 0x001a; | 668 | if (attr_id == 0 and form_id == 0) break; |
| 669 | pub const LANG_Rust = 0x001c; | 669 | try attrs.append(AbbrevAttr{ |
| 670 | pub const LANG_C11 = 0x001d; | 670 | .attr_id = attr_id, |
| 671 | pub const LANG_C_plus_plus_14 = 0x0021; | 671 | .form_id = form_id, |
| 672 | pub const LANG_Fortran03 = 0x0022; | 672 | }); |
| 673 | pub const LANG_Fortran08 = 0x0023; | 673 | } |
| 674 | pub const LANG_lo_user = 0x8000; | 674 | } |
| 675 | pub const LANG_hi_user = 0xffff; | 675 | } |
| 676 | pub const LANG_Mips_Assembler = 0x8001; | 676 | |
| 677 | pub const LANG_Upc = 0x8765; | 677 | fn parseDie(di: *DwarfInfo, in_stream: var, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { |
| 678 | pub const LANG_HP_Bliss = 0x8003; | 678 | const abbrev_code = try leb.readULEB128(u64, in_stream); |
| 679 | pub const LANG_HP_Basic91 = 0x8004; | 679 | if (abbrev_code == 0) return null; |
| 680 | pub const LANG_HP_Pascal91 = 0x8005; | 680 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; |
| 681 | pub const LANG_HP_IMacro = 0x8006; | 681 | |
| 682 | pub 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 | ||
| 885 | pub 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 @@ | ||
| 1 | pub const TAG_padding = 0x00; | ||
| 2 | pub const TAG_array_type = 0x01; | ||
| 3 | pub const TAG_class_type = 0x02; | ||
| 4 | pub const TAG_entry_point = 0x03; | ||
| 5 | pub const TAG_enumeration_type = 0x04; | ||
| 6 | pub const TAG_formal_parameter = 0x05; | ||
| 7 | pub const TAG_imported_declaration = 0x08; | ||
| 8 | pub const TAG_label = 0x0a; | ||
| 9 | pub const TAG_lexical_block = 0x0b; | ||
| 10 | pub const TAG_member = 0x0d; | ||
| 11 | pub const TAG_pointer_type = 0x0f; | ||
| 12 | pub const TAG_reference_type = 0x10; | ||
| 13 | pub const TAG_compile_unit = 0x11; | ||
| 14 | pub const TAG_string_type = 0x12; | ||
| 15 | pub const TAG_structure_type = 0x13; | ||
| 16 | pub const TAG_subroutine = 0x14; | ||
| 17 | pub const TAG_subroutine_type = 0x15; | ||
| 18 | pub const TAG_typedef = 0x16; | ||
| 19 | pub const TAG_union_type = 0x17; | ||
| 20 | pub const TAG_unspecified_parameters = 0x18; | ||
| 21 | pub const TAG_variant = 0x19; | ||
| 22 | pub const TAG_common_block = 0x1a; | ||
| 23 | pub const TAG_common_inclusion = 0x1b; | ||
| 24 | pub const TAG_inheritance = 0x1c; | ||
| 25 | pub const TAG_inlined_subroutine = 0x1d; | ||
| 26 | pub const TAG_module = 0x1e; | ||
| 27 | pub const TAG_ptr_to_member_type = 0x1f; | ||
| 28 | pub const TAG_set_type = 0x20; | ||
| 29 | pub const TAG_subrange_type = 0x21; | ||
| 30 | pub const TAG_with_stmt = 0x22; | ||
| 31 | pub const TAG_access_declaration = 0x23; | ||
| 32 | pub const TAG_base_type = 0x24; | ||
| 33 | pub const TAG_catch_block = 0x25; | ||
| 34 | pub const TAG_const_type = 0x26; | ||
| 35 | pub const TAG_constant = 0x27; | ||
| 36 | pub const TAG_enumerator = 0x28; | ||
| 37 | pub const TAG_file_type = 0x29; | ||
| 38 | pub const TAG_friend = 0x2a; | ||
| 39 | pub const TAG_namelist = 0x2b; | ||
| 40 | pub const TAG_namelist_item = 0x2c; | ||
| 41 | pub const TAG_packed_type = 0x2d; | ||
| 42 | pub const TAG_subprogram = 0x2e; | ||
| 43 | pub const TAG_template_type_param = 0x2f; | ||
| 44 | pub const TAG_template_value_param = 0x30; | ||
| 45 | pub const TAG_thrown_type = 0x31; | ||
| 46 | pub const TAG_try_block = 0x32; | ||
| 47 | pub const TAG_variant_part = 0x33; | ||
| 48 | pub const TAG_variable = 0x34; | ||
| 49 | pub const TAG_volatile_type = 0x35; | ||
| 50 | |||
| 51 | // DWARF 3 | ||
| 52 | pub const TAG_dwarf_procedure = 0x36; | ||
| 53 | pub const TAG_restrict_type = 0x37; | ||
| 54 | pub const TAG_interface_type = 0x38; | ||
| 55 | pub const TAG_namespace = 0x39; | ||
| 56 | pub const TAG_imported_module = 0x3a; | ||
| 57 | pub const TAG_unspecified_type = 0x3b; | ||
| 58 | pub const TAG_partial_unit = 0x3c; | ||
| 59 | pub const TAG_imported_unit = 0x3d; | ||
| 60 | pub const TAG_condition = 0x3f; | ||
| 61 | pub const TAG_shared_type = 0x40; | ||
| 62 | |||
| 63 | // DWARF 4 | ||
| 64 | pub const TAG_type_unit = 0x41; | ||
| 65 | pub const TAG_rvalue_reference_type = 0x42; | ||
| 66 | pub const TAG_template_alias = 0x43; | ||
| 67 | |||
| 68 | pub const TAG_lo_user = 0x4080; | ||
| 69 | pub const TAG_hi_user = 0xffff; | ||
| 70 | |||
| 71 | // SGI/MIPS Extensions. | ||
| 72 | pub const DW_TAG_MIPS_loop = 0x4081; | ||
| 73 | |||
| 74 | // HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . | ||
| 75 | pub const TAG_HP_array_descriptor = 0x4090; | ||
| 76 | pub const TAG_HP_Bliss_field = 0x4091; | ||
| 77 | pub const TAG_HP_Bliss_field_set = 0x4092; | ||
| 78 | |||
| 79 | // GNU extensions. | ||
| 80 | pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90. | ||
| 81 | pub const TAG_function_template = 0x4102; // For C++. | ||
| 82 | pub const TAG_class_template = 0x4103; //For C++. | ||
| 83 | pub const TAG_GNU_BINCL = 0x4104; | ||
| 84 | pub const TAG_GNU_EINCL = 0x4105; | ||
| 85 | |||
| 86 | // Template template parameter. | ||
| 87 | // See http://gcc.gnu.org/wiki/TemplateParmsDwarf . | ||
| 88 | pub 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. | ||
| 94 | pub const TAG_GNU_template_parameter_pack = 0x4107; | ||
| 95 | pub 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. | ||
| 100 | pub const TAG_GNU_call_site = 0x4109; | ||
| 101 | pub const TAG_GNU_call_site_parameter = 0x410a; | ||
| 102 | // Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf. | ||
| 103 | pub const TAG_upc_shared_type = 0x8765; | ||
| 104 | pub const TAG_upc_strict_type = 0x8766; | ||
| 105 | pub const TAG_upc_relaxed_type = 0x8767; | ||
| 106 | // PGI (STMicroelectronics; extensions. No documentation available. | ||
| 107 | pub const TAG_PGI_kanji_type = 0xA000; | ||
| 108 | pub const TAG_PGI_interface_block = 0xA020; | ||
| 109 | |||
| 110 | pub const FORM_addr = 0x01; | ||
| 111 | pub const FORM_block2 = 0x03; | ||
| 112 | pub const FORM_block4 = 0x04; | ||
| 113 | pub const FORM_data2 = 0x05; | ||
| 114 | pub const FORM_data4 = 0x06; | ||
| 115 | pub const FORM_data8 = 0x07; | ||
| 116 | pub const FORM_string = 0x08; | ||
| 117 | pub const FORM_block = 0x09; | ||
| 118 | pub const FORM_block1 = 0x0a; | ||
| 119 | pub const FORM_data1 = 0x0b; | ||
| 120 | pub const FORM_flag = 0x0c; | ||
| 121 | pub const FORM_sdata = 0x0d; | ||
| 122 | pub const FORM_strp = 0x0e; | ||
| 123 | pub const FORM_udata = 0x0f; | ||
| 124 | pub const FORM_ref_addr = 0x10; | ||
| 125 | pub const FORM_ref1 = 0x11; | ||
| 126 | pub const FORM_ref2 = 0x12; | ||
| 127 | pub const FORM_ref4 = 0x13; | ||
| 128 | pub const FORM_ref8 = 0x14; | ||
| 129 | pub const FORM_ref_udata = 0x15; | ||
| 130 | pub const FORM_indirect = 0x16; | ||
| 131 | pub const FORM_sec_offset = 0x17; | ||
| 132 | pub const FORM_exprloc = 0x18; | ||
| 133 | pub const FORM_flag_present = 0x19; | ||
| 134 | pub const FORM_ref_sig8 = 0x20; | ||
| 135 | |||
| 136 | // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. | ||
| 137 | pub const FORM_GNU_addr_index = 0x1f01; | ||
| 138 | pub 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 . | ||
| 142 | pub const FORM_GNU_ref_alt = 0x1f20; | ||
| 143 | pub const FORM_GNU_strp_alt = 0x1f21; | ||
| 144 | |||
| 145 | pub const AT_sibling = 0x01; | ||
| 146 | pub const AT_location = 0x02; | ||
| 147 | pub const AT_name = 0x03; | ||
| 148 | pub const AT_ordering = 0x09; | ||
| 149 | pub const AT_subscr_data = 0x0a; | ||
| 150 | pub const AT_byte_size = 0x0b; | ||
| 151 | pub const AT_bit_offset = 0x0c; | ||
| 152 | pub const AT_bit_size = 0x0d; | ||
| 153 | pub const AT_element_list = 0x0f; | ||
| 154 | pub const AT_stmt_list = 0x10; | ||
| 155 | pub const AT_low_pc = 0x11; | ||
| 156 | pub const AT_high_pc = 0x12; | ||
| 157 | pub const AT_language = 0x13; | ||
| 158 | pub const AT_member = 0x14; | ||
| 159 | pub const AT_discr = 0x15; | ||
| 160 | pub const AT_discr_value = 0x16; | ||
| 161 | pub const AT_visibility = 0x17; | ||
| 162 | pub const AT_import = 0x18; | ||
| 163 | pub const AT_string_length = 0x19; | ||
| 164 | pub const AT_common_reference = 0x1a; | ||
| 165 | pub const AT_comp_dir = 0x1b; | ||
| 166 | pub const AT_const_value = 0x1c; | ||
| 167 | pub const AT_containing_type = 0x1d; | ||
| 168 | pub const AT_default_value = 0x1e; | ||
| 169 | pub const AT_inline = 0x20; | ||
| 170 | pub const AT_is_optional = 0x21; | ||
| 171 | pub const AT_lower_bound = 0x22; | ||
| 172 | pub const AT_producer = 0x25; | ||
| 173 | pub const AT_prototyped = 0x27; | ||
| 174 | pub const AT_return_addr = 0x2a; | ||
| 175 | pub const AT_start_scope = 0x2c; | ||
| 176 | pub const AT_bit_stride = 0x2e; | ||
| 177 | pub const AT_upper_bound = 0x2f; | ||
| 178 | pub const AT_abstract_origin = 0x31; | ||
| 179 | pub const AT_accessibility = 0x32; | ||
| 180 | pub const AT_address_class = 0x33; | ||
| 181 | pub const AT_artificial = 0x34; | ||
| 182 | pub const AT_base_types = 0x35; | ||
| 183 | pub const AT_calling_convention = 0x36; | ||
| 184 | pub const AT_count = 0x37; | ||
| 185 | pub const AT_data_member_location = 0x38; | ||
| 186 | pub const AT_decl_column = 0x39; | ||
| 187 | pub const AT_decl_file = 0x3a; | ||
| 188 | pub const AT_decl_line = 0x3b; | ||
| 189 | pub const AT_declaration = 0x3c; | ||
| 190 | pub const AT_discr_list = 0x3d; | ||
| 191 | pub const AT_encoding = 0x3e; | ||
| 192 | pub const AT_external = 0x3f; | ||
| 193 | pub const AT_frame_base = 0x40; | ||
| 194 | pub const AT_friend = 0x41; | ||
| 195 | pub const AT_identifier_case = 0x42; | ||
| 196 | pub const AT_macro_info = 0x43; | ||
| 197 | pub const AT_namelist_items = 0x44; | ||
| 198 | pub const AT_priority = 0x45; | ||
| 199 | pub const AT_segment = 0x46; | ||
| 200 | pub const AT_specification = 0x47; | ||
| 201 | pub const AT_static_link = 0x48; | ||
| 202 | pub const AT_type = 0x49; | ||
| 203 | pub const AT_use_location = 0x4a; | ||
| 204 | pub const AT_variable_parameter = 0x4b; | ||
| 205 | pub const AT_virtuality = 0x4c; | ||
| 206 | pub const AT_vtable_elem_location = 0x4d; | ||
| 207 | |||
| 208 | // DWARF 3 values. | ||
| 209 | pub const AT_allocated = 0x4e; | ||
| 210 | pub const AT_associated = 0x4f; | ||
| 211 | pub const AT_data_location = 0x50; | ||
| 212 | pub const AT_byte_stride = 0x51; | ||
| 213 | pub const AT_entry_pc = 0x52; | ||
| 214 | pub const AT_use_UTF8 = 0x53; | ||
| 215 | pub const AT_extension = 0x54; | ||
| 216 | pub const AT_ranges = 0x55; | ||
| 217 | pub const AT_trampoline = 0x56; | ||
| 218 | pub const AT_call_column = 0x57; | ||
| 219 | pub const AT_call_file = 0x58; | ||
| 220 | pub const AT_call_line = 0x59; | ||
| 221 | pub const AT_description = 0x5a; | ||
| 222 | pub const AT_binary_scale = 0x5b; | ||
| 223 | pub const AT_decimal_scale = 0x5c; | ||
| 224 | pub const AT_small = 0x5d; | ||
| 225 | pub const AT_decimal_sign = 0x5e; | ||
| 226 | pub const AT_digit_count = 0x5f; | ||
| 227 | pub const AT_picture_string = 0x60; | ||
| 228 | pub const AT_mutable = 0x61; | ||
| 229 | pub const AT_threads_scaled = 0x62; | ||
| 230 | pub const AT_explicit = 0x63; | ||
| 231 | pub const AT_object_pointer = 0x64; | ||
| 232 | pub const AT_endianity = 0x65; | ||
| 233 | pub const AT_elemental = 0x66; | ||
| 234 | pub const AT_pure = 0x67; | ||
| 235 | pub const AT_recursive = 0x68; | ||
| 236 | |||
| 237 | // DWARF 4. | ||
| 238 | pub const AT_signature = 0x69; | ||
| 239 | pub const AT_main_subprogram = 0x6a; | ||
| 240 | pub const AT_data_bit_offset = 0x6b; | ||
| 241 | pub const AT_const_expr = 0x6c; | ||
| 242 | pub const AT_enum_class = 0x6d; | ||
| 243 | pub const AT_linkage_name = 0x6e; | ||
| 244 | |||
| 245 | // DWARF 5 | ||
| 246 | pub const AT_alignment = 0x88; | ||
| 247 | |||
| 248 | pub const AT_lo_user = 0x2000; // Implementation-defined range start. | ||
| 249 | pub const AT_hi_user = 0x3fff; // Implementation-defined range end. | ||
| 250 | |||
| 251 | // SGI/MIPS extensions. | ||
| 252 | pub const AT_MIPS_fde = 0x2001; | ||
| 253 | pub const AT_MIPS_loop_begin = 0x2002; | ||
| 254 | pub const AT_MIPS_tail_loop_begin = 0x2003; | ||
| 255 | pub const AT_MIPS_epilog_begin = 0x2004; | ||
| 256 | pub const AT_MIPS_loop_unroll_factor = 0x2005; | ||
| 257 | pub const AT_MIPS_software_pipeline_depth = 0x2006; | ||
| 258 | pub const AT_MIPS_linkage_name = 0x2007; | ||
| 259 | pub const AT_MIPS_stride = 0x2008; | ||
| 260 | pub const AT_MIPS_abstract_name = 0x2009; | ||
| 261 | pub const AT_MIPS_clone_origin = 0x200a; | ||
| 262 | pub const AT_MIPS_has_inlines = 0x200b; | ||
| 263 | |||
| 264 | // HP extensions. | ||
| 265 | pub const AT_HP_block_index = 0x2000; | ||
| 266 | pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde. | ||
| 267 | pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll. | ||
| 268 | pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride. | ||
| 269 | pub const AT_HP_actuals_stmt_list = 0x2010; | ||
| 270 | pub const AT_HP_proc_per_section = 0x2011; | ||
| 271 | pub const AT_HP_raw_data_ptr = 0x2012; | ||
| 272 | pub const AT_HP_pass_by_reference = 0x2013; | ||
| 273 | pub const AT_HP_opt_level = 0x2014; | ||
| 274 | pub const AT_HP_prof_version_id = 0x2015; | ||
| 275 | pub const AT_HP_opt_flags = 0x2016; | ||
| 276 | pub const AT_HP_cold_region_low_pc = 0x2017; | ||
| 277 | pub const AT_HP_cold_region_high_pc = 0x2018; | ||
| 278 | pub const AT_HP_all_variables_modifiable = 0x2019; | ||
| 279 | pub const AT_HP_linkage_name = 0x201a; | ||
| 280 | pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g. | ||
| 281 | pub const AT_HP_unit_name = 0x201f; | ||
| 282 | pub const AT_HP_unit_size = 0x2020; | ||
| 283 | pub const AT_HP_widened_byte_size = 0x2021; | ||
| 284 | pub const AT_HP_definition_points = 0x2022; | ||
| 285 | pub const AT_HP_default_location = 0x2023; | ||
| 286 | pub const AT_HP_is_result_param = 0x2029; | ||
| 287 | |||
| 288 | // GNU extensions. | ||
| 289 | pub const AT_sf_names = 0x2101; | ||
| 290 | pub const AT_src_info = 0x2102; | ||
| 291 | pub const AT_mac_info = 0x2103; | ||
| 292 | pub const AT_src_coords = 0x2104; | ||
| 293 | pub const AT_body_begin = 0x2105; | ||
| 294 | pub const AT_body_end = 0x2106; | ||
| 295 | pub const AT_GNU_vector = 0x2107; | ||
| 296 | // Thread-safety annotations. | ||
| 297 | // See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . | ||
| 298 | pub const AT_GNU_guarded_by = 0x2108; | ||
| 299 | pub const AT_GNU_pt_guarded_by = 0x2109; | ||
| 300 | pub const AT_GNU_guarded = 0x210a; | ||
| 301 | pub const AT_GNU_pt_guarded = 0x210b; | ||
| 302 | pub const AT_GNU_locks_excluded = 0x210c; | ||
| 303 | pub const AT_GNU_exclusive_locks_required = 0x210d; | ||
| 304 | pub const AT_GNU_shared_locks_required = 0x210e; | ||
| 305 | // One-definition rule violation detection. | ||
| 306 | // See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo . | ||
| 307 | pub const AT_GNU_odr_signature = 0x210f; | ||
| 308 | // Template template argument name. | ||
| 309 | // See http://gcc.gnu.org/wiki/TemplateParmsDwarf . | ||
| 310 | pub 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 . | ||
| 313 | pub const AT_GNU_call_site_value = 0x2111; | ||
| 314 | pub const AT_GNU_call_site_data_value = 0x2112; | ||
| 315 | pub const AT_GNU_call_site_target = 0x2113; | ||
| 316 | pub const AT_GNU_call_site_target_clobbered = 0x2114; | ||
| 317 | pub const AT_GNU_tail_call = 0x2115; | ||
| 318 | pub const AT_GNU_all_tail_call_sites = 0x2116; | ||
| 319 | pub const AT_GNU_all_call_sites = 0x2117; | ||
| 320 | pub const AT_GNU_all_source_call_sites = 0x2118; | ||
| 321 | // Section offset into .debug_macro section. | ||
| 322 | pub const AT_GNU_macros = 0x2119; | ||
| 323 | // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. | ||
| 324 | pub const AT_GNU_dwo_name = 0x2130; | ||
| 325 | pub const AT_GNU_dwo_id = 0x2131; | ||
| 326 | pub const AT_GNU_ranges_base = 0x2132; | ||
| 327 | pub const AT_GNU_addr_base = 0x2133; | ||
| 328 | pub const AT_GNU_pubnames = 0x2134; | ||
| 329 | pub const AT_GNU_pubtypes = 0x2135; | ||
| 330 | // VMS extensions. | ||
| 331 | pub 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 . | ||
| 335 | pub const AT_use_GNAT_descriptive_type = 0x2301; | ||
| 336 | pub const AT_GNAT_descriptive_type = 0x2302; | ||
| 337 | // UPC extension. | ||
| 338 | pub const AT_upc_threads_scaled = 0x3210; | ||
| 339 | // PGI (STMicroelectronics) extensions. | ||
| 340 | pub const AT_PGI_lbase = 0x3a00; | ||
| 341 | pub const AT_PGI_soffset = 0x3a01; | ||
| 342 | pub const AT_PGI_lstride = 0x3a02; | ||
| 343 | |||
| 344 | pub const OP_addr = 0x03; | ||
| 345 | pub const OP_deref = 0x06; | ||
| 346 | pub const OP_const1u = 0x08; | ||
| 347 | pub const OP_const1s = 0x09; | ||
| 348 | pub const OP_const2u = 0x0a; | ||
| 349 | pub const OP_const2s = 0x0b; | ||
| 350 | pub const OP_const4u = 0x0c; | ||
| 351 | pub const OP_const4s = 0x0d; | ||
| 352 | pub const OP_const8u = 0x0e; | ||
| 353 | pub const OP_const8s = 0x0f; | ||
| 354 | pub const OP_constu = 0x10; | ||
| 355 | pub const OP_consts = 0x11; | ||
| 356 | pub const OP_dup = 0x12; | ||
| 357 | pub const OP_drop = 0x13; | ||
| 358 | pub const OP_over = 0x14; | ||
| 359 | pub const OP_pick = 0x15; | ||
| 360 | pub const OP_swap = 0x16; | ||
| 361 | pub const OP_rot = 0x17; | ||
| 362 | pub const OP_xderef = 0x18; | ||
| 363 | pub const OP_abs = 0x19; | ||
| 364 | pub const OP_and = 0x1a; | ||
| 365 | pub const OP_div = 0x1b; | ||
| 366 | pub const OP_minus = 0x1c; | ||
| 367 | pub const OP_mod = 0x1d; | ||
| 368 | pub const OP_mul = 0x1e; | ||
| 369 | pub const OP_neg = 0x1f; | ||
| 370 | pub const OP_not = 0x20; | ||
| 371 | pub const OP_or = 0x21; | ||
| 372 | pub const OP_plus = 0x22; | ||
| 373 | pub const OP_plus_uconst = 0x23; | ||
| 374 | pub const OP_shl = 0x24; | ||
| 375 | pub const OP_shr = 0x25; | ||
| 376 | pub const OP_shra = 0x26; | ||
| 377 | pub const OP_xor = 0x27; | ||
| 378 | pub const OP_bra = 0x28; | ||
| 379 | pub const OP_eq = 0x29; | ||
| 380 | pub const OP_ge = 0x2a; | ||
| 381 | pub const OP_gt = 0x2b; | ||
| 382 | pub const OP_le = 0x2c; | ||
| 383 | pub const OP_lt = 0x2d; | ||
| 384 | pub const OP_ne = 0x2e; | ||
| 385 | pub const OP_skip = 0x2f; | ||
| 386 | pub const OP_lit0 = 0x30; | ||
| 387 | pub const OP_lit1 = 0x31; | ||
| 388 | pub const OP_lit2 = 0x32; | ||
| 389 | pub const OP_lit3 = 0x33; | ||
| 390 | pub const OP_lit4 = 0x34; | ||
| 391 | pub const OP_lit5 = 0x35; | ||
| 392 | pub const OP_lit6 = 0x36; | ||
| 393 | pub const OP_lit7 = 0x37; | ||
| 394 | pub const OP_lit8 = 0x38; | ||
| 395 | pub const OP_lit9 = 0x39; | ||
| 396 | pub const OP_lit10 = 0x3a; | ||
| 397 | pub const OP_lit11 = 0x3b; | ||
| 398 | pub const OP_lit12 = 0x3c; | ||
| 399 | pub const OP_lit13 = 0x3d; | ||
| 400 | pub const OP_lit14 = 0x3e; | ||
| 401 | pub const OP_lit15 = 0x3f; | ||
| 402 | pub const OP_lit16 = 0x40; | ||
| 403 | pub const OP_lit17 = 0x41; | ||
| 404 | pub const OP_lit18 = 0x42; | ||
| 405 | pub const OP_lit19 = 0x43; | ||
| 406 | pub const OP_lit20 = 0x44; | ||
| 407 | pub const OP_lit21 = 0x45; | ||
| 408 | pub const OP_lit22 = 0x46; | ||
| 409 | pub const OP_lit23 = 0x47; | ||
| 410 | pub const OP_lit24 = 0x48; | ||
| 411 | pub const OP_lit25 = 0x49; | ||
| 412 | pub const OP_lit26 = 0x4a; | ||
| 413 | pub const OP_lit27 = 0x4b; | ||
| 414 | pub const OP_lit28 = 0x4c; | ||
| 415 | pub const OP_lit29 = 0x4d; | ||
| 416 | pub const OP_lit30 = 0x4e; | ||
| 417 | pub const OP_lit31 = 0x4f; | ||
| 418 | pub const OP_reg0 = 0x50; | ||
| 419 | pub const OP_reg1 = 0x51; | ||
| 420 | pub const OP_reg2 = 0x52; | ||
| 421 | pub const OP_reg3 = 0x53; | ||
| 422 | pub const OP_reg4 = 0x54; | ||
| 423 | pub const OP_reg5 = 0x55; | ||
| 424 | pub const OP_reg6 = 0x56; | ||
| 425 | pub const OP_reg7 = 0x57; | ||
| 426 | pub const OP_reg8 = 0x58; | ||
| 427 | pub const OP_reg9 = 0x59; | ||
| 428 | pub const OP_reg10 = 0x5a; | ||
| 429 | pub const OP_reg11 = 0x5b; | ||
| 430 | pub const OP_reg12 = 0x5c; | ||
| 431 | pub const OP_reg13 = 0x5d; | ||
| 432 | pub const OP_reg14 = 0x5e; | ||
| 433 | pub const OP_reg15 = 0x5f; | ||
| 434 | pub const OP_reg16 = 0x60; | ||
| 435 | pub const OP_reg17 = 0x61; | ||
| 436 | pub const OP_reg18 = 0x62; | ||
| 437 | pub const OP_reg19 = 0x63; | ||
| 438 | pub const OP_reg20 = 0x64; | ||
| 439 | pub const OP_reg21 = 0x65; | ||
| 440 | pub const OP_reg22 = 0x66; | ||
| 441 | pub const OP_reg23 = 0x67; | ||
| 442 | pub const OP_reg24 = 0x68; | ||
| 443 | pub const OP_reg25 = 0x69; | ||
| 444 | pub const OP_reg26 = 0x6a; | ||
| 445 | pub const OP_reg27 = 0x6b; | ||
| 446 | pub const OP_reg28 = 0x6c; | ||
| 447 | pub const OP_reg29 = 0x6d; | ||
| 448 | pub const OP_reg30 = 0x6e; | ||
| 449 | pub const OP_reg31 = 0x6f; | ||
| 450 | pub const OP_breg0 = 0x70; | ||
| 451 | pub const OP_breg1 = 0x71; | ||
| 452 | pub const OP_breg2 = 0x72; | ||
| 453 | pub const OP_breg3 = 0x73; | ||
| 454 | pub const OP_breg4 = 0x74; | ||
| 455 | pub const OP_breg5 = 0x75; | ||
| 456 | pub const OP_breg6 = 0x76; | ||
| 457 | pub const OP_breg7 = 0x77; | ||
| 458 | pub const OP_breg8 = 0x78; | ||
| 459 | pub const OP_breg9 = 0x79; | ||
| 460 | pub const OP_breg10 = 0x7a; | ||
| 461 | pub const OP_breg11 = 0x7b; | ||
| 462 | pub const OP_breg12 = 0x7c; | ||
| 463 | pub const OP_breg13 = 0x7d; | ||
| 464 | pub const OP_breg14 = 0x7e; | ||
| 465 | pub const OP_breg15 = 0x7f; | ||
| 466 | pub const OP_breg16 = 0x80; | ||
| 467 | pub const OP_breg17 = 0x81; | ||
| 468 | pub const OP_breg18 = 0x82; | ||
| 469 | pub const OP_breg19 = 0x83; | ||
| 470 | pub const OP_breg20 = 0x84; | ||
| 471 | pub const OP_breg21 = 0x85; | ||
| 472 | pub const OP_breg22 = 0x86; | ||
| 473 | pub const OP_breg23 = 0x87; | ||
| 474 | pub const OP_breg24 = 0x88; | ||
| 475 | pub const OP_breg25 = 0x89; | ||
| 476 | pub const OP_breg26 = 0x8a; | ||
| 477 | pub const OP_breg27 = 0x8b; | ||
| 478 | pub const OP_breg28 = 0x8c; | ||
| 479 | pub const OP_breg29 = 0x8d; | ||
| 480 | pub const OP_breg30 = 0x8e; | ||
| 481 | pub const OP_breg31 = 0x8f; | ||
| 482 | pub const OP_regx = 0x90; | ||
| 483 | pub const OP_fbreg = 0x91; | ||
| 484 | pub const OP_bregx = 0x92; | ||
| 485 | pub const OP_piece = 0x93; | ||
| 486 | pub const OP_deref_size = 0x94; | ||
| 487 | pub const OP_xderef_size = 0x95; | ||
| 488 | pub const OP_nop = 0x96; | ||
| 489 | |||
| 490 | // DWARF 3 extensions. | ||
| 491 | pub const OP_push_object_address = 0x97; | ||
| 492 | pub const OP_call2 = 0x98; | ||
| 493 | pub const OP_call4 = 0x99; | ||
| 494 | pub const OP_call_ref = 0x9a; | ||
| 495 | pub const OP_form_tls_address = 0x9b; | ||
| 496 | pub const OP_call_frame_cfa = 0x9c; | ||
| 497 | pub const OP_bit_piece = 0x9d; | ||
| 498 | |||
| 499 | // DWARF 4 extensions. | ||
| 500 | pub const OP_implicit_value = 0x9e; | ||
| 501 | pub const OP_stack_value = 0x9f; | ||
| 502 | |||
| 503 | pub const OP_lo_user = 0xe0; // Implementation-defined range start. | ||
| 504 | pub const OP_hi_user = 0xff; // Implementation-defined range end. | ||
| 505 | |||
| 506 | // GNU extensions. | ||
| 507 | pub const OP_GNU_push_tls_address = 0xe0; | ||
| 508 | // The following is for marking variables that are uninitialized. | ||
| 509 | pub const OP_GNU_uninit = 0xf0; | ||
| 510 | pub 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 . | ||
| 513 | pub 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 . | ||
| 516 | pub const OP_GNU_entry_value = 0xf3; | ||
| 517 | // The GNU typed stack extension. | ||
| 518 | // See http://www.dwarfstd.org/doc/040408.1.html . | ||
| 519 | pub const OP_GNU_const_type = 0xf4; | ||
| 520 | pub const OP_GNU_regval_type = 0xf5; | ||
| 521 | pub const OP_GNU_deref_type = 0xf6; | ||
| 522 | pub const OP_GNU_convert = 0xf7; | ||
| 523 | pub const OP_GNU_reinterpret = 0xf9; | ||
| 524 | // The GNU parameter ref extension. | ||
| 525 | pub const OP_GNU_parameter_ref = 0xfa; | ||
| 526 | // Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. | ||
| 527 | pub const OP_GNU_addr_index = 0xfb; | ||
| 528 | pub const OP_GNU_const_index = 0xfc; | ||
| 529 | // HP extensions. | ||
| 530 | pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address. | ||
| 531 | pub const OP_HP_is_value = 0xe1; | ||
| 532 | pub const OP_HP_fltconst4 = 0xe2; | ||
| 533 | pub const OP_HP_fltconst8 = 0xe3; | ||
| 534 | pub const OP_HP_mod_range = 0xe4; | ||
| 535 | pub const OP_HP_unmod_range = 0xe5; | ||
| 536 | pub const OP_HP_tls = 0xe6; | ||
| 537 | // PGI (STMicroelectronics) extensions. | ||
| 538 | pub const OP_PGI_omp_thread_num = 0xf8; | ||
| 539 | |||
| 540 | pub const ATE_void = 0x0; | ||
| 541 | pub const ATE_address = 0x1; | ||
| 542 | pub const ATE_boolean = 0x2; | ||
| 543 | pub const ATE_complex_float = 0x3; | ||
| 544 | pub const ATE_float = 0x4; | ||
| 545 | pub const ATE_signed = 0x5; | ||
| 546 | pub const ATE_signed_char = 0x6; | ||
| 547 | pub const ATE_unsigned = 0x7; | ||
| 548 | pub const ATE_unsigned_char = 0x8; | ||
| 549 | |||
| 550 | // DWARF 3. | ||
| 551 | pub const ATE_imaginary_float = 0x9; | ||
| 552 | pub const ATE_packed_decimal = 0xa; | ||
| 553 | pub const ATE_numeric_string = 0xb; | ||
| 554 | pub const ATE_edited = 0xc; | ||
| 555 | pub const ATE_signed_fixed = 0xd; | ||
| 556 | pub const ATE_unsigned_fixed = 0xe; | ||
| 557 | pub const ATE_decimal_float = 0xf; | ||
| 558 | |||
| 559 | // DWARF 4. | ||
| 560 | pub const ATE_UTF = 0x10; | ||
| 561 | |||
| 562 | pub const ATE_lo_user = 0x80; | ||
| 563 | pub const ATE_hi_user = 0xff; | ||
| 564 | |||
| 565 | // HP extensions. | ||
| 566 | pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit). | ||
| 567 | pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit). | ||
| 568 | pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit). | ||
| 569 | pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit). | ||
| 570 | pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64). | ||
| 571 | pub const ATE_HP_imaginary_float80 = 0x85; | ||
| 572 | pub const ATE_HP_imaginary_float128 = 0x86; | ||
| 573 | pub const ATE_HP_VAX_float = 0x88; // F or G floating. | ||
| 574 | pub const ATE_HP_VAX_float_d = 0x89; // D floating. | ||
| 575 | pub const ATE_HP_packed_decimal = 0x8a; // Cobol. | ||
| 576 | pub const ATE_HP_zoned_decimal = 0x8b; // Cobol. | ||
| 577 | pub const ATE_HP_edited = 0x8c; // Cobol. | ||
| 578 | pub const ATE_HP_signed_fixed = 0x8d; // Cobol. | ||
| 579 | pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol. | ||
| 580 | pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex. | ||
| 581 | pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex. | ||
| 582 | |||
| 583 | pub const CFA_advance_loc = 0x40; | ||
| 584 | pub const CFA_offset = 0x80; | ||
| 585 | pub const CFA_restore = 0xc0; | ||
| 586 | pub const CFA_nop = 0x00; | ||
| 587 | pub const CFA_set_loc = 0x01; | ||
| 588 | pub const CFA_advance_loc1 = 0x02; | ||
| 589 | pub const CFA_advance_loc2 = 0x03; | ||
| 590 | pub const CFA_advance_loc4 = 0x04; | ||
| 591 | pub const CFA_offset_extended = 0x05; | ||
| 592 | pub const CFA_restore_extended = 0x06; | ||
| 593 | pub const CFA_undefined = 0x07; | ||
| 594 | pub const CFA_same_value = 0x08; | ||
| 595 | pub const CFA_register = 0x09; | ||
| 596 | pub const CFA_remember_state = 0x0a; | ||
| 597 | pub const CFA_restore_state = 0x0b; | ||
| 598 | pub const CFA_def_cfa = 0x0c; | ||
| 599 | pub const CFA_def_cfa_register = 0x0d; | ||
| 600 | pub const CFA_def_cfa_offset = 0x0e; | ||
| 601 | |||
| 602 | // DWARF 3. | ||
| 603 | pub const CFA_def_cfa_expression = 0x0f; | ||
| 604 | pub const CFA_expression = 0x10; | ||
| 605 | pub const CFA_offset_extended_sf = 0x11; | ||
| 606 | pub const CFA_def_cfa_sf = 0x12; | ||
| 607 | pub const CFA_def_cfa_offset_sf = 0x13; | ||
| 608 | pub const CFA_val_offset = 0x14; | ||
| 609 | pub const CFA_val_offset_sf = 0x15; | ||
| 610 | pub const CFA_val_expression = 0x16; | ||
| 611 | |||
| 612 | pub const CFA_lo_user = 0x1c; | ||
| 613 | pub const CFA_hi_user = 0x3f; | ||
| 614 | |||
| 615 | // SGI/MIPS specific. | ||
| 616 | pub const CFA_MIPS_advance_loc8 = 0x1d; | ||
| 617 | |||
| 618 | // GNU extensions. | ||
| 619 | pub const CFA_GNU_window_save = 0x2d; | ||
| 620 | pub const CFA_GNU_args_size = 0x2e; | ||
| 621 | pub const CFA_GNU_negative_offset_extended = 0x2f; | ||
| 622 | |||
| 623 | pub const CHILDREN_no = 0x00; | ||
| 624 | pub const CHILDREN_yes = 0x01; | ||
| 625 | |||
| 626 | pub const LNS_extended_op = 0x00; | ||
| 627 | pub const LNS_copy = 0x01; | ||
| 628 | pub const LNS_advance_pc = 0x02; | ||
| 629 | pub const LNS_advance_line = 0x03; | ||
| 630 | pub const LNS_set_file = 0x04; | ||
| 631 | pub const LNS_set_column = 0x05; | ||
| 632 | pub const LNS_negate_stmt = 0x06; | ||
| 633 | pub const LNS_set_basic_block = 0x07; | ||
| 634 | pub const LNS_const_add_pc = 0x08; | ||
| 635 | pub const LNS_fixed_advance_pc = 0x09; | ||
| 636 | pub const LNS_set_prologue_end = 0x0a; | ||
| 637 | pub const LNS_set_epilogue_begin = 0x0b; | ||
| 638 | pub const LNS_set_isa = 0x0c; | ||
| 639 | |||
| 640 | pub const LNE_end_sequence = 0x01; | ||
| 641 | pub const LNE_set_address = 0x02; | ||
| 642 | pub const LNE_define_file = 0x03; | ||
| 643 | pub const LNE_set_discriminator = 0x04; | ||
| 644 | pub const LNE_lo_user = 0x80; | ||
| 645 | pub const LNE_hi_user = 0xff; | ||
| 646 | |||
| 647 | pub const LANG_C89 = 0x0001; | ||
| 648 | pub const LANG_C = 0x0002; | ||
| 649 | pub const LANG_Ada83 = 0x0003; | ||
| 650 | pub const LANG_C_plus_plus = 0x0004; | ||
| 651 | pub const LANG_Cobol74 = 0x0005; | ||
| 652 | pub const LANG_Cobol85 = 0x0006; | ||
| 653 | pub const LANG_Fortran77 = 0x0007; | ||
| 654 | pub const LANG_Fortran90 = 0x0008; | ||
| 655 | pub const LANG_Pascal83 = 0x0009; | ||
| 656 | pub const LANG_Modula2 = 0x000a; | ||
| 657 | pub const LANG_Java = 0x000b; | ||
| 658 | pub const LANG_C99 = 0x000c; | ||
| 659 | pub const LANG_Ada95 = 0x000d; | ||
| 660 | pub const LANG_Fortran95 = 0x000e; | ||
| 661 | pub const LANG_PLI = 0x000f; | ||
| 662 | pub const LANG_ObjC = 0x0010; | ||
| 663 | pub const LANG_ObjC_plus_plus = 0x0011; | ||
| 664 | pub const LANG_UPC = 0x0012; | ||
| 665 | pub const LANG_D = 0x0013; | ||
| 666 | pub const LANG_Python = 0x0014; | ||
| 667 | pub const LANG_Go = 0x0016; | ||
| 668 | pub const LANG_C_plus_plus_11 = 0x001a; | ||
| 669 | pub const LANG_Rust = 0x001c; | ||
| 670 | pub const LANG_C11 = 0x001d; | ||
| 671 | pub const LANG_C_plus_plus_14 = 0x0021; | ||
| 672 | pub const LANG_Fortran03 = 0x0022; | ||
| 673 | pub const LANG_Fortran08 = 0x0023; | ||
| 674 | pub const LANG_lo_user = 0x8000; | ||
| 675 | pub const LANG_hi_user = 0xffff; | ||
| 676 | pub const LANG_Mips_Assembler = 0x8001; | ||
| 677 | pub const LANG_Upc = 0x8765; | ||
| 678 | pub const LANG_HP_Bliss = 0x8003; | ||
| 679 | pub const LANG_HP_Basic91 = 0x8004; | ||
| 680 | pub const LANG_HP_Pascal91 = 0x8005; | ||
| 681 | pub const LANG_HP_IMacro = 0x8006; | ||
| 682 | pub 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; |
| 11 | const maxInt = std.math.maxInt; | 11 | const maxInt = std.math.maxInt; |
| 12 | const max = std.math.max; | 12 | const max = std.math.max; |
| 13 | 13 | ||
| 14 | pub const DynLib = switch (builtin.os) { | 14 | pub 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 the | 91 | // The address to the link_map structure is stored in the |
| 92 | // second slot | 92 | // 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 | }; |
| 391 | 391 | ||
| 392 | test "dynamic_library" { | 392 | test "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, |
| 351 | 351 | ||
| 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 | }; |
| 381 | 371 | ||
| 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 | }; |
| 387 | 377 | ||
| ... | @@ -554,6 +544,21 @@ pub const Elf = struct { | ... | @@ -554,6 +544,21 @@ pub const Elf = struct { |
| 554 | }; | 544 | }; |
| 555 | 545 | ||
| 556 | pub const EI_NIDENT = 16; | 546 | pub const EI_NIDENT = 16; |
| 547 | |||
| 548 | pub const EI_CLASS = 4; | ||
| 549 | pub const ELFCLASSNONE = 0; | ||
| 550 | pub const ELFCLASS32 = 1; | ||
| 551 | pub const ELFCLASS64 = 2; | ||
| 552 | pub const ELFCLASSNUM = 3; | ||
| 553 | |||
| 554 | pub const EI_DATA = 5; | ||
| 555 | pub const ELFDATANONE = 0; | ||
| 556 | pub const ELFDATA2LSB = 1; | ||
| 557 | pub const ELFDATA2MSB = 2; | ||
| 558 | pub const ELFDATANUM = 3; | ||
| 559 | |||
| 560 | pub const EI_VERSION = 6; | ||
| 561 | |||
| 557 | pub const Elf32_Half = u16; | 562 | pub const Elf32_Half = u16; |
| 558 | pub const Elf64_Half = u16; | 563 | pub const Elf64_Half = u16; |
| 559 | pub const Elf32_Word = u32; | 564 | pub 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 | }; |
| 704 | pub const Elf32_Dyn = extern struct { | 709 | pub 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 | }; |
| 711 | pub const Elf64_Dyn = extern struct { | 713 | pub 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 | }; |
| 718 | pub const Elf32_Verdef = extern struct { | 717 | pub 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; |
| 274 | 274 | ||
| 275 | // https://github.com/ziglang/zig/issues/3251 | 275 | // https://github.com/ziglang/zig/issues/3251 |
| 276 | if (builtin.os == .freebsd) return error.SkipZigTest; | 276 | if (builtin.os.tag == .freebsd) return error.SkipZigTest; |
| 277 | 277 | ||
| 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/1908 | 86 | // 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/3251 | 88 | // 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 mode | 90 | // 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; |
| 92 | 92 |
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; |
| 124 | 124 | ||
| 125 | // TODO https://github.com/ziglang/zig/issues/3251 | 125 | // 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; |
| 127 | 127 | ||
| 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, |
| 36 | 36 | ||
| 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 | }; |
| 54 | 54 | ||
| 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 | }; |
| 73 | 73 | ||
| 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; |
| 174 | 174 | ||
| 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 | } |
| 405 | 405 | ||
| 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 { |
| 628 | 628 | ||
| 629 | self.workerRun(); | 629 | self.workerRun(); |
| 630 | 630 | ||
| 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 stop | 680 | // 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 fail | 684 | // 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 | } |
| 904 | 904 | ||
| 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 threads | 907 | // 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 msg | 990 | 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/3157 | 1018 | // 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 | } |
| 1073 | 1073 | ||
| 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 to | 29 | /// 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. |
| 32 | pub const MAX_PATH_BYTES = switch (builtin.os) { | 32 | pub 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 surrogate | 35 | // 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( |
| 47 | 47 | ||
| 48 | /// Whether or not async file system syscalls need a dedicated thread because the operating | 48 | /// 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. |
| 50 | pub const need_async_thread = std.io.is_async and switch (builtin.os) { | 50 | pub 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 { |
| 394 | 394 | ||
| 395 | const IteratorError = error{AccessDenied} || os.UnexpectedError; | 395 | const IteratorError = error{AccessDenied} || os.UnexpectedError; |
| 396 | 396 | ||
| 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 invalid | 409 | /// 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 | }; |
| 645 | 645 | ||
| 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 { |
| 720 | 720 | ||
| 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 | else | 732 | 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 | else | 736 | 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 | } |
| 740 | 747 | ||
| 741 | /// Same as `openFile` but Windows-only and the path parameter is | 748 | /// 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 { |
| 763 | 770 | ||
| 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 { |
| 923 | 930 | ||
| 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 { |
| 934 | 941 | ||
| 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, just | 1340 | /// 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 { |
| 1343 | 1350 | ||
| 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. |
| 1376 | pub fn cwd() Dir { | 1383 | pub 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 { |
| 1553 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; | 1560 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; |
| 1554 | 1561 | ||
| 1555 | pub fn openSelfExe() OpenSelfExeError!File { | 1562 | pub 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 | } |
| 1569 | 1576 | ||
| 1570 | test "openSelfExe" { | 1577 | test "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. |
| 1637 | pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 { | 1644 | pub 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 directory | 1648 | // 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, |
| 22 | 22 | ||
| 23 | /// Even when std.io.mode is async, it is still sometimes desirable to perform blocking I/O, although | 23 | /// 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, |
| 26 | 26 | ||
| ... | @@ -29,7 +29,7 @@ pub const File = struct { | ... | @@ -29,7 +29,7 @@ pub const File = struct { |
| 29 | 29 | ||
| 30 | pub const Mode = os.mode_t; | 30 | pub const Mode = os.mode_t; |
| 31 | 31 | ||
| 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 | }; |
| 44 | 49 | ||
| 45 | /// TODO https://github.com/ziglang/zig/issues/3802 | 50 | /// TODO https://github.com/ziglang/zig/issues/3802 |
| ... | @@ -78,7 +83,7 @@ pub const File = struct { | ... | @@ -78,7 +83,7 @@ pub const File = struct { |
| 78 | 83 | ||
| 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 { |
| 123 | 128 | ||
| 124 | /// TODO: integrate with async I/O | 129 | /// 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 { |
| 133 | 138 | ||
| 134 | /// TODO: integrate with async I/O | 139 | /// 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 { |
| 157 | 162 | ||
| 158 | /// TODO: integrate with async I/O | 163 | /// 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 nanoseconds | 209 | /// 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 requirement | 14 | /// TODO determine if we can remove the allocator requirement |
| 15 | pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 { | 15 | pub 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; |
| 13 | 13 | ||
| 14 | pub const sep_windows = '\\'; | 14 | pub const sep_windows = '\\'; |
| 15 | pub const sep_posix = '/'; | 15 | pub const sep_posix = '/'; |
| 16 | pub const sep = if (builtin.os == .windows) sep_windows else sep_posix; | 16 | pub const sep = if (builtin.os.tag == .windows) sep_windows else sep_posix; |
| 17 | 17 | ||
| 18 | pub const sep_str_windows = "\\"; | 18 | pub const sep_str_windows = "\\"; |
| 19 | pub const sep_str_posix = "/"; | 19 | pub const sep_str_posix = "/"; |
| 20 | pub const sep_str = if (builtin.os == .windows) sep_str_windows else sep_str_posix; | 20 | pub const sep_str = if (builtin.os.tag == .windows) sep_str_windows else sep_str_posix; |
| 21 | 21 | ||
| 22 | pub const delimiter_windows = ';'; | 22 | pub const delimiter_windows = ';'; |
| 23 | pub const delimiter_posix = ':'; | 23 | pub const delimiter_posix = ':'; |
| 24 | pub const delimiter = if (builtin.os == .windows) delimiter_windows else delimiter_posix; | 24 | pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix; |
| 25 | 25 | ||
| 26 | pub fn isSep(byte: u8) bool { | 26 | pub 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 | } |
| 76 | 76 | ||
| 77 | pub const join = if (builtin.os == .windows) joinWindows else joinPosix; | 77 | pub const join = if (builtin.os.tag == .windows) joinWindows else joinPosix; |
| 78 | 78 | ||
| 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 | } |
| 130 | 130 | ||
| 131 | pub fn isAbsoluteC(path_c: [*:0]const u8) bool { | 131 | pub 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 | } |
| 138 | 138 | ||
| 139 | pub fn isAbsolute(path: []const u8) bool { | 139 | pub 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 | } |
| 319 | 319 | ||
| 320 | pub fn diskDesignator(path: []const u8) []const u8 { | 320 | pub 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 { |
| 383 | 383 | ||
| 384 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. | 384 | /// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`. |
| 385 | pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 385 | pub 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. |
| 401 | pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 401 | pub 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 getCwd | 403 | 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 | } |
| 406 | 406 | ||
| ... | @@ -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 getCwd | 498 | 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 getCwd | 513 | 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 one | 514 | // 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. |
| 582 | pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 582 | pub 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 getCwd | 584 | 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 | } |
| 587 | 587 | ||
| ... | @@ -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 getCwd | 606 | 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 { |
| 645 | test "resolve" { | 645 | test "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/3288 | 661 | // 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 null | 733 | /// then returns null |
| 734 | pub fn dirname(path: []const u8) ?[]const u8 { | 734 | pub 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 | } |
| 865 | 865 | ||
| 866 | pub fn basename(path: []const u8) []const u8 { | 866 | pub 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 `\\`. |
| 982 | pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 { | 982 | pub 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, |
| 44 | 44 | ||
| 45 | const OsData = switch (builtin.os) { | 45 | const OsData = switch (builtin.os.tag) { |
| 46 | // TODO https://github.com/ziglang/zig/issues/3778 | 46 | // 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); |
| 123 | 123 | ||
| 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 { |
| 172 | 172 | ||
| 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 lock | 177 | // 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 | } |
| 224 | 224 | ||
| 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)); |
| 26 | 26 | ||
| 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 | }, |
| 33 | 33 | ||
| 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 | }, |
| 42 | 42 | ||
| 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 | } |
| 169 | 169 | ||
| 170 | fn mode(comptime x: comptime_int) comptime_int { | 170 | fn 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 | } |
| 173 | 173 | ||
| 174 | pub fn main() !void { | 174 | pub 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); |
| 370 | 370 | ||
| 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); |
| 295 | 295 | ||
| 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; |
| 10 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 11 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 12 | 12 | ||
| 13 | const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast; | 13 | const want_modification_safety = builtin.mode != .ReleaseFast; |
| 14 | const debug_u32 = if (want_modification_safety) u32 else void; | 14 | const debug_u32 = if (want_modification_safety) u32 else void; |
| 15 | 15 | ||
| 16 | pub fn AutoHashMap(comptime K: type, comptime V: type) type { | 16 | pub 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. |
| 37 | pub const page_allocator = if (std.Target.current.isWasm()) | 37 | pub const page_allocator = if (std.Target.current.isWasm()) |
| 38 | &wasm_page_allocator_state | 38 | &wasm_page_allocator_state |
| 39 | else if (std.Target.current.getOs() == .freestanding) | 39 | else if (std.Target.current.os.tag == .freestanding) |
| 40 | root.os.heap.page_allocator | 40 | root.os.heap.page_allocator |
| 41 | else | 41 | else |
| 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{}; |
| 59 | 59 | ||
| 60 | if (builtin.os == .windows) { | 60 | if (builtin.os.tag == .windows) { |
| 61 | const w = os.windows; | 61 | const w = os.windows; |
| 62 | 62 | ||
| 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 { |
| 143 | 143 | ||
| 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 { |
| 183 | 183 | ||
| 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 | }; |
| 414 | 414 | ||
| 415 | pub const HeapAllocator = switch (builtin.os) { | 415 | pub 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 | } |
| 857 | 857 | ||
| 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 sure | 860 | // VirtualAlloc returns 64K aligned addresses. We want to make sure |
| 861 | // PageAllocator works beyond that, as it's not tested by | 861 | // PageAllocator works beyond that, as it's not tested by |
| ... | @@ -868,7 +868,7 @@ test "PageAllocator" { | ... | @@ -868,7 +868,7 @@ test "PageAllocator" { |
| 868 | } | 868 | } |
| 869 | 869 | ||
| 870 | test "HeapAllocator" { | 870 | test "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(); |
| 874 | 874 |
lib/std/io.zig+17-17| ... | @@ -35,7 +35,7 @@ else | ... | @@ -35,7 +35,7 @@ else |
| 35 | pub const is_async = mode != .blocking; | 35 | pub const is_async = mode != .blocking; |
| 36 | 36 | ||
| 37 | fn getStdOutHandle() os.fd_t { | 37 | fn 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 | } |
| 41 | 41 | ||
| ... | @@ -54,7 +54,7 @@ pub fn getStdOut() File { | ... | @@ -54,7 +54,7 @@ pub fn getStdOut() File { |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | fn getStdErrHandle() os.fd_t { | 56 | fn 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 | } |
| 60 | 60 | ||
| ... | @@ -74,7 +74,7 @@ pub fn getStdErr() File { | ... | @@ -74,7 +74,7 @@ pub fn getStdErr() File { |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | fn getStdInHandle() os.fd_t { | 76 | fn 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 | } |
| 80 | 80 | ||
| ... | @@ -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 | }; |
| 377 | 377 | ||
| 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 { |
| 666 | 666 | ||
| 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; |
| 673 | 673 | ||
| ... | @@ -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_buffer | 701 | //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 | } |
| 79 | 79 | ||
| ... | @@ -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 | }; |
| 26 | 26 | ||
| 27 | pub 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.3BSD | 38 | /// 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 files | 39 | /// "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 y | 33 | /// - pow(x, y) = nan for finite x < 0 and finite non-integer y |
| 34 | pub fn pow(comptime T: type, x: T, y: T) T { | 34 | pub 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 | } |
| 38 | 38 |
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); |
| 27 | 27 | ||
| 28 | comptime assert(@typeInfo(T) == builtin.TypeId.Int); | 28 | comptime assert(@typeInfo(T) == .Int); |
| 29 | 29 | ||
| 30 | // powi(x, +-0) = 1 for any x | 30 | // 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 | } |
| 472 | 484 | ||
| 473 | pub 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 | |||
| 479 | pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { | 486 | pub 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 | } |
| 482 | 489 | ||
| 490 | /// Deprecated. Use `span`. | ||
| 483 | pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { | 491 | pub 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. | ||
| 500 | pub 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 | |||
| 520 | test "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. | ||
| 537 | pub 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 | |||
| 547 | test "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. | ||
| 556 | pub 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 | |||
| 575 | test "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 | |||
| 588 | pub 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 | } |
| 486 | 595 | ||
| 487 | /// Returns true if all elements in a slice are equal to the scalar value provided | 596 | /// 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" { |
| 637 | pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType { | 746 | pub 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 | } |
| 671 | 780 | ||
| 672 | pub const readIntLittle = switch (builtin.endian) { | 781 | pub const readIntLittle = switch (builtin.endian) { |
| 673 | builtin.Endian.Little => readIntNative, | 782 | .Little => readIntNative, |
| 674 | builtin.Endian.Big => readIntForeign, | 783 | .Big => readIntForeign, |
| 675 | }; | 784 | }; |
| 676 | 785 | ||
| 677 | pub const readIntBig = switch (builtin.endian) { | 786 | pub const readIntBig = switch (builtin.endian) { |
| 678 | builtin.Endian.Little => readIntForeign, | 787 | .Little => readIntForeign, |
| 679 | builtin.Endian.Big => readIntNative, | 788 | .Big => readIntNative, |
| 680 | }; | 789 | }; |
| 681 | 790 | ||
| 682 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 791 | /// 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 | } |
| 701 | 810 | ||
| 702 | pub const readIntSliceLittle = switch (builtin.endian) { | 811 | pub const readIntSliceLittle = switch (builtin.endian) { |
| 703 | builtin.Endian.Little => readIntSliceNative, | 812 | .Little => readIntSliceNative, |
| 704 | builtin.Endian.Big => readIntSliceForeign, | 813 | .Big => readIntSliceForeign, |
| 705 | }; | 814 | }; |
| 706 | 815 | ||
| 707 | pub const readIntSliceBig = switch (builtin.endian) { | 816 | pub const readIntSliceBig = switch (builtin.endian) { |
| 708 | builtin.Endian.Little => readIntSliceForeign, | 817 | .Little => readIntSliceForeign, |
| 709 | builtin.Endian.Big => readIntSliceNative, | 818 | .Big => readIntSliceNative, |
| 710 | }; | 819 | }; |
| 711 | 820 | ||
| 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 | } |
| 784 | 893 | ||
| 785 | pub const writeIntLittle = switch (builtin.endian) { | 894 | pub const writeIntLittle = switch (builtin.endian) { |
| 786 | builtin.Endian.Little => writeIntNative, | 895 | .Little => writeIntNative, |
| 787 | builtin.Endian.Big => writeIntForeign, | 896 | .Big => writeIntForeign, |
| 788 | }; | 897 | }; |
| 789 | 898 | ||
| 790 | pub const writeIntBig = switch (builtin.endian) { | 899 | pub const writeIntBig = switch (builtin.endian) { |
| 791 | builtin.Endian.Little => writeIntForeign, | 900 | .Little => writeIntForeign, |
| 792 | builtin.Endian.Big => writeIntNative, | 901 | .Big => writeIntNative, |
| 793 | }; | 902 | }; |
| 794 | 903 | ||
| 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 | } |
| 842 | 951 | ||
| 843 | pub const writeIntSliceNative = switch (builtin.endian) { | 952 | pub const writeIntSliceNative = switch (builtin.endian) { |
| 844 | builtin.Endian.Little => writeIntSliceLittle, | 953 | .Little => writeIntSliceLittle, |
| 845 | builtin.Endian.Big => writeIntSliceBig, | 954 | .Big => writeIntSliceBig, |
| 846 | }; | 955 | }; |
| 847 | 956 | ||
| 848 | pub const writeIntSliceForeign = switch (builtin.endian) { | 957 | pub const writeIntSliceForeign = switch (builtin.endian) { |
| 849 | builtin.Endian.Little => writeIntSliceBig, | 958 | .Little => writeIntSliceBig, |
| 850 | builtin.Endian.Big => writeIntSliceLittle, | 959 | .Big => writeIntSliceLittle, |
| 851 | }; | 960 | }; |
| 852 | 961 | ||
| 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. |
| 859 | pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { | 968 | pub 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 | } |
| 866 | 975 | ||
| 867 | test "writeIntBig and writeIntLittle" { | 976 | test "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. |
| 1398 | pub fn littleToNative(comptime T: type, x: T) T { | 1507 | pub 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 | } |
| 1404 | 1513 | ||
| 1405 | /// Converts a big-endian integer to host endianness. | 1514 | /// Converts a big-endian integer to host endianness. |
| 1406 | pub fn bigToNative(comptime T: type, x: T) T { | 1515 | pub 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 | } |
| 1412 | 1521 | ||
| 1413 | /// Converts an integer from specified endianness to host endianness. | 1522 | /// Converts an integer from specified endianness to host endianness. |
| 1414 | pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { | 1523 | pub 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 | } |
| 1420 | 1529 | ||
| 1421 | /// Converts an integer which has host endianness to the desired endianness. | 1530 | /// Converts an integer which has host endianness to the desired endianness. |
| 1422 | pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { | 1531 | pub 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 | } |
| 1428 | 1537 | ||
| 1429 | /// Converts an integer which has host endianness to little endian. | 1538 | /// Converts an integer which has host endianness to little endian. |
| 1430 | pub fn nativeToLittle(comptime T: type, x: T) T { | 1539 | pub 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 | } |
| 1436 | 1545 | ||
| 1437 | /// Converts an integer which has host endianness to big endian. | 1546 | /// Converts an integer which has host endianness to big endian. |
| 1438 | pub fn nativeToBig(comptime T: type, x: T) T { | 1547 | pub 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 | } |
| 1444 | 1553 | ||
| 1445 | fn AsBytesReturnType(comptime P: type) type { | 1554 | fn 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)); |
| 1448 | 1557 | ||
| 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)) { |
| 1469 | test "asBytes" { | 1578 | test "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 | }; |
| 1475 | 1584 | ||
| 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 { |
| 1508 | test "toBytes" { | 1617 | test "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 | } |
| 1514 | 1623 | ||
| 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 | } |
| 1521 | 1630 | ||
| 1522 | fn BytesAsValueReturnType(comptime T: type, comptime B: type) type { | 1631 | fn BytesAsValueReturnType(comptime T: type, comptime B: type) type { |
| 1523 | const size = @as(usize, @sizeOf(T)); | 1632 | const size = @as(usize, @sizeOf(T)); |
| 1524 | 1633 | ||
| 1525 | if (comptime !trait.is(builtin.TypeId.Pointer)(B) or | 1634 | 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 |
| 1542 | test "bytesAsValue" { | 1651 | test "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 | }; |
| 1548 | 1657 | ||
| 1549 | testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*); | 1658 | testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*); |
| 1550 | 1659 | ||
| 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 | } |
| 1584 | test "bytesToValue" { | 1693 | test "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 | }; |
| 1589 | 1698 | ||
| 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 | } |
| 1755 | 1864 | ||
| 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. |
| 1757 | pub 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 |
| 1867 | pub 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); |
| 1759 | 1873 | ||
| 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 | } |
| 117 | 117 | ||
| 118 | /// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel | ||
| 119 | pub 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 | |||
| 138 | test "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 | |||
| 118 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { | 144 | pub 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 | } |
| 76 | else if (builtin.os == .windows) | 76 | else 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 | } |
| 164 | else if (builtin.link_libc or builtin.os == .linux) | 164 | else 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.rs | 165 | // 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 | } |
| 354 | 354 | ||
| 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) !* |
| 501 | 501 | ||
| 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 | } |
| 64 | 64 | ||
| 65 | test "resolve DNS" { | 65 | test "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" { |
| 81 | test "listen on a port, send bytes, receive bytes" { | 81 | test "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; |
| 83 | 83 | ||
| 84 | if (std.builtin.os != .linux) { | 84 | if (std.builtin.os.tag != .linux) { |
| 85 | // TODO build abstractions for other operating systems | 85 | // 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.system | 56 | root.os.system |
| 57 | else if (builtin.link_libc) | 57 | else if (builtin.link_libc) |
| 58 | std.c | 58 | std.c |
| 59 | else switch (builtin.os) { | 59 | else 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. |
| 95 | pub fn close(fd: fd_t) void { | 95 | pub 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 standard | 121 | /// appropriate OS-specific library call. Otherwise it uses the zig standard |
| 122 | /// library implementation. | 122 | /// library implementation. |
| 123 | pub fn getrandom(buffer: []u8) GetRandomError!void { | 123 | pub 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 or | 129 | 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; |
| 131 | 131 | ||
| 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, so | 188 | // 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 {}; |
| 199 | 199 | ||
| 200 | // TODO the rest of the implementation of abort() from musl libc here | 200 | // 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 code | 206 | 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 | } |
| 225 | 225 | ||
| 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 signals | 228 | // 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 handled | 299 | /// 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. |
| 301 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | 301 | pub 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 | } |
| 305 | 305 | ||
| 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 | /// * Windows | 352 | /// * 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. |
| 354 | pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | 354 | pub 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 requests | 356 | // 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 are | 406 | /// 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. |
| 408 | pub fn pread(fd: fd_t, buf: []u8, offset: u64) ReadError!usize { | 408 | pub 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 | } |
| 412 | 412 | ||
| ... | @@ -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 | } |
| 495 | 495 | ||
| 496 | if (builtin.os == .windows) { | 496 | if (builtin.os.tag == .windows) { |
| 497 | // TODO batch these into parallel requests | 497 | // 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 handled | 557 | /// 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. |
| 559 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { | 559 | pub 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 | } |
| 563 | 563 | ||
| 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 are | 650 | /// 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. |
| 652 | pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) WriteError!void { | 652 | pub 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 | } |
| 656 | 656 | ||
| ... | @@ -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 | } |
| 741 | 741 | ||
| 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. |
| 1095 | 1095 | ||
| 1096 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { | 1096 | pub 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/4524 | 1135 | // 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`. |
| 1169 | pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 { | 1169 | pub 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{ |
| 1199 | 1199 | ||
| 1200 | /// The result is a slice of out_buffer, indexed from 0. | 1200 | /// The result is a slice of out_buffer, indexed from 0. |
| 1201 | pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { | 1201 | pub 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 | } |
| 1205 | 1205 | ||
| ... | @@ -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`. |
| 1242 | pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void { | 1242 | pub 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`. |
| 1256 | pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void { | 1256 | pub 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`. |
| 1331 | pub fn unlink(file_path: []const u8) UnlinkError!void { | 1331 | pub 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 { |
| 1340 | 1340 | ||
| 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. |
| 1342 | pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void { | 1342 | pub 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. |
| 1373 | pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void { | 1373 | pub 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 |
| 1382 | 1382 | ||
| 1383 | /// Same as `unlinkat` but `file_path` is a null-terminated string. | 1383 | /// Same as `unlinkat` but `file_path` is a null-terminated string. |
| 1384 | pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { | 1384 | pub 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 |
| 1438 | 1438 | ||
| 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{ |
| 1493 | 1493 | ||
| 1494 | /// Change the name or location of a file. | 1494 | /// Change the name or location of a file. |
| 1495 | pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { | 1495 | pub 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 { |
| 1506 | 1506 | ||
| 1507 | /// Same as `rename` except the parameters are null-terminated byte arrays. | 1507 | /// Same as `rename` except the parameters are null-terminated byte arrays. |
| 1508 | pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void { | 1508 | pub 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. |
| 1563 | pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { | 1563 | pub 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 { |
| 1572 | 1572 | ||
| 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. |
| 1574 | pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { | 1574 | pub 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{ |
| 1611 | 1611 | ||
| 1612 | /// Deletes an empty directory. | 1612 | /// Deletes an empty directory. |
| 1613 | pub fn rmdir(dir_path: []const u8) DeleteDirError!void { | 1613 | pub 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 { |
| 1622 | 1622 | ||
| 1623 | /// Same as `rmdir` except the parameter is null-terminated. | 1623 | /// Same as `rmdir` except the parameter is null-terminated. |
| 1624 | pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void { | 1624 | pub 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. |
| 1660 | pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { | 1660 | pub 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 { |
| 1669 | 1669 | ||
| 1670 | /// Same as `chdir` except the parameter is null-terminated. | 1670 | /// Same as `chdir` except the parameter is null-terminated. |
| 1671 | pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void { | 1671 | pub 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. |
| 1702 | pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { | 1702 | pub 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 { |
| 1711 | 1711 | ||
| 1712 | /// Same as `readlink` except `file_path` is null-terminated. | 1712 | /// Same as `readlink` except `file_path` is null-terminated. |
| 1713 | pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { | 1713 | pub 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 | } |
| 1733 | 1733 | ||
| 1734 | pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { | 1734 | pub 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 { |
| 1800 | 1800 | ||
| 1801 | /// Test whether a file descriptor refers to a terminal. | 1801 | /// Test whether a file descriptor refers to a terminal. |
| 1802 | pub fn isatty(handle: fd_t) bool { | 1802 | pub 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; |
| 1806 | 1806 | ||
| ... | @@ -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 { |
| 1828 | 1828 | ||
| 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 | } |
| 1837 | 1837 | ||
| 1838 | pub fn isCygwinPty(handle: fd_t) bool { | 1838 | pub fn isCygwinPty(handle: fd_t) bool { |
| 1839 | if (builtin.os != .windows) return false; | 1839 | if (builtin.os.tag != .windows) return false; |
| 1840 | 1840 | ||
| 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 file | 2589 | /// 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. |
| 2591 | pub fn access(path: []const u8, mode: u32) AccessError!void { | 2591 | pub 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; |
| 2603 | 2603 | ||
| 2604 | /// Same as `access` except `path` is null-terminated. | 2604 | /// Same as `access` except `path` is null-terminated. |
| 2605 | pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { | 2605 | pub 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. |
| 2646 | pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void { | 2646 | pub 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 |
| 2654 | 2654 | ||
| 2655 | /// Same as `faccessat` except the path parameter is null-terminated. | 2655 | /// Same as `faccessat` except the path parameter is null-terminated. |
| 2656 | pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void { | 2656 | pub 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; |
| 2768 | 2769 | ||
| 2769 | pub fn sysctl( | 2770 | pub 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; |
| 2811 | 2814 | ||
| 2812 | /// Repositions read/write file offset relative to the beginning. | 2815 | /// Repositions read/write file offset relative to the beginning. |
| 2813 | pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { | 2816 | pub 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 unsigned | 2832 | 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 { |
| 2840 | 2843 | ||
| 2841 | /// Repositions read/write file offset relative to the current offset. | 2844 | /// Repositions read/write file offset relative to the current offset. |
| 2842 | pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { | 2845 | pub 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 { |
| 2868 | 2871 | ||
| 2869 | /// Repositions read/write file offset relative to the end. | 2872 | /// Repositions read/write file offset relative to the end. |
| 2870 | pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { | 2873 | pub 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 { |
| 2896 | 2899 | ||
| 2897 | /// Returns the read/write file offset relative to the beginning. | 2900 | /// Returns the read/write file offset relative to the beginning. |
| 2898 | pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { | 2901 | pub 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`. |
| 2959 | pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { | 2962 | pub 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 |
| 2967 | 2970 | ||
| 2968 | /// Same as `realpath` except `pathname` is null-terminated. | 2971 | /// Same as `realpath` except `pathname` is null-terminated. |
| 2969 | pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { | 2972 | pub 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); |
| 2977 | 2980 | ||
| ... | @@ -3121,7 +3124,7 @@ pub fn dl_iterate_phdr( | ... | @@ -3121,7 +3124,7 @@ pub fn dl_iterate_phdr( |
| 3121 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; | 3124 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; |
| 3122 | 3125 | ||
| 3123 | pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { | 3126 | pub 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 | } |
| 3145 | 3148 | ||
| 3146 | pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { | 3149 | pub 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; |
| 3223 | 3226 | ||
| 3224 | pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { | 3227 | pub 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"); |
| 3227 | 3230 | ||
| 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 | } |
| 3310 | 3306 | ||
| 3311 | @compileError("TODO implement gethostname for this OS"); | 3307 | @compileError("TODO implement gethostname for this OS"); |
| 3312 | } | 3308 | } |
| 3313 | 3309 | ||
| 3310 | pub 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 | |||
| 3314 | pub fn res_mkquery( | 3319 | pub 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 | }; |
| 3612 | 3617 | ||
| 3613 | pub fn sched_yield() SchedYieldError!void { | 3618 | pub 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 not | 3620 | // 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 added | 3 | //! Root source files can define `os.bits` and these will additionally be added |
| 4 | //! to the namespace. | 4 | //! to the namespace. |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const std = @import("std"); |
| 7 | const root = @import("root"); | 7 | const root = @import("root"); |
| 8 | 8 | ||
| 9 | pub usingnamespace switch (builtin.os) { | 9 | pub 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 | } |
| 1071 | 1071 | ||
| 1072 | test "" { | 1072 | test "" { |
| 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 | } |
| 76 | 80 | ||
| 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 the | 59 | // 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 | } |
| 152 | 152 | ||
| 153 | test "sigaltstack" { | 153 | test "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; |
| 155 | 155 | ||
| 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 | } |
| 205 | 205 | ||
| 206 | test "dl_iterate_phdr" { | 206 | test "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; |
| 209 | 209 | ||
| 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 | } |
| 214 | 214 | ||
| 215 | test "gethostname" { | 215 | test "gethostname" { |
| 216 | if (builtin.os == .windows) | 216 | if (builtin.os.tag == .windows) |
| 217 | return error.SkipZigTest; | 217 | return error.SkipZigTest; |
| 218 | 218 | ||
| 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 | } |
| 223 | 223 | ||
| 224 | test "pipe" { | 224 | test "pipe" { |
| 225 | if (builtin.os == .windows) | 225 | if (builtin.os.tag == .windows) |
| 226 | return error.SkipZigTest; | 226 | return error.SkipZigTest; |
| 227 | 227 | ||
| 228 | var fds = try os.pipe(); | 228 | var fds = try os.pipe(); |
| ... | @@ -241,7 +241,7 @@ test "argsAlloc" { | ... | @@ -241,7 +241,7 @@ test "argsAlloc" { |
| 241 | 241 | ||
| 242 | test "memfd_create" { | 242 | test "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/4019 | 246 | // 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 | } |
| 259 | 259 | ||
| 260 | test "mmap" { | 260 | test "mmap" { |
| 261 | if (builtin.os == .windows) | 261 | if (builtin.os.tag == .windows) |
| 262 | return error.SkipZigTest; | 262 | return error.SkipZigTest; |
| 263 | 263 | ||
| 264 | // Simple mmap() call with non page-aligned size | 264 | // Simple mmap() call with non page-aligned size |
| ... | @@ -353,7 +353,7 @@ test "mmap" { | ... | @@ -353,7 +353,7 @@ test "mmap" { |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | test "getenv" { | 355 | test "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; |
| 23 | pub const BOOLEAN = BYTE; | 23 | pub const BOOLEAN = BYTE; |
| 24 | pub const BYTE = u8; | 24 | pub const BYTE = u8; |
| 25 | pub const CHAR = u8; | 25 | pub const CHAR = u8; |
| 26 | pub const UCHAR = u8; | ||
| 26 | pub const FLOAT = f32; | 27 | pub const FLOAT = f32; |
| 27 | pub const HANDLE = *c_void; | 28 | pub const HANDLE = *c_void; |
| 28 | pub const HCRYPTPROV = ULONG_PTR; | 29 | pub const HCRYPTPROV = ULONG_PTR; |
| ... | @@ -54,6 +55,7 @@ pub const WORD = u16; | ... | @@ -54,6 +55,7 @@ pub const WORD = u16; |
| 54 | pub const DWORD = u32; | 55 | pub const DWORD = u32; |
| 55 | pub const DWORD64 = u64; | 56 | pub const DWORD64 = u64; |
| 56 | pub const LARGE_INTEGER = i64; | 57 | pub const LARGE_INTEGER = i64; |
| 58 | pub const ULARGE_INTEGER = u64; | ||
| 57 | pub const USHORT = u16; | 59 | pub const USHORT = u16; |
| 58 | pub const SHORT = i16; | 60 | pub const SHORT = i16; |
| 59 | pub const ULONG = u32; | 61 | pub 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 | }; |
| 1147 | 1149 | ||
| 1150 | const ACTIVATION_CONTEXT_DATA = @OpaqueType(); | ||
| 1151 | const ASSEMBLY_STORAGE_MAP = @OpaqueType(); | ||
| 1152 | const FLS_CALLBACK_INFO = @OpaqueType(); | ||
| 1153 | const RTL_BITMAP = @OpaqueType(); | ||
| 1154 | pub const PRTL_BITMAP = *RTL_BITMAP; | ||
| 1155 | const 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 | ||
| 1148 | pub const PEB = extern struct { | 1161 | pub 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 | }; |
| 1169 | 1314 | ||
| 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 | ||
| 1170 | pub const PEB_LDR_DATA = extern struct { | 1320 | pub 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 | }; |
| 1175 | 1347 | ||
| 1176 | pub const RTL_USER_PROCESS_PARAMETERS = extern struct { | 1348 | pub 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 | }; |
| 1323 | pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX; | 1495 | pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX; |
| 1496 | |||
| 1497 | pub const OSVERSIONINFOW = extern struct { | ||
| 1498 | dwOSVersionInfoSize: ULONG, | ||
| 1499 | dwMajorVersion: ULONG, | ||
| 1500 | dwMinorVersion: ULONG, | ||
| 1501 | dwBuildNumber: ULONG, | ||
| 1502 | dwPlatformId: ULONG, | ||
| 1503 | szCSDVersion: [128]WCHAR, | ||
| 1504 | }; | ||
| 1505 | pub const POSVERSIONINFOW = *OSVERSIONINFOW; | ||
| 1506 | pub const LPOSVERSIONINFOW = *OSVERSIONINFOW; | ||
| 1507 | pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW; | ||
| 1508 | pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW; |
lib/std/os/windows/ntdll.zig+9-1| ... | @@ -1,6 +1,14 @@ | ... | @@ -1,6 +1,14 @@ |
| 1 | usingnamespace @import("bits.zig"); | 1 | usingnamespace @import("bits.zig"); |
| 2 | 2 | ||
| 3 | pub extern "NtDll" fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) callconv(.Stdcall) WORD; | 3 | pub extern "NtDll" fn RtlGetVersion( |
| 4 | lpVersionInformation: PRTL_OSVERSIONINFOW, | ||
| 5 | ) callconv(.Stdcall) NTSTATUS; | ||
| 6 | pub extern "NtDll" fn RtlCaptureStackBackTrace( | ||
| 7 | FramesToSkip: DWORD, | ||
| 8 | FramesToCapture: DWORD, | ||
| 9 | BackTrace: **c_void, | ||
| 10 | BackTraceHash: ?*DWORD, | ||
| 11 | ) callconv(.Stdcall) WORD; | ||
| 4 | pub extern "NtDll" fn NtQueryInformationFile( | 12 | pub 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 we | 593 | // 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. |
| 595 | test "PackedIntArray at end of available memory" { | 595 | test "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 | } |
| 613 | 613 | ||
| 614 | test "PackedIntSlice at end of available memory" { | 614 | test "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(); |
| 38 | 38 | ||
| 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; |
| 41 | 41 | ||
| 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; |
| 67 | 67 | ||
| ... | @@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{ | ... | @@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{ |
| 137 | 137 | ||
| 138 | /// Caller must free returned memory. | 138 | /// Caller must free returned memory. |
| 139 | pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { | 139 | pub 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 | }; |
| 339 | 339 | ||
| 340 | pub const ArgIterator = struct { | 340 | pub const ArgIterator = struct { |
| 341 | const InnerType = if (builtin.os == .windows) ArgIteratorWindows else ArgIteratorPosix; | 341 | const InnerType = if (builtin.os.tag == .windows) ArgIteratorWindows else ArgIteratorPosix; |
| 342 | 342 | ||
| 343 | inner: InnerType, | 343 | inner: InnerType, |
| 344 | 344 | ||
| 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 WASI | 347 | // 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 { |
| 355 | 355 | ||
| 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 { |
| 380 | 380 | ||
| 381 | /// Caller must call argsFree on result. | 381 | /// Caller must call argsFree on result. |
| 382 | pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { | 382 | pub 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; |
| 386 | 386 | ||
| ... | @@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { | ... | @@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void { | 447 | pub 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 terminated | 450 | 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 { |
| 498 | 498 | ||
| 499 | /// POSIX function which gets a uid from username. | 499 | /// POSIX function which gets a uid from username. |
| 500 | pub fn getUserInfo(name: []const u8) !UserInfo { | 500 | pub 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 | } |
| 592 | 592 | ||
| 593 | pub fn getBaseAddress() usize { | 593 | pub 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 | } |
| 610 | 610 | ||
| 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. | ||
| 612 | pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 { | 616 | pub 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 { |
| 16 | 16 | ||
| 17 | pub const OsEvent = if (builtin.single_threaded) | 17 | pub const OsEvent = if (builtin.single_threaded) |
| 18 | DebugEvent | 18 | 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 | PosixEvent | 20 | PosixEvent |
| 21 | else | 21 | 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 EINVAL | 107 | // on dragonfly, *destroy() functions can return EINVAL |
| 108 | // for statically initialized pthread structures | 108 | // 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; |
| 110 | 110 | ||
| 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 | } |
| 217 | 217 | ||
| 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 | }; |
| 20 | const is_freestanding = switch (builtin.os) { | 20 | const 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 | } |
| 48 | 48 | ||
| 49 | fn strlen(s: [*:0]const u8) callconv(.C) usize { | 49 | fn strlen(s: [*:0]const u8) callconv(.C) usize { |
| 50 | return std.mem.len(u8, s); | 50 | return std.mem.len(s); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int { | 53 | fn 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" { |
| 178 | comptime { | 178 | comptime { |
| 179 | if (builtin.mode != builtin.Mode.ReleaseFast and | 179 | if (builtin.mode != builtin.Mode.ReleaseFast and |
| 180 | builtin.mode != builtin.Mode.ReleaseSmall and | 180 | 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | ||
| 2 | const is_test = builtin.is_test; | 3 | const is_test = builtin.is_test; |
| 3 | 4 | ||
| 4 | const is_gnu = switch (builtin.abi) { | 5 | const is_gnu = std.Target.current.abi.isGnu(); |
| 5 | .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true, | 6 | const is_mingw = builtin.os.tag == .windows and is_gnu; |
| 6 | else => false, | ||
| 7 | }; | ||
| 8 | const is_mingw = builtin.os == .windows and is_gnu; | ||
| 9 | 7 | ||
| 10 | comptime { | 8 | comptime { |
| 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 }); |
| 182 | 180 | ||
| 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 | } |
| 186 | 184 | ||
| ... | @@ -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 | } |
| 252 | 250 | ||
| 253 | if (builtin.os == .windows) { | 251 | if (builtin.os.tag == .windows) { |
| 254 | // Default stack-probe functions emitted by LLVM | 252 | // 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 { |
| 307 | pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { | 305 | pub 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, |
| 26 | 26 | ||
| 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, |
| 27 | 27 | ||
| 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); // sNaN | 90 | test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN |
| 91 | // On x86 the NaN becomes quiet because the return is pushed on the x87 | 91 | // On x86 the NaN becomes quiet because the return is pushed on the x87 |
| 92 | // stack due to ABI requirements | 92 | // 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); // sNaN | 94 | test__extendhfsf2(0x7c01, 0x7f802000); // sNaN |
| 95 | 95 | ||
| 96 | test__extendhfsf2(0, 0); // 0 | 96 | 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, |
| 26 | 26 | ||
| 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, |
| 47 | 47 | ||
| 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn __truncsfhf2(a: f32) callconv(.C) u16 { | 3 | pub 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 | } |
| 6 | 6 | ||
| 7 | pub fn __truncdfhf2(a: f64) callconv(.C) u16 { | 7 | pub 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 | } |
| 10 | 10 | ||
| 11 | pub fn __trunctfsf2(a: f128) callconv(.C) f32 { | 11 | pub 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 | } |
| 14 | 14 | ||
| 15 | pub fn __trunctfdf2(a: f128) callconv(.C) f64 { | 15 | pub 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 | } |
| 18 | 18 | ||
| 19 | pub fn __truncdfsf2(a: f64) callconv(.C) f32 { | 19 | pub 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 | } |
| 22 | 22 | ||
| 23 | pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 { | 23 | pub 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 | } |
| 37 | 37 | ||
| 38 | inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { | 38 | fn 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"); |
| 2 | const is_test = builtin.is_test; | 2 | const is_test = builtin.is_test; |
| 3 | 3 | ||
| 4 | const low = switch (builtin.endian) { | 4 | const low = switch (builtin.endian) { |
| 5 | builtin.Endian.Big => 1, | 5 | .Big => 1, |
| 6 | builtin.Endian.Little => 0, | 6 | .Little => 0, |
| 7 | }; | 7 | }; |
| 8 | const high = 1 - low; | 8 | const high = 1 - low; |
| 9 | 9 |
lib/std/special/init-exe/build.zig+10| ... | @@ -1,8 +1,18 @@ | ... | @@ -1,8 +1,18 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: *Builder) void { | 3 | pub 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(); |
| 8 | 18 |
lib/std/special/init-exe/src/main.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn main() anyerror!void { | 3 | pub 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 be | 46 | // 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"; |
| 12 | 12 | ||
| 13 | comptime { | 13 | comptime { |
| 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") and | 24 | 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 | } |
| 79 | 79 | ||
| 80 | fn _start() callconv(.Naked) noreturn { | 80 | fn _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 { |
| 133 | 133 | ||
| 134 | // TODO https://github.com/ziglang/zig/issues/265 | 134 | // TODO https://github.com/ziglang/zig/issues/265 |
| 135 | fn posixCallMainAndExit() noreturn { | 135 | fn 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]; |
| 146 | 146 | ||
| 147 | if (builtin.os == .linux) { | 147 | if (builtin.os.tag == .linux) { |
| 148 | // Find the beginning of the auxiliary vector | 148 | // 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 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const builtin = std.builtin; | 3 | const builtin = std.builtin; |
| 4 | const Version = std.builtin.Version; | ||
| 4 | 5 | ||
| 5 | /// TODO Nearly all the functions in this namespace would be | 6 | /// TODO Nearly all the functions in this namespace would be |
| 6 | /// better off if https://github.com/ziglang/zig/issues/425 | 7 | /// better off if https://github.com/ziglang/zig/issues/425 |
| 7 | /// was solved. | 8 | /// was solved. |
| 8 | pub const Target = union(enum) { | 9 | pub const Target = struct { |
| 9 | Native: void, | 10 | cpu: Cpu, |
| 10 | Cross: Cross, | 11 | os: Os, |
| 11 | 12 | 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, |
| 50 | 51 | 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 | }; |
| 61 | 291 | ||
| ... | @@ -98,11 +328,10 @@ pub const Target = union(enum) { | ... | @@ -98,11 +328,10 @@ pub const Target = union(enum) { |
| 98 | macabi, | 328 | macabi, |
| 99 | 329 | ||
| 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 | } |
| 149 | 378 | ||
| 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 | }; |
| 160 | 400 | ||
| ... | @@ -177,12 +417,6 @@ pub const Target = union(enum) { | ... | @@ -177,12 +417,6 @@ pub const Target = union(enum) { |
| 177 | EfiRuntimeDriver, | 417 | EfiRuntimeDriver, |
| 178 | }; | 418 | }; |
| 179 | 419 | ||
| 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 | /// Architecture | 421 | /// 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 | } |
| 230 | 464 | ||
| 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 | } |
| 256 | 496 | ||
| 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); |
| 259 | 508 | ||
| ... | @@ -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 | } |
| 397 | 646 | ||
| 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 | } |
| 510 | 759 | ||
| 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 | }; |
| 589 | 889 | ||
| 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 | }; |
| 605 | 937 | ||
| 606 | /// The "default" set of CPU features for cross-compiling. A conservative set | 938 | /// 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 | }; |
| 641 | 944 | ||
| 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 | }; |
| 649 | 950 | ||
| 650 | pub const stack_align = 16; | 951 | pub const stack_align = 16; |
| 651 | 952 | ||
| 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 | } |
| 693 | 956 | ||
| 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 not | 958 | 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 | } |
| 699 | 960 | ||
| 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 | } |
| 707 | 964 | ||
| 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 | } |
| 715 | 968 | ||
| 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-gnu | 971 | .windows => return ".exe", |
| 719 | /// The fields are, respectively: | 972 | .uefi => return ".efi", |
| 720 | /// * CPU Architecture | 973 | else => if (cpu_arch.isWasm()) { |
| 721 | /// * Operating System | 974 | return ".wasm"; |
| 722 | /// * C ABI (optional) | 975 | } else { |
| 723 | arch_os_abi: []const u8, | 976 | return ""; |
| 724 | 977 | }, | |
| 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 | } |
| 826 | 980 | ||
| 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 | } |
| 833 | 984 | ||
| 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 | } |
| 855 | 994 | ||
| 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 | } |
| 865 | 998 | ||
| 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 | } |
| 875 | 1012 | ||
| 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 | } |
| 882 | 1016 | ||
| 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 | } |
| 889 | 1023 | 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 | } |
| 900 | 1028 | ||
| 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 | } |
| 917 | 1032 | ||
| 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 | } |
| 921 | 1036 | ||
| 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 | } |
| 928 | 1040 | ||
| 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 | } |
| 956 | 1044 | ||
| 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 | } |
| 963 | 1051 | ||
| 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 | } |
| 991 | 1055 | ||
| 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 | } |
| 998 | 1059 | ||
| 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 | } |
| 1002 | 1063 | ||
| 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 | } |
| 1067 | 1067 | ||
| 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 | } |
| 1124 | 1071 | ||
| 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 | }; |
| 1130 | 1077 | ||
| 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 | } |
| 1140 | 1087 | ||
| 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 | } |
| 1162 | 1106 | ||
| 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 | else | 1120 | return result; |
| 1177 | "/system/bin/linker"); | ||
| 1178 | } | 1121 | } |
| 1179 | 1122 | ||
| 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; |
| 1183 | 1126 | 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 | } |
| 1202 | 1160 | ||
| 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"), |
| 1212 | 1184 | ||
| 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"), |
| 1216 | 1188 | ||
| 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 | }, | ||
| 1231 | 1212 | ||
| 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 | }), |
| 1240 | 1221 | ||
| 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"), |
| 1243 | 1224 | ||
| 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, | ||
| 1247 | 1234 | ||
| 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 | }, |
| 1277 | 1262 | ||
| 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, |
| 1288 | 1276 | ||
| 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 | |||
| 1294 | test "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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const TypeId = builtin.TypeId; | ||
| 3 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 4 | 2 | ||
| 5 | pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator; | 3 | pub 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 { |
| 65 | 63 | ||
| 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 | }, |
| 76 | 71 | .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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = std.builtin; | ||
| 3 | const os = std.os; | 3 | const os = std.os; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const windows = std.os.windows; | 5 | const windows = std.os.windows; |
| ... | @@ -9,14 +9,14 @@ const assert = std.debug.assert; | ... | @@ -9,14 +9,14 @@ const assert = std.debug.assert; |
| 9 | pub const Thread = struct { | 9 | pub const Thread = struct { |
| 10 | data: Data, | 10 | data: Data, |
| 11 | 11 | ||
| 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; |
| 13 | 13 | ||
| 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_t | 18 | 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 | } else | 57 | } 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); |
| 152 | 152 | ||
| 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 i386 | 317 | // 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; |
| 319 | 319 | ||
| 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 | } |
| 363 | 363 | ||
| 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 | }; |
| 370 | 369 | ||
| 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 cast | 373 | 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = std.builtin; | ||
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const testing = std.testing; | 4 | const testing = std.testing; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| ... | @@ -7,10 +7,12 @@ const math = std.math; | ... | @@ -7,10 +7,12 @@ const math = std.math; |
| 7 | 7 | ||
| 8 | pub const epoch = @import("time/epoch.zig"); | 8 | pub const epoch = @import("time/epoch.zig"); |
| 9 | 9 | ||
| 10 | const 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/O | 13 | /// TODO integrate with evented I/O |
| 12 | pub fn sleep(nanoseconds: u64) void { | 14 | pub 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 milliseconds | 33 | /// 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? |
| 33 | pub fn milliTimestamp() u64 { | 35 | pub fn milliTimestamp() u64 { |
| 34 | if (builtin.os == .windows) { | 36 | if (is_windows) { |
| 35 | //FileTime has a granularity of 100 nanoseconds | 37 | //FileTime has a granularity of 100 nanoseconds |
| 36 | // and uses the NTFS/Windows epoch | 38 | // 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; |
| 47 | 49 | ||
| 48 | // TODO: Verify that precision is ignored | 50 | // 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 the | 104 | ///if we used resolution's value when performing the |
| 103 | /// performance counter calc on windows/darwin, it would | 105 | /// performance counter calc on windows/darwin, it would |
| 104 | /// be less precise | 106 | /// 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; |
| 129 | 131 | ||
| 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 | } |
| 173 | 175 | ||
| 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 | } |
| 185 | 187 | ||
| 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 | } |
| 9 | 9 | ||
| 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, %%edi | 13 | \\ roll $3, %%edi ; roll $13, %%edi |
| 14 | \\ roll $29, %%edi ; roll $19, %%edi | 14 | \\ 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, %%rdi | 24 | \\ rolq $3, %%rdi ; rolq $13, %%rdi |
| 25 | \\ rolq $61, %%rdi ; rolq $51, %%rdi | 25 | \\ 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 |
| 6 | pub const render = @import("zig/render.zig").render; | 6 | pub const render = @import("zig/render.zig").render; |
| 7 | pub const ast = @import("zig/ast.zig"); | 7 | pub const ast = @import("zig/ast.zig"); |
| 8 | pub const system = @import("zig/system.zig"); | 8 | pub const system = @import("zig/system.zig"); |
| 9 | pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; | ||
| 9 | 10 | ||
| 10 | test "std.zig tests" { | 11 | test "" { |
| 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const Target = std.Target; | ||
| 4 | const 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. | ||
| 9 | pub 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 | |||
| 750 | test "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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const elf = std.elf; | ||
| 2 | const mem = std.mem; | 3 | const mem = std.mem; |
| 4 | const fs = std.fs; | ||
| 3 | const Allocator = std.mem.Allocator; | 5 | const Allocator = std.mem.Allocator; |
| 4 | const ArrayList = std.ArrayList; | 6 | const ArrayList = std.ArrayList; |
| 5 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 6 | const process = std.process; | 8 | const process = std.process; |
| 9 | const Target = std.Target; | ||
| 10 | const CrossTarget = std.zig.CrossTarget; | ||
| 7 | 11 | ||
| 8 | const is_windows = std.Target.current.isWindows(); | 12 | const is_windows = Target.current.os.tag == .windows; |
| 9 | 13 | ||
| 10 | pub const NativePaths = struct { | 14 | pub 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 | } |
| 78 | 82 | ||
| 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); |
| 81 | 85 | ||
| 82 | // TODO: $ ld --verbose | grep SEARCH_DIR | 86 | // 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 | |||
| 169 | pub 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 { |
| 70 | 70 | ||
| 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 { |
| 1072 | 1072 | ||
| 1073 | pub const struct_ZigClangAPValue = extern struct { | 1073 | pub 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 | }; |
| 1077 | pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType; | 1077 | pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType; |
| 1078 | 1078 |
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. |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| ... | @@ -6,14 +6,6 @@ const fs = std.fs; | ... | @@ -6,14 +6,6 @@ const fs = std.fs; |
| 6 | 6 | ||
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | 8 | ||
| 9 | pub 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 result | 9 | /// Caller must free result |
| 18 | pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { | 10 | pub 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 { |
| 1803 | 1803 | ||
| 1804 | // Look at the params and ref() other instructions | 1804 | // 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; |
| 7 | const Batch = std.event.Batch; | 7 | const Batch = std.event.Batch; |
| 8 | 8 | ||
| 9 | const is_darwin = Target.current.isDarwin(); | 9 | const is_darwin = Target.current.isDarwin(); |
| 10 | const is_windows = Target.current.isWindows(); | 10 | const is_windows = Target.current.os.tag == .windows; |
| 11 | const is_freebsd = Target.current.isFreeBSD(); | ||
| 12 | const is_netbsd = Target.current.isNetBSD(); | ||
| 13 | const is_linux = Target.current.isLinux(); | ||
| 14 | const is_dragonfly = Target.current.isDragonFlyBSD(); | ||
| 15 | const is_gnu = Target.current.isGnu(); | 11 | const is_gnu = Target.current.isGnu(); |
| 16 | 12 | ||
| 17 | usingnamespace @import("windows_sdk.zig"); | 13 | usingnamespace @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 | } |
| 618 | 614 | ||
| 619 | /// Caller owns returned memory. | ||
| 620 | pub 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 | |||
| 717 | const Search = struct { | 615 | const 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 | } |
| 535 | 535 | ||
| 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 when | 82 | const info = try std.zig.system.NativeTargetInfo.detect(allocator); |
| 83 | // compiling the compiler | 83 | 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 | } |
| 793 | 793 | ||
| 794 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { | 794 | fn 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 | } |
| 797 | 797 | ||
| 798 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { | 798 | fn 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 | } |
| 874 | 874 |
src-self-hosted/print_targets.zig+6-6| ... | @@ -124,7 +124,7 @@ pub fn cmdTargets( | ... | @@ -124,7 +124,7 @@ pub fn cmdTargets( |
| 124 | 124 | ||
| 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)); |
| 205 | 205 | ||
| 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); |
| 209 | 209 | ||
| 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-hosted | 228 | // TODO implement native glibc version detection in self-hosted |
| 229 | try jws.endObject(); | 229 | try jws.endObject(); |
| 230 | 230 |
src-self-hosted/stage2.zig+279-124| ... | @@ -10,6 +10,7 @@ const Allocator = mem.Allocator; | ... | @@ -10,6 +10,7 @@ const Allocator = mem.Allocator; |
| 10 | const ArrayList = std.ArrayList; | 10 | const ArrayList = std.ArrayList; |
| 11 | const Buffer = std.Buffer; | 11 | const Buffer = std.Buffer; |
| 12 | const Target = std.Target; | 12 | const Target = std.Target; |
| 13 | const CrossTarget = std.zig.CrossTarget; | ||
| 13 | const self_hosted_main = @import("main.zig"); | 14 | const self_hosted_main = @import("main.zig"); |
| 14 | const errmsg = @import("errmsg.zig"); | 15 | const errmsg = @import("errmsg.zig"); |
| 15 | const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; | 16 | const 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 | }; |
| 114 | 117 | ||
| 115 | const FILE = std.c.FILE; | 118 | const 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 | } |
| 633 | 636 | ||
| 634 | fn cmdTargets(zig_triple: [*:0]const u8) !void { | 637 | fn 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 .{}; |
| 710 | 720 | ||
| 711 | try stage1_target.fromTarget(target); | 721 | try stage1_target.fromTarget(target); |
| 712 | } | 722 | } |
| 713 | 723 | ||
| 714 | fn 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 warning | 724 | // ABI warning |
| 777 | const Stage2LibCInstallation = extern struct { | 725 | const 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 { |
| 948 | 896 | ||
| 949 | is_native: bool, | 897 | is_native: bool, |
| 950 | 898 | ||
| 951 | glibc_version: ?*Stage2GLibCVersion, // null means default | 899 | glibc_or_darwin_version: ?*Stage2SemVer, |
| 952 | 900 | ||
| 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, | ||
| 957 | 906 | ||
| 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 .{}; | ||
| 960 | 911 | ||
| 961 | const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch | 912 | 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 | } |
| 973 | 924 | ||
| 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 LLVM | 928 | 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_UnknownArch | 1135 | .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 | }; |
| 1000 | 1150 | ||
| 1151 | fn enumInt(comptime Enum: type, int: c_int) Enum { | ||
| 1152 | return @intToEnum(Enum, @intCast(@TagType(Enum), int)); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | fn 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 warning | 1176 | // ABI warning |
| 1002 | const Stage2GLibCVersion = extern struct { | 1177 | const Stage2SemVer = extern struct { |
| 1003 | major: u32, | 1178 | major: u32, |
| 1004 | minor: u32, | 1179 | minor: u32, |
| 1005 | patch: u32, | 1180 | patch: u32, |
| 1006 | }; | 1181 | }; |
| 1007 | 1182 | ||
| 1008 | // ABI warning | ||
| 1009 | export 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 | |||
| 1024 | fn enumInt(comptime Enum: type, int: c_int) Enum { | ||
| 1025 | return @intToEnum(Enum, @intCast(@TagType(Enum), int)); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | // ABI warning | 1183 | // ABI warning |
| 1029 | const Stage2NativePaths = extern struct { | 1184 | const 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 | } |
| 4851 | 4851 | ||
| 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)]; |
| 4854 | 4854 | ||
| 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 | |||
| 38 | pub 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; |
| 2251 | 2251 | ||
| 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; |
| 2261 | 2258 | ||
| 2262 | const char **llvm_argv; | 2259 | const char **llvm_argv; |
| ... | @@ -3266,7 +3263,6 @@ struct IrInstSrcContainerInitList { | ... | @@ -3266,7 +3263,6 @@ struct IrInstSrcContainerInitList { |
| 3266 | struct IrInstSrcContainerInitFieldsField { | 3263 | struct 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 | }; |
| 3272 | 3268 |
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) { |
| 3955 | 3963 | ||
| 3956 | // TODO more validation for types that can't be used for export/extern variables | 3964 | // 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 | } |
| 4777 | 4783 | ||
| 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 | } | ||
| 4786 | 4793 | ||
| 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) { |
| 5390 | 5401 | ||
| 5391 | static bool can_mutate_comptime_var_state(ZigValue *value) { | 5402 | static 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; |
| 5419 | 5432 | ||
| 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 | } |
| 6691 | 6706 | ||
| 6692 | static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) { | 6707 | static 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_ |
| 6713 | 6736 | ||
| 6714 | bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { | 6737 | bool 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 | } |
| 8710 | 8736 | ||
| 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; |
| 8714 | 8739 | ||
| ... | @@ -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); |
| 8720 | 8745 | ||
| 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); | ||
| 8728 | 8748 | ||
| 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, ""); |
| 8751 | 8769 | ||
| 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 | }; |
| 34 | 34 | ||
| 35 | static 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 | |||
| 60 | static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) { | 35 | static 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 | } |
| 162 | 137 | ||
| 163 | void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) { | ||
| 164 | g->mmacosx_version_min = mmacosx_version_min; | ||
| 165 | } | ||
| 166 | |||
| 167 | void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min) { | ||
| 168 | g->mios_version_min = mios_version_min; | ||
| 169 | } | ||
| 170 | |||
| 171 | void codegen_set_rdynamic(CodeGen *g, bool rdynamic) { | 138 | void 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); |
| 3335 | 3315 | ||
| ... | @@ -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 |
| 4466 | 4446 | ||
| 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; |
| 4471 | 4451 | ||
| 4472 | // The field has no bits but we still have to change the discriminant | 4452 | // 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 | }; |
| 5028 | 5008 | ||
| 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(); | ||
| 5060 | 5051 | ||
| 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 | } | ||
| 5089 | 5075 | ||
| 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); |
| 5091 | 5077 | ||
| ... | @@ -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 | } |
| 8843 | 8828 | ||
| 8844 | static 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 | |||
| 8866 | static void detect_libc(CodeGen *g) { | 8829 | static void detect_libc(CodeGen *g) { |
| 8867 | Error err; | 8830 | Error err; |
| 8868 | 8831 | ||
| ... | @@ -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); |
| 10350 | 10313 | ||
| 10351 | // gen_c_objects appends objects to g->link_objects which we want to include in the hash | 10314 | // 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); | ||
| 10446 | 10408 | ||
| 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; | ||
| 10643 | 10604 | ||
| 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 |
| 10647 | 10608 | ||
| 10648 | codegen_set_errmsg_color(child_gen, parent_gen->err_color); | 10609 | codegen_set_errmsg_color(child_gen, parent_gen->err_color); |
| 10649 | 10610 | ||
| 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; |
| 10654 | 10612 | ||
| 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 | } |
| 10766 | 10719 | ||
| 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); |
| 35 | void codegen_add_framework(CodeGen *codegen, const char *name); | 35 | void codegen_add_framework(CodeGen *codegen, const char *name); |
| 36 | void codegen_add_rpath(CodeGen *codegen, const char *name); | 36 | void codegen_add_rpath(CodeGen *codegen, const char *name); |
| 37 | void codegen_set_rdynamic(CodeGen *g, bool rdynamic); | 37 | void codegen_set_rdynamic(CodeGen *g, bool rdynamic); |
| 38 | void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min); | ||
| 39 | void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min); | ||
| 40 | void codegen_set_linker_script(CodeGen *g, const char *linker_script); | 38 | void codegen_set_linker_script(CodeGen *g, const char *linker_script); |
| 41 | void codegen_set_test_filter(CodeGen *g, Buf *filter); | 39 | void codegen_set_test_filter(CodeGen *g, Buf *filter); |
| 42 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); | 40 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); |
src/compiler.cpp-25| ... | @@ -4,31 +4,6 @@ | ... | @@ -4,31 +4,6 @@ |
| 4 | 4 | ||
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | 6 | ||
| 7 | Buf *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 | |||
| 32 | Error get_compiler_id(Buf **result) { | 7 | Error get_compiler_id(Buf **result) { |
| 33 | static Buf saved_compiler_id = BUF_INIT; | 8 | static Buf saved_compiler_id = BUF_INIT; |
| 34 | 9 |
src/compiler.hpp-1| ... | @@ -12,7 +12,6 @@ | ... | @@ -12,7 +12,6 @@ |
| 12 | #include "error.hpp" | 12 | #include "error.hpp" |
| 13 | 13 | ||
| 14 | Error get_compiler_id(Buf **result); | 14 | Error get_compiler_id(Buf **result); |
| 15 | Buf *get_self_libc_path(void); | ||
| 16 | 15 | ||
| 17 | Buf *get_zig_lib_dir(void); | 16 | Buf *get_zig_lib_dir(void); |
| 18 | Buf *get_zig_special_dir(Buf *zig_lib_dir); | 17 | Buf *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); |
| 192 | 192 | ||
| 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 |
| 224 | 224 | ||
| 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(); |
| 247 | 247 | ||
| 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]; |
| 295 | 295 | ||
| 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 | } |
| 364 | 364 | ||
| 365 | #ifdef ZIG_OS_LINUX | ||
| 366 | #include <unistd.h> | ||
| 367 | Error 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 | ||
| 397 | Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) { | ||
| 398 | return ErrorUnknownABI; | ||
| 399 | } | ||
| 400 | #endif | ||
| 401 | |||
| 402 | size_t glibc_lib_count(void) { | 365 | size_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 index | 37 | // 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 |
| 43 | Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target, | 43 | Error 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); |
| 45 | 45 | ||
| 46 | // returns ErrorUnknownABI when glibc is not the native libc | ||
| 47 | Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver); | ||
| 48 | |||
| 49 | size_t glibc_lib_count(void); | 46 | size_t glibc_lib_count(void); |
| 50 | const ZigGLibCLib *glibc_lib_enum(size_t index); | 47 | const ZigGLibCLib *glibc_lib_enum(size_t index); |
| 51 | const ZigGLibCLib *glibc_lib_find(const char *name); | 48 | const 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; |
| 12557 | 12557 | ||
| 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 | } |
| 12563 | 12563 | ||
| 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 | } | ||
| 12565 | 12574 | ||
| 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, |
| 14833 | 14842 | ||
| 14834 | // cast from inferred struct type to array, union, or struct | 14843 | // 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 | } |
| 20371 | 20381 | ||
| 20382 | static 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 | |||
| 20372 | static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { | 20393 | static 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; |
| 25922 | 25946 | ||
| 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 |
| 26218 | 26252 | ||
| 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 | } |
| 26233 | 26266 | ||
| 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 | } |
| 26237 | 26279 | ||
| 26238 | static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { | 26280 | static 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 | } |
| 27819 | 27861 | ||
| 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 | } |
| 27826 | 27874 | ||
| ... | @@ -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 |
| 27878 | 27926 | ||
| 27879 | ZigType *usize = ira->codegen->builtin_types.entry_usize; | 27927 | ZigType *usize = ira->codegen->builtin_types.entry_usize; |
| 27880 | 27928 | ||
| 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 | } |
| 27887 | 27935 | ||
| 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; |
| 27891 | 27939 | ||
| 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 | } |
| 27909 | 27965 |
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 | } |
| 1752 | 1752 | ||
| 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 | } |
| 1759 | 1759 | ||
| ... | @@ -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 | } |
| 2378 | 2378 | ||
| 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). | ||
| 2384 | static 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 | |||
| 2418 | enum DarwinPlatformKind { | ||
| 2419 | MacOS, | ||
| 2420 | IPhoneOS, | ||
| 2421 | IPhoneOSSimulator, | ||
| 2422 | }; | ||
| 2423 | |||
| 2424 | struct DarwinPlatform { | ||
| 2425 | DarwinPlatformKind kind; | ||
| 2426 | int major; | ||
| 2427 | int minor; | ||
| 2428 | int micro; | ||
| 2429 | }; | ||
| 2430 | |||
| 2431 | static 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 | |||
| 2472 | static void construct_linker_job_macho(LinkJob *lj) { | 2379 | static void construct_linker_job_macho(LinkJob *lj) { |
| 2473 | CodeGen *g = lj->codegen; | 2380 | CodeGen *g = lj->codegen; |
| 2474 | 2381 | ||
| ... | @@ -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)); |
| 2514 | 2421 | ||
| 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, |
| 2530 | 2435 | 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)); | ||
| 2533 | 2437 | ||
| 2438 | lj->args.append("-sdk_version"); | ||
| 2439 | lj->args.append(buf_ptr(version_string)); | ||
| 2440 | } | ||
| 2534 | 2441 | ||
| 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); |
| 504 | 498 | ||
| 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 | } | ||
| 507 | 504 | ||
| 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(); |
| 979 | 970 | ||
| 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 | } | ||
| 1009 | 977 | ||
| 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) { |
| 1226 | 1194 | ||
| 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 | } |
| 1266 | 1233 | ||
| 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 | } | ||
| 1280 | 1235 | ||
| 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 | } | ||
| 1369 | 1327 | ||
| 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 | #else | 1074 | #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) {} |
| 91 | void stage2_progress_disable_tty(Stage2Progress *progress) {} | 91 | void stage2_progress_disable_tty(Stage2Progress *progress) {} |
| 92 | void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} | 92 | void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} |
| 93 | 93 | ||
| 94 | Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) { | 94 | static 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 | |||
| 171 | static 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 | |||
| 194 | Error 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; |
| 96 | 198 | ||
| 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 | } |
| 154 | 253 | ||
| 254 | if (dynamic_linker != nullptr) { | ||
| 255 | target->dynamic_linker = dynamic_linker; | ||
| 256 | } | ||
| 155 | return ErrorNone; | 257 | return ErrorNone; |
| 156 | } | 258 | } |
| 157 | 259 | ||
| ... | @@ -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 | } |
| 188 | 290 | ||
| 189 | enum 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 | |||
| 194 | enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) { | 291 | enum 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 | }; |
| 107 | 109 | ||
| 108 | // ABI warning | 110 | // ABI warning |
| ... | @@ -268,14 +270,12 @@ enum Os { | ... | @@ -268,14 +270,12 @@ enum Os { |
| 268 | }; | 270 | }; |
| 269 | 271 | ||
| 270 | // ABI warning | 272 | // ABI warning |
| 271 | struct ZigGLibCVersion { | 273 | struct Stage2SemVer { |
| 272 | uint32_t major; // always 2 | 274 | uint32_t major; |
| 273 | uint32_t minor; | 275 | uint32_t minor; |
| 274 | uint32_t patch; | 276 | uint32_t patch; |
| 275 | }; | 277 | }; |
| 276 | 278 | ||
| 277 | struct Stage2TargetData; | ||
| 278 | |||
| 279 | // ABI warning | 279 | // ABI warning |
| 280 | struct ZigTarget { | 280 | struct ZigTarget { |
| 281 | enum ZigLLVM_ArchType arch; | 281 | enum ZigLLVM_ArchType arch; |
| ... | @@ -286,20 +286,20 @@ struct ZigTarget { | ... | @@ -286,20 +286,20 @@ struct ZigTarget { |
| 286 | 286 | ||
| 287 | bool is_native; | 287 | bool is_native; |
| 288 | 288 | ||
| 289 | struct ZigGLibCVersion *glibc_version; // null means default | 289 | // null means default. this is double-purposed to be darwin min version |
| 290 | struct Stage2SemVer *glibc_or_darwin_version; | ||
| 290 | 291 | ||
| 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 | }; |
| 296 | 299 | ||
| 297 | // ABI warning | 300 | // ABI warning |
| 298 | ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, | 301 | ZIG_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 | ||
| 302 | ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu); | ||
| 303 | 303 | ||
| 304 | 304 | ||
| 305 | // ABI warning | 305 | // 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 | } |
| 288 | 288 | ||
| 289 | static 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 | |||
| 366 | const char *target_os_name(Os os_type) { | 289 | const 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 | } |
| 425 | 348 | ||
| 426 | Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { | 349 | Error 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 | } |
| 448 | 371 | ||
| 449 | void 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 | |||
| 472 | void target_init_default_glibc_version(ZigTarget *target) { | 372 | void 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 | } |
| 475 | 375 | ||
| 476 | Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) { | 376 | Error 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 | } |
| 511 | 411 | ||
| 512 | Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu) { | 412 | Error 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 | } |
| 515 | 415 | ||
| 516 | const char *target_arch_name(ZigLLVM_ArchType arch) { | 416 | const 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 | }; |
| 43 | 43 | ||
| 44 | Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu); | 44 | Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker); |
| 45 | Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len); | 45 | Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len); |
| 46 | Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); | 46 | Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); |
| 47 | Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); | 47 | Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); |
| 48 | 48 | ||
| 49 | Error target_parse_glibc_version(ZigGLibCVersion *out, const char *text); | 49 | Error target_parse_glibc_version(Stage2SemVer *out, const char *text); |
| 50 | void target_init_default_glibc_version(ZigTarget *target); | 50 | void target_init_default_glibc_version(ZigTarget *target); |
| 51 | 51 | ||
| 52 | size_t target_arch_count(void); | 52 | size_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); |
| 73 | const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat); | 73 | const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat); |
| 74 | ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target); | 74 | ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target); |
| 75 | 75 | ||
| 76 | void get_native_target(ZigTarget *target); | ||
| 77 | void target_triple_llvm(Buf *triple, const ZigTarget *target); | 76 | void target_triple_llvm(Buf *triple, const ZigTarget *target); |
| 78 | void target_triple_zig(Buf *triple, const ZigTarget *target); | 77 | void target_triple_zig(Buf *triple, const ZigTarget *target); |
| 79 | 78 |
test/assemble_and_link.zig+2-2| ... | @@ -1,8 +1,8 @@ | ... | @@ -1,8 +1,8 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const std = @import("std"); |
| 2 | const tests = @import("tests.zig"); | 2 | const tests = @import("tests.zig"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompareOutputContext) void { | 4 | pub 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 | \\.text | 7 | \\.text |
| 8 | \\.globl _start | 8 | \\.globl _start |
test/cli.zig+2-3| ... | @@ -1,5 +1,4 @@ | ... | @@ -1,5 +1,4 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 3 | const testing = std.testing; | 2 | const testing = std.testing; |
| 4 | const process = std.process; | 3 | const process = std.process; |
| 5 | const fs = std.fs; | 4 | const 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 { |
| 93 | fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { | 92 | fn 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 | } |
| 98 | 97 | ||
| 99 | fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { | 98 | fn 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; |
| 101 | 100 | ||
| 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | 1 | const std = @import("std"); |
| 3 | const os = std.os; | 2 | const os = std.os; |
| 4 | const tests = @import("tests.zig"); | 3 | const 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"); |
| 132 | 131 | ||
| 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/515 | 137 | \\ // 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 | , ""); |
| 307 | 306 | ||
| 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/515 | 312 | \\ // See https://github.com/ziglang/zig/issues/515 |
test/compile_errors.zig+37-25| ... | @@ -1,8 +1,34 @@ | ... | @@ -1,8 +1,34 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const std = @import("std"); |
| 3 | const Target = @import("std").Target; | ||
| 4 | 3 | ||
| 5 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 4 | pub 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 | }); |
| 1428 | 1450 | ||
| 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 | }); |
| 2718 | 2740 | ||
| 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; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const fs = std.fs; | 8 | const fs = std.fs; |
| 9 | const warn = std.debug.warn; | 9 | const warn = std.debug.warn; |
| 10 | const CrossTarget = std.zig.CrossTarget; | ||
| 10 | 11 | ||
| 11 | pub const TranslateCContext = struct { | 12 | pub 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{}, |
| 23 | 24 | ||
| 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std"); | 1 | const std = @import("std"); |
| 3 | const os = std.os; | 2 | const os = std.os; |
| 4 | const tests = @import("tests.zig"); | 3 | const tests = @import("tests.zig"); |
| 5 | 4 | ||
| 5 | // zig fmt: off | ||
| 6 | pub fn addCases(cases: *tests.StackTracesContext) void { | 6 | pub 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 | ; |
| 58 | 59 | ||
| 59 | // zig fmt: off | 60 | 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 | // debug | 312 | // debug |
| 313 | \\error: TheSkyIsFalling | 313 | \\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-safe | 319 | // release-safe |
| 320 | \\error: TheSkyIsFalling | 320 | \\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 | // debug | 339 | // debug |
| 340 | \\error: TheSkyIsFalling | 340 | \\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-safe | 349 | // release-safe |
| 350 | \\error: TheSkyIsFalling | 350 | \\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 | // debug | 372 | // debug |
| 373 | \\error: TheSkyIsFalling | 373 | \\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-safe | 388 | // release-safe |
| 389 | \\error: TheSkyIsFalling | 389 | \\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 | // debug | 442 | // debug |
| 443 | \\error: TheSkyIsFalling | 443 | \\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 | // debug | 468 | // debug |
| 469 | \\error: TheSkyIsFalling | 469 | \\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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const config = @import("builtin"); | ||
| 3 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 4 | 3 | ||
| 4 | const is_x86_64_linux = std.Target.current.cpu.arch == .x86_64 and std.Target.current.os.tag == .linux; | ||
| 5 | |||
| 5 | comptime { | 6 | comptime { |
| 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 | } |
| 14 | 15 | ||
| 15 | test "module level assembly" { | 16 | test "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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | test "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 | |||
| 16 | const S = struct { | ||
| 17 | a: u32, | ||
| 18 | b: Map, | ||
| 19 | |||
| 20 | const Map = StringHashMap(*S); | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub fn StringHashMap(comptime V: type) type { | ||
| 24 | return HashMap([]const u8, V); | ||
| 25 | } | ||
| 26 | |||
| 27 | pub 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | ||
| 4 | 3 | ||
| 5 | test "@byteSwap integers" { | 4 | test "@byteSwap integers" { |
| 6 | const ByteSwapIntTest = struct { | 5 | const ByteSwapIntTest = struct { |
| ... | @@ -41,10 +40,10 @@ test "@byteSwap integers" { | ... | @@ -41,10 +40,10 @@ test "@byteSwap integers" { |
| 41 | 40 | ||
| 42 | test "@byteSwap vectors" { | 41 | test "@byteSwap vectors" { |
| 43 | // https://github.com/ziglang/zig/issues/3563 | 42 | // 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; |
| 45 | 44 | ||
| 46 | // https://github.com/ziglang/zig/issues/3317 | 45 | // 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; |
| 48 | 47 | ||
| 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 | } |
| 489 | 489 | ||
| 490 | test "@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 | |||
| 490 | test "@intCast to u0 and use the result" { | 501 | test "@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 | } |
| 200 | 200 | ||
| 201 | fn testEnumTagNameBare(n: BareNumber) []const u8 { | 201 | test "@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 | |||
| 206 | test "@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 | |||
| 211 | fn testEnumTagNameBare(n: var) []const u8 { | ||
| 202 | return @tagName(n); | 212 | return @tagName(n); |
| 203 | } | 213 | } |
| 204 | 214 | ||
| ... | @@ -208,6 +218,17 @@ const BareNumber = enum { | ... | @@ -208,6 +218,17 @@ const BareNumber = enum { |
| 208 | Three, | 218 | Three, |
| 209 | }; | 219 | }; |
| 210 | 220 | ||
| 221 | const ExternDuplicates = extern enum(u8) { | ||
| 222 | A = 1, | ||
| 223 | B = 1, | ||
| 224 | }; | ||
| 225 | |||
| 226 | const NonExhaustive = enum(u8) { | ||
| 227 | A, | ||
| 228 | B, | ||
| 229 | _, | ||
| 230 | }; | ||
| 231 | |||
| 211 | test "enum alignment" { | 232 | test "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 | |||
| 811 | test "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 @@ |
| 1 | const expect = @import("std").testing.expect; | 1 | const std = @import("std"); |
| 2 | const testing = std.testing; | ||
| 3 | const expect = testing.expect; | ||
| 4 | const expectEqual = testing.expectEqual; | ||
| 2 | 5 | ||
| 3 | test "params" { | 6 | test "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 | |||
| 279 | test "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 | } |
| 526 | 526 | ||
| 527 | test "f128" { | 527 | test "f128" { |
| 528 | if (std.Target.current.isWindows()) { | 528 | if (std.Target.current.os.tag == .windows) { |
| 529 | // TODO https://github.com/ziglang/zig/issues/508 | 529 | // 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 | } |
| 620 | 620 | ||
| 621 | test "NaN comparison" { | 621 | test "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); |
| 337 | 337 | ||
| 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const std = @import("std"); |
| 2 | const expect = @import("std").testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | 3 | ||
| 4 | test "namespace depends on compile var" { | 4 | test "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 | } |
| 11 | const some_namespace = switch (builtin.os) { | 11 | const 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 | |||
| 322 | test "@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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const std = @import("std"); |
| 2 | const expect = @import("std").testing.expect; | 2 | const builtin = std.builtin; |
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 3 | 5 | ||
| 4 | test "@sizeOf and @TypeOf" { | 6 | test "@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 | |||
| 141 | test "@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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | 3 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 4 | const mem = std.mem; | 5 | const mem = std.mem; |
| 5 | 6 | ||
| 6 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | 7 | const 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 | } |
| 44 | 45 | ||
| 46 | test "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 | |||
| 45 | fn sliceSum(comptime q: []const u8) i32 { | 57 | fn 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 | |||
| 113 | test "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"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | const builtin = @import("builtin"); | ||
| 6 | 5 | ||
| 7 | test "implicit cast vector to array - bool" { | 6 | test "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" { |
| 114 | 113 | ||
| 115 | test "vector casts of sizes not divisable by 8" { | 114 | test "vector casts of sizes not divisable by 8" { |
| 116 | // https://github.com/ziglang/zig/issues/3563 | 115 | // 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; |
| 118 | 117 | ||
| 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 architectures | 24 | 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 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | extern var obj1_integer: usize; | ||
| 4 | extern var obj2_integer: usize; | ||
| 5 | |||
| 6 | test "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 @@ | ||
| 1 | extern var internal_integer: usize = 1; | ||
| 2 | extern var obj1_integer: usize = 421; | ||
| 3 | |||
| 4 | comptime { | ||
| 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 @@ | ||
| 1 | extern var internal_integer: usize = 2; | ||
| 2 | extern var obj2_integer: usize = 422; | ||
| 3 | |||
| 4 | comptime { | ||
| 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | ||
| 2 | const debug = std.debug; | 3 | const debug = std.debug; |
| 3 | const warn = debug.warn; | 4 | const warn = debug.warn; |
| 4 | const build = std.build; | 5 | const build = std.build; |
| 5 | pub const Target = build.Target; | 6 | const CrossTarget = std.zig.CrossTarget; |
| 6 | pub const CrossTarget = build.CrossTarget; | ||
| 7 | const Buffer = std.Buffer; | 7 | const Buffer = std.Buffer; |
| 8 | const io = std.io; | 8 | const io = std.io; |
| 9 | const fs = std.fs; | 9 | const fs = std.fs; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const fmt = std.fmt; | 11 | const fmt = std.fmt; |
| 12 | const ArrayList = std.ArrayList; | 12 | const ArrayList = std.ArrayList; |
| 13 | const builtin = @import("builtin"); | ||
| 14 | const Mode = builtin.Mode; | 13 | const Mode = builtin.Mode; |
| 15 | const LibExeObjStep = build.LibExeObjStep; | 14 | const LibExeObjStep = build.LibExeObjStep; |
| 16 | 15 | ||
| ... | @@ -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 |
| 31 | pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext; | 30 | pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutputContext; |
| 32 | 31 | ||
| 33 | const TestTarget = struct { | 32 | const 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 | }, |
| 54 | 53 | ||
| 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 | }, |
| 84 | 77 | ||
| 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 | }, |
| 104 | 93 | ||
| 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 | }, |
| 134 | 117 | ||
| 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/3287 | 131 | // 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 | //}, |
| 156 | 139 | ||
| 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 | }, |
| 176 | 155 | ||
| 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 | }, |
| 186 | 163 | ||
| 187 | // https://github.com/ziglang/zig/issues/4485 | 164 | // 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 | //}, |
| 198 | 173 | ||
| 199 | // https://github.com/ziglang/zig/issues/3340 | 174 | // 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 | //}, |
| 210 | 183 | ||
| 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/3295 | 190 | // TODO https://github.com/ziglang/zig/issues/3295 |
| 220 | .disable_native = true, | 191 | .disable_native = true, |
| 221 | }, | 192 | }, |
| 222 | 193 | ||
| 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 | }, |
| 232 | 201 | ||
| 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 | }, |
| 242 | 209 | ||
| 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 | }, |
| 253 | 218 | ||
| 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); |
| 467 | 430 | ||
| 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; |
| 471 | 434 | ||
| 472 | if (skip_libc and test_target.link_libc) | 435 | if (skip_libc and test_target.link_libc) |
| 473 | continue; | 436 | continue; |
| 474 | 437 | ||
| 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( |
| 482 | 445 | ||
| 483 | const ArchTag = @TagType(builtin.Arch); | 446 | const ArchTag = @TagType(builtin.Arch); |
| 484 | if (test_target.disable_native and | 447 | if (test_target.disable_native and |
| 485 | test_target.target.getOs() == builtin.os and | 448 | 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; |
| 495 | 458 | ||
| 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 | else | 463 | else |
| 501 | "bare"; | 464 | "bare"; |
| 502 | 465 | ||
| 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; | ||
| 507 | 467 | ||
| 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 windows | 656 | // 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{}, |
| 751 | 711 | ||
| 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; |
| 841 | 801 | ||
| 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 | } |
| 849 | 806 | ||
| 850 | switch (self.build_mode) { | 807 | switch (self.build_mode) { |
test/translate_c.zig+11-13| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const std = @import("std"); |
| 3 | const Target = @import("std").Target; | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | ||
| 5 | pub fn addCases(cases: *tests.TranslateCContext) void { | 5 | pub 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 | }); |
| 667 | 667 | ||
| 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_int | 669 | // 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 | }); |
| 1066 | 1066 | ||
| 1067 | if (builtin.os != builtin.Os.windows) { | 1067 | if (std.Target.current.os.tag != .windows) { |
| 1068 | // sysv_abi not currently supported on windows | 1068 | // 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 | }); |
| 1095 | 1095 | ||
| 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 | }); |
| 1115 | 1113 | ||
| 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 | }); |
| 1126 | 1124 | ||
| 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 | }); |
| 1598 | 1596 | ||
| 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 and | 1598 | // When clang uses the <arch>-windows-none triple it behaves as MSVC and |
| 1601 | // interprets the inner `struct Bar` as an anonymous structure | 1599 | // interprets the inner `struct Bar` as an anonymous structure |
| 1602 | cases.add("type referenced struct", | 1600 | cases.add("type referenced struct", |