mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 23:22:44 +00:00
Merge remote-tracking branch 'origin/master' into llvm10
This commit is contained in:
commit
d1cb16aace
@ -305,7 +305,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
|
||||
}
|
||||
dependOnLib(b, exe, ctx.llvm);
|
||||
|
||||
if (exe.target.getOs() == .linux) {
|
||||
if (exe.target.getOsTag() == .linux) {
|
||||
try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
|
||||
\\Unable to determine path to libstdc++.a
|
||||
\\On Fedora, install libstdc++-static and try again.
|
||||
|
@ -1,5 +1,5 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const fs = std.fs;
|
||||
const process = std.process;
|
||||
@ -10,8 +10,8 @@ const testing = std.testing;
|
||||
|
||||
const max_doc_file_size = 10 * 1024 * 1024;
|
||||
|
||||
const exe_ext = @as(std.build.Target, std.build.Target.Native).exeFileExt();
|
||||
const obj_ext = @as(std.build.Target, std.build.Target.Native).oFileExt();
|
||||
const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
|
||||
const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
|
||||
const tmp_dir_name = "docgen_tmp";
|
||||
const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
|
||||
|
||||
@ -521,7 +521,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
|
||||
return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {}", .{code_kind_str});
|
||||
}
|
||||
|
||||
var mode = builtin.Mode.Debug;
|
||||
var mode: builtin.Mode = .Debug;
|
||||
var link_objects = std.ArrayList([]const u8).init(allocator);
|
||||
defer link_objects.deinit();
|
||||
var target_str: ?[]const u8 = null;
|
||||
@ -533,9 +533,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
|
||||
const end_code_tag = try eatToken(tokenizer, Token.Id.TagContent);
|
||||
const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end];
|
||||
if (mem.eql(u8, end_tag_name, "code_release_fast")) {
|
||||
mode = builtin.Mode.ReleaseFast;
|
||||
mode = .ReleaseFast;
|
||||
} else if (mem.eql(u8, end_tag_name, "code_release_safe")) {
|
||||
mode = builtin.Mode.ReleaseSafe;
|
||||
mode = .ReleaseSafe;
|
||||
} else if (mem.eql(u8, end_tag_name, "code_link_object")) {
|
||||
_ = try eatToken(tokenizer, Token.Id.Separator);
|
||||
const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
|
||||
@ -1001,30 +1001,30 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
|
||||
for (toc.nodes) |node| {
|
||||
switch (node) {
|
||||
Node.Content => |data| {
|
||||
.Content => |data| {
|
||||
try out.write(data);
|
||||
},
|
||||
Node.Link => |info| {
|
||||
.Link => |info| {
|
||||
if (!toc.urls.contains(info.url)) {
|
||||
return parseError(tokenizer, info.token, "url not found: {}", .{info.url});
|
||||
}
|
||||
try out.print("<a href=\"#{}\">{}</a>", .{ info.url, info.name });
|
||||
},
|
||||
Node.Nav => {
|
||||
.Nav => {
|
||||
try out.write(toc.toc);
|
||||
},
|
||||
Node.Builtin => |tok| {
|
||||
.Builtin => |tok| {
|
||||
try out.write("<pre>");
|
||||
try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
|
||||
try out.write("</pre>");
|
||||
},
|
||||
Node.HeaderOpen => |info| {
|
||||
.HeaderOpen => |info| {
|
||||
try out.print(
|
||||
"<h{} id=\"{}\"><a href=\"#toc-{}\">{}</a> <a class=\"hdr\" href=\"#{}\">§</a></h{}>\n",
|
||||
.{ info.n, info.url, info.url, info.name, info.url, info.n },
|
||||
);
|
||||
},
|
||||
Node.SeeAlso => |items| {
|
||||
.SeeAlso => |items| {
|
||||
try out.write("<p>See also:</p><ul>\n");
|
||||
for (items) |item| {
|
||||
const url = try urlize(allocator, item.name);
|
||||
@ -1035,10 +1035,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
}
|
||||
try out.write("</ul>\n");
|
||||
},
|
||||
Node.Syntax => |content_tok| {
|
||||
.Syntax => |content_tok| {
|
||||
try tokenizeAndPrint(tokenizer, out, content_tok);
|
||||
},
|
||||
Node.Code => |code| {
|
||||
.Code => |code| {
|
||||
code_progress_index += 1;
|
||||
warn("docgen example code {}/{}...", .{ code_progress_index, tokenizer.code_node_count });
|
||||
|
||||
@ -1075,16 +1075,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", .{code.name});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try build_args.append("--release-safe");
|
||||
try out.print(" --release-safe", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try build_args.append("--release-fast");
|
||||
try out.print(" --release-fast", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try build_args.append("--release-small");
|
||||
try out.print(" --release-small", .{});
|
||||
},
|
||||
@ -1142,13 +1142,14 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
try out.print("\n{}</code></pre>\n", .{colored_stderr});
|
||||
break :code_block;
|
||||
}
|
||||
const exec_result = exec(allocator, &env_map, build_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{});
|
||||
const exec_result = exec(allocator, &env_map, build_args.toSliceConst()) catch
|
||||
return parseError(tokenizer, code.source_token, "example failed to compile", .{});
|
||||
|
||||
if (code.target_str) |triple| {
|
||||
if (mem.startsWith(u8, triple, "wasm32") or
|
||||
mem.startsWith(u8, triple, "riscv64-linux") or
|
||||
mem.startsWith(u8, triple, "x86_64-linux") and
|
||||
(builtin.os != .linux or builtin.arch != .x86_64))
|
||||
(mem.startsWith(u8, triple, "x86_64-linux") and
|
||||
std.Target.current.os.tag != .linux or std.Target.current.cpu.arch != .x86_64))
|
||||
{
|
||||
// skip execution
|
||||
try out.print("</code></pre>\n", .{});
|
||||
@ -1207,16 +1208,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try test_args.append("--release-safe");
|
||||
try out.print(" --release-safe", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try test_args.append("--release-fast");
|
||||
try out.print(" --release-fast", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try test_args.append("--release-small");
|
||||
try out.print(" --release-small", .{});
|
||||
},
|
||||
@ -1249,16 +1250,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try test_args.append("--release-safe");
|
||||
try out.print(" --release-safe", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try test_args.append("--release-fast");
|
||||
try out.print(" --release-fast", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try test_args.append("--release-small");
|
||||
try out.print(" --release-small", .{});
|
||||
},
|
||||
@ -1306,16 +1307,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
});
|
||||
var mode_arg: []const u8 = "";
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try test_args.append("--release-safe");
|
||||
mode_arg = " --release-safe";
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try test_args.append("--release-fast");
|
||||
mode_arg = " --release-fast";
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try test_args.append("--release-small");
|
||||
mode_arg = " --release-small";
|
||||
},
|
||||
@ -1386,20 +1387,20 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
}
|
||||
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try build_args.append("--release-safe");
|
||||
if (!code.is_inline) {
|
||||
try out.print(" --release-safe", .{});
|
||||
}
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try build_args.append("--release-fast");
|
||||
if (!code.is_inline) {
|
||||
try out.print(" --release-fast", .{});
|
||||
}
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try build_args.append("--release-small");
|
||||
if (!code.is_inline) {
|
||||
try out.print(" --release-small", .{});
|
||||
@ -1461,16 +1462,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
|
||||
});
|
||||
try out.print("<pre><code class=\"shell\">$ zig build-lib {}.zig", .{code.name});
|
||||
switch (code.mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => {
|
||||
.Debug => {},
|
||||
.ReleaseSafe => {
|
||||
try test_args.append("--release-safe");
|
||||
try out.print(" --release-safe", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseFast => {
|
||||
.ReleaseFast => {
|
||||
try test_args.append("--release-fast");
|
||||
try out.print(" --release-fast", .{});
|
||||
},
|
||||
builtin.Mode.ReleaseSmall => {
|
||||
.ReleaseSmall => {
|
||||
try test_args.append("--release-small");
|
||||
try out.print(" --release-small", .{});
|
||||
},
|
||||
|
@ -965,7 +965,8 @@ const nan = std.math.nan(f128);
|
||||
but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:</p>
|
||||
{#code_begin|obj|foo#}
|
||||
{#code_release_fast#}
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const big = @as(f64, 1 << 40);
|
||||
|
||||
export fn foo_strict(x: f64) f64 {
|
||||
@ -2063,15 +2064,15 @@ test "pointer child type" {
|
||||
alignment of the underlying type, it can be omitted from the type:
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
const assert = @import("std").debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test "variable alignment" {
|
||||
var x: i32 = 1234;
|
||||
const align_of_i32 = @alignOf(@TypeOf(x));
|
||||
assert(@TypeOf(&x) == *i32);
|
||||
assert(*i32 == *align(align_of_i32) i32);
|
||||
if (builtin.arch == builtin.Arch.x86_64) {
|
||||
if (std.Target.current.cpu.arch == .x86_64) {
|
||||
assert((*i32).alignment == 4);
|
||||
}
|
||||
}
|
||||
@ -2474,7 +2475,7 @@ test "default struct initialization fields" {
|
||||
</p>
|
||||
{#code_begin|test#}
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const Full = packed struct {
|
||||
@ -3204,8 +3205,8 @@ test "separate scopes" {
|
||||
|
||||
{#header_open|switch#}
|
||||
{#code_begin|test|switch#}
|
||||
const assert = @import("std").debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test "switch simple" {
|
||||
const a: u64 = 10;
|
||||
@ -3249,16 +3250,16 @@ test "switch simple" {
|
||||
}
|
||||
|
||||
// Switch expressions can be used outside a function:
|
||||
const os_msg = switch (builtin.os) {
|
||||
builtin.Os.linux => "we found a linux user",
|
||||
const os_msg = switch (std.Target.current.os.tag) {
|
||||
.linux => "we found a linux user",
|
||||
else => "not a linux user",
|
||||
};
|
||||
|
||||
// Inside a function, switch statements implicitly are compile-time
|
||||
// evaluated if the target expression is compile-time known.
|
||||
test "switch inside function" {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.fuchsia => {
|
||||
switch (std.Target.current.os.tag) {
|
||||
.fuchsia => {
|
||||
// On an OS other than fuchsia, block is not even analyzed,
|
||||
// so this compile error is not triggered.
|
||||
// On fuchsia this compile error would be triggered.
|
||||
@ -7330,8 +7331,6 @@ test "main" {
|
||||
the {#syntax#}export{#endsyntax#} keyword used on a function:
|
||||
</p>
|
||||
{#code_begin|obj#}
|
||||
const builtin = @import("builtin");
|
||||
|
||||
comptime {
|
||||
@export(internalName, .{ .name = "foo", .linkage = .Strong });
|
||||
}
|
||||
@ -9363,7 +9362,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
|
||||
</p>
|
||||
{#code_begin|test|detect_test#}
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test "builtin.is_test" {
|
||||
@ -9681,7 +9680,8 @@ WebAssembly.instantiate(typedArray, {
|
||||
<pre><code>$ node test.js
|
||||
The result is 3</code></pre>
|
||||
{#header_open|WASI#}
|
||||
<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>
|
||||
<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>
|
||||
{#code_begin|exe|wasi#}
|
||||
{#target_wasi#}
|
||||
const std = @import("std");
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std.zig");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
@ -15,6 +15,7 @@ const BufSet = std.BufSet;
|
||||
const BufMap = std.BufMap;
|
||||
const fmt_lib = std.fmt;
|
||||
const File = std.fs.File;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
pub const FmtStep = @import("build/fmt.zig").FmtStep;
|
||||
pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
|
||||
@ -521,24 +522,91 @@ pub const Builder = struct {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/// Exposes standard `zig build` options for choosing a target. Pass `null` to support all targets.
|
||||
pub fn standardTargetOptions(self: *Builder, supported_targets: ?[]const Target) Target {
|
||||
if (supported_targets) |target_list| {
|
||||
// TODO detect multiple args and emit an error message
|
||||
// there's probably a better way to collect the target
|
||||
for (target_list) |targ| {
|
||||
const targ_str = targ.zigTriple(self.allocator) catch unreachable;
|
||||
const targ_desc = targ.allocDescription(self.allocator) catch unreachable;
|
||||
const this_targ_opt = self.option(bool, targ_str, targ_desc) orelse false;
|
||||
if (this_targ_opt) {
|
||||
return targ;
|
||||
pub const StandardTargetOptionsArgs = struct {
|
||||
whitelist: ?[]const CrossTarget = null,
|
||||
|
||||
default_target: CrossTarget = CrossTarget{},
|
||||
};
|
||||
|
||||
/// Exposes standard `zig build` options for choosing a target.
|
||||
pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
|
||||
const triple = self.option(
|
||||
[]const u8,
|
||||
"target",
|
||||
"The CPU architecture, OS, and ABI to build for.",
|
||||
) orelse return args.default_target;
|
||||
|
||||
// TODO add cpu and features as part of the target triple
|
||||
|
||||
var diags: CrossTarget.ParseOptions.Diagnostics = .{};
|
||||
const selected_target = CrossTarget.parse(.{
|
||||
.arch_os_abi = triple,
|
||||
.diagnostics = &diags,
|
||||
}) catch |err| switch (err) {
|
||||
error.UnknownCpuModel => {
|
||||
std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
|
||||
diags.cpu_name.?,
|
||||
@tagName(diags.arch.?),
|
||||
});
|
||||
for (diags.arch.?.allCpuModels()) |cpu| {
|
||||
std.debug.warn(" {}\n", .{cpu.name});
|
||||
}
|
||||
process.exit(1);
|
||||
},
|
||||
error.UnknownCpuFeature => {
|
||||
std.debug.warn(
|
||||
\\Unknown CPU feature: '{}'
|
||||
\\Available CPU features for architecture '{}':
|
||||
\\
|
||||
, .{
|
||||
diags.unknown_feature_name,
|
||||
@tagName(diags.arch.?),
|
||||
});
|
||||
for (diags.arch.?.allFeaturesList()) |feature| {
|
||||
std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
|
||||
}
|
||||
process.exit(1);
|
||||
},
|
||||
error.UnknownOperatingSystem => {
|
||||
std.debug.warn(
|
||||
\\Unknown OS: '{}'
|
||||
\\Available operating systems:
|
||||
\\
|
||||
, .{diags.os_name});
|
||||
inline for (std.meta.fields(std.Target.Os.Tag)) |field| {
|
||||
std.debug.warn(" {}\n", .{field.name});
|
||||
}
|
||||
process.exit(1);
|
||||
},
|
||||
else => |e| {
|
||||
std.debug.warn("Unable to parse target '{}': {}\n", .{ triple, @errorName(e) });
|
||||
process.exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable;
|
||||
|
||||
if (args.whitelist) |list| whitelist_check: {
|
||||
// Make sure it's a match of one of the list.
|
||||
for (list) |t| {
|
||||
const t_triple = t.zigTriple(self.allocator) catch unreachable;
|
||||
if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
|
||||
break :whitelist_check;
|
||||
}
|
||||
}
|
||||
return Target.Native;
|
||||
} else {
|
||||
const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native;
|
||||
return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target
|
||||
std.debug.warn("Chosen target '{}' does not match one of the supported targets:\n", .{
|
||||
selected_canonicalized_triple,
|
||||
});
|
||||
for (list) |t| {
|
||||
const t_triple = t.zigTriple(self.allocator) catch unreachable;
|
||||
std.debug.warn(" {}\n", .{t_triple});
|
||||
}
|
||||
// TODO instead of process exit, return error and have a zig build flag implemented by
|
||||
// the build runner that turns process exits into error return traces
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return selected_target;
|
||||
}
|
||||
|
||||
pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
|
||||
@ -796,7 +864,7 @@ pub const Builder = struct {
|
||||
|
||||
pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
|
||||
// TODO report error for ambiguous situations
|
||||
const exe_extension = (Target{ .Native = {} }).exeFileExt();
|
||||
const exe_extension = @as(CrossTarget, .{}).exeFileExt();
|
||||
for (self.search_prefixes.toSliceConst()) |search_prefix| {
|
||||
for (names) |name| {
|
||||
if (fs.path.isAbsolute(name)) {
|
||||
@ -971,21 +1039,19 @@ pub const Builder = struct {
|
||||
};
|
||||
|
||||
test "builder.findProgram compiles" {
|
||||
// TODO: uncomment and fix the leak
|
||||
// const builder = try Builder.create(std.testing.allocator, "zig", "zig-cache", "zig-cache");
|
||||
const builder = try Builder.create(std.heap.page_allocator, "zig", "zig-cache", "zig-cache");
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const builder = try Builder.create(&arena.allocator, "zig", "zig-cache", "zig-cache");
|
||||
defer builder.destroy();
|
||||
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
|
||||
}
|
||||
|
||||
/// Deprecated. Use `builtin.Version`.
|
||||
/// Deprecated. Use `std.builtin.Version`.
|
||||
pub const Version = builtin.Version;
|
||||
|
||||
/// Deprecated. Use `std.Target.Cross`.
|
||||
pub const CrossTarget = std.Target.Cross;
|
||||
|
||||
/// Deprecated. Use `std.Target`.
|
||||
pub const Target = std.Target;
|
||||
/// Deprecated. Use `std.zig.CrossTarget`.
|
||||
pub const Target = std.zig.CrossTarget;
|
||||
|
||||
pub const Pkg = struct {
|
||||
name: []const u8,
|
||||
@ -1038,7 +1104,7 @@ pub const LibExeObjStep = struct {
|
||||
step: Step,
|
||||
builder: *Builder,
|
||||
name: []const u8,
|
||||
target: Target,
|
||||
target: CrossTarget = CrossTarget{},
|
||||
linker_script: ?[]const u8 = null,
|
||||
version_script: ?[]const u8 = null,
|
||||
out_filename: []const u8,
|
||||
@ -1076,7 +1142,7 @@ pub const LibExeObjStep = struct {
|
||||
out_pdb_filename: []const u8,
|
||||
packages: ArrayList(Pkg),
|
||||
build_options_contents: std.Buffer,
|
||||
system_linker_hack: bool,
|
||||
system_linker_hack: bool = false,
|
||||
|
||||
object_src: []const u8,
|
||||
|
||||
@ -1091,7 +1157,6 @@ pub const LibExeObjStep = struct {
|
||||
install_step: ?*InstallArtifactStep,
|
||||
|
||||
libc_file: ?[]const u8 = null,
|
||||
target_glibc: ?Version = null,
|
||||
|
||||
valgrind_support: ?bool = null,
|
||||
|
||||
@ -1112,8 +1177,6 @@ pub const LibExeObjStep = struct {
|
||||
/// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
|
||||
glibc_multi_install_dir: ?[]const u8 = null,
|
||||
|
||||
dynamic_linker: ?[]const u8 = null,
|
||||
|
||||
/// Position Independent Code
|
||||
force_pic: ?bool = null,
|
||||
|
||||
@ -1191,7 +1254,6 @@ pub const LibExeObjStep = struct {
|
||||
.kind = kind,
|
||||
.root_src = root_src,
|
||||
.name = name,
|
||||
.target = Target.Native,
|
||||
.frameworks = BufSet.init(builder.allocator),
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.version = ver,
|
||||
@ -1210,7 +1272,6 @@ pub const LibExeObjStep = struct {
|
||||
.object_src = undefined,
|
||||
.build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
|
||||
.c_std = Builder.CStd.C99,
|
||||
.system_linker_hack = false,
|
||||
.override_lib_dir = null,
|
||||
.main_pkg_path = null,
|
||||
.exec_cmd_args = null,
|
||||
@ -1282,36 +1343,11 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Deprecated. Use `setTheTarget`.
|
||||
pub fn setTarget(
|
||||
self: *LibExeObjStep,
|
||||
target_arch: builtin.Arch,
|
||||
target_os: builtin.Os,
|
||||
target_abi: builtin.Abi,
|
||||
) void {
|
||||
return self.setTheTarget(Target{
|
||||
.Cross = CrossTarget{
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.abi = target_abi,
|
||||
.cpu_features = target_arch.getBaselineCpuFeatures(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn setTheTarget(self: *LibExeObjStep, target: Target) void {
|
||||
pub fn setTarget(self: *LibExeObjStep, target: CrossTarget) void {
|
||||
self.target = target;
|
||||
self.computeOutFileNames();
|
||||
}
|
||||
|
||||
pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
|
||||
self.target_glibc = Version{
|
||||
.major = major,
|
||||
.minor = minor,
|
||||
.patch = patch,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
|
||||
self.output_dir = self.builder.dupePath(dir);
|
||||
}
|
||||
@ -1692,7 +1728,7 @@ pub const LibExeObjStep = struct {
|
||||
.NotFound => return error.VcpkgNotFound,
|
||||
.Found => |root| {
|
||||
const allocator = self.builder.allocator;
|
||||
const triplet = try Target.vcpkgTriplet(allocator, self.target, linkage);
|
||||
const triplet = try self.target.vcpkgTriplet(allocator, linkage);
|
||||
defer self.builder.allocator.free(triplet);
|
||||
|
||||
const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });
|
||||
@ -1862,10 +1898,10 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
switch (self.build_mode) {
|
||||
builtin.Mode.Debug => {},
|
||||
builtin.Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
|
||||
builtin.Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
|
||||
builtin.Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
|
||||
.Debug => {},
|
||||
.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
|
||||
.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
|
||||
.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
|
||||
}
|
||||
|
||||
try zig_args.append("--cache-dir");
|
||||
@ -1905,47 +1941,46 @@ pub const LibExeObjStep = struct {
|
||||
try zig_args.append(@tagName(self.code_model));
|
||||
}
|
||||
|
||||
switch (self.target) {
|
||||
.Native => {},
|
||||
.Cross => |cross| {
|
||||
try zig_args.append("-target");
|
||||
try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable);
|
||||
if (!self.target.isNative()) {
|
||||
try zig_args.append("-target");
|
||||
try zig_args.append(try self.target.zigTriple(builder.allocator));
|
||||
|
||||
const all_features = self.target.getArch().allFeaturesList();
|
||||
var populated_cpu_features = cross.cpu.model.features;
|
||||
populated_cpu_features.populateDependencies(all_features);
|
||||
// TODO this logic can disappear if cpu model + features becomes part of the target triple
|
||||
const cross = self.target.toTarget();
|
||||
const all_features = cross.cpu.arch.allFeaturesList();
|
||||
var populated_cpu_features = cross.cpu.model.features;
|
||||
populated_cpu_features.populateDependencies(all_features);
|
||||
|
||||
if (populated_cpu_features.eql(cross.cpu.features)) {
|
||||
// The CPU name alone is sufficient.
|
||||
// If it is the baseline CPU, no command line args are required.
|
||||
if (cross.cpu.model != Target.Cpu.baseline(self.target.getArch()).model) {
|
||||
try zig_args.append("-mcpu");
|
||||
try zig_args.append(cross.cpu.model.name);
|
||||
}
|
||||
} else {
|
||||
var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
|
||||
try mcpu_buffer.append(cross.cpu.model.name);
|
||||
|
||||
for (all_features) |feature, i_usize| {
|
||||
const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
|
||||
const in_cpu_set = populated_cpu_features.isEnabled(i);
|
||||
const in_actual_set = cross.cpu.features.isEnabled(i);
|
||||
if (in_cpu_set and !in_actual_set) {
|
||||
try mcpu_buffer.appendByte('-');
|
||||
try mcpu_buffer.append(feature.name);
|
||||
} else if (!in_cpu_set and in_actual_set) {
|
||||
try mcpu_buffer.appendByte('+');
|
||||
try mcpu_buffer.append(feature.name);
|
||||
}
|
||||
}
|
||||
try zig_args.append(mcpu_buffer.toSliceConst());
|
||||
if (populated_cpu_features.eql(cross.cpu.features)) {
|
||||
// The CPU name alone is sufficient.
|
||||
// If it is the baseline CPU, no command line args are required.
|
||||
if (cross.cpu.model != std.Target.Cpu.baseline(cross.cpu.arch).model) {
|
||||
try zig_args.append("-mcpu");
|
||||
try zig_args.append(cross.cpu.model.name);
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu=");
|
||||
try mcpu_buffer.append(cross.cpu.model.name);
|
||||
|
||||
if (self.target_glibc) |ver| {
|
||||
try zig_args.append("-target-glibc");
|
||||
try zig_args.append(builder.fmt("{}.{}.{}", .{ ver.major, ver.minor, ver.patch }));
|
||||
for (all_features) |feature, i_usize| {
|
||||
const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
|
||||
const in_cpu_set = populated_cpu_features.isEnabled(i);
|
||||
const in_actual_set = cross.cpu.features.isEnabled(i);
|
||||
if (in_cpu_set and !in_actual_set) {
|
||||
try mcpu_buffer.appendByte('-');
|
||||
try mcpu_buffer.append(feature.name);
|
||||
} else if (!in_cpu_set and in_actual_set) {
|
||||
try mcpu_buffer.appendByte('+');
|
||||
try mcpu_buffer.append(feature.name);
|
||||
}
|
||||
}
|
||||
try zig_args.append(mcpu_buffer.toSliceConst());
|
||||
}
|
||||
|
||||
if (self.target.dynamic_linker.get()) |dynamic_linker| {
|
||||
try zig_args.append("--dynamic-linker");
|
||||
try zig_args.append(dynamic_linker);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.linker_script) |linker_script| {
|
||||
@ -1953,11 +1988,6 @@ pub const LibExeObjStep = struct {
|
||||
zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
|
||||
}
|
||||
|
||||
if (self.dynamic_linker) |dynamic_linker| {
|
||||
try zig_args.append("--dynamic-linker");
|
||||
try zig_args.append(dynamic_linker);
|
||||
}
|
||||
|
||||
if (self.version_script) |version_script| {
|
||||
try zig_args.append("--version-script");
|
||||
try zig_args.append(builder.pathFromRoot(version_script));
|
||||
@ -1975,7 +2005,7 @@ pub const LibExeObjStep = struct {
|
||||
} else switch (self.target.getExternalExecutor()) {
|
||||
.native, .unavailable => {},
|
||||
.qemu => |bin_name| if (self.enable_qemu) qemu: {
|
||||
const need_cross_glibc = self.target.isGnu() and self.target.isLinux() and self.is_linking_libc;
|
||||
const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
|
||||
const glibc_dir_arg = if (need_cross_glibc)
|
||||
self.glibc_multi_install_dir orelse break :qemu
|
||||
else
|
||||
@ -2420,10 +2450,7 @@ const VcpkgRootStatus = enum {
|
||||
Found,
|
||||
};
|
||||
|
||||
pub const VcpkgLinkage = enum {
|
||||
Static,
|
||||
Dynamic,
|
||||
};
|
||||
pub const VcpkgLinkage = std.builtin.LinkMode;
|
||||
|
||||
pub const InstallDir = enum {
|
||||
Prefix,
|
||||
|
@ -82,7 +82,7 @@ pub const RunStep = struct {
|
||||
|
||||
var key: []const u8 = undefined;
|
||||
var prev_path: ?[]const u8 = undefined;
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
key = "Path";
|
||||
prev_path = env_map.get(key);
|
||||
if (prev_path == null) {
|
||||
|
@ -7,6 +7,7 @@ const LibExeObjStep = build.LibExeObjStep;
|
||||
const CheckFileStep = build.CheckFileStep;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
pub const TranslateCStep = struct {
|
||||
step: Step,
|
||||
@ -14,7 +15,7 @@ pub const TranslateCStep = struct {
|
||||
source: build.FileSource,
|
||||
output_dir: ?[]const u8,
|
||||
out_basename: []const u8,
|
||||
target: std.Target = .Native,
|
||||
target: CrossTarget = CrossTarget{},
|
||||
|
||||
pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
|
||||
const self = builder.allocator.create(TranslateCStep) catch unreachable;
|
||||
@ -39,7 +40,7 @@ pub const TranslateCStep = struct {
|
||||
) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn setTarget(self: *TranslateCStep, target: std.Target) void {
|
||||
pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
|
||||
self.target = target;
|
||||
}
|
||||
|
||||
@ -63,12 +64,9 @@ pub const TranslateCStep = struct {
|
||||
try argv_list.append("--cache");
|
||||
try argv_list.append("on");
|
||||
|
||||
switch (self.target) {
|
||||
.Native => {},
|
||||
.Cross => {
|
||||
try argv_list.append("-target");
|
||||
try argv_list.append(try self.target.zigTriple(self.builder.allocator));
|
||||
},
|
||||
if (!self.target.isNative()) {
|
||||
try argv_list.append("-target");
|
||||
try argv_list.append(try self.target.zigTriple(self.builder.allocator));
|
||||
}
|
||||
|
||||
try argv_list.append(self.source.getPath(self.builder));
|
||||
|
@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
|
||||
child: type,
|
||||
is_allowzero: bool,
|
||||
|
||||
/// This field is an optional type.
|
||||
/// The type of the sentinel is the element type of the pointer, which is
|
||||
/// the value of the `child` field in this struct. However there is no way
|
||||
/// to refer to that type here, so we use `var`.
|
||||
@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
|
||||
len: comptime_int,
|
||||
child: type,
|
||||
|
||||
/// This field is an optional type.
|
||||
/// The type of the sentinel is the element type of the array, which is
|
||||
/// the value of the `child` field in this struct. However there is no way
|
||||
/// to refer to that type here, so we use `var`.
|
||||
@ -398,7 +400,60 @@ pub const LinkMode = enum {
|
||||
pub const Version = struct {
|
||||
major: u32,
|
||||
minor: u32,
|
||||
patch: u32,
|
||||
patch: u32 = 0,
|
||||
|
||||
pub const Range = struct {
|
||||
min: Version,
|
||||
max: Version,
|
||||
|
||||
pub fn includesVersion(self: LinuxVersionRange, ver: Version) bool {
|
||||
if (self.min.compare(ver) == .gt) return false;
|
||||
if (self.max.compare(ver) == .lt) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn order(lhs: Version, rhs: Version) std.math.Order {
|
||||
if (lhs.major < rhs.major) return .lt;
|
||||
if (lhs.major > rhs.major) return .gt;
|
||||
if (lhs.minor < rhs.minor) return .lt;
|
||||
if (lhs.minor > rhs.minor) return .gt;
|
||||
if (lhs.patch < rhs.patch) return .lt;
|
||||
if (lhs.patch > rhs.patch) return .gt;
|
||||
return .eq;
|
||||
}
|
||||
|
||||
pub fn parse(text: []const u8) !Version {
|
||||
var it = std.mem.separate(text, ".");
|
||||
return Version{
|
||||
.major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
|
||||
.minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
|
||||
.patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Version,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Error: type,
|
||||
comptime output: fn (@TypeOf(context), []const u8) Error!void,
|
||||
) Error!void {
|
||||
if (fmt.len == 0) {
|
||||
if (self.patch == 0) {
|
||||
if (self.minor == 0) {
|
||||
return std.fmt.format(context, Error, output, "{}", .{self.major});
|
||||
} else {
|
||||
return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
|
||||
}
|
||||
} else {
|
||||
return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
|
||||
}
|
||||
} else {
|
||||
@compileError("Unknown format string: '" ++ fmt ++ "'");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// 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
|
||||
root.os.panic(msg, error_return_trace);
|
||||
unreachable;
|
||||
}
|
||||
switch (os) {
|
||||
switch (os.tag) {
|
||||
.freestanding => {
|
||||
while (true) {
|
||||
@breakpoint();
|
||||
|
@ -1,5 +1,5 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const page_size = std.mem.page_size;
|
||||
|
||||
pub const tokenizer = @import("c/tokenizer.zig");
|
||||
@ -10,7 +10,7 @@ pub const ast = @import("c/ast.zig");
|
||||
|
||||
pub usingnamespace @import("os/bits.zig");
|
||||
|
||||
pub usingnamespace switch (builtin.os) {
|
||||
pub usingnamespace switch (std.Target.current.os.tag) {
|
||||
.linux => @import("c/linux.zig"),
|
||||
.windows => @import("c/windows.zig"),
|
||||
.macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
|
||||
@ -46,17 +46,16 @@ pub fn versionCheck(glibc_version: builtin.Version) type {
|
||||
return struct {
|
||||
pub const ok = blk: {
|
||||
if (!builtin.link_libc) break :blk false;
|
||||
switch (builtin.abi) {
|
||||
.musl, .musleabi, .musleabihf => break :blk true,
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => {
|
||||
const ver = builtin.glibc_version orelse break :blk false;
|
||||
if (ver.major < glibc_version.major) break :blk false;
|
||||
if (ver.major > glibc_version.major) break :blk true;
|
||||
if (ver.minor < glibc_version.minor) break :blk false;
|
||||
if (ver.minor > glibc_version.minor) break :blk true;
|
||||
break :blk ver.patch >= glibc_version.patch;
|
||||
},
|
||||
else => break :blk false,
|
||||
if (std.Target.current.abi.isMusl()) break :blk true;
|
||||
if (std.Target.current.isGnuLibC()) {
|
||||
const ver = std.Target.current.os.version_range.linux.glibc;
|
||||
const order = ver.order(glibc_version);
|
||||
break :blk switch (order) {
|
||||
.gt, .eq => true,
|
||||
.lt => false,
|
||||
};
|
||||
} else {
|
||||
break :blk false;
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -109,6 +108,7 @@ pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8
|
||||
pub extern "c" fn dup(fd: fd_t) c_int;
|
||||
pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
|
||||
pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||
pub extern "c" fn readlinkat(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||
pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||
pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
|
||||
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
|
||||
pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int;
|
||||
pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int;
|
||||
pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int;
|
||||
pub extern "c" fn uname(buf: *utsname) c_int;
|
||||
|
||||
pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
|
||||
pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;
|
||||
|
@ -94,7 +94,7 @@ pub const pthread_cond_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
|
||||
};
|
||||
const __SIZEOF_PTHREAD_COND_T = 48;
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) {
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) {
|
||||
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
|
||||
.aarch64 => 48,
|
||||
|
@ -17,9 +17,9 @@ const TailQueue = std.TailQueue;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
pub const ChildProcess = struct {
|
||||
pid: if (builtin.os == .windows) void else i32,
|
||||
handle: if (builtin.os == .windows) windows.HANDLE else void,
|
||||
thread_handle: if (builtin.os == .windows) windows.HANDLE else void,
|
||||
pid: if (builtin.os.tag == .windows) void else i32,
|
||||
handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
|
||||
thread_handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
|
||||
|
||||
allocator: *mem.Allocator,
|
||||
|
||||
@ -39,15 +39,15 @@ pub const ChildProcess = struct {
|
||||
stderr_behavior: StdIo,
|
||||
|
||||
/// Set to change the user id when spawning the child process.
|
||||
uid: if (builtin.os == .windows) void else ?u32,
|
||||
uid: if (builtin.os.tag == .windows) void else ?u32,
|
||||
|
||||
/// Set to change the group id when spawning the child process.
|
||||
gid: if (builtin.os == .windows) void else ?u32,
|
||||
gid: if (builtin.os.tag == .windows) void else ?u32,
|
||||
|
||||
/// Set to change the current working directory when spawning the child process.
|
||||
cwd: ?[]const u8,
|
||||
|
||||
err_pipe: if (builtin.os == .windows) void else [2]os.fd_t,
|
||||
err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t,
|
||||
|
||||
expand_arg0: Arg0Expand,
|
||||
|
||||
@ -96,8 +96,8 @@ pub const ChildProcess = struct {
|
||||
.term = null,
|
||||
.env_map = null,
|
||||
.cwd = null,
|
||||
.uid = if (builtin.os == .windows) {} else null,
|
||||
.gid = if (builtin.os == .windows) {} else null,
|
||||
.uid = if (builtin.os.tag == .windows) {} else null,
|
||||
.gid = if (builtin.os.tag == .windows) {} else null,
|
||||
.stdin = null,
|
||||
.stdout = null,
|
||||
.stderr = null,
|
||||
@ -118,7 +118,7 @@ pub const ChildProcess = struct {
|
||||
|
||||
/// On success must call `kill` or `wait`.
|
||||
pub fn spawn(self: *ChildProcess) SpawnError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return self.spawnWindows();
|
||||
} else {
|
||||
return self.spawnPosix();
|
||||
@ -132,7 +132,7 @@ pub const ChildProcess = struct {
|
||||
|
||||
/// Forcibly terminates child process and then cleans up all resources.
|
||||
pub fn kill(self: *ChildProcess) !Term {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return self.killWindows(1);
|
||||
} else {
|
||||
return self.killPosix();
|
||||
@ -162,7 +162,7 @@ pub const ChildProcess = struct {
|
||||
|
||||
/// Blocks until child process terminates and then cleans up all resources.
|
||||
pub fn wait(self: *ChildProcess) !Term {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return self.waitWindows();
|
||||
} else {
|
||||
return self.waitPosix();
|
||||
@ -307,7 +307,7 @@ pub const ChildProcess = struct {
|
||||
fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
|
||||
defer destroyPipe(self.err_pipe);
|
||||
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
var fd = [1]std.os.pollfd{std.os.pollfd{
|
||||
.fd = self.err_pipe[0],
|
||||
.events = std.os.POLLIN,
|
||||
@ -402,7 +402,7 @@ pub const ChildProcess = struct {
|
||||
// This pipe is used to communicate errors between the time of fork
|
||||
// and execve from the child process to the parent process.
|
||||
const err_pipe = blk: {
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
const fd = try os.eventfd(0, 0);
|
||||
// There's no distinction between the readable and the writeable
|
||||
// end with eventfd
|
||||
|
@ -120,7 +120,7 @@ fn usage() void {
|
||||
}
|
||||
|
||||
fn mode(comptime x: comptime_int) comptime_int {
|
||||
return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
|
||||
return if (builtin.mode == .Debug) x / 64 else x;
|
||||
}
|
||||
|
||||
// TODO(#1358): Replace with builtin formatted padding when available.
|
||||
|
@ -4,8 +4,8 @@ const debug = std.debug;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const line_sep = switch (builtin.os) {
|
||||
builtin.Os.windows => "\r\n",
|
||||
pub const line_sep = switch (builtin.os.tag) {
|
||||
.windows => "\r\n",
|
||||
else => "\n",
|
||||
};
|
||||
|
||||
@ -28,7 +28,7 @@ test "cstr fns" {
|
||||
|
||||
fn testCStrFnsImpl() void {
|
||||
testing.expect(cmp("aoeu", "aoez") == -1);
|
||||
testing.expect(mem.len(u8, "123456789") == 9);
|
||||
testing.expect(mem.len("123456789") == 9);
|
||||
}
|
||||
|
||||
/// Returns a mutable, null-terminated slice with the same length as `slice`.
|
||||
|
1873
lib/std/debug.zig
1873
lib/std/debug.zig
File diff suppressed because it is too large
Load Diff
1497
lib/std/dwarf.zig
1497
lib/std/dwarf.zig
File diff suppressed because it is too large
Load Diff
682
lib/std/dwarf_bits.zig
Normal file
682
lib/std/dwarf_bits.zig
Normal file
@ -0,0 +1,682 @@
|
||||
pub const TAG_padding = 0x00;
|
||||
pub const TAG_array_type = 0x01;
|
||||
pub const TAG_class_type = 0x02;
|
||||
pub const TAG_entry_point = 0x03;
|
||||
pub const TAG_enumeration_type = 0x04;
|
||||
pub const TAG_formal_parameter = 0x05;
|
||||
pub const TAG_imported_declaration = 0x08;
|
||||
pub const TAG_label = 0x0a;
|
||||
pub const TAG_lexical_block = 0x0b;
|
||||
pub const TAG_member = 0x0d;
|
||||
pub const TAG_pointer_type = 0x0f;
|
||||
pub const TAG_reference_type = 0x10;
|
||||
pub const TAG_compile_unit = 0x11;
|
||||
pub const TAG_string_type = 0x12;
|
||||
pub const TAG_structure_type = 0x13;
|
||||
pub const TAG_subroutine = 0x14;
|
||||
pub const TAG_subroutine_type = 0x15;
|
||||
pub const TAG_typedef = 0x16;
|
||||
pub const TAG_union_type = 0x17;
|
||||
pub const TAG_unspecified_parameters = 0x18;
|
||||
pub const TAG_variant = 0x19;
|
||||
pub const TAG_common_block = 0x1a;
|
||||
pub const TAG_common_inclusion = 0x1b;
|
||||
pub const TAG_inheritance = 0x1c;
|
||||
pub const TAG_inlined_subroutine = 0x1d;
|
||||
pub const TAG_module = 0x1e;
|
||||
pub const TAG_ptr_to_member_type = 0x1f;
|
||||
pub const TAG_set_type = 0x20;
|
||||
pub const TAG_subrange_type = 0x21;
|
||||
pub const TAG_with_stmt = 0x22;
|
||||
pub const TAG_access_declaration = 0x23;
|
||||
pub const TAG_base_type = 0x24;
|
||||
pub const TAG_catch_block = 0x25;
|
||||
pub const TAG_const_type = 0x26;
|
||||
pub const TAG_constant = 0x27;
|
||||
pub const TAG_enumerator = 0x28;
|
||||
pub const TAG_file_type = 0x29;
|
||||
pub const TAG_friend = 0x2a;
|
||||
pub const TAG_namelist = 0x2b;
|
||||
pub const TAG_namelist_item = 0x2c;
|
||||
pub const TAG_packed_type = 0x2d;
|
||||
pub const TAG_subprogram = 0x2e;
|
||||
pub const TAG_template_type_param = 0x2f;
|
||||
pub const TAG_template_value_param = 0x30;
|
||||
pub const TAG_thrown_type = 0x31;
|
||||
pub const TAG_try_block = 0x32;
|
||||
pub const TAG_variant_part = 0x33;
|
||||
pub const TAG_variable = 0x34;
|
||||
pub const TAG_volatile_type = 0x35;
|
||||
|
||||
// DWARF 3
|
||||
pub const TAG_dwarf_procedure = 0x36;
|
||||
pub const TAG_restrict_type = 0x37;
|
||||
pub const TAG_interface_type = 0x38;
|
||||
pub const TAG_namespace = 0x39;
|
||||
pub const TAG_imported_module = 0x3a;
|
||||
pub const TAG_unspecified_type = 0x3b;
|
||||
pub const TAG_partial_unit = 0x3c;
|
||||
pub const TAG_imported_unit = 0x3d;
|
||||
pub const TAG_condition = 0x3f;
|
||||
pub const TAG_shared_type = 0x40;
|
||||
|
||||
// DWARF 4
|
||||
pub const TAG_type_unit = 0x41;
|
||||
pub const TAG_rvalue_reference_type = 0x42;
|
||||
pub const TAG_template_alias = 0x43;
|
||||
|
||||
pub const TAG_lo_user = 0x4080;
|
||||
pub const TAG_hi_user = 0xffff;
|
||||
|
||||
// SGI/MIPS Extensions.
|
||||
pub const DW_TAG_MIPS_loop = 0x4081;
|
||||
|
||||
// HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .
|
||||
pub const TAG_HP_array_descriptor = 0x4090;
|
||||
pub const TAG_HP_Bliss_field = 0x4091;
|
||||
pub const TAG_HP_Bliss_field_set = 0x4092;
|
||||
|
||||
// GNU extensions.
|
||||
pub const TAG_format_label = 0x4101; // For FORTRAN 77 and Fortran 90.
|
||||
pub const TAG_function_template = 0x4102; // For C++.
|
||||
pub const TAG_class_template = 0x4103; //For C++.
|
||||
pub const TAG_GNU_BINCL = 0x4104;
|
||||
pub const TAG_GNU_EINCL = 0x4105;
|
||||
|
||||
// Template template parameter.
|
||||
// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
|
||||
pub const TAG_GNU_template_template_param = 0x4106;
|
||||
|
||||
// Template parameter pack extension = specified at
|
||||
// http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates
|
||||
// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
|
||||
// are properly part of DWARF 5.
|
||||
pub const TAG_GNU_template_parameter_pack = 0x4107;
|
||||
pub const TAG_GNU_formal_parameter_pack = 0x4108;
|
||||
// The GNU call site extension = specified at
|
||||
// http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
|
||||
// The values of these two TAGS are in the DW_TAG_GNU_* space until the tags
|
||||
// are properly part of DWARF 5.
|
||||
pub const TAG_GNU_call_site = 0x4109;
|
||||
pub const TAG_GNU_call_site_parameter = 0x410a;
|
||||
// Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf.
|
||||
pub const TAG_upc_shared_type = 0x8765;
|
||||
pub const TAG_upc_strict_type = 0x8766;
|
||||
pub const TAG_upc_relaxed_type = 0x8767;
|
||||
// PGI (STMicroelectronics; extensions. No documentation available.
|
||||
pub const TAG_PGI_kanji_type = 0xA000;
|
||||
pub const TAG_PGI_interface_block = 0xA020;
|
||||
|
||||
pub const FORM_addr = 0x01;
|
||||
pub const FORM_block2 = 0x03;
|
||||
pub const FORM_block4 = 0x04;
|
||||
pub const FORM_data2 = 0x05;
|
||||
pub const FORM_data4 = 0x06;
|
||||
pub const FORM_data8 = 0x07;
|
||||
pub const FORM_string = 0x08;
|
||||
pub const FORM_block = 0x09;
|
||||
pub const FORM_block1 = 0x0a;
|
||||
pub const FORM_data1 = 0x0b;
|
||||
pub const FORM_flag = 0x0c;
|
||||
pub const FORM_sdata = 0x0d;
|
||||
pub const FORM_strp = 0x0e;
|
||||
pub const FORM_udata = 0x0f;
|
||||
pub const FORM_ref_addr = 0x10;
|
||||
pub const FORM_ref1 = 0x11;
|
||||
pub const FORM_ref2 = 0x12;
|
||||
pub const FORM_ref4 = 0x13;
|
||||
pub const FORM_ref8 = 0x14;
|
||||
pub const FORM_ref_udata = 0x15;
|
||||
pub const FORM_indirect = 0x16;
|
||||
pub const FORM_sec_offset = 0x17;
|
||||
pub const FORM_exprloc = 0x18;
|
||||
pub const FORM_flag_present = 0x19;
|
||||
pub const FORM_ref_sig8 = 0x20;
|
||||
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
pub const FORM_GNU_addr_index = 0x1f01;
|
||||
pub const FORM_GNU_str_index = 0x1f02;
|
||||
|
||||
// Extensions for DWZ multifile.
|
||||
// See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .
|
||||
pub const FORM_GNU_ref_alt = 0x1f20;
|
||||
pub const FORM_GNU_strp_alt = 0x1f21;
|
||||
|
||||
pub const AT_sibling = 0x01;
|
||||
pub const AT_location = 0x02;
|
||||
pub const AT_name = 0x03;
|
||||
pub const AT_ordering = 0x09;
|
||||
pub const AT_subscr_data = 0x0a;
|
||||
pub const AT_byte_size = 0x0b;
|
||||
pub const AT_bit_offset = 0x0c;
|
||||
pub const AT_bit_size = 0x0d;
|
||||
pub const AT_element_list = 0x0f;
|
||||
pub const AT_stmt_list = 0x10;
|
||||
pub const AT_low_pc = 0x11;
|
||||
pub const AT_high_pc = 0x12;
|
||||
pub const AT_language = 0x13;
|
||||
pub const AT_member = 0x14;
|
||||
pub const AT_discr = 0x15;
|
||||
pub const AT_discr_value = 0x16;
|
||||
pub const AT_visibility = 0x17;
|
||||
pub const AT_import = 0x18;
|
||||
pub const AT_string_length = 0x19;
|
||||
pub const AT_common_reference = 0x1a;
|
||||
pub const AT_comp_dir = 0x1b;
|
||||
pub const AT_const_value = 0x1c;
|
||||
pub const AT_containing_type = 0x1d;
|
||||
pub const AT_default_value = 0x1e;
|
||||
pub const AT_inline = 0x20;
|
||||
pub const AT_is_optional = 0x21;
|
||||
pub const AT_lower_bound = 0x22;
|
||||
pub const AT_producer = 0x25;
|
||||
pub const AT_prototyped = 0x27;
|
||||
pub const AT_return_addr = 0x2a;
|
||||
pub const AT_start_scope = 0x2c;
|
||||
pub const AT_bit_stride = 0x2e;
|
||||
pub const AT_upper_bound = 0x2f;
|
||||
pub const AT_abstract_origin = 0x31;
|
||||
pub const AT_accessibility = 0x32;
|
||||
pub const AT_address_class = 0x33;
|
||||
pub const AT_artificial = 0x34;
|
||||
pub const AT_base_types = 0x35;
|
||||
pub const AT_calling_convention = 0x36;
|
||||
pub const AT_count = 0x37;
|
||||
pub const AT_data_member_location = 0x38;
|
||||
pub const AT_decl_column = 0x39;
|
||||
pub const AT_decl_file = 0x3a;
|
||||
pub const AT_decl_line = 0x3b;
|
||||
pub const AT_declaration = 0x3c;
|
||||
pub const AT_discr_list = 0x3d;
|
||||
pub const AT_encoding = 0x3e;
|
||||
pub const AT_external = 0x3f;
|
||||
pub const AT_frame_base = 0x40;
|
||||
pub const AT_friend = 0x41;
|
||||
pub const AT_identifier_case = 0x42;
|
||||
pub const AT_macro_info = 0x43;
|
||||
pub const AT_namelist_items = 0x44;
|
||||
pub const AT_priority = 0x45;
|
||||
pub const AT_segment = 0x46;
|
||||
pub const AT_specification = 0x47;
|
||||
pub const AT_static_link = 0x48;
|
||||
pub const AT_type = 0x49;
|
||||
pub const AT_use_location = 0x4a;
|
||||
pub const AT_variable_parameter = 0x4b;
|
||||
pub const AT_virtuality = 0x4c;
|
||||
pub const AT_vtable_elem_location = 0x4d;
|
||||
|
||||
// DWARF 3 values.
|
||||
pub const AT_allocated = 0x4e;
|
||||
pub const AT_associated = 0x4f;
|
||||
pub const AT_data_location = 0x50;
|
||||
pub const AT_byte_stride = 0x51;
|
||||
pub const AT_entry_pc = 0x52;
|
||||
pub const AT_use_UTF8 = 0x53;
|
||||
pub const AT_extension = 0x54;
|
||||
pub const AT_ranges = 0x55;
|
||||
pub const AT_trampoline = 0x56;
|
||||
pub const AT_call_column = 0x57;
|
||||
pub const AT_call_file = 0x58;
|
||||
pub const AT_call_line = 0x59;
|
||||
pub const AT_description = 0x5a;
|
||||
pub const AT_binary_scale = 0x5b;
|
||||
pub const AT_decimal_scale = 0x5c;
|
||||
pub const AT_small = 0x5d;
|
||||
pub const AT_decimal_sign = 0x5e;
|
||||
pub const AT_digit_count = 0x5f;
|
||||
pub const AT_picture_string = 0x60;
|
||||
pub const AT_mutable = 0x61;
|
||||
pub const AT_threads_scaled = 0x62;
|
||||
pub const AT_explicit = 0x63;
|
||||
pub const AT_object_pointer = 0x64;
|
||||
pub const AT_endianity = 0x65;
|
||||
pub const AT_elemental = 0x66;
|
||||
pub const AT_pure = 0x67;
|
||||
pub const AT_recursive = 0x68;
|
||||
|
||||
// DWARF 4.
|
||||
pub const AT_signature = 0x69;
|
||||
pub const AT_main_subprogram = 0x6a;
|
||||
pub const AT_data_bit_offset = 0x6b;
|
||||
pub const AT_const_expr = 0x6c;
|
||||
pub const AT_enum_class = 0x6d;
|
||||
pub const AT_linkage_name = 0x6e;
|
||||
|
||||
// DWARF 5
|
||||
pub const AT_alignment = 0x88;
|
||||
|
||||
pub const AT_lo_user = 0x2000; // Implementation-defined range start.
|
||||
pub const AT_hi_user = 0x3fff; // Implementation-defined range end.
|
||||
|
||||
// SGI/MIPS extensions.
|
||||
pub const AT_MIPS_fde = 0x2001;
|
||||
pub const AT_MIPS_loop_begin = 0x2002;
|
||||
pub const AT_MIPS_tail_loop_begin = 0x2003;
|
||||
pub const AT_MIPS_epilog_begin = 0x2004;
|
||||
pub const AT_MIPS_loop_unroll_factor = 0x2005;
|
||||
pub const AT_MIPS_software_pipeline_depth = 0x2006;
|
||||
pub const AT_MIPS_linkage_name = 0x2007;
|
||||
pub const AT_MIPS_stride = 0x2008;
|
||||
pub const AT_MIPS_abstract_name = 0x2009;
|
||||
pub const AT_MIPS_clone_origin = 0x200a;
|
||||
pub const AT_MIPS_has_inlines = 0x200b;
|
||||
|
||||
// HP extensions.
|
||||
pub const AT_HP_block_index = 0x2000;
|
||||
pub const AT_HP_unmodifiable = 0x2001; // Same as DW_AT_MIPS_fde.
|
||||
pub const AT_HP_prologue = 0x2005; // Same as DW_AT_MIPS_loop_unroll.
|
||||
pub const AT_HP_epilogue = 0x2008; // Same as DW_AT_MIPS_stride.
|
||||
pub const AT_HP_actuals_stmt_list = 0x2010;
|
||||
pub const AT_HP_proc_per_section = 0x2011;
|
||||
pub const AT_HP_raw_data_ptr = 0x2012;
|
||||
pub const AT_HP_pass_by_reference = 0x2013;
|
||||
pub const AT_HP_opt_level = 0x2014;
|
||||
pub const AT_HP_prof_version_id = 0x2015;
|
||||
pub const AT_HP_opt_flags = 0x2016;
|
||||
pub const AT_HP_cold_region_low_pc = 0x2017;
|
||||
pub const AT_HP_cold_region_high_pc = 0x2018;
|
||||
pub const AT_HP_all_variables_modifiable = 0x2019;
|
||||
pub const AT_HP_linkage_name = 0x201a;
|
||||
pub const AT_HP_prof_flags = 0x201b; // In comp unit of procs_info for -g.
|
||||
pub const AT_HP_unit_name = 0x201f;
|
||||
pub const AT_HP_unit_size = 0x2020;
|
||||
pub const AT_HP_widened_byte_size = 0x2021;
|
||||
pub const AT_HP_definition_points = 0x2022;
|
||||
pub const AT_HP_default_location = 0x2023;
|
||||
pub const AT_HP_is_result_param = 0x2029;
|
||||
|
||||
// GNU extensions.
|
||||
pub const AT_sf_names = 0x2101;
|
||||
pub const AT_src_info = 0x2102;
|
||||
pub const AT_mac_info = 0x2103;
|
||||
pub const AT_src_coords = 0x2104;
|
||||
pub const AT_body_begin = 0x2105;
|
||||
pub const AT_body_end = 0x2106;
|
||||
pub const AT_GNU_vector = 0x2107;
|
||||
// Thread-safety annotations.
|
||||
// See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation .
|
||||
pub const AT_GNU_guarded_by = 0x2108;
|
||||
pub const AT_GNU_pt_guarded_by = 0x2109;
|
||||
pub const AT_GNU_guarded = 0x210a;
|
||||
pub const AT_GNU_pt_guarded = 0x210b;
|
||||
pub const AT_GNU_locks_excluded = 0x210c;
|
||||
pub const AT_GNU_exclusive_locks_required = 0x210d;
|
||||
pub const AT_GNU_shared_locks_required = 0x210e;
|
||||
// One-definition rule violation detection.
|
||||
// See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo .
|
||||
pub const AT_GNU_odr_signature = 0x210f;
|
||||
// Template template argument name.
|
||||
// See http://gcc.gnu.org/wiki/TemplateParmsDwarf .
|
||||
pub const AT_GNU_template_name = 0x2110;
|
||||
// The GNU call site extension.
|
||||
// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open .
|
||||
pub const AT_GNU_call_site_value = 0x2111;
|
||||
pub const AT_GNU_call_site_data_value = 0x2112;
|
||||
pub const AT_GNU_call_site_target = 0x2113;
|
||||
pub const AT_GNU_call_site_target_clobbered = 0x2114;
|
||||
pub const AT_GNU_tail_call = 0x2115;
|
||||
pub const AT_GNU_all_tail_call_sites = 0x2116;
|
||||
pub const AT_GNU_all_call_sites = 0x2117;
|
||||
pub const AT_GNU_all_source_call_sites = 0x2118;
|
||||
// Section offset into .debug_macro section.
|
||||
pub const AT_GNU_macros = 0x2119;
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
pub const AT_GNU_dwo_name = 0x2130;
|
||||
pub const AT_GNU_dwo_id = 0x2131;
|
||||
pub const AT_GNU_ranges_base = 0x2132;
|
||||
pub const AT_GNU_addr_base = 0x2133;
|
||||
pub const AT_GNU_pubnames = 0x2134;
|
||||
pub const AT_GNU_pubtypes = 0x2135;
|
||||
// VMS extensions.
|
||||
pub const AT_VMS_rtnbeg_pd_address = 0x2201;
|
||||
// GNAT extensions.
|
||||
// GNAT descriptive type.
|
||||
// See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type .
|
||||
pub const AT_use_GNAT_descriptive_type = 0x2301;
|
||||
pub const AT_GNAT_descriptive_type = 0x2302;
|
||||
// UPC extension.
|
||||
pub const AT_upc_threads_scaled = 0x3210;
|
||||
// PGI (STMicroelectronics) extensions.
|
||||
pub const AT_PGI_lbase = 0x3a00;
|
||||
pub const AT_PGI_soffset = 0x3a01;
|
||||
pub const AT_PGI_lstride = 0x3a02;
|
||||
|
||||
pub const OP_addr = 0x03;
|
||||
pub const OP_deref = 0x06;
|
||||
pub const OP_const1u = 0x08;
|
||||
pub const OP_const1s = 0x09;
|
||||
pub const OP_const2u = 0x0a;
|
||||
pub const OP_const2s = 0x0b;
|
||||
pub const OP_const4u = 0x0c;
|
||||
pub const OP_const4s = 0x0d;
|
||||
pub const OP_const8u = 0x0e;
|
||||
pub const OP_const8s = 0x0f;
|
||||
pub const OP_constu = 0x10;
|
||||
pub const OP_consts = 0x11;
|
||||
pub const OP_dup = 0x12;
|
||||
pub const OP_drop = 0x13;
|
||||
pub const OP_over = 0x14;
|
||||
pub const OP_pick = 0x15;
|
||||
pub const OP_swap = 0x16;
|
||||
pub const OP_rot = 0x17;
|
||||
pub const OP_xderef = 0x18;
|
||||
pub const OP_abs = 0x19;
|
||||
pub const OP_and = 0x1a;
|
||||
pub const OP_div = 0x1b;
|
||||
pub const OP_minus = 0x1c;
|
||||
pub const OP_mod = 0x1d;
|
||||
pub const OP_mul = 0x1e;
|
||||
pub const OP_neg = 0x1f;
|
||||
pub const OP_not = 0x20;
|
||||
pub const OP_or = 0x21;
|
||||
pub const OP_plus = 0x22;
|
||||
pub const OP_plus_uconst = 0x23;
|
||||
pub const OP_shl = 0x24;
|
||||
pub const OP_shr = 0x25;
|
||||
pub const OP_shra = 0x26;
|
||||
pub const OP_xor = 0x27;
|
||||
pub const OP_bra = 0x28;
|
||||
pub const OP_eq = 0x29;
|
||||
pub const OP_ge = 0x2a;
|
||||
pub const OP_gt = 0x2b;
|
||||
pub const OP_le = 0x2c;
|
||||
pub const OP_lt = 0x2d;
|
||||
pub const OP_ne = 0x2e;
|
||||
pub const OP_skip = 0x2f;
|
||||
pub const OP_lit0 = 0x30;
|
||||
pub const OP_lit1 = 0x31;
|
||||
pub const OP_lit2 = 0x32;
|
||||
pub const OP_lit3 = 0x33;
|
||||
pub const OP_lit4 = 0x34;
|
||||
pub const OP_lit5 = 0x35;
|
||||
pub const OP_lit6 = 0x36;
|
||||
pub const OP_lit7 = 0x37;
|
||||
pub const OP_lit8 = 0x38;
|
||||
pub const OP_lit9 = 0x39;
|
||||
pub const OP_lit10 = 0x3a;
|
||||
pub const OP_lit11 = 0x3b;
|
||||
pub const OP_lit12 = 0x3c;
|
||||
pub const OP_lit13 = 0x3d;
|
||||
pub const OP_lit14 = 0x3e;
|
||||
pub const OP_lit15 = 0x3f;
|
||||
pub const OP_lit16 = 0x40;
|
||||
pub const OP_lit17 = 0x41;
|
||||
pub const OP_lit18 = 0x42;
|
||||
pub const OP_lit19 = 0x43;
|
||||
pub const OP_lit20 = 0x44;
|
||||
pub const OP_lit21 = 0x45;
|
||||
pub const OP_lit22 = 0x46;
|
||||
pub const OP_lit23 = 0x47;
|
||||
pub const OP_lit24 = 0x48;
|
||||
pub const OP_lit25 = 0x49;
|
||||
pub const OP_lit26 = 0x4a;
|
||||
pub const OP_lit27 = 0x4b;
|
||||
pub const OP_lit28 = 0x4c;
|
||||
pub const OP_lit29 = 0x4d;
|
||||
pub const OP_lit30 = 0x4e;
|
||||
pub const OP_lit31 = 0x4f;
|
||||
pub const OP_reg0 = 0x50;
|
||||
pub const OP_reg1 = 0x51;
|
||||
pub const OP_reg2 = 0x52;
|
||||
pub const OP_reg3 = 0x53;
|
||||
pub const OP_reg4 = 0x54;
|
||||
pub const OP_reg5 = 0x55;
|
||||
pub const OP_reg6 = 0x56;
|
||||
pub const OP_reg7 = 0x57;
|
||||
pub const OP_reg8 = 0x58;
|
||||
pub const OP_reg9 = 0x59;
|
||||
pub const OP_reg10 = 0x5a;
|
||||
pub const OP_reg11 = 0x5b;
|
||||
pub const OP_reg12 = 0x5c;
|
||||
pub const OP_reg13 = 0x5d;
|
||||
pub const OP_reg14 = 0x5e;
|
||||
pub const OP_reg15 = 0x5f;
|
||||
pub const OP_reg16 = 0x60;
|
||||
pub const OP_reg17 = 0x61;
|
||||
pub const OP_reg18 = 0x62;
|
||||
pub const OP_reg19 = 0x63;
|
||||
pub const OP_reg20 = 0x64;
|
||||
pub const OP_reg21 = 0x65;
|
||||
pub const OP_reg22 = 0x66;
|
||||
pub const OP_reg23 = 0x67;
|
||||
pub const OP_reg24 = 0x68;
|
||||
pub const OP_reg25 = 0x69;
|
||||
pub const OP_reg26 = 0x6a;
|
||||
pub const OP_reg27 = 0x6b;
|
||||
pub const OP_reg28 = 0x6c;
|
||||
pub const OP_reg29 = 0x6d;
|
||||
pub const OP_reg30 = 0x6e;
|
||||
pub const OP_reg31 = 0x6f;
|
||||
pub const OP_breg0 = 0x70;
|
||||
pub const OP_breg1 = 0x71;
|
||||
pub const OP_breg2 = 0x72;
|
||||
pub const OP_breg3 = 0x73;
|
||||
pub const OP_breg4 = 0x74;
|
||||
pub const OP_breg5 = 0x75;
|
||||
pub const OP_breg6 = 0x76;
|
||||
pub const OP_breg7 = 0x77;
|
||||
pub const OP_breg8 = 0x78;
|
||||
pub const OP_breg9 = 0x79;
|
||||
pub const OP_breg10 = 0x7a;
|
||||
pub const OP_breg11 = 0x7b;
|
||||
pub const OP_breg12 = 0x7c;
|
||||
pub const OP_breg13 = 0x7d;
|
||||
pub const OP_breg14 = 0x7e;
|
||||
pub const OP_breg15 = 0x7f;
|
||||
pub const OP_breg16 = 0x80;
|
||||
pub const OP_breg17 = 0x81;
|
||||
pub const OP_breg18 = 0x82;
|
||||
pub const OP_breg19 = 0x83;
|
||||
pub const OP_breg20 = 0x84;
|
||||
pub const OP_breg21 = 0x85;
|
||||
pub const OP_breg22 = 0x86;
|
||||
pub const OP_breg23 = 0x87;
|
||||
pub const OP_breg24 = 0x88;
|
||||
pub const OP_breg25 = 0x89;
|
||||
pub const OP_breg26 = 0x8a;
|
||||
pub const OP_breg27 = 0x8b;
|
||||
pub const OP_breg28 = 0x8c;
|
||||
pub const OP_breg29 = 0x8d;
|
||||
pub const OP_breg30 = 0x8e;
|
||||
pub const OP_breg31 = 0x8f;
|
||||
pub const OP_regx = 0x90;
|
||||
pub const OP_fbreg = 0x91;
|
||||
pub const OP_bregx = 0x92;
|
||||
pub const OP_piece = 0x93;
|
||||
pub const OP_deref_size = 0x94;
|
||||
pub const OP_xderef_size = 0x95;
|
||||
pub const OP_nop = 0x96;
|
||||
|
||||
// DWARF 3 extensions.
|
||||
pub const OP_push_object_address = 0x97;
|
||||
pub const OP_call2 = 0x98;
|
||||
pub const OP_call4 = 0x99;
|
||||
pub const OP_call_ref = 0x9a;
|
||||
pub const OP_form_tls_address = 0x9b;
|
||||
pub const OP_call_frame_cfa = 0x9c;
|
||||
pub const OP_bit_piece = 0x9d;
|
||||
|
||||
// DWARF 4 extensions.
|
||||
pub const OP_implicit_value = 0x9e;
|
||||
pub const OP_stack_value = 0x9f;
|
||||
|
||||
pub const OP_lo_user = 0xe0; // Implementation-defined range start.
|
||||
pub const OP_hi_user = 0xff; // Implementation-defined range end.
|
||||
|
||||
// GNU extensions.
|
||||
pub const OP_GNU_push_tls_address = 0xe0;
|
||||
// The following is for marking variables that are uninitialized.
|
||||
pub const OP_GNU_uninit = 0xf0;
|
||||
pub const OP_GNU_encoded_addr = 0xf1;
|
||||
// The GNU implicit pointer extension.
|
||||
// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .
|
||||
pub const OP_GNU_implicit_pointer = 0xf2;
|
||||
// The GNU entry value extension.
|
||||
// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .
|
||||
pub const OP_GNU_entry_value = 0xf3;
|
||||
// The GNU typed stack extension.
|
||||
// See http://www.dwarfstd.org/doc/040408.1.html .
|
||||
pub const OP_GNU_const_type = 0xf4;
|
||||
pub const OP_GNU_regval_type = 0xf5;
|
||||
pub const OP_GNU_deref_type = 0xf6;
|
||||
pub const OP_GNU_convert = 0xf7;
|
||||
pub const OP_GNU_reinterpret = 0xf9;
|
||||
// The GNU parameter ref extension.
|
||||
pub const OP_GNU_parameter_ref = 0xfa;
|
||||
// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
pub const OP_GNU_addr_index = 0xfb;
|
||||
pub const OP_GNU_const_index = 0xfc;
|
||||
// HP extensions.
|
||||
pub const OP_HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.
|
||||
pub const OP_HP_is_value = 0xe1;
|
||||
pub const OP_HP_fltconst4 = 0xe2;
|
||||
pub const OP_HP_fltconst8 = 0xe3;
|
||||
pub const OP_HP_mod_range = 0xe4;
|
||||
pub const OP_HP_unmod_range = 0xe5;
|
||||
pub const OP_HP_tls = 0xe6;
|
||||
// PGI (STMicroelectronics) extensions.
|
||||
pub const OP_PGI_omp_thread_num = 0xf8;
|
||||
|
||||
pub const ATE_void = 0x0;
|
||||
pub const ATE_address = 0x1;
|
||||
pub const ATE_boolean = 0x2;
|
||||
pub const ATE_complex_float = 0x3;
|
||||
pub const ATE_float = 0x4;
|
||||
pub const ATE_signed = 0x5;
|
||||
pub const ATE_signed_char = 0x6;
|
||||
pub const ATE_unsigned = 0x7;
|
||||
pub const ATE_unsigned_char = 0x8;
|
||||
|
||||
// DWARF 3.
|
||||
pub const ATE_imaginary_float = 0x9;
|
||||
pub const ATE_packed_decimal = 0xa;
|
||||
pub const ATE_numeric_string = 0xb;
|
||||
pub const ATE_edited = 0xc;
|
||||
pub const ATE_signed_fixed = 0xd;
|
||||
pub const ATE_unsigned_fixed = 0xe;
|
||||
pub const ATE_decimal_float = 0xf;
|
||||
|
||||
// DWARF 4.
|
||||
pub const ATE_UTF = 0x10;
|
||||
|
||||
pub const ATE_lo_user = 0x80;
|
||||
pub const ATE_hi_user = 0xff;
|
||||
|
||||
// HP extensions.
|
||||
pub const ATE_HP_float80 = 0x80; // Floating-point (80 bit).
|
||||
pub const ATE_HP_complex_float80 = 0x81; // Complex floating-point (80 bit).
|
||||
pub const ATE_HP_float128 = 0x82; // Floating-point (128 bit).
|
||||
pub const ATE_HP_complex_float128 = 0x83; // Complex fp (128 bit).
|
||||
pub const ATE_HP_floathpintel = 0x84; // Floating-point (82 bit IA64).
|
||||
pub const ATE_HP_imaginary_float80 = 0x85;
|
||||
pub const ATE_HP_imaginary_float128 = 0x86;
|
||||
pub const ATE_HP_VAX_float = 0x88; // F or G floating.
|
||||
pub const ATE_HP_VAX_float_d = 0x89; // D floating.
|
||||
pub const ATE_HP_packed_decimal = 0x8a; // Cobol.
|
||||
pub const ATE_HP_zoned_decimal = 0x8b; // Cobol.
|
||||
pub const ATE_HP_edited = 0x8c; // Cobol.
|
||||
pub const ATE_HP_signed_fixed = 0x8d; // Cobol.
|
||||
pub const ATE_HP_unsigned_fixed = 0x8e; // Cobol.
|
||||
pub const ATE_HP_VAX_complex_float = 0x8f; // F or G floating complex.
|
||||
pub const ATE_HP_VAX_complex_float_d = 0x90; // D floating complex.
|
||||
|
||||
pub const CFA_advance_loc = 0x40;
|
||||
pub const CFA_offset = 0x80;
|
||||
pub const CFA_restore = 0xc0;
|
||||
pub const CFA_nop = 0x00;
|
||||
pub const CFA_set_loc = 0x01;
|
||||
pub const CFA_advance_loc1 = 0x02;
|
||||
pub const CFA_advance_loc2 = 0x03;
|
||||
pub const CFA_advance_loc4 = 0x04;
|
||||
pub const CFA_offset_extended = 0x05;
|
||||
pub const CFA_restore_extended = 0x06;
|
||||
pub const CFA_undefined = 0x07;
|
||||
pub const CFA_same_value = 0x08;
|
||||
pub const CFA_register = 0x09;
|
||||
pub const CFA_remember_state = 0x0a;
|
||||
pub const CFA_restore_state = 0x0b;
|
||||
pub const CFA_def_cfa = 0x0c;
|
||||
pub const CFA_def_cfa_register = 0x0d;
|
||||
pub const CFA_def_cfa_offset = 0x0e;
|
||||
|
||||
// DWARF 3.
|
||||
pub const CFA_def_cfa_expression = 0x0f;
|
||||
pub const CFA_expression = 0x10;
|
||||
pub const CFA_offset_extended_sf = 0x11;
|
||||
pub const CFA_def_cfa_sf = 0x12;
|
||||
pub const CFA_def_cfa_offset_sf = 0x13;
|
||||
pub const CFA_val_offset = 0x14;
|
||||
pub const CFA_val_offset_sf = 0x15;
|
||||
pub const CFA_val_expression = 0x16;
|
||||
|
||||
pub const CFA_lo_user = 0x1c;
|
||||
pub const CFA_hi_user = 0x3f;
|
||||
|
||||
// SGI/MIPS specific.
|
||||
pub const CFA_MIPS_advance_loc8 = 0x1d;
|
||||
|
||||
// GNU extensions.
|
||||
pub const CFA_GNU_window_save = 0x2d;
|
||||
pub const CFA_GNU_args_size = 0x2e;
|
||||
pub const CFA_GNU_negative_offset_extended = 0x2f;
|
||||
|
||||
pub const CHILDREN_no = 0x00;
|
||||
pub const CHILDREN_yes = 0x01;
|
||||
|
||||
pub const LNS_extended_op = 0x00;
|
||||
pub const LNS_copy = 0x01;
|
||||
pub const LNS_advance_pc = 0x02;
|
||||
pub const LNS_advance_line = 0x03;
|
||||
pub const LNS_set_file = 0x04;
|
||||
pub const LNS_set_column = 0x05;
|
||||
pub const LNS_negate_stmt = 0x06;
|
||||
pub const LNS_set_basic_block = 0x07;
|
||||
pub const LNS_const_add_pc = 0x08;
|
||||
pub const LNS_fixed_advance_pc = 0x09;
|
||||
pub const LNS_set_prologue_end = 0x0a;
|
||||
pub const LNS_set_epilogue_begin = 0x0b;
|
||||
pub const LNS_set_isa = 0x0c;
|
||||
|
||||
pub const LNE_end_sequence = 0x01;
|
||||
pub const LNE_set_address = 0x02;
|
||||
pub const LNE_define_file = 0x03;
|
||||
pub const LNE_set_discriminator = 0x04;
|
||||
pub const LNE_lo_user = 0x80;
|
||||
pub const LNE_hi_user = 0xff;
|
||||
|
||||
pub const LANG_C89 = 0x0001;
|
||||
pub const LANG_C = 0x0002;
|
||||
pub const LANG_Ada83 = 0x0003;
|
||||
pub const LANG_C_plus_plus = 0x0004;
|
||||
pub const LANG_Cobol74 = 0x0005;
|
||||
pub const LANG_Cobol85 = 0x0006;
|
||||
pub const LANG_Fortran77 = 0x0007;
|
||||
pub const LANG_Fortran90 = 0x0008;
|
||||
pub const LANG_Pascal83 = 0x0009;
|
||||
pub const LANG_Modula2 = 0x000a;
|
||||
pub const LANG_Java = 0x000b;
|
||||
pub const LANG_C99 = 0x000c;
|
||||
pub const LANG_Ada95 = 0x000d;
|
||||
pub const LANG_Fortran95 = 0x000e;
|
||||
pub const LANG_PLI = 0x000f;
|
||||
pub const LANG_ObjC = 0x0010;
|
||||
pub const LANG_ObjC_plus_plus = 0x0011;
|
||||
pub const LANG_UPC = 0x0012;
|
||||
pub const LANG_D = 0x0013;
|
||||
pub const LANG_Python = 0x0014;
|
||||
pub const LANG_Go = 0x0016;
|
||||
pub const LANG_C_plus_plus_11 = 0x001a;
|
||||
pub const LANG_Rust = 0x001c;
|
||||
pub const LANG_C11 = 0x001d;
|
||||
pub const LANG_C_plus_plus_14 = 0x0021;
|
||||
pub const LANG_Fortran03 = 0x0022;
|
||||
pub const LANG_Fortran08 = 0x0023;
|
||||
pub const LANG_lo_user = 0x8000;
|
||||
pub const LANG_hi_user = 0xffff;
|
||||
pub const LANG_Mips_Assembler = 0x8001;
|
||||
pub const LANG_Upc = 0x8765;
|
||||
pub const LANG_HP_Bliss = 0x8003;
|
||||
pub const LANG_HP_Basic91 = 0x8004;
|
||||
pub const LANG_HP_Pascal91 = 0x8005;
|
||||
pub const LANG_HP_IMacro = 0x8006;
|
||||
pub const LANG_HP_Assembler = 0x8007;
|
@ -11,7 +11,7 @@ const system = std.os.system;
|
||||
const maxInt = std.math.maxInt;
|
||||
const max = std.math.max;
|
||||
|
||||
pub const DynLib = switch (builtin.os) {
|
||||
pub const DynLib = switch (builtin.os.tag) {
|
||||
.linux => if (builtin.link_libc) DlDynlib else ElfDynLib,
|
||||
.windows => WindowsDynLib,
|
||||
.macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib,
|
||||
@ -82,12 +82,12 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
|
||||
for (dyn_table) |*dyn| {
|
||||
switch (dyn.d_tag) {
|
||||
elf.DT_DEBUG => {
|
||||
const r_debug = @intToPtr(*RDebug, dyn.d_un.d_ptr);
|
||||
const r_debug = @intToPtr(*RDebug, dyn.d_val);
|
||||
if (r_debug.r_version != 1) return error.InvalidExe;
|
||||
break :init r_debug.r_map;
|
||||
},
|
||||
elf.DT_PLTGOT => {
|
||||
const got_table = @intToPtr([*]usize, dyn.d_un.d_ptr);
|
||||
const got_table = @intToPtr([*]usize, dyn.d_val);
|
||||
// The address to the link_map structure is stored in the
|
||||
// second slot
|
||||
break :init @intToPtr(?*LinkMap, got_table[1]);
|
||||
@ -390,7 +390,7 @@ pub const DlDynlib = struct {
|
||||
};
|
||||
|
||||
test "dynamic_library" {
|
||||
const libname = switch (builtin.os) {
|
||||
const libname = switch (builtin.os.tag) {
|
||||
.linux, .freebsd => "invalid_so.so",
|
||||
.windows => "invalid_dll.dll",
|
||||
.macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib",
|
||||
|
@ -349,16 +349,6 @@ pub const Elf = struct {
|
||||
program_headers: []ProgramHeader,
|
||||
allocator: *mem.Allocator,
|
||||
|
||||
/// Call close when done.
|
||||
pub fn openPath(allocator: *mem.Allocator, path: []const u8) !Elf {
|
||||
@compileError("TODO implement");
|
||||
}
|
||||
|
||||
/// Call close when done.
|
||||
pub fn openFile(allocator: *mem.Allocator, file: File) !Elf {
|
||||
@compileError("TODO implement");
|
||||
}
|
||||
|
||||
pub fn openStream(
|
||||
allocator: *mem.Allocator,
|
||||
seekable_stream: *io.SeekableStream(anyerror, anyerror),
|
||||
@ -380,8 +370,8 @@ pub const Elf = struct {
|
||||
};
|
||||
|
||||
elf.endian = switch (try in.readByte()) {
|
||||
1 => builtin.Endian.Little,
|
||||
2 => builtin.Endian.Big,
|
||||
1 => .Little,
|
||||
2 => .Big,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
@ -554,6 +544,21 @@ pub const Elf = struct {
|
||||
};
|
||||
|
||||
pub const EI_NIDENT = 16;
|
||||
|
||||
pub const EI_CLASS = 4;
|
||||
pub const ELFCLASSNONE = 0;
|
||||
pub const ELFCLASS32 = 1;
|
||||
pub const ELFCLASS64 = 2;
|
||||
pub const ELFCLASSNUM = 3;
|
||||
|
||||
pub const EI_DATA = 5;
|
||||
pub const ELFDATANONE = 0;
|
||||
pub const ELFDATA2LSB = 1;
|
||||
pub const ELFDATA2MSB = 2;
|
||||
pub const ELFDATANUM = 3;
|
||||
|
||||
pub const EI_VERSION = 6;
|
||||
|
||||
pub const Elf32_Half = u16;
|
||||
pub const Elf64_Half = u16;
|
||||
pub const Elf32_Word = u32;
|
||||
@ -703,17 +708,11 @@ pub const Elf64_Rela = extern struct {
|
||||
};
|
||||
pub const Elf32_Dyn = extern struct {
|
||||
d_tag: Elf32_Sword,
|
||||
d_un: extern union {
|
||||
d_val: Elf32_Word,
|
||||
d_ptr: Elf32_Addr,
|
||||
},
|
||||
d_val: Elf32_Addr,
|
||||
};
|
||||
pub const Elf64_Dyn = extern struct {
|
||||
d_tag: Elf64_Sxword,
|
||||
d_un: extern union {
|
||||
d_val: Elf64_Xword,
|
||||
d_ptr: Elf64_Addr,
|
||||
},
|
||||
d_val: Elf64_Addr,
|
||||
};
|
||||
pub const Elf32_Verdef = extern struct {
|
||||
vd_version: Elf32_Half,
|
||||
|
@ -273,7 +273,7 @@ test "std.event.Channel" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
// https://github.com/ziglang/zig/issues/3251
|
||||
if (builtin.os == .freebsd) return error.SkipZigTest;
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
var channel: Channel(i32) = undefined;
|
||||
channel.init(&[0]i32{});
|
||||
|
@ -86,7 +86,7 @@ test "std.event.Future" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
// https://github.com/ziglang/zig/issues/3251
|
||||
if (builtin.os == .freebsd) return error.SkipZigTest;
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
// TODO provide a way to run tests in evented I/O mode
|
||||
if (!std.io.is_async) return error.SkipZigTest;
|
||||
|
||||
|
@ -123,7 +123,7 @@ test "std.event.Lock" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/3251
|
||||
if (builtin.os == .freebsd) return error.SkipZigTest;
|
||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
||||
|
||||
var lock = Lock.init();
|
||||
defer lock.deinit();
|
||||
|
@ -34,7 +34,7 @@ pub const Loop = struct {
|
||||
handle: anyframe,
|
||||
overlapped: Overlapped,
|
||||
|
||||
pub const overlapped_init = switch (builtin.os) {
|
||||
pub const overlapped_init = switch (builtin.os.tag) {
|
||||
.windows => windows.OVERLAPPED{
|
||||
.Internal = 0,
|
||||
.InternalHigh = 0,
|
||||
@ -52,7 +52,7 @@ pub const Loop = struct {
|
||||
EventFd,
|
||||
};
|
||||
|
||||
pub const EventFd = switch (builtin.os) {
|
||||
pub const EventFd = switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => KEventFd,
|
||||
.linux => struct {
|
||||
base: ResumeNode,
|
||||
@ -71,7 +71,7 @@ pub const Loop = struct {
|
||||
kevent: os.Kevent,
|
||||
};
|
||||
|
||||
pub const Basic = switch (builtin.os) {
|
||||
pub const Basic = switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => KEventBasic,
|
||||
.linux => struct {
|
||||
base: ResumeNode,
|
||||
@ -173,7 +173,7 @@ pub const Loop = struct {
|
||||
const wakeup_bytes = [_]u8{0x1} ** 8;
|
||||
|
||||
fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
self.os_data.fs_queue = std.atomic.Queue(Request).init();
|
||||
self.os_data.fs_queue_item = 0;
|
||||
@ -404,7 +404,7 @@ pub const Loop = struct {
|
||||
}
|
||||
|
||||
fn deinitOsData(self: *Loop) void {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
noasync os.close(self.os_data.final_eventfd);
|
||||
while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);
|
||||
@ -568,7 +568,7 @@ pub const Loop = struct {
|
||||
};
|
||||
const eventfd_node = &resume_stack_node.data;
|
||||
eventfd_node.base.handle = next_tick_node.data;
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => {
|
||||
const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent);
|
||||
const empty_kevs = &[0]os.Kevent{};
|
||||
@ -628,7 +628,7 @@ pub const Loop = struct {
|
||||
|
||||
self.workerRun();
|
||||
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux,
|
||||
.macosx,
|
||||
.freebsd,
|
||||
@ -678,7 +678,7 @@ pub const Loop = struct {
|
||||
const prev = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
|
||||
if (prev == 1) {
|
||||
// cause all the threads to stop
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
self.posixFsRequest(&self.os_data.fs_end_request);
|
||||
// writing 8 bytes to an eventfd cannot fail
|
||||
@ -902,7 +902,7 @@ pub const Loop = struct {
|
||||
self.finishOneEvent();
|
||||
}
|
||||
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
// only process 1 event so we don't steal from other threads
|
||||
var events: [1]os.linux.epoll_event = undefined;
|
||||
@ -989,7 +989,7 @@ pub const Loop = struct {
|
||||
fn posixFsRequest(self: *Loop, request_node: *Request.Node) void {
|
||||
self.beginOneEvent(); // finished in posixFsRun after processing the msg
|
||||
self.os_data.fs_queue.put(request_node);
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => {
|
||||
const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wake);
|
||||
const empty_kevs = &[0]os.Kevent{};
|
||||
@ -1018,7 +1018,7 @@ pub const Loop = struct {
|
||||
// https://github.com/ziglang/zig/issues/3157
|
||||
fn posixFsRun(self: *Loop) void {
|
||||
while (true) {
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
@atomicStore(i32, &self.os_data.fs_queue_item, 0, .SeqCst);
|
||||
}
|
||||
while (self.os_data.fs_queue.get()) |node| {
|
||||
@ -1053,7 +1053,7 @@ pub const Loop = struct {
|
||||
}
|
||||
self.finishOneEvent();
|
||||
}
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
|
||||
switch (os.linux.getErrno(rc)) {
|
||||
@ -1071,7 +1071,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
|
||||
const OsData = switch (builtin.os) {
|
||||
const OsData = switch (builtin.os.tag) {
|
||||
.linux => LinuxOsData,
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => KEventData,
|
||||
.windows => struct {
|
||||
|
@ -414,10 +414,9 @@ pub fn formatType(
|
||||
if (max_depth == 0) {
|
||||
return output(context, "{ ... }");
|
||||
}
|
||||
comptime var field_i = 0;
|
||||
try output(context, "{");
|
||||
inline for (StructT.fields) |f| {
|
||||
if (field_i == 0) {
|
||||
inline for (StructT.fields) |f, i| {
|
||||
if (i == 0) {
|
||||
try output(context, " .");
|
||||
} else {
|
||||
try output(context, ", .");
|
||||
@ -425,7 +424,6 @@ pub fn formatType(
|
||||
try output(context, f.name);
|
||||
try output(context, " = ");
|
||||
try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
|
||||
field_i += 1;
|
||||
}
|
||||
try output(context, " }");
|
||||
},
|
||||
@ -443,10 +441,12 @@ pub fn formatType(
|
||||
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
|
||||
},
|
||||
.Many, .C => {
|
||||
if (ptr_info.sentinel) |sentinel| {
|
||||
return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
|
||||
}
|
||||
if (ptr_info.child == u8) {
|
||||
if (fmt.len > 0 and fmt[0] == 's') {
|
||||
const len = mem.len(u8, value);
|
||||
return formatText(value[0..len], fmt, options, context, Errors, output);
|
||||
return formatText(mem.span(value), fmt, options, context, Errors, output);
|
||||
}
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
|
||||
|
@ -29,7 +29,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
|
||||
/// All file system operations which return a path are guaranteed to
|
||||
/// fit into a UTF-8 encoded array of this length.
|
||||
/// The byte count includes room for a null sentinel byte.
|
||||
pub const MAX_PATH_BYTES = switch (builtin.os) {
|
||||
pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
|
||||
.linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX,
|
||||
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
|
||||
// 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(
|
||||
|
||||
/// Whether or not async file system syscalls need a dedicated thread because the operating
|
||||
/// system does not support non-blocking I/O on the file system.
|
||||
pub const need_async_thread = std.io.is_async and switch (builtin.os) {
|
||||
pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) {
|
||||
.windows, .other => false,
|
||||
else => true,
|
||||
};
|
||||
@ -270,7 +270,7 @@ pub const AtomicFile = struct {
|
||||
assert(!self.finished);
|
||||
self.file.close();
|
||||
self.finished = true;
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
|
||||
const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));
|
||||
return os.renameW(&tmp_path_w, &dest_path_w);
|
||||
@ -394,7 +394,7 @@ pub const Dir = struct {
|
||||
|
||||
const IteratorError = error{AccessDenied} || os.UnexpectedError;
|
||||
|
||||
pub const Iterator = switch (builtin.os) {
|
||||
pub const Iterator = switch (builtin.os.tag) {
|
||||
.macosx, .ios, .freebsd, .netbsd, .dragonfly => struct {
|
||||
dir: Dir,
|
||||
seek: i64,
|
||||
@ -409,7 +409,7 @@ pub const Dir = struct {
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Error!?Entry {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .ios => return self.nextDarwin(),
|
||||
.freebsd, .netbsd, .dragonfly => return self.nextBsd(),
|
||||
else => @compileError("unimplemented"),
|
||||
@ -644,7 +644,7 @@ pub const Dir = struct {
|
||||
};
|
||||
|
||||
pub fn iterate(self: Dir) Iterator {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{
|
||||
.dir = self,
|
||||
.seek = 0,
|
||||
@ -710,7 +710,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.openFileW(&path_w, flags);
|
||||
}
|
||||
@ -720,7 +720,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Same as `openFile` but the path parameter is null-terminated.
|
||||
pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
|
||||
return self.openFileW(&path_w, flags);
|
||||
}
|
||||
@ -731,11 +731,18 @@ pub const Dir = struct {
|
||||
@as(u32, os.O_WRONLY)
|
||||
else
|
||||
@as(u32, os.O_RDONLY);
|
||||
const fd = if (need_async_thread)
|
||||
const fd = if (need_async_thread and !flags.always_blocking)
|
||||
try std.event.Loop.instance.?.openatZ(self.fd, sub_path, os_flags, 0)
|
||||
else
|
||||
try os.openatC(self.fd, sub_path, os_flags, 0);
|
||||
return File{ .handle = fd, .io_mode = .blocking };
|
||||
return File{
|
||||
.handle = fd,
|
||||
.io_mode = .blocking,
|
||||
.async_block_allowed = if (flags.always_blocking)
|
||||
File.async_block_allowed_yes
|
||||
else
|
||||
File.async_block_allowed_no,
|
||||
};
|
||||
}
|
||||
|
||||
/// Same as `openFile` but Windows-only and the path parameter is
|
||||
@ -753,7 +760,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.createFileW(&path_w, flags);
|
||||
}
|
||||
@ -763,7 +770,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Same as `createFile` but the path parameter is null-terminated.
|
||||
pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
return self.createFileW(&path_w, flags);
|
||||
}
|
||||
@ -894,7 +901,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
|
||||
if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.openDirTraverseW(&sub_path_w);
|
||||
}
|
||||
@ -912,7 +919,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {
|
||||
if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.openDirListW(&sub_path_w);
|
||||
}
|
||||
@ -923,7 +930,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Same as `openDirTraverse` except the parameter is null-terminated.
|
||||
pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
return self.openDirTraverseW(&sub_path_w);
|
||||
} else {
|
||||
@ -934,7 +941,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Same as `openDirList` except the parameter is null-terminated.
|
||||
pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
|
||||
return self.openDirListW(&sub_path_w);
|
||||
} else {
|
||||
@ -1076,7 +1083,7 @@ pub const Dir = struct {
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
||||
if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.deleteDirW(&sub_path_w);
|
||||
}
|
||||
@ -1333,7 +1340,7 @@ pub const Dir = struct {
|
||||
/// For example, instead of testing if a file exists and then opening it, just
|
||||
/// open it and handle the error for file not found.
|
||||
pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
|
||||
return self.accessW(&sub_path_w, flags);
|
||||
}
|
||||
@ -1343,7 +1350,7 @@ pub const Dir = struct {
|
||||
|
||||
/// Same as `access` except the path parameter is null-terminated.
|
||||
pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path);
|
||||
return self.accessW(&sub_path_w, flags);
|
||||
}
|
||||
@ -1374,7 +1381,7 @@ pub const Dir = struct {
|
||||
/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
|
||||
/// On POSIX targets, this function is comptime-callable.
|
||||
pub fn cwd() Dir {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
|
||||
} else {
|
||||
return Dir{ .fd = os.AT_FDCWD };
|
||||
@ -1553,10 +1560,10 @@ pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||
pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;
|
||||
|
||||
pub fn openSelfExe() OpenSelfExeError!File {
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
return openFileAbsoluteC("/proc/self/exe", .{});
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const wide_slice = selfExePathW();
|
||||
const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
|
||||
return cwd().openReadW(&prefixed_path_w);
|
||||
@ -1568,7 +1575,7 @@ pub fn openSelfExe() OpenSelfExeError!File {
|
||||
}
|
||||
|
||||
test "openSelfExe" {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux, .macosx, .ios, .windows, .freebsd, .dragonfly => (try openSelfExe()).close(),
|
||||
else => return error.SkipZigTest, // Unsupported OS.
|
||||
}
|
||||
@ -1593,7 +1600,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
|
||||
if (rc != 0) return error.NameTooLong;
|
||||
return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer));
|
||||
}
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => return os.readlinkC("/proc/self/exe", out_buffer),
|
||||
.freebsd, .dragonfly => {
|
||||
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 {
|
||||
/// Get the directory path that contains the current executable.
|
||||
/// Returned value is a slice of out_buffer.
|
||||
pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
// If the currently executing binary has been deleted,
|
||||
// the file path looks something like `/a/b/c/exe (deleted)`
|
||||
// This path cannot be opened, but it's valid for determining the directory
|
||||
|
@ -20,7 +20,7 @@ pub const File = struct {
|
||||
/// or, more specifically, whether the I/O is blocking.
|
||||
io_mode: io.Mode,
|
||||
|
||||
/// Even when std.io.mode is async, it is still sometimes desirable to perform blocking I/O, although
|
||||
/// Even when 'std.io.mode' is async, it is still sometimes desirable to perform blocking I/O, although
|
||||
/// not by default. For example, when printing a stack trace to stderr.
|
||||
async_block_allowed: @TypeOf(async_block_allowed_no) = async_block_allowed_no,
|
||||
|
||||
@ -29,7 +29,7 @@ pub const File = struct {
|
||||
|
||||
pub const Mode = os.mode_t;
|
||||
|
||||
pub const default_mode = switch (builtin.os) {
|
||||
pub const default_mode = switch (builtin.os.tag) {
|
||||
.windows => 0,
|
||||
else => 0o666,
|
||||
};
|
||||
@ -40,6 +40,11 @@ pub const File = struct {
|
||||
pub const OpenFlags = struct {
|
||||
read: bool = true,
|
||||
write: bool = false,
|
||||
|
||||
/// This prevents `O_NONBLOCK` from being passed even if `std.io.is_async`.
|
||||
/// It allows the use of `noasync` when calling functions related to opening
|
||||
/// the file, reading, and writing.
|
||||
always_blocking: bool = false,
|
||||
};
|
||||
|
||||
/// TODO https://github.com/ziglang/zig/issues/3802
|
||||
@ -78,7 +83,7 @@ pub const File = struct {
|
||||
|
||||
/// Test whether ANSI escape codes will be treated as such.
|
||||
pub fn supportsAnsiEscapeCodes(self: File) bool {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return os.isCygwinPty(self.handle);
|
||||
}
|
||||
if (self.isTty()) {
|
||||
@ -123,7 +128,7 @@ pub const File = struct {
|
||||
|
||||
/// TODO: integrate with async I/O
|
||||
pub fn getEndPos(self: File) GetPosError!u64 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.GetFileSizeEx(self.handle);
|
||||
}
|
||||
return (try self.stat()).size;
|
||||
@ -133,7 +138,7 @@ pub const File = struct {
|
||||
|
||||
/// TODO: integrate with async I/O
|
||||
pub fn mode(self: File) ModeError!Mode {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return {};
|
||||
}
|
||||
return (try self.stat()).mode;
|
||||
@ -157,7 +162,7 @@ pub const File = struct {
|
||||
|
||||
/// TODO: integrate with async I/O
|
||||
pub fn stat(self: File) StatError!Stat {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||
var info: windows.FILE_ALL_INFORMATION = undefined;
|
||||
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 {
|
||||
/// last modification timestamp in nanoseconds
|
||||
mtime: i64,
|
||||
) UpdateTimesError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const atime_ft = windows.nanoSecondsToFileTime(atime);
|
||||
const mtime_ft = windows.nanoSecondsToFileTime(mtime);
|
||||
return windows.SetFileTime(self.handle, null, &atime_ft, &mtime_ft);
|
||||
|
@ -13,7 +13,7 @@ pub const GetAppDataDirError = error{
|
||||
/// Caller owns returned memory.
|
||||
/// TODO determine if we can remove the allocator requirement
|
||||
pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
var dir_path_ptr: [*:0]u16 = undefined;
|
||||
switch (os.windows.shell32.SHGetKnownFolderPath(
|
||||
|
@ -13,18 +13,18 @@ const process = std.process;
|
||||
|
||||
pub const sep_windows = '\\';
|
||||
pub const sep_posix = '/';
|
||||
pub const sep = if (builtin.os == .windows) sep_windows else sep_posix;
|
||||
pub const sep = if (builtin.os.tag == .windows) sep_windows else sep_posix;
|
||||
|
||||
pub const sep_str_windows = "\\";
|
||||
pub const sep_str_posix = "/";
|
||||
pub const sep_str = if (builtin.os == .windows) sep_str_windows else sep_str_posix;
|
||||
pub const sep_str = if (builtin.os.tag == .windows) sep_str_windows else sep_str_posix;
|
||||
|
||||
pub const delimiter_windows = ';';
|
||||
pub const delimiter_posix = ':';
|
||||
pub const delimiter = if (builtin.os == .windows) delimiter_windows else delimiter_posix;
|
||||
pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix;
|
||||
|
||||
pub fn isSep(byte: u8) bool {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return byte == '/' or byte == '\\';
|
||||
} else {
|
||||
return byte == '/';
|
||||
@ -74,7 +74,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u
|
||||
return buf;
|
||||
}
|
||||
|
||||
pub const join = if (builtin.os == .windows) joinWindows else joinPosix;
|
||||
pub const join = if (builtin.os.tag == .windows) joinWindows else joinPosix;
|
||||
|
||||
/// Naively combines a series of paths with the native path seperator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
@ -129,7 +129,7 @@ test "join" {
|
||||
}
|
||||
|
||||
pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return isAbsoluteWindowsC(path_c);
|
||||
} else {
|
||||
return isAbsolutePosixC(path_c);
|
||||
@ -137,7 +137,7 @@ pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
|
||||
}
|
||||
|
||||
pub fn isAbsolute(path: []const u8) bool {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return isAbsoluteWindows(path);
|
||||
} else {
|
||||
return isAbsolutePosix(path);
|
||||
@ -318,7 +318,7 @@ test "windowsParsePath" {
|
||||
}
|
||||
|
||||
pub fn diskDesignator(path: []const u8) []const u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return diskDesignatorWindows(path);
|
||||
} else {
|
||||
return "";
|
||||
@ -383,7 +383,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
|
||||
|
||||
/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
|
||||
pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return resolveWindows(allocator, paths);
|
||||
} else {
|
||||
return resolvePosix(allocator, paths);
|
||||
@ -400,7 +400,7 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
/// Without performing actual syscalls, resolving `..` could be incorrect.
|
||||
pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) {
|
||||
assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
return process.getCwdAlloc(allocator);
|
||||
}
|
||||
|
||||
@ -495,7 +495,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
result_disk_designator = result[0..result_index];
|
||||
},
|
||||
WindowsPath.Kind.None => {
|
||||
assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
const parsed_cwd = windowsParsePath(cwd);
|
||||
@ -510,7 +510,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
},
|
||||
}
|
||||
} else {
|
||||
assert(builtin.os == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
assert(builtin.os.tag == .windows); // resolveWindows called on non windows can't use getCwd
|
||||
// TODO call get cwd for the result_disk_designator instead of the global one
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
@ -581,7 +581,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
/// Without performing actual syscalls, resolving `..` could be incorrect.
|
||||
pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) {
|
||||
assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd
|
||||
assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
|
||||
return process.getCwdAlloc(allocator);
|
||||
}
|
||||
|
||||
@ -603,7 +603,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
if (have_abs) {
|
||||
result = try allocator.alloc(u8, max_size);
|
||||
} else {
|
||||
assert(builtin.os != .windows); // resolvePosix called on windows can't use getCwd
|
||||
assert(builtin.os.tag != .windows); // resolvePosix called on windows can't use getCwd
|
||||
const cwd = try process.getCwdAlloc(allocator);
|
||||
defer allocator.free(cwd);
|
||||
result = try allocator.alloc(u8, max_size + cwd.len + 1);
|
||||
@ -645,7 +645,7 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
test "resolve" {
|
||||
const cwd = try process.getCwdAlloc(testing.allocator);
|
||||
defer testing.allocator.free(cwd);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
|
||||
cwd[0] = asciiUpper(cwd[0]);
|
||||
}
|
||||
@ -661,7 +661,7 @@ test "resolveWindows" {
|
||||
// TODO https://github.com/ziglang/zig/issues/3288
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const cwd = try process.getCwdAlloc(testing.allocator);
|
||||
defer testing.allocator.free(cwd);
|
||||
const parsed_cwd = windowsParsePath(cwd);
|
||||
@ -732,7 +732,7 @@ fn testResolvePosix(paths: []const []const u8, expected: []const u8) !void {
|
||||
/// If the path is a file in the current directory (no directory component)
|
||||
/// then returns null
|
||||
pub fn dirname(path: []const u8) ?[]const u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return dirnameWindows(path);
|
||||
} else {
|
||||
return dirnamePosix(path);
|
||||
@ -864,7 +864,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
|
||||
}
|
||||
|
||||
pub fn basename(path: []const u8) []const u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return basenameWindows(path);
|
||||
} else {
|
||||
return basenamePosix(path);
|
||||
@ -980,7 +980,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
|
||||
/// string is returned.
|
||||
/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
|
||||
pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return relativeWindows(allocator, from, to);
|
||||
} else {
|
||||
return relativePosix(allocator, from, to);
|
||||
|
@ -42,7 +42,7 @@ pub fn Watch(comptime V: type) type {
|
||||
os_data: OsData,
|
||||
allocator: *Allocator,
|
||||
|
||||
const OsData = switch (builtin.os) {
|
||||
const OsData = switch (builtin.os.tag) {
|
||||
// TODO https://github.com/ziglang/zig/issues/3778
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
|
||||
.linux => LinuxOsData,
|
||||
@ -121,7 +121,7 @@ pub fn Watch(comptime V: type) type {
|
||||
const self = try allocator.create(Self);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
|
||||
errdefer os.close(inotify_fd);
|
||||
@ -172,7 +172,7 @@ pub fn Watch(comptime V: type) type {
|
||||
|
||||
/// All addFile calls and removeFile calls must have completed.
|
||||
pub fn deinit(self: *Self) void {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => {
|
||||
// TODO we need to cancel the frames before destroying the lock
|
||||
self.os_data.table_lock.deinit();
|
||||
@ -223,7 +223,7 @@ pub fn Watch(comptime V: type) type {
|
||||
}
|
||||
|
||||
pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value),
|
||||
.linux => return addFileLinux(self, file_path, value),
|
||||
.windows => return addFileWindows(self, file_path, value),
|
||||
|
@ -25,13 +25,13 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
|
||||
const info = @typeInfo(@TypeOf(key));
|
||||
|
||||
switch (info.Pointer.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => switch (strat) {
|
||||
.One => switch (strat) {
|
||||
.Shallow => hash(hasher, @ptrToInt(key), .Shallow),
|
||||
.Deep => hash(hasher, key.*, .Shallow),
|
||||
.DeepRecursive => hash(hasher, key.*, .DeepRecursive),
|
||||
},
|
||||
|
||||
builtin.TypeInfo.Pointer.Size.Slice => switch (strat) {
|
||||
.Slice => switch (strat) {
|
||||
.Shallow => {
|
||||
hashPointer(hasher, key.ptr, .Shallow);
|
||||
hash(hasher, key.len, .Shallow);
|
||||
@ -40,9 +40,7 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
|
||||
.DeepRecursive => hashArray(hasher, key, .DeepRecursive),
|
||||
},
|
||||
|
||||
builtin.TypeInfo.Pointer.Size.Many,
|
||||
builtin.TypeInfo.Pointer.Size.C,
|
||||
=> switch (strat) {
|
||||
.Many, .C, => switch (strat) {
|
||||
.Shallow => hash(hasher, @ptrToInt(key), .Shallow),
|
||||
else => @compileError(
|
||||
\\ unknown-length pointers and C pointers cannot be hashed deeply.
|
||||
|
@ -168,7 +168,7 @@ fn usage() void {
|
||||
}
|
||||
|
||||
fn mode(comptime x: comptime_int) comptime_int {
|
||||
return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
|
||||
return if (builtin.mode == .Debug) x / 64 else x;
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
@ -11,7 +11,7 @@ pub const CityHash32 = struct {
|
||||
fn fetch32(ptr: [*]const u8) u32 {
|
||||
var v: u32 = undefined;
|
||||
@memcpy(@ptrCast([*]u8, &v), ptr, 4);
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
return @byteSwap(u32, v);
|
||||
return v;
|
||||
}
|
||||
@ -174,7 +174,7 @@ pub const CityHash64 = struct {
|
||||
fn fetch32(ptr: [*]const u8) u32 {
|
||||
var v: u32 = undefined;
|
||||
@memcpy(@ptrCast([*]u8, &v), ptr, 4);
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
return @byteSwap(u32, v);
|
||||
return v;
|
||||
}
|
||||
@ -182,7 +182,7 @@ pub const CityHash64 = struct {
|
||||
fn fetch64(ptr: [*]const u8) u64 {
|
||||
var v: u64 = undefined;
|
||||
@memcpy(@ptrCast([*]u8, &v), ptr, 8);
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
return @byteSwap(u64, v);
|
||||
return v;
|
||||
}
|
||||
@ -369,7 +369,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {
|
||||
key[i] = @intCast(u8, i);
|
||||
|
||||
var h = hash_fn(key[0..i], 256 - i);
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
h = @byteSwap(@TypeOf(h), h);
|
||||
@memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub const Murmur2_32 = struct {
|
||||
var h1: u32 = seed ^ len;
|
||||
for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
|
||||
var k1: u32 = v;
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
k1 = @byteSwap(u32, k1);
|
||||
k1 *%= m;
|
||||
k1 ^= k1 >> 24;
|
||||
@ -102,7 +102,7 @@ pub const Murmur2_64 = struct {
|
||||
var h1: u64 = seed ^ (len *% m);
|
||||
for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
|
||||
var k1: u64 = v;
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
k1 = @byteSwap(u64, k1);
|
||||
k1 *%= m;
|
||||
k1 ^= k1 >> 47;
|
||||
@ -115,7 +115,7 @@ pub const Murmur2_64 = struct {
|
||||
if (rest > 0) {
|
||||
var k1: u64 = 0;
|
||||
@memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
k1 = @byteSwap(u64, k1);
|
||||
h1 ^= k1;
|
||||
h1 *%= m;
|
||||
@ -182,7 +182,7 @@ pub const Murmur3_32 = struct {
|
||||
var h1: u32 = seed;
|
||||
for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
|
||||
var k1: u32 = v;
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
k1 = @byteSwap(u32, k1);
|
||||
k1 *%= c1;
|
||||
k1 = rotl32(k1, 15);
|
||||
@ -294,7 +294,7 @@ fn SMHasherTest(comptime hash_fn: var, comptime hashbits: u32) u32 {
|
||||
key[i] = @truncate(u8, i);
|
||||
|
||||
var h = hash_fn(key[0..i], 256 - i);
|
||||
if (builtin.endian == builtin.Endian.Big)
|
||||
if (builtin.endian == .Big)
|
||||
h = @byteSwap(@TypeOf(h), h);
|
||||
@memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
|
||||
}
|
||||
@ -308,7 +308,7 @@ test "murmur2_32" {
|
||||
var v1: u64 = 0x1234567812345678;
|
||||
var v0le: u32 = v0;
|
||||
var v1le: u64 = v1;
|
||||
if (builtin.endian == builtin.Endian.Big) {
|
||||
if (builtin.endian == .Big) {
|
||||
v0le = @byteSwap(u32, v0le);
|
||||
v1le = @byteSwap(u64, v1le);
|
||||
}
|
||||
@ -322,7 +322,7 @@ test "murmur2_64" {
|
||||
var v1: u64 = 0x1234567812345678;
|
||||
var v0le: u32 = v0;
|
||||
var v1le: u64 = v1;
|
||||
if (builtin.endian == builtin.Endian.Big) {
|
||||
if (builtin.endian == .Big) {
|
||||
v0le = @byteSwap(u32, v0le);
|
||||
v1le = @byteSwap(u64, v1le);
|
||||
}
|
||||
@ -336,7 +336,7 @@ test "murmur3_32" {
|
||||
var v1: u64 = 0x1234567812345678;
|
||||
var v0le: u32 = v0;
|
||||
var v1le: u64 = v1;
|
||||
if (builtin.endian == builtin.Endian.Big) {
|
||||
if (builtin.endian == .Big) {
|
||||
v0le = @byteSwap(u32, v0le);
|
||||
v1le = @byteSwap(u64, v1le);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ const Wyhash = std.hash.Wyhash;
|
||||
const Allocator = mem.Allocator;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const want_modification_safety = builtin.mode != builtin.Mode.ReleaseFast;
|
||||
const want_modification_safety = builtin.mode != .ReleaseFast;
|
||||
const debug_u32 = if (want_modification_safety) u32 else void;
|
||||
|
||||
pub fn AutoHashMap(comptime K: type, comptime V: type) type {
|
||||
|
@ -36,7 +36,7 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new
|
||||
/// Thread-safe and lock-free.
|
||||
pub const page_allocator = if (std.Target.current.isWasm())
|
||||
&wasm_page_allocator_state
|
||||
else if (std.Target.current.getOs() == .freestanding)
|
||||
else if (std.Target.current.os.tag == .freestanding)
|
||||
root.os.heap.page_allocator
|
||||
else
|
||||
&page_allocator_state;
|
||||
@ -57,7 +57,7 @@ const PageAllocator = struct {
|
||||
fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
|
||||
if (n == 0) return &[0]u8{};
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const w = os.windows;
|
||||
|
||||
// Although officially it's at least aligned to page boundary,
|
||||
@ -143,7 +143,7 @@ const PageAllocator = struct {
|
||||
|
||||
fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
|
||||
const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const w = os.windows;
|
||||
if (new_size == 0) {
|
||||
// From the docs:
|
||||
@ -183,7 +183,7 @@ const PageAllocator = struct {
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
|
||||
const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (old_mem.len == 0) {
|
||||
return alloc(allocator, new_size, new_align);
|
||||
}
|
||||
@ -412,7 +412,7 @@ const WasmPageAllocator = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const HeapAllocator = switch (builtin.os) {
|
||||
pub const HeapAllocator = switch (builtin.os.tag) {
|
||||
.windows => struct {
|
||||
allocator: Allocator,
|
||||
heap_handle: ?HeapHandle,
|
||||
@ -855,7 +855,7 @@ test "PageAllocator" {
|
||||
try testAllocatorAlignedShrink(allocator);
|
||||
}
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// Trying really large alignment. As mentionned in the implementation,
|
||||
// VirtualAlloc returns 64K aligned addresses. We want to make sure
|
||||
// PageAllocator works beyond that, as it's not tested by
|
||||
@ -868,7 +868,7 @@ test "PageAllocator" {
|
||||
}
|
||||
|
||||
test "HeapAllocator" {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
var heap_allocator = HeapAllocator.init();
|
||||
defer heap_allocator.deinit();
|
||||
|
||||
|
@ -35,7 +35,7 @@ else
|
||||
pub const is_async = mode != .blocking;
|
||||
|
||||
fn getStdOutHandle() os.fd_t {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return os.windows.peb().ProcessParameters.hStdOutput;
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ pub fn getStdOut() File {
|
||||
}
|
||||
|
||||
fn getStdErrHandle() os.fd_t {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return os.windows.peb().ProcessParameters.hStdError;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ pub fn getStdErr() File {
|
||||
}
|
||||
|
||||
fn getStdInHandle() os.fd_t {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return os.windows.peb().ProcessParameters.hStdInput;
|
||||
}
|
||||
|
||||
@ -348,11 +348,11 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
|
||||
const shift = u7_bit_count - n;
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
out_buffer = @as(Buf, self.bit_buffer >> shift);
|
||||
self.bit_buffer <<= n;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
const value = (self.bit_buffer << shift) >> shift;
|
||||
out_buffer = @as(Buf, value);
|
||||
self.bit_buffer >>= n;
|
||||
@ -376,7 +376,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
};
|
||||
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
if (n >= u8_bit_count) {
|
||||
out_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
out_buffer <<= 1;
|
||||
@ -392,7 +392,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
|
||||
self.bit_count = shift;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
if (n >= u8_bit_count) {
|
||||
out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
|
||||
out_bits.* += u8_bit_count;
|
||||
@ -666,8 +666,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
|
||||
const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
|
||||
var in_buffer = switch (endian) {
|
||||
builtin.Endian.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
|
||||
builtin.Endian.Little => buf_value,
|
||||
.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
|
||||
.Little => buf_value,
|
||||
};
|
||||
var in_bits = bits;
|
||||
|
||||
@ -675,13 +675,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
const bits_remaining = u8_bit_count - self.bit_count;
|
||||
const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
|
||||
const v = @intCast(u8, in_buffer >> shift);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer <<= n;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer >>= n;
|
||||
@ -701,13 +701,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
//copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
|
||||
while (in_bits >= u8_bit_count) {
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
const v = @intCast(u8, in_buffer >> high_byte_shift);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer <<= 1;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer >>= @intCast(u3, u8_bit_count - 1);
|
||||
@ -720,8 +720,8 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
|
||||
if (in_bits > 0) {
|
||||
self.bit_count = @intCast(u4, in_bits);
|
||||
self.bit_buffer = switch (endian) {
|
||||
builtin.Endian.Big => @truncate(u8, in_buffer >> high_byte_shift),
|
||||
builtin.Endian.Little => @truncate(u8, in_buffer),
|
||||
.Big => @truncate(u8, in_buffer >> high_byte_shift),
|
||||
.Little => @truncate(u8, in_buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -858,10 +858,10 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,
|
||||
var result = @as(U, 0);
|
||||
for (buffer) |byte, i| {
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
result = (result << u8_bit_count) | byte;
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
result |= @as(U, byte) << @intCast(Log2U, u8_bit_count * i);
|
||||
},
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ pub const SliceSeekableInStream = struct {
|
||||
fn seekToFn(in_stream: *SeekableInStream, pos: u64) SeekError!void {
|
||||
const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
|
||||
const usize_pos = @intCast(usize, pos);
|
||||
if (usize_pos >= self.slice.len) return error.EndOfStream;
|
||||
if (usize_pos > self.slice.len) return error.EndOfStream;
|
||||
self.pos = usize_pos;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ pub const SliceSeekableInStream = struct {
|
||||
self.pos -= abs_amt;
|
||||
} else {
|
||||
const usize_amt = @intCast(usize, amt);
|
||||
if (self.pos + usize_amt >= self.slice.len) return error.EndOfStream;
|
||||
if (self.pos + usize_amt > self.slice.len) return error.EndOfStream;
|
||||
self.pos += usize_amt;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,17 @@ pub const load_command = extern struct {
|
||||
cmdsize: u32,
|
||||
};
|
||||
|
||||
pub const uuid_command = extern struct {
|
||||
/// LC_UUID
|
||||
cmd: u32,
|
||||
|
||||
/// sizeof(struct uuid_command)
|
||||
cmdsize: u32,
|
||||
|
||||
/// the 128-bit uuid
|
||||
uuid: [16]u8,
|
||||
};
|
||||
|
||||
/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
|
||||
/// "stab" style symbol table information as described in the header files
|
||||
/// <nlist.h> and <stab.h>.
|
||||
|
@ -32,7 +32,7 @@ const expect = std.testing.expect;
|
||||
/// - pow(-inf, y) = pow(-0, -y)
|
||||
/// - pow(x, y) = nan for finite x < 0 and finite non-integer y
|
||||
pub fn pow(comptime T: type, x: T, y: T) T {
|
||||
if (@typeInfo(T) == builtin.TypeId.Int) {
|
||||
if (@typeInfo(T) == .Int) {
|
||||
return math.powi(T, x, y) catch unreachable;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
|
||||
}!T) {
|
||||
const info = @typeInfo(T);
|
||||
|
||||
comptime assert(@typeInfo(T) == builtin.TypeId.Int);
|
||||
comptime assert(@typeInfo(T) == .Int);
|
||||
|
||||
// powi(x, +-0) = 1 for any x
|
||||
if (y == 0 or y == -0) {
|
||||
|
234
lib/std/mem.zig
234
lib/std/mem.zig
@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
|
||||
}
|
||||
return array;
|
||||
},
|
||||
.Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {
|
||||
@compileError("Can't set a "++ @typeName(T) ++" to zero.");
|
||||
.Vector,
|
||||
.ErrorUnion,
|
||||
.ErrorSet,
|
||||
.Union,
|
||||
.Fn,
|
||||
.BoundFn,
|
||||
.Type,
|
||||
.NoReturn,
|
||||
.Undefined,
|
||||
.Opaque,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
=> {
|
||||
@compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn len(comptime T: type, ptr: [*:0]const T) usize {
|
||||
var count: usize = 0;
|
||||
while (ptr[count] != 0) : (count += 1) {}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Deprecated. Use `span`.
|
||||
pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
|
||||
return ptr[0..len(T, ptr) :0];
|
||||
return ptr[0..len(ptr) :0];
|
||||
}
|
||||
|
||||
/// Deprecated. Use `span`.
|
||||
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
|
||||
return ptr[0..len(T, ptr) :0];
|
||||
return ptr[0..len(ptr) :0];
|
||||
}
|
||||
|
||||
/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
|
||||
/// returns a slice. If there is a sentinel on the input type, there will be a
|
||||
/// sentinel on the output type. The constness of the output type matches
|
||||
/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated,
|
||||
/// and assumed to not allow null.
|
||||
pub fn Span(comptime T: type) type {
|
||||
var ptr_info = @typeInfo(T).Pointer;
|
||||
switch (ptr_info.size) {
|
||||
.One => switch (@typeInfo(ptr_info.child)) {
|
||||
.Array => |info| {
|
||||
ptr_info.child = info.child;
|
||||
ptr_info.sentinel = info.sentinel;
|
||||
},
|
||||
else => @compileError("invalid type given to std.mem.Span"),
|
||||
},
|
||||
.C => {
|
||||
ptr_info.sentinel = 0;
|
||||
ptr_info.is_allowzero = false;
|
||||
},
|
||||
.Many, .Slice => {},
|
||||
}
|
||||
ptr_info.size = .Slice;
|
||||
return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
|
||||
}
|
||||
|
||||
test "Span" {
|
||||
testing.expect(Span(*[5]u16) == []u16);
|
||||
testing.expect(Span(*const [5]u16) == []const u16);
|
||||
testing.expect(Span([]u16) == []u16);
|
||||
testing.expect(Span([]const u8) == []const u8);
|
||||
testing.expect(Span([:1]u16) == [:1]u16);
|
||||
testing.expect(Span([:1]const u8) == [:1]const u8);
|
||||
testing.expect(Span([*:1]u16) == [:1]u16);
|
||||
testing.expect(Span([*:1]const u8) == [:1]const u8);
|
||||
testing.expect(Span([*c]u16) == [:0]u16);
|
||||
testing.expect(Span([*c]const u8) == [:0]const u8);
|
||||
}
|
||||
|
||||
/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
|
||||
/// returns a slice. If there is a sentinel on the input type, there will be a
|
||||
/// sentinel on the output type. The constness of the output type matches
|
||||
/// the constness of the input type.
|
||||
pub fn span(ptr: var) Span(@TypeOf(ptr)) {
|
||||
const Result = Span(@TypeOf(ptr));
|
||||
const l = len(ptr);
|
||||
if (@typeInfo(Result).Pointer.sentinel) |s| {
|
||||
return ptr[0..l :s];
|
||||
} else {
|
||||
return ptr[0..l];
|
||||
}
|
||||
}
|
||||
|
||||
test "span" {
|
||||
var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
|
||||
const ptr = array[0..2 :3].ptr;
|
||||
testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
|
||||
testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
|
||||
}
|
||||
|
||||
/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
|
||||
/// or a slice, and returns the length.
|
||||
pub fn len(ptr: var) usize {
|
||||
return switch (@typeInfo(@TypeOf(ptr))) {
|
||||
.Array => |info| info.len,
|
||||
.Pointer => |info| switch (info.size) {
|
||||
.One => switch (@typeInfo(info.child)) {
|
||||
.Array => |x| x.len,
|
||||
else => @compileError("invalid type given to std.mem.length"),
|
||||
},
|
||||
.Many => if (info.sentinel) |sentinel|
|
||||
indexOfSentinel(info.child, sentinel, ptr)
|
||||
else
|
||||
@compileError("length of pointer with no sentinel"),
|
||||
.C => indexOfSentinel(info.child, 0, ptr),
|
||||
.Slice => ptr.len,
|
||||
},
|
||||
else => @compileError("invalid type given to std.mem.length"),
|
||||
};
|
||||
}
|
||||
|
||||
test "len" {
|
||||
testing.expect(len("aoeu") == 4);
|
||||
|
||||
{
|
||||
var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
|
||||
testing.expect(len(&array) == 5);
|
||||
testing.expect(len(array[0..3]) == 3);
|
||||
array[2] = 0;
|
||||
const ptr = array[0..2 :0].ptr;
|
||||
testing.expect(len(ptr) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
|
||||
var i: usize = 0;
|
||||
while (ptr[i] != sentinel) {
|
||||
i += 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/// Returns true if all elements in a slice are equal to the scalar value provided
|
||||
@ -637,12 +746,12 @@ test "mem.indexOf" {
|
||||
pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType {
|
||||
var result: ReturnType = 0;
|
||||
switch (endian) {
|
||||
builtin.Endian.Big => {
|
||||
.Big => {
|
||||
for (bytes) |b| {
|
||||
result = (result << 8) | b;
|
||||
}
|
||||
},
|
||||
builtin.Endian.Little => {
|
||||
.Little => {
|
||||
const ShiftType = math.Log2Int(ReturnType);
|
||||
for (bytes) |b, index| {
|
||||
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)
|
||||
}
|
||||
|
||||
pub const readIntLittle = switch (builtin.endian) {
|
||||
builtin.Endian.Little => readIntNative,
|
||||
builtin.Endian.Big => readIntForeign,
|
||||
.Little => readIntNative,
|
||||
.Big => readIntForeign,
|
||||
};
|
||||
|
||||
pub const readIntBig = switch (builtin.endian) {
|
||||
builtin.Endian.Little => readIntForeign,
|
||||
builtin.Endian.Big => readIntNative,
|
||||
.Little => readIntForeign,
|
||||
.Big => readIntNative,
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
}
|
||||
|
||||
pub const readIntSliceLittle = switch (builtin.endian) {
|
||||
builtin.Endian.Little => readIntSliceNative,
|
||||
builtin.Endian.Big => readIntSliceForeign,
|
||||
.Little => readIntSliceNative,
|
||||
.Big => readIntSliceForeign,
|
||||
};
|
||||
|
||||
pub const readIntSliceBig = switch (builtin.endian) {
|
||||
builtin.Endian.Little => readIntSliceForeign,
|
||||
builtin.Endian.Big => readIntSliceNative,
|
||||
.Little => readIntSliceForeign,
|
||||
.Big => readIntSliceNative,
|
||||
};
|
||||
|
||||
/// 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
|
||||
}
|
||||
|
||||
pub const writeIntLittle = switch (builtin.endian) {
|
||||
builtin.Endian.Little => writeIntNative,
|
||||
builtin.Endian.Big => writeIntForeign,
|
||||
.Little => writeIntNative,
|
||||
.Big => writeIntForeign,
|
||||
};
|
||||
|
||||
pub const writeIntBig = switch (builtin.endian) {
|
||||
builtin.Endian.Little => writeIntForeign,
|
||||
builtin.Endian.Big => writeIntNative,
|
||||
.Little => writeIntForeign,
|
||||
.Big => writeIntNative,
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
}
|
||||
|
||||
pub const writeIntSliceNative = switch (builtin.endian) {
|
||||
builtin.Endian.Little => writeIntSliceLittle,
|
||||
builtin.Endian.Big => writeIntSliceBig,
|
||||
.Little => writeIntSliceLittle,
|
||||
.Big => writeIntSliceBig,
|
||||
};
|
||||
|
||||
pub const writeIntSliceForeign = switch (builtin.endian) {
|
||||
builtin.Endian.Little => writeIntSliceBig,
|
||||
builtin.Endian.Big => writeIntSliceLittle,
|
||||
.Little => writeIntSliceBig,
|
||||
.Big => writeIntSliceLittle,
|
||||
};
|
||||
|
||||
/// Writes a twos-complement integer to memory, with the specified endianness.
|
||||
@ -858,10 +967,10 @@ pub const writeIntSliceForeign = switch (builtin.endian) {
|
||||
/// use writeInt instead.
|
||||
pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void {
|
||||
comptime assert(T.bit_count % 8 == 0);
|
||||
switch (endian) {
|
||||
builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value),
|
||||
builtin.Endian.Big => return writeIntSliceBig(T, buffer, value),
|
||||
}
|
||||
return switch (endian) {
|
||||
.Little => writeIntSliceLittle(T, buffer, value),
|
||||
.Big => writeIntSliceBig(T, buffer, value),
|
||||
};
|
||||
}
|
||||
|
||||
test "writeIntBig and writeIntLittle" {
|
||||
@ -1397,54 +1506,54 @@ test "rotate" {
|
||||
/// Converts a little-endian integer to host endianness.
|
||||
pub fn littleToNative(comptime T: type, x: T) T {
|
||||
return switch (builtin.endian) {
|
||||
builtin.Endian.Little => x,
|
||||
builtin.Endian.Big => @byteSwap(T, x),
|
||||
.Little => x,
|
||||
.Big => @byteSwap(T, x),
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts a big-endian integer to host endianness.
|
||||
pub fn bigToNative(comptime T: type, x: T) T {
|
||||
return switch (builtin.endian) {
|
||||
builtin.Endian.Little => @byteSwap(T, x),
|
||||
builtin.Endian.Big => x,
|
||||
.Little => @byteSwap(T, x),
|
||||
.Big => x,
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts an integer from specified endianness to host endianness.
|
||||
pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T {
|
||||
return switch (endianness_of_x) {
|
||||
builtin.Endian.Little => littleToNative(T, x),
|
||||
builtin.Endian.Big => bigToNative(T, x),
|
||||
.Little => littleToNative(T, x),
|
||||
.Big => bigToNative(T, x),
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts an integer which has host endianness to the desired endianness.
|
||||
pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T {
|
||||
return switch (desired_endianness) {
|
||||
builtin.Endian.Little => nativeToLittle(T, x),
|
||||
builtin.Endian.Big => nativeToBig(T, x),
|
||||
.Little => nativeToLittle(T, x),
|
||||
.Big => nativeToBig(T, x),
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts an integer which has host endianness to little endian.
|
||||
pub fn nativeToLittle(comptime T: type, x: T) T {
|
||||
return switch (builtin.endian) {
|
||||
builtin.Endian.Little => x,
|
||||
builtin.Endian.Big => @byteSwap(T, x),
|
||||
.Little => x,
|
||||
.Big => @byteSwap(T, x),
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts an integer which has host endianness to big endian.
|
||||
pub fn nativeToBig(comptime T: type, x: T) T {
|
||||
return switch (builtin.endian) {
|
||||
builtin.Endian.Little => @byteSwap(T, x),
|
||||
builtin.Endian.Big => x,
|
||||
.Little => @byteSwap(T, x),
|
||||
.Big => x,
|
||||
};
|
||||
}
|
||||
|
||||
fn AsBytesReturnType(comptime P: type) type {
|
||||
if (comptime !trait.isSingleItemPtr(P))
|
||||
@compileError("expected single item " ++ "pointer, passed " ++ @typeName(P));
|
||||
@compileError("expected single item pointer, passed " ++ @typeName(P));
|
||||
|
||||
const size = @as(usize, @sizeOf(meta.Child(P)));
|
||||
const alignment = comptime meta.alignment(P);
|
||||
@ -1469,8 +1578,8 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {
|
||||
test "asBytes" {
|
||||
const deadbeef = @as(u32, 0xDEADBEEF);
|
||||
const deadbeef_bytes = switch (builtin.endian) {
|
||||
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
|
||||
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
|
||||
.Big => "\xDE\xAD\xBE\xEF",
|
||||
.Little => "\xEF\xBE\xAD\xDE",
|
||||
};
|
||||
|
||||
testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));
|
||||
@ -1508,21 +1617,21 @@ pub fn toBytes(value: var) [@sizeOf(@TypeOf(value))]u8 {
|
||||
test "toBytes" {
|
||||
var my_bytes = toBytes(@as(u32, 0x12345678));
|
||||
switch (builtin.endian) {
|
||||
builtin.Endian.Big => testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")),
|
||||
builtin.Endian.Little => testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")),
|
||||
.Big => testing.expect(eql(u8, &my_bytes, "\x12\x34\x56\x78")),
|
||||
.Little => testing.expect(eql(u8, &my_bytes, "\x78\x56\x34\x12")),
|
||||
}
|
||||
|
||||
my_bytes[0] = '\x99';
|
||||
switch (builtin.endian) {
|
||||
builtin.Endian.Big => testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")),
|
||||
builtin.Endian.Little => testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")),
|
||||
.Big => testing.expect(eql(u8, &my_bytes, "\x99\x34\x56\x78")),
|
||||
.Little => testing.expect(eql(u8, &my_bytes, "\x99\x56\x34\x12")),
|
||||
}
|
||||
}
|
||||
|
||||
fn BytesAsValueReturnType(comptime T: type, comptime B: type) type {
|
||||
const size = @as(usize, @sizeOf(T));
|
||||
|
||||
if (comptime !trait.is(builtin.TypeId.Pointer)(B) or
|
||||
if (comptime !trait.is(.Pointer)(B) or
|
||||
(meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8))
|
||||
{
|
||||
@compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));
|
||||
@ -1542,15 +1651,15 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @Typ
|
||||
test "bytesAsValue" {
|
||||
const deadbeef = @as(u32, 0xDEADBEEF);
|
||||
const deadbeef_bytes = switch (builtin.endian) {
|
||||
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
|
||||
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
|
||||
.Big => "\xDE\xAD\xBE\xEF",
|
||||
.Little => "\xEF\xBE\xAD\xDE",
|
||||
};
|
||||
|
||||
testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*);
|
||||
|
||||
var codeface_bytes: [4]u8 = switch (builtin.endian) {
|
||||
builtin.Endian.Big => "\xC0\xDE\xFA\xCE",
|
||||
builtin.Endian.Little => "\xCE\xFA\xDE\xC0",
|
||||
.Big => "\xC0\xDE\xFA\xCE",
|
||||
.Little => "\xCE\xFA\xDE\xC0",
|
||||
}.*;
|
||||
var codeface = bytesAsValue(u32, &codeface_bytes);
|
||||
testing.expect(codeface.* == 0xC0DEFACE);
|
||||
@ -1583,8 +1692,8 @@ pub fn bytesToValue(comptime T: type, bytes: var) T {
|
||||
}
|
||||
test "bytesToValue" {
|
||||
const deadbeef_bytes = switch (builtin.endian) {
|
||||
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
|
||||
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
|
||||
.Big => "\xDE\xAD\xBE\xEF",
|
||||
.Little => "\xEF\xBE\xAD\xDE",
|
||||
};
|
||||
|
||||
const deadbeef = bytesToValue(u32, deadbeef_bytes);
|
||||
@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
|
||||
return *[length]meta.Child(meta.Child(T));
|
||||
}
|
||||
|
||||
///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
|
||||
pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) {
|
||||
/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
|
||||
/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
|
||||
pub fn subArrayPtr(
|
||||
ptr: var,
|
||||
comptime start: usize,
|
||||
comptime length: usize,
|
||||
) SubArrayPtrReturnType(@TypeOf(ptr), length) {
|
||||
assert(start + length <= ptr.*.len);
|
||||
|
||||
const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
|
||||
|
@ -115,6 +115,32 @@ test "std.meta.Child" {
|
||||
testing.expect(Child(?u8) == u8);
|
||||
}
|
||||
|
||||
/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
|
||||
pub fn Sentinel(comptime T: type) Child(T) {
|
||||
// comptime asserts that ptr has a sentinel
|
||||
switch (@typeInfo(T)) {
|
||||
.Array => |arrayInfo| {
|
||||
return comptime arrayInfo.sentinel.?;
|
||||
},
|
||||
.Pointer => |ptrInfo| {
|
||||
switch (ptrInfo.size) {
|
||||
.Many, .Slice => {
|
||||
return comptime ptrInfo.sentinel.?;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
|
||||
}
|
||||
|
||||
test "std.meta.Sentinel" {
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
|
||||
testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
|
||||
}
|
||||
|
||||
pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
|
||||
return switch (@typeInfo(T)) {
|
||||
.Struct => |info| info.layout,
|
||||
|
@ -73,7 +73,7 @@ pub const Mutex = if (builtin.single_threaded)
|
||||
return self.tryAcquire() orelse @panic("deadlock detected");
|
||||
}
|
||||
}
|
||||
else if (builtin.os == .windows)
|
||||
else if (builtin.os.tag == .windows)
|
||||
// https://locklessinc.com/articles/keyed_events/
|
||||
extern union {
|
||||
locked: u8,
|
||||
@ -161,7 +161,7 @@ else if (builtin.os == .windows)
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (builtin.link_libc or builtin.os == .linux)
|
||||
else if (builtin.link_libc or builtin.os.tag == .linux)
|
||||
// stack-based version of https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs
|
||||
struct {
|
||||
state: usize,
|
||||
|
@ -352,7 +352,7 @@ pub const Address = extern union {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path));
|
||||
const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path));
|
||||
return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
|
||||
},
|
||||
else => unreachable,
|
||||
@ -501,7 +501,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
|
||||
|
||||
return result;
|
||||
}
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
const flags = std.c.AI_NUMERICSERV;
|
||||
const family = os.AF_UNSPEC;
|
||||
var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
|
||||
|
@ -63,7 +63,7 @@ test "parse and render IPv4 addresses" {
|
||||
}
|
||||
|
||||
test "resolve DNS" {
|
||||
if (std.builtin.os == .windows) {
|
||||
if (std.builtin.os.tag == .windows) {
|
||||
// DNS resolution not implemented on Windows yet.
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -81,7 +81,7 @@ test "resolve DNS" {
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
if (!std.io.is_async) return error.SkipZigTest;
|
||||
|
||||
if (std.builtin.os != .linux) {
|
||||
if (std.builtin.os.tag != .linux) {
|
||||
// TODO build abstractions for other operating systems
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
171
lib/std/os.zig
171
lib/std/os.zig
@ -56,7 +56,7 @@ pub const system = if (@hasDecl(root, "os") and root.os != @This())
|
||||
root.os.system
|
||||
else if (builtin.link_libc)
|
||||
std.c
|
||||
else switch (builtin.os) {
|
||||
else switch (builtin.os.tag) {
|
||||
.macosx, .ios, .watchos, .tvos => darwin,
|
||||
.freebsd => freebsd,
|
||||
.linux => linux,
|
||||
@ -93,10 +93,10 @@ pub const errno = system.getErrno;
|
||||
/// must call `fsync` before `close`.
|
||||
/// Note: The Zig standard library does not support POSIX thread cancellation.
|
||||
pub fn close(fd: fd_t) void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.CloseHandle(fd);
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
_ = wasi.fd_close(fd);
|
||||
}
|
||||
if (comptime std.Target.current.isDarwin()) {
|
||||
@ -121,12 +121,12 @@ pub const GetRandomError = OpenError;
|
||||
/// appropriate OS-specific library call. Otherwise it uses the zig standard
|
||||
/// library implementation.
|
||||
pub fn getrandom(buffer: []u8) GetRandomError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.RtlGenRandom(buffer);
|
||||
}
|
||||
if (builtin.os == .linux or builtin.os == .freebsd) {
|
||||
if (builtin.os.tag == .linux or builtin.os.tag == .freebsd) {
|
||||
var buf = buffer;
|
||||
const use_c = builtin.os != .linux or
|
||||
const use_c = builtin.os.tag != .linux or
|
||||
std.c.versionCheck(builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok;
|
||||
|
||||
while (buf.len != 0) {
|
||||
@ -153,7 +153,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
switch (wasi.random_get(buffer.ptr, buffer.len)) {
|
||||
0 => return,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
@ -188,13 +188,13 @@ pub fn abort() noreturn {
|
||||
// MSVCRT abort() sometimes opens a popup window which is undesirable, so
|
||||
// even when linking libc on Windows we use our own abort implementation.
|
||||
// See https://github.com/ziglang/zig/issues/2071 for more details.
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (builtin.mode == .Debug) {
|
||||
@breakpoint();
|
||||
}
|
||||
windows.kernel32.ExitProcess(3);
|
||||
}
|
||||
if (!builtin.link_libc and builtin.os == .linux) {
|
||||
if (!builtin.link_libc and builtin.os.tag == .linux) {
|
||||
raise(SIGABRT) catch {};
|
||||
|
||||
// TODO the rest of the implementation of abort() from musl libc here
|
||||
@ -202,10 +202,10 @@ pub fn abort() noreturn {
|
||||
raise(SIGKILL) catch {};
|
||||
exit(127);
|
||||
}
|
||||
if (builtin.os == .uefi) {
|
||||
if (builtin.os.tag == .uefi) {
|
||||
exit(0); // TODO choose appropriate exit code
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
@breakpoint();
|
||||
exit(1);
|
||||
}
|
||||
@ -223,7 +223,7 @@ pub fn raise(sig: u8) RaiseError!void {
|
||||
}
|
||||
}
|
||||
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
var set: linux.sigset_t = undefined;
|
||||
// block application signals
|
||||
_ = linux.sigprocmask(SIG_BLOCK, &linux.app_mask, &set);
|
||||
@ -260,16 +260,16 @@ pub fn exit(status: u8) noreturn {
|
||||
if (builtin.link_libc) {
|
||||
system.exit(status);
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
windows.kernel32.ExitProcess(status);
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
wasi.proc_exit(status);
|
||||
}
|
||||
if (builtin.os == .linux and !builtin.single_threaded) {
|
||||
if (builtin.os.tag == .linux and !builtin.single_threaded) {
|
||||
linux.exit_group(status);
|
||||
}
|
||||
if (builtin.os == .uefi) {
|
||||
if (builtin.os.tag == .uefi) {
|
||||
// exit() is only avaliable if exitBootServices() has not been called yet.
|
||||
// This call to exit should not fail, so we don't care about its return value.
|
||||
if (uefi.system_table.boot_services) |bs| {
|
||||
@ -299,11 +299,11 @@ pub const ReadError = error{
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.ReadFile(fd, buf, null);
|
||||
}
|
||||
|
||||
if (builtin.os == .wasi and !builtin.link_libc) {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const iovs = [1]iovec{iovec{
|
||||
.iov_base = buf.ptr,
|
||||
.iov_len = buf.len,
|
||||
@ -352,7 +352,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
|
||||
/// * Windows
|
||||
/// On these systems, the read races with concurrent writes to the same file descriptor.
|
||||
pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// TODO batch these into parallel requests
|
||||
var off: usize = 0;
|
||||
var iov_i: usize = 0;
|
||||
@ -406,7 +406,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
pub fn pread(fd: fd_t, buf: []u8, offset: u64) ReadError!usize {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.ReadFile(fd, buf, offset);
|
||||
}
|
||||
|
||||
@ -493,7 +493,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
|
||||
}
|
||||
}
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// TODO batch these into parallel requests
|
||||
var off: usize = 0;
|
||||
var iov_i: usize = 0;
|
||||
@ -557,11 +557,11 @@ pub const WriteError = error{
|
||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||
pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.WriteFile(fd, bytes, null);
|
||||
}
|
||||
|
||||
if (builtin.os == .wasi and !builtin.link_libc) {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const ciovs = [1]iovec_const{iovec_const{
|
||||
.iov_base = bytes.ptr,
|
||||
.iov_len = bytes.len,
|
||||
@ -650,7 +650,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!void {
|
||||
/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
|
||||
/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
|
||||
pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) WriteError!void {
|
||||
if (comptime std.Target.current.isWindows()) {
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
return windows.WriteFile(fd, bytes, offset);
|
||||
}
|
||||
|
||||
@ -739,7 +739,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void
|
||||
}
|
||||
}
|
||||
|
||||
if (comptime std.Target.current.isWindows()) {
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
var off = offset;
|
||||
for (iov) |item| {
|
||||
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.
|
||||
|
||||
pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
|
||||
for (envp_buf) |env| {
|
||||
const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;
|
||||
const env_buf = if (env) |ptr| ptr[0 .. mem.len(ptr) + 1] else break;
|
||||
allocator.free(env_buf);
|
||||
}
|
||||
allocator.free(envp_buf);
|
||||
@ -1129,7 +1129,7 @@ pub fn getenv(key: []const u8) ?[]const u8 {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
@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.");
|
||||
}
|
||||
// TODO see https://github.com/ziglang/zig/issues/4524
|
||||
@ -1158,7 +1158,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
|
||||
const value = system.getenv(key) orelse return null;
|
||||
return mem.toSliceConst(u8, value);
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
@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.");
|
||||
}
|
||||
return getenv(mem.toSliceConst(u8, key));
|
||||
@ -1167,7 +1167,7 @@ pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
|
||||
/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
|
||||
/// See also `getenv`.
|
||||
pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
|
||||
if (builtin.os != .windows) {
|
||||
if (builtin.os.tag != .windows) {
|
||||
@compileError("std.os.getenvW is a Windows-only API");
|
||||
}
|
||||
const key_slice = mem.toSliceConst(u16, key);
|
||||
@ -1199,7 +1199,7 @@ pub const GetCwdError = error{
|
||||
|
||||
/// The result is a slice of out_buffer, indexed from 0.
|
||||
pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.GetCurrentDirectory(out_buffer);
|
||||
}
|
||||
|
||||
@ -1240,7 +1240,7 @@ pub const SymLinkError = error{
|
||||
/// If `sym_link_path` exists, it will not be overwritten.
|
||||
/// See also `symlinkC` and `symlinkW`.
|
||||
pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const target_path_w = try windows.sliceToPrefixedFileW(target_path);
|
||||
const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
|
||||
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!
|
||||
/// This is the same as `symlink` except the parameters are null-terminated pointers.
|
||||
/// See also `symlink`.
|
||||
pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const target_path_w = try windows.cStrToPrefixedFileW(target_path);
|
||||
const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
|
||||
return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
|
||||
@ -1329,7 +1329,7 @@ pub const UnlinkError = error{
|
||||
/// Delete a name and possibly the file it refers to.
|
||||
/// See also `unlinkC`.
|
||||
pub fn unlink(file_path: []const u8) UnlinkError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
return windows.DeleteFileW(&file_path_w);
|
||||
} else {
|
||||
@ -1340,7 +1340,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void {
|
||||
|
||||
/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
|
||||
pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
return windows.DeleteFileW(&file_path_w);
|
||||
}
|
||||
@ -1372,7 +1372,7 @@ pub const UnlinkatError = UnlinkError || error{
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
|
||||
if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0);
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
return unlinkatW(dirfd, &file_path_w, flags);
|
||||
}
|
||||
@ -1382,7 +1382,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
|
||||
|
||||
/// Same as `unlinkat` but `file_path` is a null-terminated string.
|
||||
pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path_c);
|
||||
return unlinkatW(dirfd, &file_path_w, flags);
|
||||
}
|
||||
@ -1438,7 +1438,7 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr
|
||||
|
||||
var attr = w.OBJECT_ATTRIBUTES{
|
||||
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = dirfd,
|
||||
.RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd,
|
||||
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
|
||||
.ObjectName = &nt_name,
|
||||
.SecurityDescriptor = null,
|
||||
@ -1493,7 +1493,7 @@ const RenameError = error{
|
||||
|
||||
/// Change the name or location of a file.
|
||||
pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(new_path);
|
||||
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 {
|
||||
|
||||
/// Same as `rename` except the parameters are null-terminated byte arrays.
|
||||
pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const old_path_w = try windows.cStrToPrefixedFileW(old_path);
|
||||
const new_path_w = try windows.cStrToPrefixedFileW(new_path);
|
||||
return renameW(&old_path_w, &new_path_w);
|
||||
@ -1561,7 +1561,7 @@ pub const MakeDirError = error{
|
||||
/// Create a directory.
|
||||
/// `mode` is ignored on Windows.
|
||||
pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
|
||||
return windows.CreateDirectoryW(&dir_path_w, null);
|
||||
} else {
|
||||
@ -1572,7 +1572,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
|
||||
|
||||
/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
|
||||
pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
|
||||
return windows.CreateDirectoryW(&dir_path_w, null);
|
||||
}
|
||||
@ -1611,7 +1611,7 @@ pub const DeleteDirError = error{
|
||||
|
||||
/// Deletes an empty directory.
|
||||
pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
|
||||
return windows.RemoveDirectoryW(&dir_path_w);
|
||||
} else {
|
||||
@ -1622,7 +1622,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
|
||||
|
||||
/// Same as `rmdir` except the parameter is null-terminated.
|
||||
pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
|
||||
return windows.RemoveDirectoryW(&dir_path_w);
|
||||
}
|
||||
@ -1658,7 +1658,7 @@ pub const ChangeCurDirError = error{
|
||||
/// Changes the current working directory of the calling process.
|
||||
/// `dir_path` is recommended to be a UTF-8 encoded string.
|
||||
pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
|
||||
@compileError("TODO implement chdir for Windows");
|
||||
} else {
|
||||
@ -1669,7 +1669,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
|
||||
|
||||
/// Same as `chdir` except the parameter is null-terminated.
|
||||
pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
|
||||
@compileError("TODO implement chdir for Windows");
|
||||
}
|
||||
@ -1700,7 +1700,7 @@ pub const ReadLinkError = error{
|
||||
/// Read value of a symbolic link.
|
||||
/// The return value is a slice of `out_buffer` from index 0.
|
||||
pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
|
||||
@compileError("TODO implement readlink for Windows");
|
||||
} else {
|
||||
@ -1711,7 +1711,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
|
||||
/// Same as `readlink` except `file_path` is null-terminated.
|
||||
pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
@compileError("TODO implement readlink for Windows");
|
||||
}
|
||||
@ -1732,7 +1732,7 @@ pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8
|
||||
}
|
||||
|
||||
pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
|
||||
@compileError("TODO implement readlink for Windows");
|
||||
}
|
||||
@ -1800,7 +1800,7 @@ pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
|
||||
|
||||
/// Test whether a file descriptor refers to a terminal.
|
||||
pub fn isatty(handle: fd_t) bool {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (isCygwinPty(handle))
|
||||
return true;
|
||||
|
||||
@ -1810,7 +1810,7 @@ pub fn isatty(handle: fd_t) bool {
|
||||
if (builtin.link_libc) {
|
||||
return system.isatty(handle) != 0;
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
var statbuf: fdstat_t = undefined;
|
||||
const err = system.fd_fdstat_get(handle, &statbuf);
|
||||
if (err != 0) {
|
||||
@ -1828,7 +1828,7 @@ pub fn isatty(handle: fd_t) bool {
|
||||
|
||||
return true;
|
||||
}
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
var wsz: linux.winsize = undefined;
|
||||
return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, @as(isize, handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
|
||||
}
|
||||
@ -1836,7 +1836,7 @@ pub fn isatty(handle: fd_t) bool {
|
||||
}
|
||||
|
||||
pub fn isCygwinPty(handle: fd_t) bool {
|
||||
if (builtin.os != .windows) return false;
|
||||
if (builtin.os.tag != .windows) return false;
|
||||
|
||||
const size = @sizeOf(windows.FILE_NAME_INFO);
|
||||
var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (size + windows.MAX_PATH);
|
||||
@ -2589,7 +2589,7 @@ pub const AccessError = error{
|
||||
/// check user's permissions for a file
|
||||
/// TODO currently this assumes `mode` is `F_OK` on Windows.
|
||||
pub fn access(path: []const u8, mode: u32) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||
_ = try windows.GetFileAttributesW(&path_w);
|
||||
return;
|
||||
@ -2603,7 +2603,7 @@ pub const accessC = accessZ;
|
||||
|
||||
/// Same as `access` except `path` is null-terminated.
|
||||
pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||
_ = try windows.GetFileAttributesW(&path_w);
|
||||
return;
|
||||
@ -2644,7 +2644,7 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v
|
||||
/// Check user's permissions for a file, based on an open directory handle.
|
||||
/// TODO currently this ignores `mode` and `flags` on Windows.
|
||||
pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.sliceToPrefixedFileW(path);
|
||||
return faccessatW(dirfd, &path_w, mode, flags);
|
||||
}
|
||||
@ -2654,7 +2654,7 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
|
||||
|
||||
/// Same as `faccessat` except the path parameter is null-terminated.
|
||||
pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try windows.cStrToPrefixedFileW(path);
|
||||
return faccessatW(dirfd, &path_w, mode, flags);
|
||||
}
|
||||
@ -2764,6 +2764,7 @@ pub const SysCtlError = error{
|
||||
PermissionDenied,
|
||||
SystemResources,
|
||||
NameTooLong,
|
||||
UnknownName,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn sysctl(
|
||||
@ -2779,6 +2780,7 @@ pub fn sysctl(
|
||||
EFAULT => unreachable,
|
||||
EPERM => return error.PermissionDenied,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOENT => return error.UnknownName,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
@ -2795,6 +2797,7 @@ pub fn sysctlbynameC(
|
||||
EFAULT => unreachable,
|
||||
EPERM => return error.PermissionDenied,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOENT => return error.UnknownName,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
@ -2811,7 +2814,7 @@ pub const SeekError = error{Unseekable} || UnexpectedError;
|
||||
|
||||
/// Repositions read/write file offset relative to the beginning.
|
||||
pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
|
||||
if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
var result: u64 = undefined;
|
||||
switch (errno(system.llseek(fd, offset, &result, SEEK_SET))) {
|
||||
0 => return,
|
||||
@ -2823,7 +2826,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.SetFilePointerEx_BEGIN(fd, offset);
|
||||
}
|
||||
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 {
|
||||
|
||||
/// Repositions read/write file offset relative to the current offset.
|
||||
pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
|
||||
if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
var result: u64 = undefined;
|
||||
switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_CUR))) {
|
||||
0 => return,
|
||||
@ -2852,7 +2855,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.SetFilePointerEx_CURRENT(fd, offset);
|
||||
}
|
||||
switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
|
||||
@ -2868,7 +2871,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
|
||||
|
||||
/// Repositions read/write file offset relative to the end.
|
||||
pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
|
||||
if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
var result: u64 = undefined;
|
||||
switch (errno(system.llseek(fd, @bitCast(u64, offset), &result, SEEK_END))) {
|
||||
0 => return,
|
||||
@ -2880,7 +2883,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.SetFilePointerEx_END(fd, offset);
|
||||
}
|
||||
switch (errno(system.lseek(fd, offset, SEEK_END))) {
|
||||
@ -2896,7 +2899,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
|
||||
|
||||
/// Returns the read/write file offset relative to the beginning.
|
||||
pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
|
||||
if (builtin.os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
if (builtin.os.tag == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
|
||||
var result: u64 = undefined;
|
||||
switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {
|
||||
0 => return result,
|
||||
@ -2908,7 +2911,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return windows.SetFilePointerEx_CURRENT_get(fd);
|
||||
}
|
||||
const rc = system.lseek(fd, 0, SEEK_CUR);
|
||||
@ -2957,7 +2960,7 @@ pub const RealPathError = error{
|
||||
/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
|
||||
/// See also `realpathC` and `realpathW`.
|
||||
pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.sliceToPrefixedFileW(pathname);
|
||||
return realpathW(&pathname_w, out_buffer);
|
||||
}
|
||||
@ -2967,11 +2970,11 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
|
||||
|
||||
/// Same as `realpath` except `pathname` is null-terminated.
|
||||
pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.cStrToPrefixedFileW(pathname);
|
||||
return realpathW(&pathname_w, out_buffer);
|
||||
}
|
||||
if (builtin.os == .linux and !builtin.link_libc) {
|
||||
if (builtin.os.tag == .linux and !builtin.link_libc) {
|
||||
const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
|
||||
defer close(fd);
|
||||
|
||||
@ -3121,7 +3124,7 @@ pub fn dl_iterate_phdr(
|
||||
pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
|
||||
|
||||
pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
|
||||
if (comptime std.Target.current.getOs() == .wasi) {
|
||||
if (std.Target.current.os.tag == .wasi) {
|
||||
var ts: timestamp_t = undefined;
|
||||
switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) {
|
||||
0 => {
|
||||
@ -3144,7 +3147,7 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
|
||||
}
|
||||
|
||||
pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
|
||||
if (comptime std.Target.current.getOs() == .wasi) {
|
||||
if (std.Target.current.os.tag == .wasi) {
|
||||
var ts: timestamp_t = undefined;
|
||||
switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) {
|
||||
0 => res.* = .{
|
||||
@ -3222,7 +3225,7 @@ pub const SigaltstackError = error{
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void {
|
||||
if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi)
|
||||
if (builtin.os.tag == .windows or builtin.os.tag == .uefi or builtin.os.tag == .wasi)
|
||||
@compileError("std.os.sigaltstack not available for this target");
|
||||
|
||||
switch (errno(system.sigaltstack(ss, old_ss))) {
|
||||
@ -3294,23 +3297,25 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 {
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
if (builtin.os == .linux) {
|
||||
var uts: utsname = undefined;
|
||||
switch (errno(system.uname(&uts))) {
|
||||
0 => {
|
||||
const hostname = mem.toSlice(u8, @ptrCast([*:0]u8, &uts.nodename));
|
||||
mem.copy(u8, name_buffer, hostname);
|
||||
return name_buffer[0..hostname.len];
|
||||
},
|
||||
EFAULT => unreachable,
|
||||
EPERM => return error.PermissionDenied,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
if (builtin.os.tag == .linux) {
|
||||
const uts = uname();
|
||||
const hostname = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.nodename));
|
||||
mem.copy(u8, name_buffer, hostname);
|
||||
return name_buffer[0..hostname.len];
|
||||
}
|
||||
|
||||
@compileError("TODO implement gethostname for this OS");
|
||||
}
|
||||
|
||||
pub fn uname() utsname {
|
||||
var uts: utsname = undefined;
|
||||
switch (errno(system.uname(&uts))) {
|
||||
0 => return uts,
|
||||
EFAULT => unreachable,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn res_mkquery(
|
||||
op: u4,
|
||||
dname: []const u8,
|
||||
@ -3611,7 +3616,7 @@ pub const SchedYieldError = error{
|
||||
};
|
||||
|
||||
pub fn sched_yield() SchedYieldError!void {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// The return value has to do with how many other threads there are; it is not
|
||||
// an error condition on Windows.
|
||||
_ = windows.kernel32.SwitchToThread();
|
||||
|
@ -3,10 +3,10 @@
|
||||
//! Root source files can define `os.bits` and these will additionally be added
|
||||
//! to the namespace.
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const root = @import("root");
|
||||
|
||||
pub usingnamespace switch (builtin.os) {
|
||||
pub usingnamespace switch (std.Target.current.os.tag) {
|
||||
.macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),
|
||||
.dragonfly => @import("bits/dragonfly.zig"),
|
||||
.freebsd => @import("bits/freebsd.zig"),
|
||||
|
@ -1070,7 +1070,7 @@ pub fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) usi
|
||||
}
|
||||
|
||||
test "" {
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
_ = @import("linux/test.zig");
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,11 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
||||
}) {
|
||||
const this_ph = @intToPtr(*elf.Phdr, ph_addr);
|
||||
switch (this_ph.p_type) {
|
||||
elf.PT_LOAD => base = vdso_addr + this_ph.p_offset - this_ph.p_vaddr,
|
||||
// On WSL1 as well as older kernels, the VDSO ELF image is pre-linked in the upper half
|
||||
// of the memory space (e.g. p_vaddr = 0xffffffffff700000 on WSL1).
|
||||
// Wrapping operations are used on this line as well as subsequent calculations relative to base
|
||||
// (lines 47, 78) to ensure no overflow check is tripped.
|
||||
elf.PT_LOAD => base = vdso_addr +% this_ph.p_offset -% this_ph.p_vaddr,
|
||||
elf.PT_DYNAMIC => maybe_dynv = @intToPtr([*]usize, vdso_addr + this_ph.p_offset),
|
||||
else => {},
|
||||
}
|
||||
@ -40,7 +44,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (dynv[i] != 0) : (i += 2) {
|
||||
const p = base + dynv[i + 1];
|
||||
const p = base +% dynv[i + 1];
|
||||
switch (dynv[i]) {
|
||||
elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
|
||||
elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
|
||||
@ -71,7 +75,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
|
||||
if (!checkver(maybe_verdef.?, versym[i], vername, strings))
|
||||
continue;
|
||||
}
|
||||
return base + syms[i].st_value;
|
||||
return base +% syms[i].st_value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -53,7 +53,7 @@ test "std.Thread.getCurrentId" {
|
||||
thread.wait();
|
||||
if (Thread.use_pthreads) {
|
||||
expect(thread_current_id == thread_id);
|
||||
} else if (builtin.os == .windows) {
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
expect(Thread.getCurrentId() != thread_current_id);
|
||||
} else {
|
||||
// If the thread completes very quickly, then thread_id can be 0. See the
|
||||
@ -151,7 +151,7 @@ test "realpath" {
|
||||
}
|
||||
|
||||
test "sigaltstack" {
|
||||
if (builtin.os == .windows or builtin.os == .wasi) return error.SkipZigTest;
|
||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
var st: os.stack_t = undefined;
|
||||
try os.sigaltstack(null, &st);
|
||||
@ -204,7 +204,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
|
||||
}
|
||||
|
||||
test "dl_iterate_phdr" {
|
||||
if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx)
|
||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macosx)
|
||||
return error.SkipZigTest;
|
||||
|
||||
var counter: usize = 0;
|
||||
@ -213,7 +213,7 @@ test "dl_iterate_phdr" {
|
||||
}
|
||||
|
||||
test "gethostname" {
|
||||
if (builtin.os == .windows)
|
||||
if (builtin.os.tag == .windows)
|
||||
return error.SkipZigTest;
|
||||
|
||||
var buf: [os.HOST_NAME_MAX]u8 = undefined;
|
||||
@ -222,7 +222,7 @@ test "gethostname" {
|
||||
}
|
||||
|
||||
test "pipe" {
|
||||
if (builtin.os == .windows)
|
||||
if (builtin.os.tag == .windows)
|
||||
return error.SkipZigTest;
|
||||
|
||||
var fds = try os.pipe();
|
||||
@ -241,7 +241,7 @@ test "argsAlloc" {
|
||||
|
||||
test "memfd_create" {
|
||||
// memfd_create is linux specific.
|
||||
if (builtin.os != .linux) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
const fd = std.os.memfd_create("test", 0) catch |err| switch (err) {
|
||||
// Related: https://github.com/ziglang/zig/issues/4019
|
||||
error.SystemOutdated => return error.SkipZigTest,
|
||||
@ -258,7 +258,7 @@ test "memfd_create" {
|
||||
}
|
||||
|
||||
test "mmap" {
|
||||
if (builtin.os == .windows)
|
||||
if (builtin.os.tag == .windows)
|
||||
return error.SkipZigTest;
|
||||
|
||||
// Simple mmap() call with non page-aligned size
|
||||
@ -353,7 +353,7 @@ test "mmap" {
|
||||
}
|
||||
|
||||
test "getenv" {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
|
||||
} else {
|
||||
expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
|
||||
|
@ -23,6 +23,7 @@ pub const BOOL = c_int;
|
||||
pub const BOOLEAN = BYTE;
|
||||
pub const BYTE = u8;
|
||||
pub const CHAR = u8;
|
||||
pub const UCHAR = u8;
|
||||
pub const FLOAT = f32;
|
||||
pub const HANDLE = *c_void;
|
||||
pub const HCRYPTPROV = ULONG_PTR;
|
||||
@ -54,6 +55,7 @@ pub const WORD = u16;
|
||||
pub const DWORD = u32;
|
||||
pub const DWORD64 = u64;
|
||||
pub const LARGE_INTEGER = i64;
|
||||
pub const ULARGE_INTEGER = u64;
|
||||
pub const USHORT = u16;
|
||||
pub const SHORT = i16;
|
||||
pub const ULONG = u32;
|
||||
@ -1145,32 +1147,202 @@ pub const UNICODE_STRING = extern struct {
|
||||
Buffer: [*]WCHAR,
|
||||
};
|
||||
|
||||
const ACTIVATION_CONTEXT_DATA = @OpaqueType();
|
||||
const ASSEMBLY_STORAGE_MAP = @OpaqueType();
|
||||
const FLS_CALLBACK_INFO = @OpaqueType();
|
||||
const RTL_BITMAP = @OpaqueType();
|
||||
pub const PRTL_BITMAP = *RTL_BITMAP;
|
||||
const KAFFINITY = usize;
|
||||
|
||||
/// Process Environment Block
|
||||
/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
|
||||
/// - https://github.com/wine-mirror/wine/blob/1aff1e6a370ee8c0213a0fd4b220d121da8527aa/include/winternl.h#L269
|
||||
/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/index.htm
|
||||
pub const PEB = extern struct {
|
||||
Reserved1: [2]BYTE,
|
||||
BeingDebugged: BYTE,
|
||||
Reserved2: [1]BYTE,
|
||||
Reserved3: [2]PVOID,
|
||||
// Versions: All
|
||||
InheritedAddressSpace: BOOLEAN,
|
||||
|
||||
// Versions: 3.51+
|
||||
ReadImageFileExecOptions: BOOLEAN,
|
||||
BeingDebugged: BOOLEAN,
|
||||
|
||||
// Versions: 5.2+ (previously was padding)
|
||||
BitField: UCHAR,
|
||||
|
||||
// Versions: all
|
||||
Mutant: HANDLE,
|
||||
ImageBaseAddress: HMODULE,
|
||||
Ldr: *PEB_LDR_DATA,
|
||||
ProcessParameters: *RTL_USER_PROCESS_PARAMETERS,
|
||||
Reserved4: [3]PVOID,
|
||||
SubSystemData: PVOID,
|
||||
ProcessHeap: HANDLE,
|
||||
|
||||
// Versions: 5.1+
|
||||
FastPebLock: *RTL_CRITICAL_SECTION,
|
||||
|
||||
// Versions: 5.2+
|
||||
AtlThunkSListPtr: PVOID,
|
||||
Reserved5: PVOID,
|
||||
Reserved6: ULONG,
|
||||
Reserved7: PVOID,
|
||||
Reserved8: ULONG,
|
||||
IFEOKey: PVOID,
|
||||
|
||||
// Versions: 6.0+
|
||||
|
||||
/// https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/crossprocessflags.htm
|
||||
CrossProcessFlags: ULONG,
|
||||
|
||||
// Versions: 6.0+
|
||||
union1: extern union {
|
||||
KernelCallbackTable: PVOID,
|
||||
UserSharedInfoPtr: PVOID,
|
||||
},
|
||||
|
||||
// Versions: 5.1+
|
||||
SystemReserved: ULONG,
|
||||
|
||||
// Versions: 5.1, (not 5.2, not 6.0), 6.1+
|
||||
AtlThunkSListPtr32: ULONG,
|
||||
Reserved9: [45]PVOID,
|
||||
Reserved10: [96]BYTE,
|
||||
PostProcessInitRoutine: PPS_POST_PROCESS_INIT_ROUTINE,
|
||||
Reserved11: [128]BYTE,
|
||||
Reserved12: [1]PVOID,
|
||||
|
||||
// Versions: 6.1+
|
||||
ApiSetMap: PVOID,
|
||||
|
||||
// Versions: all
|
||||
TlsExpansionCounter: ULONG,
|
||||
// note: there is padding here on 64 bit
|
||||
TlsBitmap: PRTL_BITMAP,
|
||||
TlsBitmapBits: [2]ULONG,
|
||||
ReadOnlySharedMemoryBase: PVOID,
|
||||
|
||||
// Versions: 1703+
|
||||
SharedData: PVOID,
|
||||
|
||||
// Versions: all
|
||||
ReadOnlyStaticServerData: *PVOID,
|
||||
AnsiCodePageData: PVOID,
|
||||
OemCodePageData: PVOID,
|
||||
UnicodeCaseTableData: PVOID,
|
||||
|
||||
// Versions: 3.51+
|
||||
NumberOfProcessors: ULONG,
|
||||
NtGlobalFlag: ULONG,
|
||||
|
||||
// Versions: all
|
||||
CriticalSectionTimeout: LARGE_INTEGER,
|
||||
|
||||
// End of Original PEB size
|
||||
|
||||
// Fields appended in 3.51:
|
||||
HeapSegmentReserve: ULONG_PTR,
|
||||
HeapSegmentCommit: ULONG_PTR,
|
||||
HeapDeCommitTotalFreeThreshold: ULONG_PTR,
|
||||
HeapDeCommitFreeBlockThreshold: ULONG_PTR,
|
||||
NumberOfHeaps: ULONG,
|
||||
MaximumNumberOfHeaps: ULONG,
|
||||
ProcessHeaps: *PVOID,
|
||||
|
||||
// Fields appended in 4.0:
|
||||
GdiSharedHandleTable: PVOID,
|
||||
ProcessStarterHelper: PVOID,
|
||||
GdiDCAttributeList: ULONG,
|
||||
// note: there is padding here on 64 bit
|
||||
LoaderLock: *RTL_CRITICAL_SECTION,
|
||||
OSMajorVersion: ULONG,
|
||||
OSMinorVersion: ULONG,
|
||||
OSBuildNumber: USHORT,
|
||||
OSCSDVersion: USHORT,
|
||||
OSPlatformId: ULONG,
|
||||
ImageSubSystem: ULONG,
|
||||
ImageSubSystemMajorVersion: ULONG,
|
||||
ImageSubSystemMinorVersion: ULONG,
|
||||
// note: there is padding here on 64 bit
|
||||
ActiveProcessAffinityMask: KAFFINITY,
|
||||
GdiHandleBuffer: [switch (@sizeOf(usize)) {
|
||||
4 => 0x22,
|
||||
8 => 0x3C,
|
||||
else => unreachable,
|
||||
}]ULONG,
|
||||
|
||||
// Fields appended in 5.0 (Windows 2000):
|
||||
PostProcessInitRoutine: PVOID,
|
||||
TlsExpansionBitmap: PRTL_BITMAP,
|
||||
TlsExpansionBitmapBits: [32]ULONG,
|
||||
SessionId: ULONG,
|
||||
// note: there is padding here on 64 bit
|
||||
// Versions: 5.1+
|
||||
AppCompatFlags: ULARGE_INTEGER,
|
||||
AppCompatFlagsUser: ULARGE_INTEGER,
|
||||
ShimData: PVOID,
|
||||
// Versions: 5.0+
|
||||
AppCompatInfo: PVOID,
|
||||
CSDVersion: UNICODE_STRING,
|
||||
|
||||
// Fields appended in 5.1 (Windows XP):
|
||||
ActivationContextData: *const ACTIVATION_CONTEXT_DATA,
|
||||
ProcessAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
|
||||
SystemDefaultActivationData: *const ACTIVATION_CONTEXT_DATA,
|
||||
SystemAssemblyStorageMap: *ASSEMBLY_STORAGE_MAP,
|
||||
MinimumStackCommit: ULONG_PTR,
|
||||
|
||||
// Fields appended in 5.2 (Windows Server 2003):
|
||||
FlsCallback: *FLS_CALLBACK_INFO,
|
||||
FlsListHead: LIST_ENTRY,
|
||||
FlsBitmap: PRTL_BITMAP,
|
||||
FlsBitmapBits: [4]ULONG,
|
||||
FlsHighIndex: ULONG,
|
||||
|
||||
// Fields appended in 6.0 (Windows Vista):
|
||||
WerRegistrationData: PVOID,
|
||||
WerShipAssertPtr: PVOID,
|
||||
|
||||
// Fields appended in 6.1 (Windows 7):
|
||||
pUnused: PVOID, // previously pContextData
|
||||
pImageHeaderHash: PVOID,
|
||||
|
||||
/// TODO: https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb/tracingflags.htm
|
||||
TracingFlags: ULONG,
|
||||
|
||||
// Fields appended in 6.2 (Windows 8):
|
||||
CsrServerReadOnlySharedMemoryBase: ULONGLONG,
|
||||
|
||||
// Fields appended in 1511:
|
||||
TppWorkerpListLock: ULONG,
|
||||
TppWorkerpList: LIST_ENTRY,
|
||||
WaitOnAddressHashTable: [0x80]PVOID,
|
||||
|
||||
// Fields appended in 1709:
|
||||
TelemetryCoverageHeader: PVOID,
|
||||
CloudFileFlags: ULONG,
|
||||
};
|
||||
|
||||
/// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.
|
||||
/// It is essentially the head of three double-linked lists of `LDR_DATA_TABLE_ENTRY` structures which each represent one loaded module.
|
||||
///
|
||||
/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
|
||||
/// - https://www.geoffchappell.com/studies/windows/win32/ntdll/structs/peb_ldr_data.htm
|
||||
pub const PEB_LDR_DATA = extern struct {
|
||||
Reserved1: [8]BYTE,
|
||||
Reserved2: [3]PVOID,
|
||||
// Versions: 3.51 and higher
|
||||
/// The size in bytes of the structure
|
||||
Length: ULONG,
|
||||
|
||||
/// TRUE if the structure is prepared.
|
||||
Initialized: BOOLEAN,
|
||||
|
||||
SsHandle: PVOID,
|
||||
InLoadOrderModuleList: LIST_ENTRY,
|
||||
InMemoryOrderModuleList: LIST_ENTRY,
|
||||
InInitializationOrderModuleList: LIST_ENTRY,
|
||||
|
||||
// Versions: 5.1 and higher
|
||||
|
||||
/// No known use of this field is known in Windows 8 and higher.
|
||||
EntryInProgress: PVOID,
|
||||
|
||||
// Versions: 6.0 from Windows Vista SP1, and higher
|
||||
ShutdownInProgress: BOOLEAN,
|
||||
|
||||
/// Though ShutdownThreadId is declared as a HANDLE,
|
||||
/// it is indeed the thread ID as suggested by its name.
|
||||
/// It is picked up from the UniqueThread member of the CLIENT_ID in the
|
||||
/// TEB of the thread that asks to terminate the process.
|
||||
ShutdownThreadId: HANDLE,
|
||||
};
|
||||
|
||||
pub const RTL_USER_PROCESS_PARAMETERS = extern struct {
|
||||
@ -1321,3 +1493,16 @@ pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct {
|
||||
Flags: ULONG_PTR,
|
||||
};
|
||||
pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX;
|
||||
|
||||
pub const OSVERSIONINFOW = extern struct {
|
||||
dwOSVersionInfoSize: ULONG,
|
||||
dwMajorVersion: ULONG,
|
||||
dwMinorVersion: ULONG,
|
||||
dwBuildNumber: ULONG,
|
||||
dwPlatformId: ULONG,
|
||||
szCSDVersion: [128]WCHAR,
|
||||
};
|
||||
pub const POSVERSIONINFOW = *OSVERSIONINFOW;
|
||||
pub const LPOSVERSIONINFOW = *OSVERSIONINFOW;
|
||||
pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW;
|
||||
pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW;
|
||||
|
@ -1,6 +1,14 @@
|
||||
usingnamespace @import("bits.zig");
|
||||
|
||||
pub extern "NtDll" fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) callconv(.Stdcall) WORD;
|
||||
pub extern "NtDll" fn RtlGetVersion(
|
||||
lpVersionInformation: PRTL_OSVERSIONINFOW,
|
||||
) callconv(.Stdcall) NTSTATUS;
|
||||
pub extern "NtDll" fn RtlCaptureStackBackTrace(
|
||||
FramesToSkip: DWORD,
|
||||
FramesToCapture: DWORD,
|
||||
BackTrace: **c_void,
|
||||
BackTraceHash: ?*DWORD,
|
||||
) callconv(.Stdcall) WORD;
|
||||
pub extern "NtDll" fn NtQueryInformationFile(
|
||||
FileHandle: HANDLE,
|
||||
IoStatusBlock: *IO_STATUS_BLOCK,
|
||||
|
@ -593,7 +593,7 @@ test "PackedInt(Array/Slice)Endian" {
|
||||
// after this one is not mapped and will cause a segfault if we
|
||||
// don't account for the bounds.
|
||||
test "PackedIntArray at end of available memory" {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
|
||||
else => return,
|
||||
}
|
||||
@ -612,7 +612,7 @@ test "PackedIntArray at end of available memory" {
|
||||
}
|
||||
|
||||
test "PackedIntSlice at end of available memory" {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
|
||||
else => return,
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
|
||||
var result = BufMap.init(allocator);
|
||||
errdefer result.deinit();
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const ptr = os.windows.peb().ProcessParameters.Environment;
|
||||
|
||||
var i: usize = 0;
|
||||
@ -61,7 +61,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
|
||||
try result.setMove(key, value);
|
||||
}
|
||||
return result;
|
||||
} else if (builtin.os == .wasi) {
|
||||
} else if (builtin.os.tag == .wasi) {
|
||||
var environ_count: usize = undefined;
|
||||
var environ_buf_size: usize = undefined;
|
||||
|
||||
@ -137,7 +137,7 @@ pub const GetEnvVarOwnedError = error{
|
||||
|
||||
/// Caller must free returned memory.
|
||||
pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const result_w = blk: {
|
||||
const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
|
||||
defer allocator.free(key_w);
|
||||
@ -338,12 +338,12 @@ pub const ArgIteratorWindows = struct {
|
||||
};
|
||||
|
||||
pub const ArgIterator = struct {
|
||||
const InnerType = if (builtin.os == .windows) ArgIteratorWindows else ArgIteratorPosix;
|
||||
const InnerType = if (builtin.os.tag == .windows) ArgIteratorWindows else ArgIteratorPosix;
|
||||
|
||||
inner: InnerType,
|
||||
|
||||
pub fn init() ArgIterator {
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
// TODO: Figure out a compatible interface accomodating WASI
|
||||
@compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
|
||||
}
|
||||
@ -355,7 +355,7 @@ pub const ArgIterator = struct {
|
||||
|
||||
/// You must free the returned memory when done.
|
||||
pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
return self.inner.next(allocator);
|
||||
} else {
|
||||
return mem.dupe(allocator, u8, self.inner.next() orelse return null);
|
||||
@ -380,7 +380,7 @@ pub fn args() ArgIterator {
|
||||
|
||||
/// Caller must call argsFree on result.
|
||||
pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
var count: usize = undefined;
|
||||
var buf_size: usize = undefined;
|
||||
|
||||
@ -445,7 +445,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 {
|
||||
}
|
||||
|
||||
pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
|
||||
if (builtin.os == .wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
const last_item = args_alloc[args_alloc.len - 1];
|
||||
const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
|
||||
const first_item_ptr = args_alloc[0].ptr;
|
||||
@ -498,7 +498,7 @@ pub const UserInfo = struct {
|
||||
|
||||
/// POSIX function which gets a uid from username.
|
||||
pub fn getUserInfo(name: []const u8) !UserInfo {
|
||||
return switch (builtin.os) {
|
||||
return switch (builtin.os.tag) {
|
||||
.linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
@ -591,7 +591,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
|
||||
}
|
||||
|
||||
pub fn getBaseAddress() usize {
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux => {
|
||||
const base = os.system.getauxval(std.elf.AT_BASE);
|
||||
if (base != 0) {
|
||||
@ -609,13 +609,17 @@ pub fn getBaseAddress() usize {
|
||||
}
|
||||
|
||||
/// Caller owns the result value and each inner slice.
|
||||
/// TODO Remove the `Allocator` requirement from this API, which will remove the `Allocator`
|
||||
/// requirement from `std.zig.system.NativeTargetInfo.detect`. Most likely this will require
|
||||
/// introducing a new, lower-level function which takes a callback function, and then this
|
||||
/// function which takes an allocator can exist on top of it.
|
||||
pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
|
||||
switch (builtin.link_mode) {
|
||||
.Static => return &[_][:0]u8{},
|
||||
.Dynamic => {},
|
||||
}
|
||||
const List = std.ArrayList([:0]u8);
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.linux,
|
||||
.freebsd,
|
||||
.netbsd,
|
||||
|
@ -16,7 +16,7 @@ pub const ResetEvent = struct {
|
||||
|
||||
pub const OsEvent = if (builtin.single_threaded)
|
||||
DebugEvent
|
||||
else if (builtin.link_libc and builtin.os != .windows and builtin.os != .linux)
|
||||
else if (builtin.link_libc and builtin.os.tag != .windows and builtin.os.tag != .linux)
|
||||
PosixEvent
|
||||
else
|
||||
AtomicEvent;
|
||||
@ -106,7 +106,7 @@ const PosixEvent = struct {
|
||||
fn deinit(self: *PosixEvent) void {
|
||||
// on dragonfly, *destroy() functions can return EINVAL
|
||||
// for statically initialized pthread structures
|
||||
const err = if (builtin.os == .dragonfly) os.EINVAL else 0;
|
||||
const err = if (builtin.os.tag == .dragonfly) os.EINVAL else 0;
|
||||
|
||||
const retm = c.pthread_mutex_destroy(&self.mutex);
|
||||
assert(retm == 0 or retm == err);
|
||||
@ -215,7 +215,7 @@ const AtomicEvent = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub const Futex = switch (builtin.os) {
|
||||
pub const Futex = switch (builtin.os.tag) {
|
||||
.windows => WindowsFutex,
|
||||
.linux => LinuxFutex,
|
||||
else => SpinFutex,
|
||||
|
@ -17,7 +17,7 @@ const is_msvc = switch (builtin.abi) {
|
||||
.msvc => true,
|
||||
else => false,
|
||||
};
|
||||
const is_freestanding = switch (builtin.os) {
|
||||
const is_freestanding = switch (builtin.os.tag) {
|
||||
.freestanding => true,
|
||||
else => false,
|
||||
};
|
||||
@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
|
||||
}
|
||||
|
||||
fn strlen(s: [*:0]const u8) callconv(.C) usize {
|
||||
return std.mem.len(u8, s);
|
||||
return std.mem.len(s);
|
||||
}
|
||||
|
||||
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
|
||||
@setCold(true);
|
||||
std.debug.panic("{}", .{msg});
|
||||
}
|
||||
if (builtin.os != .freestanding and builtin.os != .other) {
|
||||
if (builtin.os.tag != .freestanding and builtin.os.tag != .other) {
|
||||
std.os.abort();
|
||||
}
|
||||
while (true) {}
|
||||
@ -178,11 +178,11 @@ test "test_bcmp" {
|
||||
comptime {
|
||||
if (builtin.mode != builtin.Mode.ReleaseFast and
|
||||
builtin.mode != builtin.Mode.ReleaseSmall and
|
||||
builtin.os != builtin.Os.windows)
|
||||
builtin.os.tag != .windows)
|
||||
{
|
||||
@export(__stack_chk_fail, .{ .name = "__stack_chk_fail" });
|
||||
}
|
||||
if (builtin.os == builtin.Os.linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
@export(clone, .{ .name = "clone" });
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const builtin = std.builtin;
|
||||
const is_test = builtin.is_test;
|
||||
|
||||
const is_gnu = switch (builtin.abi) {
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => true,
|
||||
else => false,
|
||||
};
|
||||
const is_mingw = builtin.os == .windows and is_gnu;
|
||||
const is_gnu = std.Target.current.abi.isGnu();
|
||||
const is_mingw = builtin.os.tag == .windows and is_gnu;
|
||||
|
||||
comptime {
|
||||
const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak;
|
||||
@ -180,7 +178,7 @@ comptime {
|
||||
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
|
||||
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
|
||||
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
@export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
|
||||
}
|
||||
|
||||
@ -250,7 +248,7 @@ comptime {
|
||||
@export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
|
||||
}
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// Default stack-probe functions emitted by LLVM
|
||||
if (is_mingw) {
|
||||
@export(@import("compiler_rt/stack_probe.zig")._chkstk, .{ .name = "_alloca", .linkage = strong_linkage });
|
||||
@ -288,7 +286,7 @@ comptime {
|
||||
else => {},
|
||||
}
|
||||
} else {
|
||||
if (builtin.glibc_version != null) {
|
||||
if (std.Target.current.isGnuLibC() and builtin.link_libc) {
|
||||
@export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });
|
||||
}
|
||||
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
|
||||
@ -307,7 +305,7 @@ comptime {
|
||||
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
|
||||
@setCold(true);
|
||||
if (is_test) {
|
||||
@import("std").debug.panic("{}", .{msg});
|
||||
std.debug.panic("{}", .{msg});
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ const twords = extern union {
|
||||
all: i128,
|
||||
s: S,
|
||||
|
||||
const S = if (builtin.endian == builtin.Endian.Little)
|
||||
const S = if (builtin.endian == .Little)
|
||||
struct {
|
||||
low: u64,
|
||||
high: u64,
|
||||
|
@ -25,7 +25,7 @@ const twords = extern union {
|
||||
all: i128,
|
||||
s: S,
|
||||
|
||||
const S = if (builtin.endian == builtin.Endian.Little)
|
||||
const S = if (builtin.endian == .Little)
|
||||
struct {
|
||||
low: i64,
|
||||
high: i64,
|
||||
|
@ -90,7 +90,7 @@ test "extendhfsf2" {
|
||||
test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
|
||||
// On x86 the NaN becomes quiet because the return is pushed on the x87
|
||||
// stack due to ABI requirements
|
||||
if (builtin.arch != .i386 and builtin.os == .windows)
|
||||
if (builtin.arch != .i386 and builtin.os.tag == .windows)
|
||||
test__extendhfsf2(0x7c01, 0x7f802000); // sNaN
|
||||
|
||||
test__extendhfsf2(0, 0); // 0
|
||||
|
@ -24,7 +24,7 @@ const twords = extern union {
|
||||
all: i128,
|
||||
s: S,
|
||||
|
||||
const S = if (builtin.endian == builtin.Endian.Little)
|
||||
const S = if (builtin.endian == .Little)
|
||||
struct {
|
||||
low: u64,
|
||||
high: u64,
|
||||
|
@ -45,7 +45,7 @@ const twords = extern union {
|
||||
all: i128,
|
||||
s: S,
|
||||
|
||||
const S = if (builtin.endian == builtin.Endian.Little)
|
||||
const S = if (builtin.endian == .Little)
|
||||
struct {
|
||||
low: u64,
|
||||
high: u64,
|
||||
|
@ -1,23 +1,23 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn __truncsfhf2(a: f32) callconv(.C) u16 {
|
||||
return @bitCast(u16, truncXfYf2(f16, f32, a));
|
||||
return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f32, a }));
|
||||
}
|
||||
|
||||
pub fn __truncdfhf2(a: f64) callconv(.C) u16 {
|
||||
return @bitCast(u16, truncXfYf2(f16, f64, a));
|
||||
return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
|
||||
}
|
||||
|
||||
pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
|
||||
return truncXfYf2(f32, f128, a);
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a });
|
||||
}
|
||||
|
||||
pub fn __trunctfdf2(a: f128) callconv(.C) f64 {
|
||||
return truncXfYf2(f64, f128, a);
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f64, f128, a });
|
||||
}
|
||||
|
||||
pub fn __truncdfsf2(a: f64) callconv(.C) f32 {
|
||||
return truncXfYf2(f32, f64, a);
|
||||
return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f64, a });
|
||||
}
|
||||
|
||||
pub fn __aeabi_d2f(a: f64) callconv(.AAPCS) f32 {
|
||||
@ -35,7 +35,7 @@ pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 {
|
||||
return @call(.{ .modifier = .always_inline }, __truncsfhf2, .{a});
|
||||
}
|
||||
|
||||
inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
|
||||
fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
|
||||
const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits);
|
||||
const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits);
|
||||
const srcSigBits = std.math.floatMantissaBits(src_t);
|
||||
|
@ -2,8 +2,8 @@ const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
|
||||
const low = switch (builtin.endian) {
|
||||
builtin.Endian.Big => 1,
|
||||
builtin.Endian.Little => 0,
|
||||
.Big => 1,
|
||||
.Little => 0,
|
||||
};
|
||||
const high = 1 - low;
|
||||
|
||||
|
@ -1,8 +1,18 @@
|
||||
const Builder = @import("std").build.Builder;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const exe = b.addExecutable("$", "src/main.zig");
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
std.debug.warn("All your base are belong to us.\n", .{});
|
||||
std.debug.warn("All your codebase are belong to us.\n", .{});
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ pub const SpinLock = struct {
|
||||
// and yielding for 380-410 iterations was found to be
|
||||
// a nice sweet spot. Posix systems on the other hand,
|
||||
// especially linux, perform better by yielding the thread.
|
||||
switch (builtin.os) {
|
||||
switch (builtin.os.tag) {
|
||||
.windows => loopHint(400),
|
||||
else => std.os.sched_yield() catch loopHint(1),
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
|
||||
|
||||
comptime {
|
||||
if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
|
||||
if (builtin.os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
|
||||
if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
|
||||
@export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
|
||||
}
|
||||
} else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
|
||||
@ -20,17 +20,17 @@ comptime {
|
||||
if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
|
||||
@export(main, .{ .name = "main", .linkage = .Weak });
|
||||
}
|
||||
} else if (builtin.os == .windows) {
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
|
||||
!@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
|
||||
{
|
||||
@export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" });
|
||||
}
|
||||
} else if (builtin.os == .uefi) {
|
||||
} else if (builtin.os.tag == .uefi) {
|
||||
if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
|
||||
} else if (builtin.arch.isWasm() and builtin.os == .freestanding) {
|
||||
} else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
|
||||
if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
|
||||
} else if (builtin.os != .other and builtin.os != .freestanding) {
|
||||
} else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
|
||||
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
|
||||
}
|
||||
}
|
||||
@ -78,7 +78,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
|
||||
}
|
||||
|
||||
fn _start() callconv(.Naked) noreturn {
|
||||
if (builtin.os == builtin.Os.wasi) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
// This is marked inline because for some reason LLVM in release mode fails to inline it,
|
||||
// and we want fewer call frames in stack traces.
|
||||
std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{}));
|
||||
@ -133,7 +133,7 @@ fn WinMainCRTStartup() callconv(.Stdcall) noreturn {
|
||||
|
||||
// TODO https://github.com/ziglang/zig/issues/265
|
||||
fn posixCallMainAndExit() noreturn {
|
||||
if (builtin.os == builtin.Os.freebsd) {
|
||||
if (builtin.os.tag == .freebsd) {
|
||||
@setAlignStack(16);
|
||||
}
|
||||
const argc = starting_stack_ptr[0];
|
||||
@ -144,7 +144,7 @@ fn posixCallMainAndExit() noreturn {
|
||||
while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
|
||||
const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count];
|
||||
|
||||
if (builtin.os == .linux) {
|
||||
if (builtin.os.tag == .linux) {
|
||||
// Find the beginning of the auxiliary vector
|
||||
const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
|
||||
std.os.linux.elf_aux_maybe = auxv;
|
||||
|
1225
lib/std/target.zig
1225
lib/std/target.zig
File diff suppressed because it is too large
Load Diff
@ -1510,7 +1510,7 @@ pub const cpu = struct {
|
||||
.name = "baseline",
|
||||
.llvm_name = "generic",
|
||||
.features = featureSet(&[_]Feature{
|
||||
.v6m,
|
||||
.v7a,
|
||||
}),
|
||||
};
|
||||
pub const cortex_a12 = CpuModel{
|
||||
|
@ -1,5 +1,3 @@
|
||||
const builtin = @import("builtin");
|
||||
const TypeId = builtin.TypeId;
|
||||
const std = @import("std.zig");
|
||||
|
||||
pub const LeakCountAllocator = @import("testing/leak_count_allocator.zig").LeakCountAllocator;
|
||||
@ -65,16 +63,12 @@ pub fn expectEqual(expected: var, actual: @TypeOf(expected)) void {
|
||||
|
||||
.Pointer => |pointer| {
|
||||
switch (pointer.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One,
|
||||
builtin.TypeInfo.Pointer.Size.Many,
|
||||
builtin.TypeInfo.Pointer.Size.C,
|
||||
=> {
|
||||
.One, .Many, .C => {
|
||||
if (actual != expected) {
|
||||
std.debug.panic("expected {*}, found {*}", .{ expected, actual });
|
||||
}
|
||||
},
|
||||
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
.Slice => {
|
||||
if (actual.ptr != expected.ptr) {
|
||||
std.debug.panic("expected slice ptr {}, found {}", .{ expected.ptr, actual.ptr });
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std.zig");
|
||||
const builtin = std.builtin;
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const windows = std.os.windows;
|
||||
@ -9,14 +9,14 @@ const assert = std.debug.assert;
|
||||
pub const Thread = struct {
|
||||
data: Data,
|
||||
|
||||
pub const use_pthreads = builtin.os != .windows and builtin.link_libc;
|
||||
pub const use_pthreads = std.Target.current.os.tag != .windows and builtin.link_libc;
|
||||
|
||||
/// Represents a kernel thread handle.
|
||||
/// May be an integer or a pointer depending on the platform.
|
||||
/// On Linux and POSIX, this is the same as Id.
|
||||
pub const Handle = if (use_pthreads)
|
||||
c.pthread_t
|
||||
else switch (builtin.os) {
|
||||
else switch (std.Target.current.os.tag) {
|
||||
.linux => i32,
|
||||
.windows => windows.HANDLE,
|
||||
else => void,
|
||||
@ -25,7 +25,7 @@ pub const Thread = struct {
|
||||
/// Represents a unique ID per thread.
|
||||
/// May be an integer or pointer depending on the platform.
|
||||
/// On Linux and POSIX, this is the same as Handle.
|
||||
pub const Id = switch (builtin.os) {
|
||||
pub const Id = switch (std.Target.current.os.tag) {
|
||||
.windows => windows.DWORD,
|
||||
else => Handle,
|
||||
};
|
||||
@ -35,7 +35,7 @@ pub const Thread = struct {
|
||||
handle: Thread.Handle,
|
||||
memory: []align(mem.page_size) u8,
|
||||
}
|
||||
else switch (builtin.os) {
|
||||
else switch (std.Target.current.os.tag) {
|
||||
.linux => struct {
|
||||
handle: Thread.Handle,
|
||||
memory: []align(mem.page_size) u8,
|
||||
@ -55,7 +55,7 @@ pub const Thread = struct {
|
||||
if (use_pthreads) {
|
||||
return c.pthread_self();
|
||||
} else
|
||||
return switch (builtin.os) {
|
||||
return switch (std.Target.current.os.tag) {
|
||||
.linux => os.linux.gettid(),
|
||||
.windows => windows.kernel32.GetCurrentThreadId(),
|
||||
else => @compileError("Unsupported OS"),
|
||||
@ -83,7 +83,7 @@ pub const Thread = struct {
|
||||
else => unreachable,
|
||||
}
|
||||
os.munmap(self.data.memory);
|
||||
} else switch (builtin.os) {
|
||||
} else switch (std.Target.current.os.tag) {
|
||||
.linux => {
|
||||
while (true) {
|
||||
const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
|
||||
@ -150,7 +150,7 @@ pub const Thread = struct {
|
||||
const Context = @TypeOf(context);
|
||||
comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
|
||||
|
||||
if (builtin.os == builtin.Os.windows) {
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
const WinThread = struct {
|
||||
const OuterContext = struct {
|
||||
thread: Thread,
|
||||
@ -309,16 +309,16 @@ pub const Thread = struct {
|
||||
os.EINVAL => unreachable,
|
||||
else => return os.unexpectedErrno(@intCast(usize, err)),
|
||||
}
|
||||
} else if (builtin.os == .linux) {
|
||||
} else if (std.Target.current.os.tag == .linux) {
|
||||
var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |
|
||||
os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
|
||||
os.CLONE_DETACHED;
|
||||
var newtls: usize = undefined;
|
||||
// This structure is only needed when targeting i386
|
||||
var user_desc: if (builtin.arch == .i386) os.linux.user_desc else void = undefined;
|
||||
var user_desc: if (std.Target.current.cpu.arch == .i386) os.linux.user_desc else void = undefined;
|
||||
|
||||
if (os.linux.tls.tls_image) |tls_img| {
|
||||
if (builtin.arch == .i386) {
|
||||
if (std.Target.current.cpu.arch == .i386) {
|
||||
user_desc = os.linux.user_desc{
|
||||
.entry_number = tls_img.gdt_entry_number,
|
||||
.base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset),
|
||||
@ -362,27 +362,24 @@ pub const Thread = struct {
|
||||
}
|
||||
|
||||
pub const CpuCountError = error{
|
||||
OutOfMemory,
|
||||
PermissionDenied,
|
||||
SystemResources,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
pub fn cpuCount() CpuCountError!usize {
|
||||
if (builtin.os == .linux) {
|
||||
if (std.Target.current.os.tag == .linux) {
|
||||
const cpu_set = try os.sched_getaffinity(0);
|
||||
return @as(usize, os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast
|
||||
}
|
||||
if (builtin.os == .windows) {
|
||||
var system_info: windows.SYSTEM_INFO = undefined;
|
||||
windows.kernel32.GetSystemInfo(&system_info);
|
||||
return @intCast(usize, system_info.dwNumberOfProcessors);
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
return os.windows.peb().NumberOfProcessors;
|
||||
}
|
||||
var count: c_int = undefined;
|
||||
var count_len: usize = @sizeOf(c_int);
|
||||
const name = if (comptime std.Target.current.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
|
||||
os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
error.NameTooLong, error.UnknownName => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
return @intCast(usize, count);
|
||||
|
@ -1,5 +1,5 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std.zig");
|
||||
const builtin = std.builtin;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const os = std.os;
|
||||
@ -7,10 +7,12 @@ const math = std.math;
|
||||
|
||||
pub const epoch = @import("time/epoch.zig");
|
||||
|
||||
const is_windows = std.Target.current.os.tag == .windows;
|
||||
|
||||
/// Spurious wakeups are possible and no precision of timing is guaranteed.
|
||||
/// TODO integrate with evented I/O
|
||||
pub fn sleep(nanoseconds: u64) void {
|
||||
if (builtin.os == .windows) {
|
||||
if (is_windows) {
|
||||
const ns_per_ms = ns_per_s / ms_per_s;
|
||||
const big_ms_from_ns = nanoseconds / ns_per_ms;
|
||||
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 {
|
||||
/// Get the posix timestamp, UTC, in milliseconds
|
||||
/// TODO audit this function. is it possible to return an error?
|
||||
pub fn milliTimestamp() u64 {
|
||||
if (builtin.os == .windows) {
|
||||
if (is_windows) {
|
||||
//FileTime has a granularity of 100 nanoseconds
|
||||
// and uses the NTFS/Windows epoch
|
||||
var ft: os.windows.FILETIME = undefined;
|
||||
@ -42,7 +44,7 @@ pub fn milliTimestamp() u64 {
|
||||
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
return @divFloor(ft64, hns_per_ms) - -epoch_adj;
|
||||
}
|
||||
if (builtin.os == .wasi and !builtin.link_libc) {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
var ns: os.wasi.timestamp_t = undefined;
|
||||
|
||||
// TODO: Verify that precision is ignored
|
||||
@ -102,7 +104,7 @@ pub const Timer = struct {
|
||||
///if we used resolution's value when performing the
|
||||
/// performance counter calc on windows/darwin, it would
|
||||
/// be less precise
|
||||
frequency: switch (builtin.os) {
|
||||
frequency: switch (builtin.os.tag) {
|
||||
.windows => u64,
|
||||
.macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,
|
||||
else => void,
|
||||
@ -127,7 +129,7 @@ pub const Timer = struct {
|
||||
pub fn start() Error!Timer {
|
||||
var self: Timer = undefined;
|
||||
|
||||
if (builtin.os == .windows) {
|
||||
if (is_windows) {
|
||||
self.frequency = os.windows.QueryPerformanceFrequency();
|
||||
self.resolution = @divFloor(ns_per_s, self.frequency);
|
||||
self.start_time = os.windows.QueryPerformanceCounter();
|
||||
@ -172,7 +174,7 @@ pub const Timer = struct {
|
||||
}
|
||||
|
||||
fn clockNative() u64 {
|
||||
if (builtin.os == .windows) {
|
||||
if (is_windows) {
|
||||
return os.windows.QueryPerformanceCounter();
|
||||
}
|
||||
if (comptime std.Target.current.isDarwin()) {
|
||||
@ -184,7 +186,7 @@ pub const Timer = struct {
|
||||
}
|
||||
|
||||
fn nativeDurationToNanos(self: Timer, duration: u64) u64 {
|
||||
if (builtin.os == .windows) {
|
||||
if (is_windows) {
|
||||
return @divFloor(duration * ns_per_s, self.frequency);
|
||||
}
|
||||
if (comptime std.Target.current.isDarwin()) {
|
||||
|
@ -8,7 +8,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:
|
||||
}
|
||||
|
||||
switch (builtin.arch) {
|
||||
builtin.Arch.i386 => {
|
||||
.i386 => {
|
||||
return asm volatile (
|
||||
\\ roll $3, %%edi ; roll $13, %%edi
|
||||
\\ roll $29, %%edi ; roll $19, %%edi
|
||||
@ -19,7 +19,7 @@ pub fn doClientRequest(default: usize, request: usize, a1: usize, a2: usize, a3:
|
||||
: "cc", "memory"
|
||||
);
|
||||
},
|
||||
builtin.Arch.x86_64 => {
|
||||
.x86_64 => {
|
||||
return asm volatile (
|
||||
\\ rolq $3, %%rdi ; rolq $13, %%rdi
|
||||
\\ rolq $61, %%rdi ; rolq $51, %%rdi
|
||||
|
@ -6,11 +6,8 @@ pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStri
|
||||
pub const render = @import("zig/render.zig").render;
|
||||
pub const ast = @import("zig/ast.zig");
|
||||
pub const system = @import("zig/system.zig");
|
||||
pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
|
||||
|
||||
test "std.zig tests" {
|
||||
_ = @import("zig/ast.zig");
|
||||
_ = @import("zig/parse.zig");
|
||||
_ = @import("zig/render.zig");
|
||||
_ = @import("zig/tokenizer.zig");
|
||||
_ = @import("zig/parse_string_literal.zig");
|
||||
test "" {
|
||||
@import("std").meta.refAllDecls(@This());
|
||||
}
|
||||
|
839
lib/std/zig/cross_target.zig
Normal file
839
lib/std/zig/cross_target.zig
Normal file
@ -0,0 +1,839 @@
|
||||
const std = @import("../std.zig");
|
||||
const assert = std.debug.assert;
|
||||
const Target = std.Target;
|
||||
const mem = std.mem;
|
||||
|
||||
/// Contains all the same data as `Target`, additionally introducing the concept of "the native target".
|
||||
/// The purpose of this abstraction is to provide meaningful and unsurprising defaults.
|
||||
/// This struct does reference any resources and it is copyable.
|
||||
pub const CrossTarget = struct {
|
||||
/// `null` means native.
|
||||
cpu_arch: ?Target.Cpu.Arch = null,
|
||||
|
||||
cpu_model: CpuModel = CpuModel.determined_by_cpu_arch,
|
||||
|
||||
/// Sparse set of CPU features to add to the set from `cpu_model`.
|
||||
cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
|
||||
|
||||
/// Sparse set of CPU features to remove from the set from `cpu_model`.
|
||||
cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
|
||||
|
||||
/// `null` means native.
|
||||
os_tag: ?Target.Os.Tag = null,
|
||||
|
||||
/// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native)
|
||||
/// then `null` for this field means native.
|
||||
os_version_min: ?OsVersion = null,
|
||||
|
||||
/// When cross compiling, `null` means default (latest known OS version).
|
||||
/// When `os_tag` is native, `null` means equal to the native OS version.
|
||||
os_version_max: ?OsVersion = null,
|
||||
|
||||
/// `null` means default when cross compiling, or native when os_tag is native.
|
||||
/// If `isGnuLibC()` is `false`, this must be `null` and is ignored.
|
||||
glibc_version: ?SemVer = null,
|
||||
|
||||
/// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
|
||||
abi: ?Target.Abi = null,
|
||||
|
||||
/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
|
||||
/// based on the `os_tag`.
|
||||
dynamic_linker: DynamicLinker = DynamicLinker{},
|
||||
|
||||
pub const CpuModel = union(enum) {
|
||||
/// Always native
|
||||
native,
|
||||
|
||||
/// Always baseline
|
||||
baseline,
|
||||
|
||||
/// If CPU Architecture is native, then the CPU model will be native. Otherwise,
|
||||
/// it will be baseline.
|
||||
determined_by_cpu_arch,
|
||||
|
||||
explicit: *const Target.Cpu.Model,
|
||||
};
|
||||
|
||||
pub const OsVersion = union(enum) {
|
||||
none: void,
|
||||
semver: SemVer,
|
||||
windows: Target.Os.WindowsVersion,
|
||||
};
|
||||
|
||||
pub const SemVer = std.builtin.Version;
|
||||
|
||||
pub const DynamicLinker = Target.DynamicLinker;
|
||||
|
||||
pub fn fromTarget(target: Target) CrossTarget {
|
||||
var result: CrossTarget = .{
|
||||
.cpu_arch = target.cpu.arch,
|
||||
.cpu_model = .{ .explicit = target.cpu.model },
|
||||
.os_tag = target.os.tag,
|
||||
.os_version_min = undefined,
|
||||
.os_version_max = undefined,
|
||||
.abi = target.abi,
|
||||
.glibc_version = if (target.isGnuLibC())
|
||||
target.os.version_range.linux.glibc
|
||||
else
|
||||
null,
|
||||
};
|
||||
result.updateOsVersionRange(target.os);
|
||||
|
||||
const all_features = target.cpu.arch.allFeaturesList();
|
||||
var cpu_model_set = target.cpu.model.features;
|
||||
cpu_model_set.populateDependencies(all_features);
|
||||
{
|
||||
// The "add" set is the full set with the CPU Model set removed.
|
||||
const add_set = &result.cpu_features_add;
|
||||
add_set.* = target.cpu.features;
|
||||
add_set.removeFeatureSet(cpu_model_set);
|
||||
}
|
||||
{
|
||||
// The "sub" set is the features that are on in CPU Model set and off in the full set.
|
||||
const sub_set = &result.cpu_features_sub;
|
||||
sub_set.* = cpu_model_set;
|
||||
sub_set.removeFeatureSet(target.cpu.features);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void {
|
||||
switch (os.tag) {
|
||||
.freestanding,
|
||||
.ananas,
|
||||
.cloudabi,
|
||||
.dragonfly,
|
||||
.fuchsia,
|
||||
.kfreebsd,
|
||||
.lv2,
|
||||
.solaris,
|
||||
.haiku,
|
||||
.minix,
|
||||
.rtems,
|
||||
.nacl,
|
||||
.cnk,
|
||||
.aix,
|
||||
.cuda,
|
||||
.nvcl,
|
||||
.amdhsa,
|
||||
.ps4,
|
||||
.elfiamcu,
|
||||
.mesa3d,
|
||||
.contiki,
|
||||
.amdpal,
|
||||
.hermit,
|
||||
.hurd,
|
||||
.wasi,
|
||||
.emscripten,
|
||||
.uefi,
|
||||
.other,
|
||||
=> {
|
||||
self.os_version_min = .{ .none = {} };
|
||||
self.os_version_max = .{ .none = {} };
|
||||
},
|
||||
|
||||
.freebsd,
|
||||
.macosx,
|
||||
.ios,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
.tvos,
|
||||
.watchos,
|
||||
=> {
|
||||
self.os_version_min = .{ .semver = os.version_range.semver.min };
|
||||
self.os_version_max = .{ .semver = os.version_range.semver.max };
|
||||
},
|
||||
|
||||
.linux => {
|
||||
self.os_version_min = .{ .semver = os.version_range.linux.range.min };
|
||||
self.os_version_max = .{ .semver = os.version_range.linux.range.max };
|
||||
},
|
||||
|
||||
.windows => {
|
||||
self.os_version_min = .{ .windows = os.version_range.windows.min };
|
||||
self.os_version_max = .{ .windows = os.version_range.windows.max };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn toTarget(self: CrossTarget) Target {
|
||||
return .{
|
||||
.cpu = self.getCpu(),
|
||||
.os = self.getOs(),
|
||||
.abi = self.getAbi(),
|
||||
};
|
||||
}
|
||||
|
||||
pub const ParseOptions = struct {
|
||||
/// This is sometimes called a "triple". It looks roughly like this:
|
||||
/// riscv64-linux-musl
|
||||
/// The fields are, respectively:
|
||||
/// * CPU Architecture
|
||||
/// * Operating System (and optional version range)
|
||||
/// * C ABI (optional, with optional glibc version)
|
||||
/// The string "native" can be used for CPU architecture as well as Operating System.
|
||||
/// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted.
|
||||
arch_os_abi: []const u8 = "native",
|
||||
|
||||
/// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
|
||||
/// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
|
||||
/// to remove from the set.
|
||||
/// The following special strings are recognized for CPU Model name:
|
||||
/// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set
|
||||
/// of features that is expected to be supported on most available hardware.
|
||||
/// * "native" - The native CPU model is to be detected when compiling.
|
||||
/// If this field is not provided (`null`), then the value will depend on the
|
||||
/// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline".
|
||||
cpu_features: ?[]const u8 = null,
|
||||
|
||||
/// Absolute path to dynamic linker, to override the default, which is either a natively
|
||||
/// detected path, or a standard path.
|
||||
dynamic_linker: ?[]const u8 = null,
|
||||
|
||||
/// If this is provided, the function will populate some information about parsing failures,
|
||||
/// so that user-friendly error messages can be delivered.
|
||||
diagnostics: ?*Diagnostics = null,
|
||||
|
||||
pub const Diagnostics = struct {
|
||||
/// If the architecture was determined, this will be populated.
|
||||
arch: ?Target.Cpu.Arch = null,
|
||||
|
||||
/// If the OS name was determined, this will be populated.
|
||||
os_name: ?[]const u8 = null,
|
||||
|
||||
/// If the OS tag was determined, this will be populated.
|
||||
os_tag: ?Target.Os.Tag = null,
|
||||
|
||||
/// If the ABI was determined, this will be populated.
|
||||
abi: ?Target.Abi = null,
|
||||
|
||||
/// If the CPU name was determined, this will be populated.
|
||||
cpu_name: ?[]const u8 = null,
|
||||
|
||||
/// If error.UnknownCpuFeature is returned, this will be populated.
|
||||
unknown_feature_name: ?[]const u8 = null,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn parse(args: ParseOptions) !CrossTarget {
|
||||
var dummy_diags: ParseOptions.Diagnostics = undefined;
|
||||
const diags = args.diagnostics orelse &dummy_diags;
|
||||
|
||||
var result: CrossTarget = .{
|
||||
.dynamic_linker = DynamicLinker.init(args.dynamic_linker),
|
||||
};
|
||||
|
||||
var it = mem.separate(args.arch_os_abi, "-");
|
||||
const arch_name = it.next().?;
|
||||
const arch_is_native = mem.eql(u8, arch_name, "native");
|
||||
if (!arch_is_native) {
|
||||
result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse
|
||||
return error.UnknownArchitecture;
|
||||
}
|
||||
const arch = result.getCpuArch();
|
||||
diags.arch = arch;
|
||||
|
||||
if (it.next()) |os_text| {
|
||||
try parseOs(&result, diags, os_text);
|
||||
} else if (!arch_is_native) {
|
||||
return error.MissingOperatingSystem;
|
||||
}
|
||||
|
||||
const opt_abi_text = it.next();
|
||||
if (opt_abi_text) |abi_text| {
|
||||
var abi_it = mem.separate(abi_text, ".");
|
||||
const abi = std.meta.stringToEnum(Target.Abi, abi_it.next().?) orelse
|
||||
return error.UnknownApplicationBinaryInterface;
|
||||
result.abi = abi;
|
||||
diags.abi = abi;
|
||||
|
||||
const abi_ver_text = abi_it.rest();
|
||||
if (abi_it.next() != null) {
|
||||
if (result.isGnuLibC()) {
|
||||
result.glibc_version = SemVer.parse(abi_ver_text) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidAbiVersion,
|
||||
error.InvalidCharacter => return error.InvalidAbiVersion,
|
||||
error.InvalidVersion => return error.InvalidAbiVersion,
|
||||
};
|
||||
} else {
|
||||
return error.InvalidAbiVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (it.next() != null) return error.UnexpectedExtraField;
|
||||
|
||||
if (args.cpu_features) |cpu_features| {
|
||||
const all_features = arch.allFeaturesList();
|
||||
var index: usize = 0;
|
||||
while (index < cpu_features.len and
|
||||
cpu_features[index] != '+' and
|
||||
cpu_features[index] != '-')
|
||||
{
|
||||
index += 1;
|
||||
}
|
||||
const cpu_name = cpu_features[0..index];
|
||||
diags.cpu_name = cpu_name;
|
||||
|
||||
const add_set = &result.cpu_features_add;
|
||||
const sub_set = &result.cpu_features_sub;
|
||||
if (mem.eql(u8, cpu_name, "native")) {
|
||||
result.cpu_model = .native;
|
||||
} else if (mem.eql(u8, cpu_name, "baseline")) {
|
||||
result.cpu_model = .baseline;
|
||||
} else {
|
||||
result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) };
|
||||
}
|
||||
|
||||
while (index < cpu_features.len) {
|
||||
const op = cpu_features[index];
|
||||
const set = switch (op) {
|
||||
'+' => add_set,
|
||||
'-' => sub_set,
|
||||
else => unreachable,
|
||||
};
|
||||
index += 1;
|
||||
const start = index;
|
||||
while (index < cpu_features.len and
|
||||
cpu_features[index] != '+' and
|
||||
cpu_features[index] != '-')
|
||||
{
|
||||
index += 1;
|
||||
}
|
||||
const feature_name = cpu_features[start..index];
|
||||
for (all_features) |feature, feat_index_usize| {
|
||||
const feat_index = @intCast(Target.Cpu.Feature.Set.Index, feat_index_usize);
|
||||
if (mem.eql(u8, feature_name, feature.name)) {
|
||||
set.addFeature(feat_index);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
diags.unknown_feature_name = feature_name;
|
||||
return error.UnknownCpuFeature;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getCpu(self: CrossTarget) Target.Cpu {
|
||||
switch (self.cpu_model) {
|
||||
.native => {
|
||||
// This works when doing `zig build` because Zig generates a build executable using
|
||||
// native CPU model & features. However this will not be accurate otherwise, and
|
||||
// will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
|
||||
return Target.current.cpu;
|
||||
},
|
||||
.baseline => {
|
||||
var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
|
||||
self.updateCpuFeatures(&adjusted_baseline.features);
|
||||
return adjusted_baseline;
|
||||
},
|
||||
.determined_by_cpu_arch => if (self.cpu_arch == null) {
|
||||
// This works when doing `zig build` because Zig generates a build executable using
|
||||
// native CPU model & features. However this will not be accurate otherwise, and
|
||||
// will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
|
||||
return Target.current.cpu;
|
||||
} else {
|
||||
var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch());
|
||||
self.updateCpuFeatures(&adjusted_baseline.features);
|
||||
return adjusted_baseline;
|
||||
},
|
||||
.explicit => |model| {
|
||||
var adjusted_model = model.toCpu(self.getCpuArch());
|
||||
self.updateCpuFeatures(&adjusted_model.features);
|
||||
return adjusted_model;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getCpuArch(self: CrossTarget) Target.Cpu.Arch {
|
||||
return self.cpu_arch orelse Target.current.cpu.arch;
|
||||
}
|
||||
|
||||
pub fn getCpuModel(self: CrossTarget) *const Target.Cpu.Model {
|
||||
if (self.cpu_model) |cpu_model| return cpu_model;
|
||||
return self.getCpu().model;
|
||||
}
|
||||
|
||||
pub fn getCpuFeatures(self: CrossTarget) Target.Cpu.Feature.Set {
|
||||
return self.getCpu().features;
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getOs(self: CrossTarget) Target.Os {
|
||||
// `Target.current.os` works when doing `zig build` because Zig generates a build executable using
|
||||
// native OS version range. However this will not be accurate otherwise, and
|
||||
// will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
|
||||
var adjusted_os = if (self.os_tag) |os_tag| Target.Os.defaultVersionRange(os_tag) else Target.current.os;
|
||||
|
||||
if (self.os_version_min) |min| switch (min) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (self.getOsTag()) {
|
||||
.linux => adjusted_os.version_range.linux.range.min = semver,
|
||||
else => adjusted_os.version_range.semver.min = semver,
|
||||
},
|
||||
.windows => |win_ver| adjusted_os.version_range.windows.min = win_ver,
|
||||
};
|
||||
|
||||
if (self.os_version_max) |max| switch (max) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (self.getOsTag()) {
|
||||
.linux => adjusted_os.version_range.linux.range.max = semver,
|
||||
else => adjusted_os.version_range.semver.max = semver,
|
||||
},
|
||||
.windows => |win_ver| adjusted_os.version_range.windows.max = win_ver,
|
||||
};
|
||||
|
||||
if (self.glibc_version) |glibc| {
|
||||
assert(self.isGnuLibC());
|
||||
adjusted_os.version_range.linux.glibc = glibc;
|
||||
}
|
||||
|
||||
return adjusted_os;
|
||||
}
|
||||
|
||||
pub fn getOsTag(self: CrossTarget) Target.Os.Tag {
|
||||
return self.os_tag orelse Target.current.os.tag;
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getOsVersionMin(self: CrossTarget) OsVersion {
|
||||
if (self.os_version_min) |version_min| return version_min;
|
||||
var tmp: CrossTarget = undefined;
|
||||
tmp.updateOsVersionRange(self.getOs());
|
||||
return tmp.os_version_min.?;
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getOsVersionMax(self: CrossTarget) OsVersion {
|
||||
if (self.os_version_max) |version_max| return version_max;
|
||||
var tmp: CrossTarget = undefined;
|
||||
tmp.updateOsVersionRange(self.getOs());
|
||||
return tmp.os_version_max.?;
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getAbi(self: CrossTarget) Target.Abi {
|
||||
if (self.abi) |abi| return abi;
|
||||
|
||||
if (self.os_tag == null) {
|
||||
// This works when doing `zig build` because Zig generates a build executable using
|
||||
// native CPU model & features. However this will not be accurate otherwise, and
|
||||
// will need to be integrated with `std.zig.system.NativeTargetInfo.detect`.
|
||||
return Target.current.abi;
|
||||
}
|
||||
|
||||
return Target.Abi.default(self.getCpuArch(), self.getOs());
|
||||
}
|
||||
|
||||
pub fn isFreeBSD(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .freebsd;
|
||||
}
|
||||
|
||||
pub fn isDarwin(self: CrossTarget) bool {
|
||||
return self.getOsTag().isDarwin();
|
||||
}
|
||||
|
||||
pub fn isNetBSD(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .netbsd;
|
||||
}
|
||||
|
||||
pub fn isUefi(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .uefi;
|
||||
}
|
||||
|
||||
pub fn isDragonFlyBSD(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .dragonfly;
|
||||
}
|
||||
|
||||
pub fn isLinux(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .linux;
|
||||
}
|
||||
|
||||
pub fn isWindows(self: CrossTarget) bool {
|
||||
return self.getOsTag() == .windows;
|
||||
}
|
||||
|
||||
pub fn oFileExt(self: CrossTarget) [:0]const u8 {
|
||||
return self.getAbi().oFileExt();
|
||||
}
|
||||
|
||||
pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
|
||||
return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
|
||||
}
|
||||
|
||||
pub fn staticLibSuffix(self: CrossTarget) [:0]const u8 {
|
||||
return Target.staticLibSuffix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
|
||||
}
|
||||
|
||||
pub fn dynamicLibSuffix(self: CrossTarget) [:0]const u8 {
|
||||
return self.getOsTag().dynamicLibSuffix();
|
||||
}
|
||||
|
||||
pub fn libPrefix(self: CrossTarget) [:0]const u8 {
|
||||
return Target.libPrefix_cpu_arch_abi(self.getCpuArch(), self.getAbi());
|
||||
}
|
||||
|
||||
pub fn isNative(self: CrossTarget) bool {
|
||||
return self.cpu_arch == null and
|
||||
(self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and
|
||||
self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty() and
|
||||
self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
|
||||
self.abi == null and self.dynamic_linker.get() == null and self.glibc_version == null;
|
||||
}
|
||||
|
||||
pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![:0]u8 {
|
||||
if (self.isNative()) {
|
||||
return mem.dupeZ(allocator, u8, "native");
|
||||
}
|
||||
|
||||
const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native";
|
||||
const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
|
||||
|
||||
var result = try std.Buffer.allocPrint(allocator, "{}-{}", .{ arch_name, os_name });
|
||||
defer result.deinit();
|
||||
|
||||
// The zig target syntax does not allow specifying a max os version with no min, so
|
||||
// if either are present, we need the min.
|
||||
if (self.os_version_min != null or self.os_version_max != null) {
|
||||
switch (self.getOsVersionMin()) {
|
||||
.none => {},
|
||||
.semver => |v| try result.print(".{}", .{v}),
|
||||
.windows => |v| try result.print(".{}", .{@tagName(v)}),
|
||||
}
|
||||
}
|
||||
if (self.os_version_max) |max| {
|
||||
switch (max) {
|
||||
.none => {},
|
||||
.semver => |v| try result.print("...{}", .{v}),
|
||||
.windows => |v| try result.print("...{}", .{@tagName(v)}),
|
||||
}
|
||||
}
|
||||
|
||||
if (self.glibc_version) |v| {
|
||||
try result.print("-{}.{}", .{ @tagName(self.getAbi()), v });
|
||||
} else if (self.abi) |abi| {
|
||||
try result.print("-{}", .{@tagName(abi)});
|
||||
}
|
||||
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn allocDescription(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
|
||||
// TODO is there anything else worthy of the description that is not
|
||||
// already captured in the triple?
|
||||
return self.zigTriple(allocator);
|
||||
}
|
||||
|
||||
pub fn linuxTriple(self: CrossTarget, allocator: *mem.Allocator) ![:0]u8 {
|
||||
return Target.linuxTripleSimple(allocator, self.getCpuArch(), self.getOsTag(), self.getAbi());
|
||||
}
|
||||
|
||||
pub fn wantSharedLibSymLinks(self: CrossTarget) bool {
|
||||
return self.getOsTag() != .windows;
|
||||
}
|
||||
|
||||
pub const VcpkgLinkage = std.builtin.LinkMode;
|
||||
|
||||
/// Returned slice must be freed by the caller.
|
||||
pub fn vcpkgTriplet(self: CrossTarget, allocator: *mem.Allocator, linkage: VcpkgLinkage) ![:0]u8 {
|
||||
const arch = switch (self.getCpuArch()) {
|
||||
.i386 => "x86",
|
||||
.x86_64 => "x64",
|
||||
|
||||
.arm,
|
||||
.armeb,
|
||||
.thumb,
|
||||
.thumbeb,
|
||||
.aarch64_32,
|
||||
=> "arm",
|
||||
|
||||
.aarch64,
|
||||
.aarch64_be,
|
||||
=> "arm64",
|
||||
|
||||
else => return error.UnsupportedVcpkgArchitecture,
|
||||
};
|
||||
|
||||
const os = switch (self.getOsTag()) {
|
||||
.windows => "windows",
|
||||
.linux => "linux",
|
||||
.macosx => "macos",
|
||||
else => return error.UnsupportedVcpkgOperatingSystem,
|
||||
};
|
||||
|
||||
const static_suffix = switch (linkage) {
|
||||
.Static => "-static",
|
||||
.Dynamic => "",
|
||||
};
|
||||
|
||||
return std.fmt.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
|
||||
}
|
||||
|
||||
pub const Executor = union(enum) {
|
||||
native,
|
||||
qemu: []const u8,
|
||||
wine: []const u8,
|
||||
wasmtime: []const u8,
|
||||
unavailable,
|
||||
};
|
||||
|
||||
/// Note that even a `CrossTarget` which returns `false` for `isNative` could still be natively executed.
|
||||
/// For example `-target arm-native` running on an aarch64 host.
|
||||
pub fn getExternalExecutor(self: CrossTarget) Executor {
|
||||
const cpu_arch = self.getCpuArch();
|
||||
const os_tag = self.getOsTag();
|
||||
const os_match = os_tag == Target.current.os.tag;
|
||||
|
||||
// If the OS and CPU arch match, the binary can be considered native.
|
||||
if (os_match and cpu_arch == Target.current.cpu.arch) {
|
||||
// However, we also need to verify that the dynamic linker path is valid.
|
||||
// TODO Until that is implemented, we prevent returning `.native` when the OS is non-native.
|
||||
if (self.os_tag == null) {
|
||||
return .native;
|
||||
}
|
||||
}
|
||||
|
||||
// If the OS matches, we can use QEMU to emulate a foreign architecture.
|
||||
if (os_match) {
|
||||
return switch (cpu_arch) {
|
||||
.aarch64 => Executor{ .qemu = "qemu-aarch64" },
|
||||
.aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
|
||||
.arm => Executor{ .qemu = "qemu-arm" },
|
||||
.armeb => Executor{ .qemu = "qemu-armeb" },
|
||||
.i386 => Executor{ .qemu = "qemu-i386" },
|
||||
.mips => Executor{ .qemu = "qemu-mips" },
|
||||
.mipsel => Executor{ .qemu = "qemu-mipsel" },
|
||||
.mips64 => Executor{ .qemu = "qemu-mips64" },
|
||||
.mips64el => Executor{ .qemu = "qemu-mips64el" },
|
||||
.powerpc => Executor{ .qemu = "qemu-ppc" },
|
||||
.powerpc64 => Executor{ .qemu = "qemu-ppc64" },
|
||||
.powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
|
||||
.riscv32 => Executor{ .qemu = "qemu-riscv32" },
|
||||
.riscv64 => Executor{ .qemu = "qemu-riscv64" },
|
||||
.s390x => Executor{ .qemu = "qemu-s390x" },
|
||||
.sparc => Executor{ .qemu = "qemu-sparc" },
|
||||
.x86_64 => Executor{ .qemu = "qemu-x86_64" },
|
||||
else => return .unavailable,
|
||||
};
|
||||
}
|
||||
|
||||
switch (os_tag) {
|
||||
.windows => switch (cpu_arch.ptrBitWidth()) {
|
||||
32 => return Executor{ .wine = "wine" },
|
||||
64 => return Executor{ .wine = "wine64" },
|
||||
else => return .unavailable,
|
||||
},
|
||||
.wasi => switch (cpu_arch.ptrBitWidth()) {
|
||||
32 => return Executor{ .wasmtime = "wasmtime" },
|
||||
else => return .unavailable,
|
||||
},
|
||||
else => return .unavailable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isGnuLibC(self: CrossTarget) bool {
|
||||
return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi());
|
||||
}
|
||||
|
||||
pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) void {
|
||||
assert(self.isGnuLibC());
|
||||
self.glibc_version = SemVer{ .major = major, .minor = minor, .patch = patch };
|
||||
}
|
||||
|
||||
pub fn getObjectFormat(self: CrossTarget) ObjectFormat {
|
||||
return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());
|
||||
}
|
||||
|
||||
fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
|
||||
set.removeFeatureSet(self.cpu_features_sub);
|
||||
set.addFeatureSet(self.cpu_features_add);
|
||||
set.populateDependencies(self.getCpuArch().allFeaturesList());
|
||||
set.removeFeatureSet(self.cpu_features_sub);
|
||||
}
|
||||
|
||||
fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
|
||||
var it = mem.separate(text, ".");
|
||||
const os_name = it.next().?;
|
||||
diags.os_name = os_name;
|
||||
const os_is_native = mem.eql(u8, os_name, "native");
|
||||
if (!os_is_native) {
|
||||
result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse
|
||||
return error.UnknownOperatingSystem;
|
||||
}
|
||||
const tag = result.getOsTag();
|
||||
diags.os_tag = tag;
|
||||
|
||||
const version_text = it.rest();
|
||||
if (it.next() == null) return;
|
||||
|
||||
switch (tag) {
|
||||
.freestanding,
|
||||
.ananas,
|
||||
.cloudabi,
|
||||
.dragonfly,
|
||||
.fuchsia,
|
||||
.ios,
|
||||
.kfreebsd,
|
||||
.lv2,
|
||||
.solaris,
|
||||
.haiku,
|
||||
.minix,
|
||||
.rtems,
|
||||
.nacl,
|
||||
.cnk,
|
||||
.aix,
|
||||
.cuda,
|
||||
.nvcl,
|
||||
.amdhsa,
|
||||
.ps4,
|
||||
.elfiamcu,
|
||||
.tvos,
|
||||
.watchos,
|
||||
.mesa3d,
|
||||
.contiki,
|
||||
.amdpal,
|
||||
.hermit,
|
||||
.hurd,
|
||||
.wasi,
|
||||
.emscripten,
|
||||
.uefi,
|
||||
.other,
|
||||
=> return error.InvalidOperatingSystemVersion,
|
||||
|
||||
.freebsd,
|
||||
.macosx,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
.linux,
|
||||
=> {
|
||||
var range_it = mem.separate(version_text, "...");
|
||||
|
||||
const min_text = range_it.next().?;
|
||||
const min_ver = SemVer.parse(min_text) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidOperatingSystemVersion,
|
||||
error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
|
||||
error.InvalidVersion => return error.InvalidOperatingSystemVersion,
|
||||
};
|
||||
result.os_version_min = .{ .semver = min_ver };
|
||||
|
||||
const max_text = range_it.next() orelse return;
|
||||
const max_ver = SemVer.parse(max_text) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidOperatingSystemVersion,
|
||||
error.InvalidCharacter => return error.InvalidOperatingSystemVersion,
|
||||
error.InvalidVersion => return error.InvalidOperatingSystemVersion,
|
||||
};
|
||||
result.os_version_max = .{ .semver = max_ver };
|
||||
},
|
||||
|
||||
.windows => {
|
||||
var range_it = mem.separate(version_text, "...");
|
||||
|
||||
const min_text = range_it.next().?;
|
||||
const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
|
||||
return error.InvalidOperatingSystemVersion;
|
||||
result.os_version_min = .{ .windows = min_ver };
|
||||
|
||||
const max_text = range_it.next() orelse return;
|
||||
const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
|
||||
return error.InvalidOperatingSystemVersion;
|
||||
result.os_version_max = .{ .windows = max_ver };
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test "CrossTarget.parse" {
|
||||
if (Target.current.isGnuLibC()) {
|
||||
var cross_target = try CrossTarget.parse(.{});
|
||||
cross_target.setGnuLibCVersion(2, 1, 1);
|
||||
|
||||
const text = try cross_target.zigTriple(std.testing.allocator);
|
||||
defer std.testing.allocator.free(text);
|
||||
std.testing.expectEqualSlices(u8, "native-native-gnu.2.1.1", text);
|
||||
}
|
||||
{
|
||||
const cross_target = try CrossTarget.parse(.{
|
||||
.arch_os_abi = "aarch64-linux",
|
||||
.cpu_features = "native",
|
||||
});
|
||||
|
||||
std.testing.expect(cross_target.cpu_arch.? == .aarch64);
|
||||
std.testing.expect(cross_target.cpu_model == .native);
|
||||
}
|
||||
{
|
||||
const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" });
|
||||
|
||||
std.testing.expect(cross_target.cpu_arch == null);
|
||||
std.testing.expect(cross_target.isNative());
|
||||
|
||||
const text = try cross_target.zigTriple(std.testing.allocator);
|
||||
defer std.testing.allocator.free(text);
|
||||
std.testing.expectEqualSlices(u8, "native", text);
|
||||
}
|
||||
{
|
||||
const cross_target = try CrossTarget.parse(.{
|
||||
.arch_os_abi = "x86_64-linux-gnu",
|
||||
.cpu_features = "x86_64-sse-sse2-avx-cx8",
|
||||
});
|
||||
const target = cross_target.toTarget();
|
||||
|
||||
std.testing.expect(target.os.tag == .linux);
|
||||
std.testing.expect(target.abi == .gnu);
|
||||
std.testing.expect(target.cpu.arch == .x86_64);
|
||||
std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse));
|
||||
std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx));
|
||||
std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8));
|
||||
std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov));
|
||||
std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr));
|
||||
|
||||
const text = try cross_target.zigTriple(std.testing.allocator);
|
||||
defer std.testing.allocator.free(text);
|
||||
std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text);
|
||||
}
|
||||
{
|
||||
const cross_target = try CrossTarget.parse(.{
|
||||
.arch_os_abi = "arm-linux-musleabihf",
|
||||
.cpu_features = "generic+v8a",
|
||||
});
|
||||
const target = cross_target.toTarget();
|
||||
|
||||
std.testing.expect(target.os.tag == .linux);
|
||||
std.testing.expect(target.abi == .musleabihf);
|
||||
std.testing.expect(target.cpu.arch == .arm);
|
||||
std.testing.expect(target.cpu.model == &Target.arm.cpu.generic);
|
||||
std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a));
|
||||
|
||||
const text = try cross_target.zigTriple(std.testing.allocator);
|
||||
defer std.testing.allocator.free(text);
|
||||
std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text);
|
||||
}
|
||||
{
|
||||
const cross_target = try CrossTarget.parse(.{
|
||||
.arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27",
|
||||
.cpu_features = "generic+v8a",
|
||||
});
|
||||
const target = cross_target.toTarget();
|
||||
|
||||
std.testing.expect(target.cpu.arch == .aarch64);
|
||||
std.testing.expect(target.os.tag == .linux);
|
||||
std.testing.expect(target.os.version_range.linux.range.min.major == 3);
|
||||
std.testing.expect(target.os.version_range.linux.range.min.minor == 10);
|
||||
std.testing.expect(target.os.version_range.linux.range.min.patch == 0);
|
||||
std.testing.expect(target.os.version_range.linux.range.max.major == 4);
|
||||
std.testing.expect(target.os.version_range.linux.range.max.minor == 4);
|
||||
std.testing.expect(target.os.version_range.linux.range.max.patch == 1);
|
||||
std.testing.expect(target.os.version_range.linux.glibc.major == 2);
|
||||
std.testing.expect(target.os.version_range.linux.glibc.minor == 27);
|
||||
std.testing.expect(target.os.version_range.linux.glibc.patch == 0);
|
||||
std.testing.expect(target.abi == .gnu);
|
||||
|
||||
const text = try cross_target.zigTriple(std.testing.allocator);
|
||||
defer std.testing.allocator.free(text);
|
||||
std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text);
|
||||
}
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
const std = @import("../std.zig");
|
||||
const elf = std.elf;
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const assert = std.debug.assert;
|
||||
const process = std.process;
|
||||
const Target = std.Target;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
const is_windows = std.Target.current.isWindows();
|
||||
const is_windows = Target.current.os.tag == .windows;
|
||||
|
||||
pub const NativePaths = struct {
|
||||
include_dirs: ArrayList([:0]u8),
|
||||
@ -77,7 +81,7 @@ pub const NativePaths = struct {
|
||||
}
|
||||
|
||||
if (!is_windows) {
|
||||
const triple = try std.Target.current.linuxTriple(allocator);
|
||||
const triple = try Target.current.linuxTriple(allocator);
|
||||
|
||||
// TODO: $ ld --verbose | grep SEARCH_DIR
|
||||
// the output contains some paths that end with lib64, maybe include them too?
|
||||
@ -161,3 +165,691 @@ pub const NativePaths = struct {
|
||||
try array.append(item);
|
||||
}
|
||||
};
|
||||
|
||||
pub const NativeTargetInfo = struct {
|
||||
target: Target,
|
||||
|
||||
dynamic_linker: DynamicLinker = DynamicLinker{},
|
||||
|
||||
pub const DynamicLinker = Target.DynamicLinker;
|
||||
|
||||
pub const DetectError = error{
|
||||
OutOfMemory,
|
||||
FileSystem,
|
||||
SystemResources,
|
||||
SymLinkLoop,
|
||||
ProcessFdQuotaExceeded,
|
||||
SystemFdQuotaExceeded,
|
||||
DeviceBusy,
|
||||
};
|
||||
|
||||
/// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected
|
||||
/// natively, which should be standard or default, and which are provided explicitly, this function
|
||||
/// resolves the native components by detecting the native system, and then resolves standard/default parts
|
||||
/// relative to that.
|
||||
/// Any resources this function allocates are released before returning, and so there is no
|
||||
/// deinitialization method.
|
||||
/// TODO Remove the Allocator requirement from this function.
|
||||
pub fn detect(allocator: *Allocator, cross_target: CrossTarget) DetectError!NativeTargetInfo {
|
||||
const cpu = switch (cross_target.cpu_model) {
|
||||
.native => detectNativeCpuAndFeatures(cross_target),
|
||||
.baseline => baselineCpuAndFeatures(cross_target),
|
||||
.determined_by_cpu_arch => if (cross_target.cpu_arch == null)
|
||||
detectNativeCpuAndFeatures(cross_target)
|
||||
else
|
||||
baselineCpuAndFeatures(cross_target),
|
||||
.explicit => |model| blk: {
|
||||
var adjusted_model = model.toCpu(cross_target.getCpuArch());
|
||||
cross_target.updateCpuFeatures(&adjusted_model.features);
|
||||
break :blk adjusted_model;
|
||||
},
|
||||
};
|
||||
|
||||
var os = Target.Os.defaultVersionRange(cross_target.getOsTag());
|
||||
if (cross_target.os_tag == null) {
|
||||
switch (Target.current.os.tag) {
|
||||
.linux => {
|
||||
const uts = std.os.uname();
|
||||
const release = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.release));
|
||||
if (std.builtin.Version.parse(release)) |ver| {
|
||||
os.version_range.linux.range.min = ver;
|
||||
os.version_range.linux.range.max = ver;
|
||||
} else |err| switch (err) {
|
||||
error.Overflow => {},
|
||||
error.InvalidCharacter => {},
|
||||
error.InvalidVersion => {},
|
||||
}
|
||||
},
|
||||
.windows => {
|
||||
var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined;
|
||||
version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info));
|
||||
|
||||
switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
// Starting from the system infos build a NTDDI-like version
|
||||
// constant whose format is:
|
||||
// B0 B1 B2 B3
|
||||
// `---` `` ``--> Sub-version (Starting from Windows 10 onwards)
|
||||
// \ `--> Service pack (Always zero in the constants defined)
|
||||
// `--> OS version (Major & minor)
|
||||
const os_ver: u16 = //
|
||||
@intCast(u16, version_info.dwMajorVersion & 0xff) << 8 |
|
||||
@intCast(u16, version_info.dwMinorVersion & 0xff);
|
||||
const sp_ver: u8 = 0;
|
||||
const sub_ver: u8 = if (os_ver >= 0x0A00) subver: {
|
||||
// There's no other way to obtain this info beside
|
||||
// checking the build number against a known set of
|
||||
// values
|
||||
const known_build_numbers = [_]u32{
|
||||
10240, 10586, 14393, 15063, 16299, 17134, 17763,
|
||||
18362, 18363,
|
||||
};
|
||||
var last_idx: usize = 0;
|
||||
for (known_build_numbers) |build, i| {
|
||||
if (version_info.dwBuildNumber >= build)
|
||||
last_idx = i;
|
||||
}
|
||||
break :subver @truncate(u8, last_idx);
|
||||
} else 0;
|
||||
|
||||
const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver;
|
||||
|
||||
os.version_range.windows.max = @intToEnum(Target.Os.WindowsVersion, version);
|
||||
os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version);
|
||||
},
|
||||
.macosx => {
|
||||
var product_version: [32]u8 = undefined;
|
||||
var size: usize = product_version.len;
|
||||
|
||||
// The osproductversion sysctl was introduced first with
|
||||
// High Sierra, thankfully that's also the baseline that Zig
|
||||
// supports
|
||||
std.os.sysctlbynameC(
|
||||
"kern.osproductversion",
|
||||
&product_version,
|
||||
&size,
|
||||
null,
|
||||
0,
|
||||
) catch |err| switch (err) {
|
||||
error.UnknownName => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
const string_version = product_version[0 .. size - 1 :0];
|
||||
if (std.builtin.Version.parse(string_version)) |ver| {
|
||||
os.version_range.semver.min = ver;
|
||||
os.version_range.semver.max = ver;
|
||||
} else |err| switch (err) {
|
||||
error.Overflow => {},
|
||||
error.InvalidCharacter => {},
|
||||
error.InvalidVersion => {},
|
||||
}
|
||||
},
|
||||
.freebsd => {
|
||||
// TODO Detect native operating system version.
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (cross_target.os_version_min) |min| switch (min) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (cross_target.getOsTag()) {
|
||||
.linux => os.version_range.linux.range.min = semver,
|
||||
else => os.version_range.semver.min = semver,
|
||||
},
|
||||
.windows => |win_ver| os.version_range.windows.min = win_ver,
|
||||
};
|
||||
|
||||
if (cross_target.os_version_max) |max| switch (max) {
|
||||
.none => {},
|
||||
.semver => |semver| switch (cross_target.getOsTag()) {
|
||||
.linux => os.version_range.linux.range.max = semver,
|
||||
else => os.version_range.semver.max = semver,
|
||||
},
|
||||
.windows => |win_ver| os.version_range.windows.max = win_ver,
|
||||
};
|
||||
|
||||
if (cross_target.glibc_version) |glibc| {
|
||||
assert(cross_target.isGnuLibC());
|
||||
os.version_range.linux.glibc = glibc;
|
||||
}
|
||||
|
||||
return detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
|
||||
}
|
||||
|
||||
/// First we attempt to use the executable's own binary. If it is dynamically
|
||||
/// linked, then it should answer both the C ABI question and the dynamic linker question.
|
||||
/// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then
|
||||
/// we fall back to the defaults.
|
||||
/// TODO Remove the Allocator requirement from this function.
|
||||
fn detectAbiAndDynamicLinker(
|
||||
allocator: *Allocator,
|
||||
cpu: Target.Cpu,
|
||||
os: Target.Os,
|
||||
cross_target: CrossTarget,
|
||||
) DetectError!NativeTargetInfo {
|
||||
const native_target_has_ld = comptime Target.current.hasDynamicLinker();
|
||||
const is_linux = Target.current.os.tag == .linux;
|
||||
const have_all_info = cross_target.dynamic_linker.get() != null and
|
||||
cross_target.abi != null and (!is_linux or cross_target.abi.?.isGnu());
|
||||
const os_is_non_native = cross_target.os_tag != null;
|
||||
if (!native_target_has_ld or have_all_info or os_is_non_native) {
|
||||
return defaultAbiAndDynamicLinker(cpu, os, cross_target);
|
||||
}
|
||||
// The current target's ABI cannot be relied on for this. For example, we may build the zig
|
||||
// compiler for target riscv64-linux-musl and provide a tarball for users to download.
|
||||
// A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
|
||||
// and supported by Zig. But that means that we must detect the system ABI here rather than
|
||||
// relying on `Target.current`.
|
||||
const all_abis = comptime blk: {
|
||||
assert(@enumToInt(Target.Abi.none) == 0);
|
||||
const fields = std.meta.fields(Target.Abi)[1..];
|
||||
var array: [fields.len]Target.Abi = undefined;
|
||||
inline for (fields) |field, i| {
|
||||
array[i] = @field(Target.Abi, field.name);
|
||||
}
|
||||
break :blk array;
|
||||
};
|
||||
var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
|
||||
var ld_info_list_len: usize = 0;
|
||||
|
||||
for (all_abis) |abi| {
|
||||
// This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
|
||||
// skip adding it to `ld_info_list`.
|
||||
const target: Target = .{
|
||||
.cpu = cpu,
|
||||
.os = os,
|
||||
.abi = abi,
|
||||
};
|
||||
const ld = target.standardDynamicLinkerPath();
|
||||
if (ld.get() == null) continue;
|
||||
|
||||
ld_info_list_buffer[ld_info_list_len] = .{
|
||||
.ld = ld,
|
||||
.abi = abi,
|
||||
};
|
||||
ld_info_list_len += 1;
|
||||
}
|
||||
const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
|
||||
|
||||
if (cross_target.dynamic_linker.get()) |explicit_ld| {
|
||||
const explicit_ld_basename = fs.path.basename(explicit_ld);
|
||||
for (ld_info_list) |ld_info| {
|
||||
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
|
||||
}
|
||||
}
|
||||
|
||||
// Best case scenario: the executable is dynamically linked, and we can iterate
|
||||
// over our own shared objects and find a dynamic linker.
|
||||
self_exe: {
|
||||
const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
|
||||
defer allocator.free(lib_paths);
|
||||
|
||||
var found_ld_info: LdInfo = undefined;
|
||||
var found_ld_path: [:0]const u8 = undefined;
|
||||
|
||||
// Look for dynamic linker.
|
||||
// This is O(N^M) but typical case here is N=2 and M=10.
|
||||
find_ld: for (lib_paths) |lib_path| {
|
||||
for (ld_info_list) |ld_info| {
|
||||
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
|
||||
if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
|
||||
found_ld_info = ld_info;
|
||||
found_ld_path = lib_path;
|
||||
break :find_ld;
|
||||
}
|
||||
}
|
||||
} else break :self_exe;
|
||||
|
||||
// Look for glibc version.
|
||||
var os_adjusted = os;
|
||||
if (Target.current.os.tag == .linux and found_ld_info.abi.isGnu() and
|
||||
cross_target.glibc_version == null)
|
||||
{
|
||||
for (lib_paths) |lib_path| {
|
||||
if (std.mem.endsWith(u8, lib_path, glibc_so_basename)) {
|
||||
os_adjusted.version_range.linux.glibc = glibcVerFromSO(lib_path) catch |err| switch (err) {
|
||||
error.UnrecognizedGnuLibCFileName => continue,
|
||||
error.InvalidGnuLibCVersion => continue,
|
||||
error.GnuLibCVersionUnavailable => continue,
|
||||
else => |e| return e,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result: NativeTargetInfo = .{
|
||||
.target = .{
|
||||
.cpu = cpu,
|
||||
.os = os_adjusted,
|
||||
.abi = cross_target.abi orelse found_ld_info.abi,
|
||||
},
|
||||
.dynamic_linker = if (cross_target.dynamic_linker.get() == null)
|
||||
DynamicLinker.init(found_ld_path)
|
||||
else
|
||||
cross_target.dynamic_linker,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) {
|
||||
error.NoSpaceLeft => unreachable,
|
||||
error.NameTooLong => unreachable,
|
||||
error.PathAlreadyExists => unreachable,
|
||||
error.SharingViolation => unreachable,
|
||||
error.InvalidUtf8 => unreachable,
|
||||
error.BadPathName => unreachable,
|
||||
error.PipeBusy => unreachable,
|
||||
|
||||
error.IsDir,
|
||||
error.NotDir,
|
||||
error.AccessDenied,
|
||||
error.NoDevice,
|
||||
error.FileNotFound,
|
||||
error.FileTooBig,
|
||||
error.Unexpected,
|
||||
=> return defaultAbiAndDynamicLinker(cpu, os, cross_target),
|
||||
|
||||
else => |e| return e,
|
||||
};
|
||||
defer env_file.close();
|
||||
|
||||
// If Zig is statically linked, such as via distributed binary static builds, the above
|
||||
// trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.
|
||||
// Since that path is hard-coded into the shebang line of many portable scripts, it's a
|
||||
// reasonably reliable path to check for.
|
||||
return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
|
||||
error.FileSystem,
|
||||
error.SystemResources,
|
||||
error.SymLinkLoop,
|
||||
error.ProcessFdQuotaExceeded,
|
||||
error.SystemFdQuotaExceeded,
|
||||
=> |e| return e,
|
||||
|
||||
error.UnableToReadElfFile,
|
||||
error.InvalidElfClass,
|
||||
error.InvalidElfVersion,
|
||||
error.InvalidElfEndian,
|
||||
error.InvalidElfFile,
|
||||
error.InvalidElfMagic,
|
||||
error.Unexpected,
|
||||
error.UnexpectedEndOfFile,
|
||||
error.NameTooLong,
|
||||
// Finally, we fall back on the standard path.
|
||||
=> defaultAbiAndDynamicLinker(cpu, os, cross_target),
|
||||
};
|
||||
}
|
||||
|
||||
const glibc_so_basename = "libc.so.6";
|
||||
|
||||
fn glibcVerFromSO(so_path: [:0]const u8) !std.builtin.Version {
|
||||
var link_buf: [std.os.PATH_MAX]u8 = undefined;
|
||||
const link_name = std.os.readlinkC(so_path.ptr, &link_buf) catch |err| switch (err) {
|
||||
error.AccessDenied => return error.GnuLibCVersionUnavailable,
|
||||
error.FileSystem => return error.FileSystem,
|
||||
error.SymLinkLoop => return error.SymLinkLoop,
|
||||
error.NameTooLong => unreachable,
|
||||
error.FileNotFound => return error.GnuLibCVersionUnavailable,
|
||||
error.SystemResources => return error.SystemResources,
|
||||
error.NotDir => return error.GnuLibCVersionUnavailable,
|
||||
error.Unexpected => return error.GnuLibCVersionUnavailable,
|
||||
};
|
||||
return glibcVerFromLinkName(link_name);
|
||||
}
|
||||
|
||||
fn glibcVerFromLinkName(link_name: []const u8) !std.builtin.Version {
|
||||
// example: "libc-2.3.4.so"
|
||||
// example: "libc-2.27.so"
|
||||
const prefix = "libc-";
|
||||
const suffix = ".so";
|
||||
if (!mem.startsWith(u8, link_name, prefix) or !mem.endsWith(u8, link_name, suffix)) {
|
||||
return error.UnrecognizedGnuLibCFileName;
|
||||
}
|
||||
// chop off "libc-" and ".so"
|
||||
const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
|
||||
return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidGnuLibCVersion,
|
||||
error.InvalidCharacter => return error.InvalidGnuLibCVersion,
|
||||
error.InvalidVersion => return error.InvalidGnuLibCVersion,
|
||||
};
|
||||
}
|
||||
|
||||
pub const AbiAndDynamicLinkerFromFileError = error{
|
||||
FileSystem,
|
||||
SystemResources,
|
||||
SymLinkLoop,
|
||||
ProcessFdQuotaExceeded,
|
||||
SystemFdQuotaExceeded,
|
||||
UnableToReadElfFile,
|
||||
InvalidElfClass,
|
||||
InvalidElfVersion,
|
||||
InvalidElfEndian,
|
||||
InvalidElfFile,
|
||||
InvalidElfMagic,
|
||||
Unexpected,
|
||||
UnexpectedEndOfFile,
|
||||
NameTooLong,
|
||||
};
|
||||
|
||||
pub fn abiAndDynamicLinkerFromFile(
|
||||
file: fs.File,
|
||||
cpu: Target.Cpu,
|
||||
os: Target.Os,
|
||||
ld_info_list: []const LdInfo,
|
||||
cross_target: CrossTarget,
|
||||
) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {
|
||||
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
|
||||
_ = try preadFull(file, &hdr_buf, 0, hdr_buf.len);
|
||||
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
|
||||
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
|
||||
elf.ELFDATA2LSB => .Little,
|
||||
elf.ELFDATA2MSB => .Big,
|
||||
else => return error.InvalidElfEndian,
|
||||
};
|
||||
const need_bswap = elf_endian != std.builtin.endian;
|
||||
if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
|
||||
|
||||
const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) {
|
||||
elf.ELFCLASS32 => false,
|
||||
elf.ELFCLASS64 => true,
|
||||
else => return error.InvalidElfClass,
|
||||
};
|
||||
var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
|
||||
const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
|
||||
const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
|
||||
|
||||
var result: NativeTargetInfo = .{
|
||||
.target = .{
|
||||
.cpu = cpu,
|
||||
.os = os,
|
||||
.abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
|
||||
},
|
||||
.dynamic_linker = cross_target.dynamic_linker,
|
||||
};
|
||||
var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
|
||||
const look_for_ld = cross_target.dynamic_linker.get() == null;
|
||||
|
||||
var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined;
|
||||
if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile;
|
||||
|
||||
var ph_i: u16 = 0;
|
||||
while (ph_i < phnum) {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
|
||||
const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
|
||||
var ph_buf_i: usize = 0;
|
||||
while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
|
||||
ph_i += 1;
|
||||
phoff += phentsize;
|
||||
ph_buf_i += phentsize;
|
||||
}) {
|
||||
const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[ph_buf_i]));
|
||||
const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[ph_buf_i]));
|
||||
const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type);
|
||||
switch (p_type) {
|
||||
elf.PT_INTERP => if (look_for_ld) {
|
||||
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
|
||||
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
|
||||
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
|
||||
_ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
|
||||
// PT_INTERP includes a null byte in p_filesz.
|
||||
const len = p_filesz - 1;
|
||||
// dynamic_linker.max_byte is "max", not "len".
|
||||
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
|
||||
result.dynamic_linker.max_byte = @intCast(u8, len - 1);
|
||||
|
||||
// Use it to determine ABI.
|
||||
const full_ld_path = result.dynamic_linker.buffer[0..len];
|
||||
for (ld_info_list) |ld_info| {
|
||||
const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
|
||||
if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
|
||||
result.target.abi = ld_info.abi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
// We only need this for detecting glibc version.
|
||||
elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC() and
|
||||
cross_target.glibc_version == null)
|
||||
{
|
||||
var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
|
||||
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
|
||||
const dyn_size: u64 = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn);
|
||||
const dyn_num = p_filesz / dyn_size;
|
||||
var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined;
|
||||
var dyn_i: usize = 0;
|
||||
dyn: while (dyn_i < dyn_num) {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
|
||||
const dyn_read_byte_len = try preadFull(
|
||||
file,
|
||||
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
|
||||
dyn_off,
|
||||
dyn_size,
|
||||
);
|
||||
var dyn_buf_i: usize = 0;
|
||||
while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({
|
||||
dyn_i += 1;
|
||||
dyn_off += dyn_size;
|
||||
dyn_buf_i += dyn_size;
|
||||
}) {
|
||||
const dyn32 = @ptrCast(
|
||||
*elf.Elf32_Dyn,
|
||||
@alignCast(@alignOf(elf.Elf32_Dyn), &dyn_buf[dyn_buf_i]),
|
||||
);
|
||||
const dyn64 = @ptrCast(
|
||||
*elf.Elf64_Dyn,
|
||||
@alignCast(@alignOf(elf.Elf64_Dyn), &dyn_buf[dyn_buf_i]),
|
||||
);
|
||||
const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag);
|
||||
const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val);
|
||||
if (tag == elf.DT_RUNPATH) {
|
||||
rpath_offset = val;
|
||||
break :dyn;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Target.current.os.tag == .linux and result.target.isGnuLibC() and cross_target.glibc_version == null) {
|
||||
if (rpath_offset) |rpoff| {
|
||||
const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx);
|
||||
|
||||
var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff);
|
||||
const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize);
|
||||
const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx);
|
||||
|
||||
var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
|
||||
if (sh_buf.len < shentsize) return error.InvalidElfFile;
|
||||
|
||||
_ = try preadFull(file, &sh_buf, str_section_off, shentsize);
|
||||
const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
|
||||
const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
|
||||
const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
|
||||
const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
|
||||
var strtab_buf: [4096:0]u8 = undefined;
|
||||
const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
|
||||
const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len);
|
||||
const shstrtab = strtab_buf[0..shstrtab_read_len];
|
||||
|
||||
const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
|
||||
var sh_i: u16 = 0;
|
||||
const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
|
||||
const sh_read_byte_len = try preadFull(
|
||||
file,
|
||||
sh_buf[0 .. sh_buf.len - sh_reserve],
|
||||
shoff,
|
||||
shentsize,
|
||||
);
|
||||
var sh_buf_i: usize = 0;
|
||||
while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({
|
||||
sh_i += 1;
|
||||
shoff += shentsize;
|
||||
sh_buf_i += shentsize;
|
||||
}) {
|
||||
const sh32 = @ptrCast(
|
||||
*elf.Elf32_Shdr,
|
||||
@alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf[sh_buf_i]),
|
||||
);
|
||||
const sh64 = @ptrCast(
|
||||
*elf.Elf64_Shdr,
|
||||
@alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf[sh_buf_i]),
|
||||
);
|
||||
const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name);
|
||||
// TODO this pointer cast should not be necessary
|
||||
const sh_name = mem.toSliceConst(u8, @ptrCast([*:0]u8, shstrtab[sh_name_off..].ptr));
|
||||
if (mem.eql(u8, sh_name, ".dynstr")) {
|
||||
break :find_dyn_str .{
|
||||
.offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset),
|
||||
.size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size),
|
||||
};
|
||||
}
|
||||
}
|
||||
} else null;
|
||||
|
||||
if (dynstr) |ds| {
|
||||
const strtab_len = std.math.min(ds.size, strtab_buf.len);
|
||||
const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len);
|
||||
const strtab = strtab_buf[0..strtab_read_len];
|
||||
// TODO this pointer cast should not be necessary
|
||||
const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
|
||||
var it = mem.tokenize(rpath_list, ":");
|
||||
while (it.next()) |rpath| {
|
||||
var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
error.InvalidUtf8 => unreachable,
|
||||
error.BadPathName => unreachable,
|
||||
error.DeviceBusy => unreachable,
|
||||
|
||||
error.FileNotFound,
|
||||
error.NotDir,
|
||||
error.AccessDenied,
|
||||
error.NoDevice,
|
||||
=> continue,
|
||||
|
||||
error.ProcessFdQuotaExceeded,
|
||||
error.SystemFdQuotaExceeded,
|
||||
error.SystemResources,
|
||||
error.SymLinkLoop,
|
||||
error.Unexpected,
|
||||
=> |e| return e,
|
||||
};
|
||||
defer dir.close();
|
||||
|
||||
var link_buf: [std.os.PATH_MAX]u8 = undefined;
|
||||
const link_name = std.os.readlinkatC(
|
||||
dir.fd,
|
||||
glibc_so_basename,
|
||||
&link_buf,
|
||||
) catch |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
|
||||
error.AccessDenied,
|
||||
error.FileNotFound,
|
||||
error.NotDir,
|
||||
=> continue,
|
||||
|
||||
error.SystemResources,
|
||||
error.FileSystem,
|
||||
error.SymLinkLoop,
|
||||
error.Unexpected,
|
||||
=> |e| return e,
|
||||
};
|
||||
result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
|
||||
link_name,
|
||||
) catch |err| switch (err) {
|
||||
error.UnrecognizedGnuLibCFileName,
|
||||
error.InvalidGnuLibCVersion,
|
||||
=> continue,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
|
||||
var i: u64 = 0;
|
||||
while (i < min_read_len) {
|
||||
const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
|
||||
error.OperationAborted => unreachable, // Windows-only
|
||||
error.WouldBlock => unreachable, // Did not request blocking mode
|
||||
error.SystemResources => return error.SystemResources,
|
||||
error.IsDir => return error.UnableToReadElfFile,
|
||||
error.BrokenPipe => return error.UnableToReadElfFile,
|
||||
error.ConnectionResetByPeer => return error.UnableToReadElfFile,
|
||||
error.Unexpected => return error.Unexpected,
|
||||
error.InputOutput => return error.FileSystem,
|
||||
};
|
||||
if (len == 0) return error.UnexpectedEndOfFile;
|
||||
i += len;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: CrossTarget) !NativeTargetInfo {
|
||||
const target: Target = .{
|
||||
.cpu = cpu,
|
||||
.os = os,
|
||||
.abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
|
||||
};
|
||||
return NativeTargetInfo{
|
||||
.target = target,
|
||||
.dynamic_linker = if (cross_target.dynamic_linker.get() == null)
|
||||
target.standardDynamicLinkerPath()
|
||||
else
|
||||
cross_target.dynamic_linker,
|
||||
};
|
||||
}
|
||||
|
||||
pub const LdInfo = struct {
|
||||
ld: DynamicLinker,
|
||||
abi: Target.Abi,
|
||||
};
|
||||
|
||||
fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
|
||||
if (is_64) {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_64), int_64);
|
||||
} else {
|
||||
return int_64;
|
||||
}
|
||||
} else {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_32), int_32);
|
||||
} else {
|
||||
return int_32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detectNativeCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
|
||||
// TODO Detect native CPU model & features. Until that is implemented we use baseline.
|
||||
return baselineCpuAndFeatures(cross_target);
|
||||
}
|
||||
|
||||
fn baselineCpuAndFeatures(cross_target: CrossTarget) Target.Cpu {
|
||||
var adjusted_baseline = Target.Cpu.baseline(cross_target.getCpuArch());
|
||||
cross_target.updateCpuFeatures(&adjusted_baseline.features);
|
||||
return adjusted_baseline;
|
||||
}
|
||||
};
|
||||
|
@ -70,7 +70,7 @@ pub const CInt = struct {
|
||||
|
||||
pub fn sizeInBits(cint: CInt, self: Target) u32 {
|
||||
const arch = self.getArch();
|
||||
switch (self.getOs()) {
|
||||
switch (self.os.tag) {
|
||||
.freestanding, .other => switch (self.getArch()) {
|
||||
.msp430 => switch (cint.id) {
|
||||
.Short,
|
||||
|
@ -1072,7 +1072,7 @@ pub const struct_ZigClangExprEvalResult = extern struct {
|
||||
|
||||
pub const struct_ZigClangAPValue = extern struct {
|
||||
Kind: ZigClangAPValueKind,
|
||||
Data: if (builtin.os == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,
|
||||
Data: if (builtin.os.tag == .windows and builtin.abi == .msvc) [52]u8 else [68]u8,
|
||||
};
|
||||
pub extern fn ZigClangVarDecl_getTypeSourceInfo_getType(self: *const struct_ZigClangVarDecl) struct_ZigClangQualType;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Introspection and determination of system libraries needed by zig.
|
||||
//! Introspection and determination of system libraries needed by zig.
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
@ -6,14 +6,6 @@ const fs = std.fs;
|
||||
|
||||
const warn = std.debug.warn;
|
||||
|
||||
pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
|
||||
if (target == .Native) {
|
||||
return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
|
||||
} else {
|
||||
return target.getStandardDynamicLinkerPath(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
/// Caller must free result
|
||||
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
|
||||
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
|
||||
|
@ -1803,7 +1803,7 @@ pub const Builder = struct {
|
||||
|
||||
// Look at the params and ref() other instructions
|
||||
inline for (@typeInfo(I.Params).Struct.fields) |f| {
|
||||
switch (f.fiedl_type) {
|
||||
switch (f.field_type) {
|
||||
*Inst => @field(inst.params, f.name).ref(self),
|
||||
*BasicBlock => @field(inst.params, f.name).ref(self),
|
||||
?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self),
|
||||
|
@ -7,11 +7,7 @@ const Allocator = std.mem.Allocator;
|
||||
const Batch = std.event.Batch;
|
||||
|
||||
const is_darwin = Target.current.isDarwin();
|
||||
const is_windows = Target.current.isWindows();
|
||||
const is_freebsd = Target.current.isFreeBSD();
|
||||
const is_netbsd = Target.current.isNetBSD();
|
||||
const is_linux = Target.current.isLinux();
|
||||
const is_dragonfly = Target.current.isDragonFlyBSD();
|
||||
const is_windows = Target.current.os.tag == .windows;
|
||||
const is_gnu = Target.current.isGnu();
|
||||
|
||||
usingnamespace @import("windows_sdk.zig");
|
||||
@ -99,27 +95,27 @@ pub const LibCInstallation = struct {
|
||||
return error.ParseError;
|
||||
}
|
||||
if (self.crt_dir == null and !is_darwin) {
|
||||
try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.getOs())});
|
||||
try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.os.tag)});
|
||||
return error.ParseError;
|
||||
}
|
||||
if (self.static_crt_dir == null and is_windows and is_gnu) {
|
||||
try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{
|
||||
@tagName(Target.current.getOs()),
|
||||
@tagName(Target.current.getAbi()),
|
||||
@tagName(Target.current.os.tag),
|
||||
@tagName(Target.current.abi),
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
if (self.msvc_lib_dir == null and is_windows and !is_gnu) {
|
||||
try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{
|
||||
@tagName(Target.current.getOs()),
|
||||
@tagName(Target.current.getAbi()),
|
||||
@tagName(Target.current.os.tag),
|
||||
@tagName(Target.current.abi),
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
if (self.kernel32_lib_dir == null and is_windows and !is_gnu) {
|
||||
try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{
|
||||
@tagName(Target.current.getOs()),
|
||||
@tagName(Target.current.getAbi()),
|
||||
@tagName(Target.current.os.tag),
|
||||
@tagName(Target.current.abi),
|
||||
});
|
||||
return error.ParseError;
|
||||
}
|
||||
@ -216,10 +212,10 @@ pub const LibCInstallation = struct {
|
||||
var batch = Batch(FindError!void, 2, .auto_async).init();
|
||||
errdefer batch.wait() catch {};
|
||||
batch.add(&async self.findNativeIncludeDirPosix(args));
|
||||
if (is_freebsd or is_netbsd) {
|
||||
self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib");
|
||||
} else if (is_linux or is_dragonfly) {
|
||||
batch.add(&async self.findNativeCrtDirPosix(args));
|
||||
switch (Target.current.os.tag) {
|
||||
.freebsd, .netbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"),
|
||||
.linux, .dragonfly => batch.add(&async self.findNativeCrtDirPosix(args)),
|
||||
else => {},
|
||||
}
|
||||
break :blk batch.wait();
|
||||
};
|
||||
@ -616,104 +612,6 @@ fn printVerboseInvocation(
|
||||
}
|
||||
}
|
||||
|
||||
/// Caller owns returned memory.
|
||||
pub fn detectNativeDynamicLinker(allocator: *Allocator) error{
|
||||
OutOfMemory,
|
||||
TargetHasNoDynamicLinker,
|
||||
UnknownDynamicLinkerPath,
|
||||
}![:0]u8 {
|
||||
if (!comptime Target.current.hasDynamicLinker()) {
|
||||
return error.TargetHasNoDynamicLinker;
|
||||
}
|
||||
|
||||
// The current target's ABI cannot be relied on for this. For example, we may build the zig
|
||||
// compiler for target riscv64-linux-musl and provide a tarball for users to download.
|
||||
// A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
|
||||
// and supported by Zig. But that means that we must detect the system ABI here rather than
|
||||
// relying on `std.Target.current`.
|
||||
|
||||
const LdInfo = struct {
|
||||
ld_path: []u8,
|
||||
abi: Target.Abi,
|
||||
};
|
||||
var ld_info_list = std.ArrayList(LdInfo).init(allocator);
|
||||
defer {
|
||||
for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path);
|
||||
ld_info_list.deinit();
|
||||
}
|
||||
|
||||
const all_abis = comptime blk: {
|
||||
const fields = std.meta.fields(Target.Abi);
|
||||
var array: [fields.len]Target.Abi = undefined;
|
||||
inline for (fields) |field, i| {
|
||||
array[i] = @field(Target.Abi, field.name);
|
||||
}
|
||||
break :blk array;
|
||||
};
|
||||
for (all_abis) |abi| {
|
||||
// This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
|
||||
// skip adding it to `ld_info_list`.
|
||||
const target: Target = .{
|
||||
.Cross = .{
|
||||
.cpu = Target.Cpu.baseline(Target.current.getArch()),
|
||||
.os = Target.current.getOs(),
|
||||
.abi = abi,
|
||||
},
|
||||
};
|
||||
const standard_ld_path = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => continue,
|
||||
};
|
||||
errdefer allocator.free(standard_ld_path);
|
||||
try ld_info_list.append(.{
|
||||
.ld_path = standard_ld_path,
|
||||
.abi = abi,
|
||||
});
|
||||
}
|
||||
|
||||
// Best case scenario: the zig compiler is dynamically linked, and we can iterate
|
||||
// over our own shared objects and find a dynamic linker.
|
||||
{
|
||||
const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
|
||||
defer allocator.free(lib_paths);
|
||||
|
||||
// This is O(N^M) but typical case here is N=2 and M=10.
|
||||
for (lib_paths) |lib_path| {
|
||||
for (ld_info_list.toSlice()) |ld_info| {
|
||||
const standard_ld_basename = fs.path.basename(ld_info.ld_path);
|
||||
if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
|
||||
return std.mem.dupeZ(allocator, u8, lib_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If Zig is statically linked, such as via distributed binary static builds, the above
|
||||
// trick won't work. What are we left with? Try to run the system C compiler and get
|
||||
// it to tell us the dynamic linker path.
|
||||
// TODO: instead of this, look at the shared libs of /usr/bin/env.
|
||||
for (ld_info_list.toSlice()) |ld_info| {
|
||||
const standard_ld_basename = fs.path.basename(ld_info.ld_path);
|
||||
|
||||
const full_ld_path = ccPrintFileName(.{
|
||||
.allocator = allocator,
|
||||
.search_basename = standard_ld_basename,
|
||||
.want_dirname = .full_path,
|
||||
}) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.LibCRuntimeNotFound,
|
||||
error.CCompilerExitCode,
|
||||
error.CCompilerCrashed,
|
||||
error.UnableToSpawnCCompiler,
|
||||
=> continue,
|
||||
};
|
||||
return full_ld_path;
|
||||
}
|
||||
|
||||
// Finally, we fall back on the standard path.
|
||||
return Target.current.getStandardDynamicLinkerPath(allocator);
|
||||
}
|
||||
|
||||
const Search = struct {
|
||||
path: []const u8,
|
||||
version: []const u8,
|
||||
|
@ -515,7 +515,7 @@ const DarwinPlatform = struct {
|
||||
break :blk ver;
|
||||
},
|
||||
.None => blk: {
|
||||
assert(comp.target.getOs() == .macosx);
|
||||
assert(comp.target.os.tag == .macosx);
|
||||
result.kind = .MacOS;
|
||||
break :blk "10.14";
|
||||
},
|
||||
@ -534,7 +534,7 @@ const DarwinPlatform = struct {
|
||||
}
|
||||
|
||||
if (result.kind == .IPhoneOS) {
|
||||
switch (comp.target.getArch()) {
|
||||
switch (comp.target.cpu.arch) {
|
||||
.i386,
|
||||
.x86_64,
|
||||
=> result.kind = .IPhoneOSSimulator,
|
||||
|
@ -79,9 +79,9 @@ pub fn main() !void {
|
||||
} else if (mem.eql(u8, cmd, "libc")) {
|
||||
return cmdLibC(allocator, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "targets")) {
|
||||
// TODO figure out the current target rather than using the target that was specified when
|
||||
// compiling the compiler
|
||||
return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, Target.current);
|
||||
const info = try std.zig.system.NativeTargetInfo.detect(allocator);
|
||||
defer info.deinit(allocator);
|
||||
return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);
|
||||
} else if (mem.eql(u8, cmd, "version")) {
|
||||
return cmdVersion(allocator, cmd_args);
|
||||
} 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
|
||||
}
|
||||
|
||||
fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
|
||||
try stdout.print("{}\n", .{std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)});
|
||||
try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
|
||||
}
|
||||
|
||||
fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
|
||||
@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
|
||||
\\ZIG_DIA_GUIDS_LIB {}
|
||||
\\
|
||||
, .{
|
||||
std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),
|
||||
std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),
|
||||
std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),
|
||||
std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),
|
||||
std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),
|
||||
std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),
|
||||
c.ZIG_CMAKE_BINARY_DIR,
|
||||
c.ZIG_CXX_COMPILER,
|
||||
c.ZIG_LLD_INCLUDE_PATH,
|
||||
c.ZIG_LLD_LIBRARIES,
|
||||
c.ZIG_LLVM_CONFIG_EXE,
|
||||
c.ZIG_DIA_GUIDS_LIB,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ pub fn cmdTargets(
|
||||
|
||||
try jws.objectField("os");
|
||||
try jws.beginArray();
|
||||
inline for (@typeInfo(Target.Os).Enum.fields) |field| {
|
||||
inline for (@typeInfo(Target.Os.Tag).Enum.fields) |field| {
|
||||
try jws.arrayElem();
|
||||
try jws.emitString(field.name);
|
||||
}
|
||||
@ -201,16 +201,16 @@ pub fn cmdTargets(
|
||||
try jws.objectField("cpu");
|
||||
try jws.beginObject();
|
||||
try jws.objectField("arch");
|
||||
try jws.emitString(@tagName(native_target.getArch()));
|
||||
try jws.emitString(@tagName(native_target.cpu.arch));
|
||||
|
||||
try jws.objectField("name");
|
||||
const cpu = native_target.getCpu();
|
||||
const cpu = native_target.cpu;
|
||||
try jws.emitString(cpu.model.name);
|
||||
|
||||
{
|
||||
try jws.objectField("features");
|
||||
try jws.beginArray();
|
||||
for (native_target.getArch().allFeaturesList()) |feature, i_usize| {
|
||||
for (native_target.cpu.arch.allFeaturesList()) |feature, i_usize| {
|
||||
const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize);
|
||||
if (cpu.features.isEnabled(index)) {
|
||||
try jws.arrayElem();
|
||||
@ -222,9 +222,9 @@ pub fn cmdTargets(
|
||||
try jws.endObject();
|
||||
}
|
||||
try jws.objectField("os");
|
||||
try jws.emitString(@tagName(native_target.getOs()));
|
||||
try jws.emitString(@tagName(native_target.os.tag));
|
||||
try jws.objectField("abi");
|
||||
try jws.emitString(@tagName(native_target.getAbi()));
|
||||
try jws.emitString(@tagName(native_target.abi));
|
||||
// TODO implement native glibc version detection in self-hosted
|
||||
try jws.endObject();
|
||||
|
||||
|
@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Buffer = std.Buffer;
|
||||
const Target = std.Target;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
const self_hosted_main = @import("main.zig");
|
||||
const errmsg = @import("errmsg.zig");
|
||||
const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
|
||||
@ -87,7 +88,7 @@ const Error = extern enum {
|
||||
NotLazy,
|
||||
IsAsync,
|
||||
ImportOutsidePkgPath,
|
||||
UnknownCpu,
|
||||
UnknownCpuModel,
|
||||
UnknownCpuFeature,
|
||||
InvalidCpuFeatures,
|
||||
InvalidLlvmCpuFeaturesFormat,
|
||||
@ -110,6 +111,8 @@ const Error = extern enum {
|
||||
WindowsSdkNotFound,
|
||||
UnknownDynamicLinkerPath,
|
||||
TargetHasNoDynamicLinker,
|
||||
InvalidAbiVersion,
|
||||
InvalidOperatingSystemVersion,
|
||||
};
|
||||
|
||||
const FILE = std.c.FILE;
|
||||
@ -632,13 +635,9 @@ export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
|
||||
}
|
||||
|
||||
fn cmdTargets(zig_triple: [*:0]const u8) !void {
|
||||
var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
|
||||
target.Cross.cpu = blk: {
|
||||
const llvm = @import("llvm.zig");
|
||||
const llvm_cpu_name = llvm.GetHostCPUName();
|
||||
const llvm_cpu_features = llvm.GetNativeFeatures();
|
||||
break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);
|
||||
};
|
||||
var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
|
||||
var dynamic_linker: ?[*:0]u8 = null;
|
||||
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
|
||||
return @import("print_targets.zig").cmdTargets(
|
||||
std.heap.c_allocator,
|
||||
&[0][]u8{},
|
||||
@ -652,16 +651,24 @@ export fn stage2_target_parse(
|
||||
target: *Stage2Target,
|
||||
zig_triple: ?[*:0]const u8,
|
||||
mcpu: ?[*:0]const u8,
|
||||
dynamic_linker: ?[*:0]const u8,
|
||||
) Error {
|
||||
stage2TargetParse(target, zig_triple, mcpu) catch |err| switch (err) {
|
||||
stage2TargetParse(target, zig_triple, mcpu, dynamic_linker) catch |err| switch (err) {
|
||||
error.OutOfMemory => return .OutOfMemory,
|
||||
error.UnknownArchitecture => return .UnknownArchitecture,
|
||||
error.UnknownOperatingSystem => return .UnknownOperatingSystem,
|
||||
error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
|
||||
error.MissingOperatingSystem => return .MissingOperatingSystem,
|
||||
error.MissingArchitecture => return .MissingArchitecture,
|
||||
error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
|
||||
error.UnexpectedExtraField => return .SemanticAnalyzeFail,
|
||||
error.InvalidAbiVersion => return .InvalidAbiVersion,
|
||||
error.InvalidOperatingSystemVersion => return .InvalidOperatingSystemVersion,
|
||||
error.FileSystem => return .FileSystem,
|
||||
error.SymLinkLoop => return .SymLinkLoop,
|
||||
error.SystemResources => return .SystemResources,
|
||||
error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
|
||||
error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
|
||||
error.DeviceBusy => return .DeviceBusy,
|
||||
};
|
||||
return .None;
|
||||
}
|
||||
@ -670,17 +677,20 @@ fn stage2TargetParse(
|
||||
stage1_target: *Stage2Target,
|
||||
zig_triple_oz: ?[*:0]const u8,
|
||||
mcpu_oz: ?[*:0]const u8,
|
||||
dynamic_linker_oz: ?[*:0]const u8,
|
||||
) !void {
|
||||
const target: Target = if (zig_triple_oz) |zig_triple_z| blk: {
|
||||
const target: CrossTarget = if (zig_triple_oz) |zig_triple_z| blk: {
|
||||
const zig_triple = mem.toSliceConst(u8, zig_triple_z);
|
||||
const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline";
|
||||
var diags: std.Target.ParseOptions.Diagnostics = .{};
|
||||
break :blk Target.parse(.{
|
||||
const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
|
||||
const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
|
||||
var diags: CrossTarget.ParseOptions.Diagnostics = .{};
|
||||
break :blk CrossTarget.parse(.{
|
||||
.arch_os_abi = zig_triple,
|
||||
.cpu_features = mcpu,
|
||||
.dynamic_linker = dynamic_linker,
|
||||
.diagnostics = &diags,
|
||||
}) catch |err| switch (err) {
|
||||
error.UnknownCpu => {
|
||||
error.UnknownCpuModel => {
|
||||
std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
|
||||
diags.cpu_name.?,
|
||||
@tagName(diags.arch.?),
|
||||
@ -706,73 +716,11 @@ fn stage2TargetParse(
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
} else Target.Native;
|
||||
} else .{};
|
||||
|
||||
try stage1_target.fromTarget(target);
|
||||
}
|
||||
|
||||
fn initStage1TargetCpuFeatures(stage1_target: *Stage2Target, cpu: Target.Cpu) !void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{
|
||||
cpu.model.name,
|
||||
cpu.features.asBytes(),
|
||||
});
|
||||
errdefer allocator.free(cache_hash);
|
||||
|
||||
const generic_arch_name = cpu.arch.genericName();
|
||||
var builtin_str_buffer = try std.Buffer.allocPrint(allocator,
|
||||
\\Cpu{{
|
||||
\\ .arch = .{},
|
||||
\\ .model = &Target.{}.cpu.{},
|
||||
\\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
|
||||
\\
|
||||
, .{
|
||||
@tagName(cpu.arch),
|
||||
generic_arch_name,
|
||||
cpu.model.name,
|
||||
generic_arch_name,
|
||||
generic_arch_name,
|
||||
});
|
||||
defer builtin_str_buffer.deinit();
|
||||
|
||||
var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
|
||||
defer llvm_features_buffer.deinit();
|
||||
|
||||
for (cpu.arch.allFeaturesList()) |feature, index_usize| {
|
||||
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
|
||||
const is_enabled = cpu.features.isEnabled(index);
|
||||
|
||||
if (feature.llvm_name) |llvm_name| {
|
||||
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
|
||||
try llvm_features_buffer.appendByte(plus_or_minus);
|
||||
try llvm_features_buffer.append(llvm_name);
|
||||
try llvm_features_buffer.append(",");
|
||||
}
|
||||
|
||||
if (is_enabled) {
|
||||
// TODO some kind of "zig identifier escape" function rather than
|
||||
// unconditionally using @"" syntax
|
||||
try builtin_str_buffer.append(" .@\"");
|
||||
try builtin_str_buffer.append(feature.name);
|
||||
try builtin_str_buffer.append("\",\n");
|
||||
}
|
||||
}
|
||||
|
||||
try builtin_str_buffer.append(
|
||||
\\ }),
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
|
||||
assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
|
||||
llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
|
||||
|
||||
stage1_target.llvm_cpu_name = if (cpu.model.llvm_name) |s| s.ptr else null;
|
||||
stage1_target.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr;
|
||||
stage1_target.builtin_str = builtin_str_buffer.toOwnedSlice().ptr;
|
||||
stage1_target.cache_hash = cache_hash.ptr;
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
const Stage2LibCInstallation = extern struct {
|
||||
include_dir: [*:0]const u8,
|
||||
@ -948,15 +896,18 @@ const Stage2Target = extern struct {
|
||||
|
||||
is_native: bool,
|
||||
|
||||
glibc_version: ?*Stage2GLibCVersion, // null means default
|
||||
glibc_or_darwin_version: ?*Stage2SemVer,
|
||||
|
||||
llvm_cpu_name: ?[*:0]const u8,
|
||||
llvm_cpu_features: ?[*:0]const u8,
|
||||
builtin_str: ?[*:0]const u8,
|
||||
cpu_builtin_str: ?[*:0]const u8,
|
||||
cache_hash: ?[*:0]const u8,
|
||||
os_builtin_str: ?[*:0]const u8,
|
||||
|
||||
fn toTarget(in_target: Stage2Target) Target {
|
||||
if (in_target.is_native) return .Native;
|
||||
dynamic_linker: ?[*:0]const u8,
|
||||
|
||||
fn toTarget(in_target: Stage2Target) CrossTarget {
|
||||
if (in_target.is_native) return .{};
|
||||
|
||||
const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
|
||||
const in_os = in_target.os;
|
||||
@ -965,66 +916,270 @@ const Stage2Target = extern struct {
|
||||
return .{
|
||||
.Cross = .{
|
||||
.cpu = Target.Cpu.baseline(enumInt(Target.Cpu.Arch, in_arch)),
|
||||
.os = enumInt(Target.Os, in_os),
|
||||
.os = Target.Os.defaultVersionRange(enumInt(Target.Os.Tag, in_os)),
|
||||
.abi = enumInt(Target.Abi, in_abi),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn fromTarget(self: *Stage2Target, target: Target) !void {
|
||||
const cpu = switch (target) {
|
||||
.Native => blk: {
|
||||
// TODO self-host CPU model and feature detection instead of relying on LLVM
|
||||
const llvm = @import("llvm.zig");
|
||||
const llvm_cpu_name = llvm.GetHostCPUName();
|
||||
const llvm_cpu_features = llvm.GetNativeFeatures();
|
||||
break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features);
|
||||
},
|
||||
.Cross => target.getCpu(),
|
||||
fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
var dynamic_linker: ?[*:0]u8 = null;
|
||||
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
|
||||
|
||||
var cache_hash = try std.Buffer.allocPrint(allocator, "{}\n{}\n", .{
|
||||
target.cpu.model.name,
|
||||
target.cpu.features.asBytes(),
|
||||
});
|
||||
defer cache_hash.deinit();
|
||||
|
||||
const generic_arch_name = target.cpu.arch.genericName();
|
||||
var cpu_builtin_str_buffer = try std.Buffer.allocPrint(allocator,
|
||||
\\Cpu{{
|
||||
\\ .arch = .{},
|
||||
\\ .model = &Target.{}.cpu.{},
|
||||
\\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
|
||||
\\
|
||||
, .{
|
||||
@tagName(target.cpu.arch),
|
||||
generic_arch_name,
|
||||
target.cpu.model.name,
|
||||
generic_arch_name,
|
||||
generic_arch_name,
|
||||
});
|
||||
defer cpu_builtin_str_buffer.deinit();
|
||||
|
||||
var llvm_features_buffer = try std.Buffer.initSize(allocator, 0);
|
||||
defer llvm_features_buffer.deinit();
|
||||
|
||||
for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
|
||||
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
|
||||
const is_enabled = target.cpu.features.isEnabled(index);
|
||||
|
||||
if (feature.llvm_name) |llvm_name| {
|
||||
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
|
||||
try llvm_features_buffer.appendByte(plus_or_minus);
|
||||
try llvm_features_buffer.append(llvm_name);
|
||||
try llvm_features_buffer.append(",");
|
||||
}
|
||||
|
||||
if (is_enabled) {
|
||||
// TODO some kind of "zig identifier escape" function rather than
|
||||
// unconditionally using @"" syntax
|
||||
try cpu_builtin_str_buffer.append(" .@\"");
|
||||
try cpu_builtin_str_buffer.append(feature.name);
|
||||
try cpu_builtin_str_buffer.append("\",\n");
|
||||
}
|
||||
}
|
||||
|
||||
try cpu_builtin_str_buffer.append(
|
||||
\\ }),
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
|
||||
assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ","));
|
||||
llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
|
||||
|
||||
var os_builtin_str_buffer = try std.Buffer.allocPrint(allocator,
|
||||
\\Os{{
|
||||
\\ .tag = .{},
|
||||
\\ .version_range = .{{
|
||||
, .{@tagName(target.os.tag)});
|
||||
defer os_builtin_str_buffer.deinit();
|
||||
|
||||
// We'll re-use the OS version range builtin string for the cache hash.
|
||||
const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
|
||||
|
||||
@setEvalBranchQuota(2000);
|
||||
switch (target.os.tag) {
|
||||
.freestanding,
|
||||
.ananas,
|
||||
.cloudabi,
|
||||
.dragonfly,
|
||||
.fuchsia,
|
||||
.ios,
|
||||
.kfreebsd,
|
||||
.lv2,
|
||||
.solaris,
|
||||
.haiku,
|
||||
.minix,
|
||||
.rtems,
|
||||
.nacl,
|
||||
.cnk,
|
||||
.aix,
|
||||
.cuda,
|
||||
.nvcl,
|
||||
.amdhsa,
|
||||
.ps4,
|
||||
.elfiamcu,
|
||||
.tvos,
|
||||
.watchos,
|
||||
.mesa3d,
|
||||
.contiki,
|
||||
.amdpal,
|
||||
.hermit,
|
||||
.hurd,
|
||||
.wasi,
|
||||
.emscripten,
|
||||
.uefi,
|
||||
.other,
|
||||
=> try os_builtin_str_buffer.append(" .none = {} }\n"),
|
||||
|
||||
.freebsd,
|
||||
.macosx,
|
||||
.netbsd,
|
||||
.openbsd,
|
||||
=> try os_builtin_str_buffer.print(
|
||||
\\ .semver = .{{
|
||||
\\ .min = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ .max = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ }}}},
|
||||
\\
|
||||
, .{
|
||||
target.os.version_range.semver.min.major,
|
||||
target.os.version_range.semver.min.minor,
|
||||
target.os.version_range.semver.min.patch,
|
||||
|
||||
target.os.version_range.semver.max.major,
|
||||
target.os.version_range.semver.max.minor,
|
||||
target.os.version_range.semver.max.patch,
|
||||
}),
|
||||
|
||||
.linux => try os_builtin_str_buffer.print(
|
||||
\\ .linux = .{{
|
||||
\\ .range = .{{
|
||||
\\ .min = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ .max = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ }},
|
||||
\\ .glibc = .{{
|
||||
\\ .major = {},
|
||||
\\ .minor = {},
|
||||
\\ .patch = {},
|
||||
\\ }},
|
||||
\\ }}}},
|
||||
\\
|
||||
, .{
|
||||
target.os.version_range.linux.range.min.major,
|
||||
target.os.version_range.linux.range.min.minor,
|
||||
target.os.version_range.linux.range.min.patch,
|
||||
|
||||
target.os.version_range.linux.range.max.major,
|
||||
target.os.version_range.linux.range.max.minor,
|
||||
target.os.version_range.linux.range.max.patch,
|
||||
|
||||
target.os.version_range.linux.glibc.major,
|
||||
target.os.version_range.linux.glibc.minor,
|
||||
target.os.version_range.linux.glibc.patch,
|
||||
}),
|
||||
|
||||
.windows => try os_builtin_str_buffer.print(
|
||||
\\ .windows = .{{
|
||||
\\ .min = .{},
|
||||
\\ .max = .{},
|
||||
\\ }}}},
|
||||
\\
|
||||
, .{
|
||||
@tagName(target.os.version_range.windows.min),
|
||||
@tagName(target.os.version_range.windows.max),
|
||||
}),
|
||||
}
|
||||
try os_builtin_str_buffer.append("};\n");
|
||||
|
||||
try cache_hash.append(
|
||||
os_builtin_str_buffer.toSlice()[os_builtin_str_ver_start_index..os_builtin_str_buffer.len()],
|
||||
);
|
||||
|
||||
const glibc_or_darwin_version = blk: {
|
||||
if (target.isGnuLibC()) {
|
||||
const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
|
||||
const stage2_glibc = target.os.version_range.linux.glibc;
|
||||
stage1_glibc.* = .{
|
||||
.major = stage2_glibc.major,
|
||||
.minor = stage2_glibc.minor,
|
||||
.patch = stage2_glibc.patch,
|
||||
};
|
||||
break :blk stage1_glibc;
|
||||
} else if (target.isDarwin()) {
|
||||
const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
|
||||
const stage2_semver = target.os.version_range.semver.min;
|
||||
stage1_semver.* = .{
|
||||
.major = stage2_semver.major,
|
||||
.minor = stage2_semver.minor,
|
||||
.patch = stage2_semver.patch,
|
||||
};
|
||||
break :blk stage1_semver;
|
||||
} else {
|
||||
break :blk null;
|
||||
}
|
||||
};
|
||||
|
||||
self.* = .{
|
||||
.arch = @enumToInt(target.getArch()) + 1, // skip over ZigLLVM_UnknownArch
|
||||
.arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
|
||||
.vendor = 0,
|
||||
.os = @enumToInt(target.getOs()),
|
||||
.abi = @enumToInt(target.getAbi()),
|
||||
.llvm_cpu_name = null,
|
||||
.llvm_cpu_features = null,
|
||||
.builtin_str = null,
|
||||
.cache_hash = null,
|
||||
.is_native = target == .Native,
|
||||
.glibc_version = null,
|
||||
.os = @enumToInt(target.os.tag),
|
||||
.abi = @enumToInt(target.abi),
|
||||
.llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
|
||||
.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
|
||||
.cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
|
||||
.os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
|
||||
.cache_hash = cache_hash.toOwnedSlice().ptr,
|
||||
.is_native = cross_target.isNative(),
|
||||
.glibc_or_darwin_version = glibc_or_darwin_version,
|
||||
.dynamic_linker = dynamic_linker,
|
||||
};
|
||||
try initStage1TargetCpuFeatures(self, cpu);
|
||||
}
|
||||
};
|
||||
|
||||
// ABI warning
|
||||
const Stage2GLibCVersion = extern struct {
|
||||
major: u32,
|
||||
minor: u32,
|
||||
patch: u32,
|
||||
};
|
||||
|
||||
// ABI warning
|
||||
export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
|
||||
const target = in_target.toTarget();
|
||||
const result = @import("introspect.zig").detectDynamicLinker(
|
||||
std.heap.c_allocator,
|
||||
target,
|
||||
) catch |err| switch (err) {
|
||||
error.OutOfMemory => return .OutOfMemory,
|
||||
error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
|
||||
error.TargetHasNoDynamicLinker => return .TargetHasNoDynamicLinker,
|
||||
};
|
||||
out_ptr.* = result.ptr;
|
||||
out_len.* = result.len;
|
||||
return .None;
|
||||
}
|
||||
|
||||
fn enumInt(comptime Enum: type, int: c_int) Enum {
|
||||
return @intToEnum(Enum, @intCast(@TagType(Enum), int));
|
||||
}
|
||||
|
||||
fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
|
||||
var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
|
||||
if (cross_target.cpu_arch == null or cross_target.cpu_model == .native) {
|
||||
// TODO We want to just use detected_info.target but implementing
|
||||
// CPU model & feature detection is todo so here we rely on LLVM.
|
||||
const llvm = @import("llvm.zig");
|
||||
const llvm_cpu_name = llvm.GetHostCPUName();
|
||||
const llvm_cpu_features = llvm.GetNativeFeatures();
|
||||
const arch = std.Target.current.cpu.arch;
|
||||
info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
|
||||
cross_target.updateCpuFeatures(&info.target.cpu.features);
|
||||
info.target.cpu.arch = cross_target.getCpuArch();
|
||||
}
|
||||
if (info.dynamic_linker.get()) |dl| {
|
||||
dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
|
||||
} else {
|
||||
dynamic_linker_ptr.* = null;
|
||||
}
|
||||
return info.target;
|
||||
}
|
||||
|
||||
// ABI warning
|
||||
const Stage2SemVer = extern struct {
|
||||
major: u32,
|
||||
minor: u32,
|
||||
patch: u32,
|
||||
};
|
||||
|
||||
// ABI warning
|
||||
const Stage2NativePaths = extern struct {
|
||||
include_dirs_ptr: [*][*:0]u8,
|
||||
|
@ -4850,7 +4850,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
|
||||
}
|
||||
|
||||
const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
|
||||
const slice = begin_c[0..mem.len(u8, begin_c)];
|
||||
const slice = begin_c[0..mem.len(begin_c)];
|
||||
|
||||
tok_list.shrink(0);
|
||||
var tokenizer = std.c.Tokenizer{
|
||||
|
@ -34,25 +34,3 @@ pub fn initializeAllTargets() void {
|
||||
llvm.InitializeAllAsmPrinters();
|
||||
llvm.InitializeAllAsmParsers();
|
||||
}
|
||||
|
||||
pub fn getTriple(allocator: *std.mem.Allocator, self: std.Target) !std.Buffer {
|
||||
var result = try std.Buffer.initSize(allocator, 0);
|
||||
errdefer result.deinit();
|
||||
|
||||
// LLVM WebAssembly output support requires the target to be activated at
|
||||
// build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
|
||||
//
|
||||
// LLVM determines the output format based on the abi suffix,
|
||||
// defaulting to an object based on the architecture. The default format in
|
||||
// LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
|
||||
// explicitly set this ourself in order for it to work.
|
||||
//
|
||||
// This is fixed in LLVM 7 and you will be able to get wasm output by
|
||||
// using the target triple `wasm32-unknown-unknown-unknown`.
|
||||
const env_name = if (self.isWasm()) "wasm" else @tagName(self.getAbi());
|
||||
|
||||
var out = &std.io.BufferOutStream.init(&result).stream;
|
||||
try out.print("{}-unknown-{}-{}", .{ @tagName(self.getArch()), @tagName(self.getOs()), env_name });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -2249,14 +2249,11 @@ struct CodeGen {
|
||||
bool test_is_evented;
|
||||
CodeModel code_model;
|
||||
|
||||
Buf *mmacosx_version_min;
|
||||
Buf *mios_version_min;
|
||||
Buf *root_out_name;
|
||||
Buf *test_filter;
|
||||
Buf *test_name_prefix;
|
||||
Buf *zig_lib_dir;
|
||||
Buf *zig_std_dir;
|
||||
Buf *dynamic_linker_path;
|
||||
Buf *version_script_path;
|
||||
|
||||
const char **llvm_argv;
|
||||
@ -3266,7 +3263,6 @@ struct IrInstSrcContainerInitList {
|
||||
struct IrInstSrcContainerInitFieldsField {
|
||||
Buf *name;
|
||||
AstNode *source_node;
|
||||
TypeStructField *type_struct_field;
|
||||
IrInstSrc *result_loc;
|
||||
};
|
||||
|
||||
|
153
src/analyze.cpp
153
src/analyze.cpp
@ -1131,18 +1131,26 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
|
||||
Error err;
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
assert(type_val->special == ConstValSpecialStatic);
|
||||
if ((type_val->data.x_type->id == ZigTypeIdStruct &&
|
||||
type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) ||
|
||||
(type_val->data.x_type->id == ZigTypeIdUnion &&
|
||||
type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits) ||
|
||||
type_val->data.x_type->id == ZigTypeIdPointer)
|
||||
|
||||
// Self-referencing types via pointers are allowed and have non-zero size
|
||||
ZigType *ty = type_val->data.x_type;
|
||||
while (ty->id == ZigTypeIdPointer &&
|
||||
!ty->data.pointer.resolve_loop_flag_zero_bits)
|
||||
{
|
||||
ty = ty->data.pointer.child_type;
|
||||
}
|
||||
|
||||
if ((ty->id == ZigTypeIdStruct && ty->data.structure.resolve_loop_flag_zero_bits) ||
|
||||
(ty->id == ZigTypeIdUnion && ty->data.unionation.resolve_loop_flag_zero_bits) ||
|
||||
(ty->id == ZigTypeIdPointer && ty->data.pointer.resolve_loop_flag_zero_bits))
|
||||
{
|
||||
// Does a struct/union which contains a pointer field to itself have bits? Yes.
|
||||
*is_zero_bits = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))
|
||||
return err;
|
||||
|
||||
*is_zero_bits = (type_val->data.x_type->abi_size == 0);
|
||||
return ErrorNone;
|
||||
}
|
||||
@ -3955,7 +3963,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
|
||||
|
||||
// TODO more validation for types that can't be used for export/extern variables
|
||||
ZigType *implicit_type = nullptr;
|
||||
if (explicit_type != nullptr && explicit_type->id == ZigTypeIdInvalid) {
|
||||
if (explicit_type != nullptr && type_is_invalid(explicit_type)) {
|
||||
implicit_type = explicit_type;
|
||||
} else if (var_decl->expr) {
|
||||
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) {
|
||||
if (return_err_set_type->data.error_set.infer_fn != nullptr &&
|
||||
return_err_set_type->data.error_set.incomplete)
|
||||
{
|
||||
ZigType *inferred_err_set_type;
|
||||
// The inferred error set type is null if the function doesn't
|
||||
// return any error
|
||||
ZigType *inferred_err_set_type = nullptr;
|
||||
|
||||
if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
|
||||
inferred_err_set_type = fn->src_implicit_return_type;
|
||||
} else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
|
||||
inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
|
||||
} else {
|
||||
add_node_error(g, return_type_node,
|
||||
buf_sprintf("function with inferred error set must return at least one possible error"));
|
||||
fn->anal_state = FnAnalStateInvalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (inferred_err_set_type->data.error_set.infer_fn != nullptr &&
|
||||
inferred_err_set_type->data.error_set.incomplete)
|
||||
{
|
||||
if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
|
||||
fn->anal_state = FnAnalStateInvalid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return_err_set_type->data.error_set.incomplete = false;
|
||||
if (type_is_global_error_set(inferred_err_set_type)) {
|
||||
return_err_set_type->data.error_set.err_count = UINT32_MAX;
|
||||
} else {
|
||||
return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
|
||||
if (inferred_err_set_type->data.error_set.err_count > 0) {
|
||||
return_err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);
|
||||
for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {
|
||||
return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];
|
||||
if (inferred_err_set_type != nullptr) {
|
||||
if (inferred_err_set_type->data.error_set.infer_fn != nullptr &&
|
||||
inferred_err_set_type->data.error_set.incomplete)
|
||||
{
|
||||
if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
|
||||
fn->anal_state = FnAnalStateInvalid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return_err_set_type->data.error_set.incomplete = false;
|
||||
if (type_is_global_error_set(inferred_err_set_type)) {
|
||||
return_err_set_type->data.error_set.err_count = UINT32_MAX;
|
||||
} else {
|
||||
return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
|
||||
if (inferred_err_set_type->data.error_set.err_count > 0) {
|
||||
return_err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);
|
||||
for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {
|
||||
return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return_err_set_type->data.error_set.incomplete = false;
|
||||
return_err_set_type->data.error_set.err_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5390,6 +5401,8 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
|
||||
|
||||
static bool can_mutate_comptime_var_state(ZigValue *value) {
|
||||
assert(value != nullptr);
|
||||
if (value->special == ConstValSpecialUndef)
|
||||
return false;
|
||||
switch (value->type->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -5418,6 +5431,8 @@ static bool can_mutate_comptime_var_state(ZigValue *value) {
|
||||
return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
|
||||
|
||||
case ZigTypeIdArray:
|
||||
if (value->special == ConstValSpecialUndef)
|
||||
return false;
|
||||
if (value->type->data.array.len == 0)
|
||||
return false;
|
||||
switch (value->data.x_array.special) {
|
||||
@ -6690,8 +6705,16 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
|
||||
}
|
||||
|
||||
static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_t len) {
|
||||
assert(a->data.x_array.special != ConstArraySpecialUndef);
|
||||
assert(b->data.x_array.special != ConstArraySpecialUndef);
|
||||
if (a->data.x_array.special == ConstArraySpecialUndef &&
|
||||
b->data.x_array.special == ConstArraySpecialUndef)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (a->data.x_array.special == ConstArraySpecialUndef ||
|
||||
b->data.x_array.special == ConstArraySpecialUndef)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (a->data.x_array.special == ConstArraySpecialBuf &&
|
||||
b->data.x_array.special == ConstArraySpecialBuf)
|
||||
{
|
||||
@ -6713,8 +6736,6 @@ static bool const_values_equal_array(CodeGen *g, ZigValue *a, ZigValue *b, size_
|
||||
|
||||
bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
|
||||
if (a->type->id != b->type->id) return false;
|
||||
assert(a->special == ConstValSpecialStatic);
|
||||
assert(b->special == ConstValSpecialStatic);
|
||||
if (a->type == b->type) {
|
||||
switch (type_has_one_possible_value(g, a->type)) {
|
||||
case OnePossibleValueInvalid:
|
||||
@ -6725,6 +6746,11 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (a->special == ConstValSpecialUndef || b->special == ConstValSpecialUndef) {
|
||||
return a->special == b->special;
|
||||
}
|
||||
assert(a->special == ConstValSpecialStatic);
|
||||
assert(b->special == ConstValSpecialStatic);
|
||||
switch (a->type->id) {
|
||||
case ZigTypeIdOpaque:
|
||||
zig_unreachable();
|
||||
@ -8708,7 +8734,6 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
|
||||
if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return;
|
||||
}
|
||||
|
||||
LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
|
||||
ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
|
||||
if (type->data.maybe.resolve_status >= wanted_resolve_status) return;
|
||||
|
||||
@ -8718,35 +8743,28 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus
|
||||
};
|
||||
LLVMStructSetBody(type->llvm_type, elem_types, 2, false);
|
||||
|
||||
uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type);
|
||||
uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type);
|
||||
uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
|
||||
uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_child_index);
|
||||
uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, maybe_null_index);
|
||||
|
||||
uint64_t maybe_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, bool_llvm_type);
|
||||
uint64_t maybe_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, bool_llvm_type);
|
||||
uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1);
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
|
||||
|
||||
ZigLLVMDIType *di_element_types[] = {
|
||||
ZigLLVMDIType *di_element_types[2];
|
||||
di_element_types[maybe_child_index] =
|
||||
ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
|
||||
"val", di_file, line,
|
||||
val_debug_size_in_bits,
|
||||
val_debug_align_in_bits,
|
||||
8 * child_type->abi_size,
|
||||
8 * child_type->abi_align,
|
||||
val_offset_in_bits,
|
||||
ZigLLVM_DIFlags_Zero, child_llvm_di_type),
|
||||
ZigLLVM_DIFlags_Zero, child_llvm_di_type);
|
||||
di_element_types[maybe_null_index] =
|
||||
ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
|
||||
"maybe", di_file, line,
|
||||
maybe_debug_size_in_bits,
|
||||
maybe_debug_align_in_bits,
|
||||
8*g->builtin_types.entry_bool->abi_size,
|
||||
8*g->builtin_types.entry_bool->abi_align,
|
||||
maybe_offset_in_bits,
|
||||
ZigLLVM_DIFlags_Zero, bool_llvm_di_type),
|
||||
};
|
||||
ZigLLVM_DIFlags_Zero, bool_llvm_di_type);
|
||||
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
|
||||
compile_unit_scope,
|
||||
buf_ptr(&type->name),
|
||||
di_file, line, debug_size_in_bits, debug_align_in_bits, ZigLLVM_DIFlags_Zero,
|
||||
di_file, line, 8 * type->abi_size, 8 * type->abi_align, ZigLLVM_DIFlags_Zero,
|
||||
nullptr, di_element_types, 2, 0, nullptr, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
|
||||
@ -9387,13 +9405,24 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) {
|
||||
dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i;
|
||||
}
|
||||
} else if (dest->type->id == ZigTypeIdArray) {
|
||||
if (dest->data.x_array.special == ConstArraySpecialNone) {
|
||||
dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(dest->type->data.array.len);
|
||||
for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) {
|
||||
copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]);
|
||||
dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray;
|
||||
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest;
|
||||
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i;
|
||||
switch (dest->data.x_array.special) {
|
||||
case ConstArraySpecialNone: {
|
||||
dest->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(dest->type->data.array.len);
|
||||
for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) {
|
||||
copy_const_val(g, &dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]);
|
||||
dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray;
|
||||
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest;
|
||||
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConstArraySpecialUndef: {
|
||||
// Nothing to copy; the above memcpy did everything we needed.
|
||||
break;
|
||||
}
|
||||
case ConstArraySpecialBuf: {
|
||||
dest->data.x_array.data.s_buf = buf_create_from_buf(src->data.x_array.data.s_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) {
|
||||
|
147
src/codegen.cpp
147
src/codegen.cpp
@ -32,31 +32,6 @@ enum ResumeId {
|
||||
ResumeIdCall,
|
||||
};
|
||||
|
||||
static void init_darwin_native(CodeGen *g) {
|
||||
char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
|
||||
char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
|
||||
|
||||
// Allow conflicts among OSX and iOS, but choose the default platform.
|
||||
if (osx_target && ios_target) {
|
||||
if (g->zig_target->arch == ZigLLVM_arm ||
|
||||
g->zig_target->arch == ZigLLVM_aarch64 ||
|
||||
g->zig_target->arch == ZigLLVM_thumb)
|
||||
{
|
||||
osx_target = nullptr;
|
||||
} else {
|
||||
ios_target = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (osx_target) {
|
||||
g->mmacosx_version_min = buf_create_from_str(osx_target);
|
||||
} else if (ios_target) {
|
||||
g->mios_version_min = buf_create_from_str(ios_target);
|
||||
} else if (g->zig_target->os != OsIOS) {
|
||||
g->mmacosx_version_min = buf_create_from_str("10.14");
|
||||
}
|
||||
}
|
||||
|
||||
static ZigPackage *new_package(const char *root_src_dir, const char *root_src_path, const char *pkg_path) {
|
||||
ZigPackage *entry = heap::c_allocator.create<ZigPackage>();
|
||||
entry->package_table.init(4);
|
||||
@ -160,14 +135,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) {
|
||||
g->darwin_frameworks.append(buf_create_from_str(framework));
|
||||
}
|
||||
|
||||
void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) {
|
||||
g->mmacosx_version_min = mmacosx_version_min;
|
||||
}
|
||||
|
||||
void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min) {
|
||||
g->mios_version_min = mios_version_min;
|
||||
}
|
||||
|
||||
void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
|
||||
g->linker_rdynamic = rdynamic;
|
||||
}
|
||||
@ -972,7 +939,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
||||
case PanicMsgIdExactDivisionRemainder:
|
||||
return buf_create_from_str("exact division produced remainder");
|
||||
case PanicMsgIdUnwrapOptionalFail:
|
||||
return buf_create_from_str("attempt to unwrap null");
|
||||
return buf_create_from_str("attempt to use null value");
|
||||
case PanicMsgIdUnreachable:
|
||||
return buf_create_from_str("reached unreachable code");
|
||||
case PanicMsgIdInvalidErrorCode:
|
||||
@ -3325,11 +3292,24 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
|
||||
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
|
||||
size_t field_count = wanted_type->data.enumeration.src_field_count;
|
||||
LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
|
||||
|
||||
HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
occupied_tag_values.init(field_count);
|
||||
|
||||
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
|
||||
TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
|
||||
|
||||
Buf *name = type_enum_field->name;
|
||||
auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
|
||||
if (entry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
|
||||
&wanted_type->data.enumeration.fields[field_i].value);
|
||||
&type_enum_field->value);
|
||||
LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
|
||||
}
|
||||
occupied_tag_values.deinit();
|
||||
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
|
||||
gen_safety_crash(g, PanicMsgIdBadEnumValue);
|
||||
|
||||
@ -4466,7 +4446,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutableGen *execu
|
||||
|
||||
if (!type_has_bits(field->type_entry)) {
|
||||
ZigType *tag_type = union_type->data.unionation.tag_type;
|
||||
if (!instruction->initializing || !type_has_bits(tag_type))
|
||||
if (!instruction->initializing || tag_type == nullptr || !type_has_bits(tag_type))
|
||||
return nullptr;
|
||||
|
||||
// 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) {
|
||||
LLVMConstNull(usize->llvm_type),
|
||||
};
|
||||
|
||||
HashMap<BigInt, Buf *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
occupied_tag_values.init(field_count);
|
||||
|
||||
for (size_t field_i = 0; field_i < field_count; field_i += 1) {
|
||||
Buf *name = enum_type->data.enumeration.fields[field_i].name;
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
|
||||
|
||||
Buf *name = type_enum_field->name;
|
||||
auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
|
||||
if (entry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true);
|
||||
LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
|
||||
LLVMSetInitializer(str_global, str_init);
|
||||
@ -5057,6 +5047,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
|
||||
LLVMPositionBuilderAtEnd(g->builder, return_block);
|
||||
LLVMBuildRet(g->builder, slice_global);
|
||||
}
|
||||
occupied_tag_values.deinit();
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
|
||||
if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) {
|
||||
@ -5081,11 +5072,6 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutableGen *executa
|
||||
{
|
||||
ZigType *enum_type = instruction->target->value->type;
|
||||
assert(enum_type->id == ZigTypeIdEnum);
|
||||
if (enum_type->data.enumeration.non_exhaustive) {
|
||||
add_node_error(g, instruction->base.base.source_node,
|
||||
buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
|
||||
codegen_report_errors_and_exit(g);
|
||||
}
|
||||
|
||||
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
|
||||
|
||||
@ -8518,25 +8504,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
|
||||
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
|
||||
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
|
||||
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
|
||||
buf_append_str(contents, "/// Deprecated: use `std.Target.cpu.arch`\n");
|
||||
buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
|
||||
buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
|
||||
{
|
||||
buf_append_str(contents, "pub const cpu: Cpu = ");
|
||||
if (g->zig_target->builtin_str != nullptr) {
|
||||
buf_append_str(contents, g->zig_target->builtin_str);
|
||||
if (g->zig_target->cpu_builtin_str != nullptr) {
|
||||
buf_append_str(contents, g->zig_target->cpu_builtin_str);
|
||||
} else {
|
||||
buf_append_str(contents, "Target.Cpu.baseline(arch);\n");
|
||||
buf_appendf(contents, "Target.Cpu.baseline(.%s);\n", cur_arch);
|
||||
}
|
||||
}
|
||||
if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {
|
||||
buf_appendf(contents,
|
||||
"pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n",
|
||||
g->zig_target->glibc_version->major,
|
||||
g->zig_target->glibc_version->minor,
|
||||
g->zig_target->glibc_version->patch);
|
||||
} else {
|
||||
buf_appendf(contents, "pub const glibc_version: ?Version = null;\n");
|
||||
{
|
||||
buf_append_str(contents, "pub const os = ");
|
||||
if (g->zig_target->os_builtin_str != nullptr) {
|
||||
buf_append_str(contents, g->zig_target->os_builtin_str);
|
||||
} else {
|
||||
buf_appendf(contents, "Target.Os.defaultVersionRange(.%s);\n", cur_os);
|
||||
}
|
||||
}
|
||||
buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
|
||||
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) {
|
||||
if (g->zig_target->cache_hash != nullptr) {
|
||||
cache_str(&cache_hash, g->zig_target->cache_hash);
|
||||
}
|
||||
if (g->zig_target->glibc_version != nullptr) {
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->major);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->minor);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->patch);
|
||||
if (g->zig_target->glibc_or_darwin_version != nullptr) {
|
||||
cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->major);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->minor);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->patch);
|
||||
}
|
||||
cache_bool(&cache_hash, g->have_err_ret_tracing);
|
||||
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
|
||||
@ -8841,28 +8826,6 @@ static void init(CodeGen *g) {
|
||||
}
|
||||
}
|
||||
|
||||
static void detect_dynamic_linker(CodeGen *g) {
|
||||
Error err;
|
||||
|
||||
if (g->dynamic_linker_path != nullptr)
|
||||
return;
|
||||
if (!g->have_dynamic_link)
|
||||
return;
|
||||
if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
|
||||
return;
|
||||
|
||||
char *dynamic_linker_ptr;
|
||||
size_t dynamic_linker_len;
|
||||
if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
|
||||
if (err == ErrorTargetHasNoDynamicLinker) return;
|
||||
fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
|
||||
// Skips heap::c_allocator because the memory is allocated by stage2 library.
|
||||
free(dynamic_linker_ptr);
|
||||
}
|
||||
|
||||
static void detect_libc(CodeGen *g) {
|
||||
Error err;
|
||||
|
||||
@ -10298,10 +10261,13 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
if (g->zig_target->cache_hash != nullptr) {
|
||||
cache_str(ch, g->zig_target->cache_hash);
|
||||
}
|
||||
if (g->zig_target->glibc_version != nullptr) {
|
||||
cache_int(ch, g->zig_target->glibc_version->major);
|
||||
cache_int(ch, g->zig_target->glibc_version->minor);
|
||||
cache_int(ch, g->zig_target->glibc_version->patch);
|
||||
if (g->zig_target->glibc_or_darwin_version != nullptr) {
|
||||
cache_int(ch, g->zig_target->glibc_or_darwin_version->major);
|
||||
cache_int(ch, g->zig_target->glibc_or_darwin_version->minor);
|
||||
cache_int(ch, g->zig_target->glibc_or_darwin_version->patch);
|
||||
}
|
||||
if (g->zig_target->dynamic_linker != nullptr) {
|
||||
cache_str(ch, g->zig_target->dynamic_linker);
|
||||
}
|
||||
cache_int(ch, detect_subsystem(g));
|
||||
cache_bool(ch, g->strip_debug_symbols);
|
||||
@ -10329,8 +10295,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
cache_bool(ch, g->emit_bin);
|
||||
cache_bool(ch, g->emit_llvm_ir);
|
||||
cache_bool(ch, g->emit_asm);
|
||||
cache_buf_opt(ch, g->mmacosx_version_min);
|
||||
cache_buf_opt(ch, g->mios_version_min);
|
||||
cache_usize(ch, g->version_major);
|
||||
cache_usize(ch, g->version_minor);
|
||||
cache_usize(ch, g->version_patch);
|
||||
@ -10345,7 +10309,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
cache_str(ch, g->libc->msvc_lib_dir);
|
||||
cache_str(ch, g->libc->kernel32_lib_dir);
|
||||
}
|
||||
cache_buf_opt(ch, g->dynamic_linker_path);
|
||||
cache_buf_opt(ch, g->version_script_path);
|
||||
|
||||
// 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) {
|
||||
g->have_err_ret_tracing = detect_err_ret_tracing(g);
|
||||
g->have_sanitize_c = detect_sanitize_c(g);
|
||||
detect_libc(g);
|
||||
detect_dynamic_linker(g);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
if (g->enable_cache) {
|
||||
@ -10639,7 +10601,6 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o
|
||||
child_gen->verbose_cc = parent_gen->verbose_cc;
|
||||
child_gen->verbose_llvm_cpu_features = parent_gen->verbose_llvm_cpu_features;
|
||||
child_gen->llvm_argv = parent_gen->llvm_argv;
|
||||
child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path;
|
||||
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
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
|
||||
|
||||
codegen_set_errmsg_color(child_gen, parent_gen->err_color);
|
||||
|
||||
codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
|
||||
codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
|
||||
|
||||
child_gen->enable_cache = true;
|
||||
|
||||
return child_gen;
|
||||
@ -10757,11 +10715,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
|
||||
g->each_lib_rpath = false;
|
||||
} else {
|
||||
g->each_lib_rpath = true;
|
||||
|
||||
if (target_os_is_darwin(g->zig_target->os)) {
|
||||
init_darwin_native(g);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (target_os_requires_libc(g->zig_target->os)) {
|
||||
|
@ -35,8 +35,6 @@ LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
|
||||
void codegen_add_framework(CodeGen *codegen, const char *name);
|
||||
void codegen_add_rpath(CodeGen *codegen, const char *name);
|
||||
void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
|
||||
void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
|
||||
void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
|
||||
void codegen_set_linker_script(CodeGen *g, const char *linker_script);
|
||||
void codegen_set_test_filter(CodeGen *g, Buf *filter);
|
||||
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
|
||||
|
@ -4,31 +4,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Buf *get_self_libc_path(void) {
|
||||
static Buf saved_libc_path = BUF_INIT;
|
||||
static bool searched_for_libc = false;
|
||||
|
||||
for (;;) {
|
||||
if (saved_libc_path.list.length != 0) {
|
||||
return &saved_libc_path;
|
||||
}
|
||||
if (searched_for_libc)
|
||||
return nullptr;
|
||||
ZigList<Buf *> lib_paths = {};
|
||||
Error err;
|
||||
if ((err = os_self_exe_shared_libs(lib_paths)))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < lib_paths.length; i += 1) {
|
||||
Buf *lib_path = lib_paths.at(i);
|
||||
if (buf_ends_with_str(lib_path, "libc.so.6")) {
|
||||
buf_init_from_buf(&saved_libc_path, lib_path);
|
||||
return &saved_libc_path;
|
||||
}
|
||||
}
|
||||
searched_for_libc = true;
|
||||
}
|
||||
}
|
||||
|
||||
Error get_compiler_id(Buf **result) {
|
||||
static Buf saved_compiler_id = BUF_INIT;
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "error.hpp"
|
||||
|
||||
Error get_compiler_id(Buf **result);
|
||||
Buf *get_self_libc_path(void);
|
||||
|
||||
Buf *get_zig_lib_dir(void);
|
||||
Buf *get_zig_special_dir(Buf *zig_lib_dir);
|
||||
|
@ -81,6 +81,8 @@ const char *err_str(Error err) {
|
||||
case ErrorWindowsSdkNotFound: return "Windows SDK not found";
|
||||
case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path";
|
||||
case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker";
|
||||
case ErrorInvalidAbiVersion: return "invalid C ABI version";
|
||||
case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
|
||||
}
|
||||
return "(invalid error)";
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) break;
|
||||
Buf *ver_buf = buf_create_from_slice(opt_component.value);
|
||||
ZigGLibCVersion *this_ver = glibc_abi->all_versions.add_one();
|
||||
Stage2SemVer *this_ver = glibc_abi->all_versions.add_one();
|
||||
if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {
|
||||
if (verbose) {
|
||||
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
|
||||
cache_buf(cache_hash, compiler_id);
|
||||
cache_int(cache_hash, target->arch);
|
||||
cache_int(cache_hash, target->abi);
|
||||
cache_int(cache_hash, target->glibc_version->major);
|
||||
cache_int(cache_hash, target->glibc_version->minor);
|
||||
cache_int(cache_hash, target->glibc_version->patch);
|
||||
cache_int(cache_hash, target->glibc_or_darwin_version->major);
|
||||
cache_int(cache_hash, target->glibc_or_darwin_version->minor);
|
||||
cache_int(cache_hash, target->glibc_or_darwin_version->patch);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
@ -224,10 +224,10 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
|
||||
|
||||
uint8_t target_ver_index = 0;
|
||||
for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) {
|
||||
const ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(target_ver_index);
|
||||
if (this_ver->major == target->glibc_version->major &&
|
||||
this_ver->minor == target->glibc_version->minor &&
|
||||
this_ver->patch == target->glibc_version->patch)
|
||||
const Stage2SemVer *this_ver = &glibc_abi->all_versions.at(target_ver_index);
|
||||
if (this_ver->major == target->glibc_or_darwin_version->major &&
|
||||
this_ver->minor == target->glibc_or_darwin_version->minor &&
|
||||
this_ver->patch == target->glibc_or_darwin_version->patch)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -235,9 +235,9 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
|
||||
if (target_ver_index == glibc_abi->all_versions.length) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",
|
||||
target->glibc_version->major,
|
||||
target->glibc_version->minor,
|
||||
target->glibc_version->patch);
|
||||
target->glibc_or_darwin_version->major,
|
||||
target->glibc_or_darwin_version->minor,
|
||||
target->glibc_or_darwin_version->patch);
|
||||
}
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
@ -246,7 +246,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
|
||||
Buf *map_contents = buf_alloc();
|
||||
|
||||
for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) {
|
||||
const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_i);
|
||||
const Stage2SemVer *ver = &glibc_abi->all_versions.at(ver_i);
|
||||
if (ver->patch == 0) {
|
||||
buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);
|
||||
} else {
|
||||
@ -294,7 +294,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
|
||||
uint8_t ver_index = ver_list->versions[ver_i];
|
||||
|
||||
Buf *stub_name;
|
||||
const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_index);
|
||||
const Stage2SemVer *ver = &glibc_abi->all_versions.at(ver_index);
|
||||
const char *sym_name = buf_ptr(libc_fn->name);
|
||||
if (ver->patch == 0) {
|
||||
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) {
|
||||
a->abi == b->abi;
|
||||
}
|
||||
|
||||
#ifdef ZIG_OS_LINUX
|
||||
#include <unistd.h>
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
|
||||
Buf *self_libc_path = get_self_libc_path();
|
||||
if (self_libc_path == nullptr) {
|
||||
// TODO There is still more we could do to detect the native glibc version. For example,
|
||||
// we could look at the ELF file of `/usr/bin/env`, find `libc.so.6`, and then `readlink`
|
||||
// to find out the glibc version. This is relevant for the static zig builds distributed
|
||||
// on the download page, since the above detection based on zig's own dynamic linking
|
||||
// will not work.
|
||||
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
Buf *link_name = buf_alloc();
|
||||
buf_resize(link_name, 4096);
|
||||
ssize_t amt = readlink(buf_ptr(self_libc_path), buf_ptr(link_name), buf_len(link_name));
|
||||
if (amt == -1) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
buf_resize(link_name, amt);
|
||||
if (!buf_starts_with_str(link_name, "libc-") || !buf_ends_with_str(link_name, ".so")) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
// example: "libc-2.3.4.so"
|
||||
// example: "libc-2.27.so"
|
||||
buf_resize(link_name, buf_len(link_name) - 3); // chop off ".so"
|
||||
glibc_ver->major = 2;
|
||||
glibc_ver->minor = 0;
|
||||
glibc_ver->patch = 0;
|
||||
return target_parse_glibc_version(glibc_ver, buf_ptr(link_name) + 5);
|
||||
}
|
||||
#else
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t glibc_lib_count(void) {
|
||||
return array_length(glibc_libs);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ struct ZigGLibCAbi {
|
||||
Buf *abi_txt_path;
|
||||
Buf *vers_txt_path;
|
||||
Buf *fns_txt_path;
|
||||
ZigList<ZigGLibCVersion> all_versions;
|
||||
ZigList<Stage2SemVer> all_versions;
|
||||
ZigList<ZigGLibCFn> all_functions;
|
||||
// The value is a pointer to all_functions.length items and each item is an index
|
||||
// into all_functions.
|
||||
@ -43,9 +43,6 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo
|
||||
Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
|
||||
Buf **out_dir, bool verbose, Stage2ProgressNode *progress_node);
|
||||
|
||||
// returns ErrorUnknownABI when glibc is not the native libc
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver);
|
||||
|
||||
size_t glibc_lib_count(void);
|
||||
const ZigGLibCLib *glibc_lib_enum(size_t index);
|
||||
const ZigGLibCLib *glibc_lib_find(const char *name);
|
||||
|
106
src/ir.cpp
106
src/ir.cpp
@ -12555,13 +12555,22 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc
|
||||
{
|
||||
Error err;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, array_ptr->value->type->data.pointer.child_type,
|
||||
ResolveStatusAlignmentKnown)))
|
||||
{
|
||||
assert(array_ptr->value->type->id == ZigTypeIdPointer);
|
||||
|
||||
if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, array_ptr->value->type));
|
||||
assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
|
||||
|
||||
const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len;
|
||||
|
||||
// A zero-sized array can always be casted irregardless of the destination
|
||||
// alignment
|
||||
if (array_len != 0) {
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type,
|
||||
get_ptr_align(ira->codegen, array_ptr->value->type));
|
||||
}
|
||||
|
||||
if (instr_is_comptime(array_ptr)) {
|
||||
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,
|
||||
|
||||
// cast from inferred struct type to array, union, or struct
|
||||
if (is_anon_container(actual_type)) {
|
||||
AstNode *decl_node = actual_type->data.structure.decl_node;
|
||||
ir_assert(decl_node->type == NodeTypeContainerInitExpr, source_instr);
|
||||
ContainerInitKind init_kind = decl_node->data.container_init_expr.kind;
|
||||
uint32_t field_count = actual_type->data.structure.src_field_count;
|
||||
if (wanted_type->id == ZigTypeIdArray && (init_kind == ContainerInitKindArray || field_count == 0) &&
|
||||
const bool is_array_init =
|
||||
actual_type->data.structure.special == StructSpecialInferredTuple;
|
||||
const uint32_t field_count = actual_type->data.structure.src_field_count;
|
||||
|
||||
if (wanted_type->id == ZigTypeIdArray && (is_array_init || field_count == 0) &&
|
||||
wanted_type->data.array.len == field_count)
|
||||
{
|
||||
return ir_analyze_struct_literal_to_array(ira, source_instr, value, wanted_type);
|
||||
} else if (wanted_type->id == ZigTypeIdStruct &&
|
||||
(init_kind == ContainerInitKindStruct || field_count == 0))
|
||||
(!is_array_init || field_count == 0))
|
||||
{
|
||||
return ir_analyze_struct_literal_to_struct(ira, source_instr, value, wanted_type);
|
||||
} else if (wanted_type->id == ZigTypeIdUnion && init_kind == ContainerInitKindStruct && field_count == 1) {
|
||||
} else if (wanted_type->id == ZigTypeIdUnion && !is_array_init && field_count == 1) {
|
||||
return ir_analyze_struct_literal_to_union(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
}
|
||||
@ -17799,6 +17808,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
|
||||
}
|
||||
} break;
|
||||
case ZigTypeIdInt:
|
||||
want_var_export = true;
|
||||
break;
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
@ -20369,6 +20379,17 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
|
||||
ptr_type->data.pointer.allow_zero);
|
||||
}
|
||||
|
||||
static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) {
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
return get_pointer_to_type_extra(g,
|
||||
ptr_type->data.pointer.child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
ptr_type->data.pointer.ptr_len,
|
||||
ptr_type->data.pointer.explicit_alignment,
|
||||
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
|
||||
allow_zero);
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
|
||||
Error err;
|
||||
IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
|
||||
@ -23148,12 +23169,15 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
|
||||
if (instr_is_comptime(target)) {
|
||||
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
if (target->value->type->data.enumeration.non_exhaustive) {
|
||||
ir_add_error(ira, &instruction->base.base,
|
||||
buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
|
||||
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
|
||||
if (field == nullptr) {
|
||||
Buf *int_buf = buf_alloc();
|
||||
bigint_append_buf(int_buf, &target->value->data.x_bigint, 10);
|
||||
|
||||
ir_add_error(ira, &target->base,
|
||||
buf_sprintf("no tag by value %s", buf_ptr(int_buf)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
|
||||
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
|
||||
IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr);
|
||||
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
|
||||
ZigType *non_sentinel_slice_ptr_type;
|
||||
ZigType *elem_type;
|
||||
|
||||
bool generate_non_null_assert = false;
|
||||
|
||||
if (array_type->id == ZigTypeIdArray) {
|
||||
elem_type = array_type->data.array.child_type;
|
||||
bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic &&
|
||||
@ -25947,6 +25973,14 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
||||
elem_type = array_type->data.pointer.child_type;
|
||||
if (array_type->data.pointer.ptr_len == PtrLenC) {
|
||||
array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
|
||||
|
||||
// C pointers are allowzero by default.
|
||||
// However, we want to be able to slice them without generating an allowzero slice (see issue #4401).
|
||||
// To achieve this, we generate a runtime safety check and make the slice type non-allowzero.
|
||||
if (array_type->data.pointer.allow_zero) {
|
||||
array_type = adjust_ptr_allow_zero(ira->codegen, array_type, false);
|
||||
generate_non_null_assert = true;
|
||||
}
|
||||
}
|
||||
ZigType *maybe_sentineled_slice_ptr_type = array_type;
|
||||
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
|
||||
|
||||
IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
|
||||
return_type, nullptr, true, true);
|
||||
|
||||
if (result_loc != nullptr) {
|
||||
if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
|
||||
return result_loc;
|
||||
@ -26231,8 +26264,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
return ir_build_slice_gen(ira, &instruction->base.base, return_type,
|
||||
ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc);
|
||||
if (generate_non_null_assert) {
|
||||
IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
|
||||
|
||||
if (type_is_invalid(ptr_val->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
|
||||
}
|
||||
|
||||
return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
|
||||
casted_start, end, instruction->safety_check_on, result_loc);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
IrInstGen *result = ir_const(ira, source_instr, ptr_type);
|
||||
result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
|
||||
result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar;
|
||||
result->value->data.x_ptr.data.hard_coded_addr.addr = addr;
|
||||
if (ptr_type->id == ZigTypeIdOptional && addr == 0) {
|
||||
result->value->data.x_ptr.special = ConstPtrSpecialNull;
|
||||
result->value->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
} else {
|
||||
result->value->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
|
||||
result->value->data.x_ptr.mut = ConstPtrMutRuntimeVar;
|
||||
result->value->data.x_ptr.data.hard_coded_addr.addr = addr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -27878,15 +27926,15 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr
|
||||
|
||||
ZigType *usize = ira->codegen->builtin_types.entry_usize;
|
||||
|
||||
// We check size explicitly so we can use get_src_ptr_type here.
|
||||
if (get_src_ptr_type(target->value->type) == nullptr) {
|
||||
ZigType *src_ptr_type = get_src_ptr_type(target->value->type);
|
||||
if (src_ptr_type == nullptr) {
|
||||
ir_add_error(ira, &target->base,
|
||||
buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value->type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
bool has_bits;
|
||||
if ((err = type_has_bits2(ira->codegen, target->value->type, &has_bits)))
|
||||
if ((err = type_has_bits2(ira->codegen, src_ptr_type, &has_bits)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
if (!has_bits) {
|
||||
@ -27899,11 +27947,19 @@ static IrInstGen *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstSrcPtr
|
||||
ZigValue *val = ir_resolve_const(ira, target, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
|
||||
// Since we've already run this type trough get_codegen_ptr_type it is
|
||||
// safe to access the x_ptr fields
|
||||
if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
IrInstGen *result = ir_const(ira, &instruction->base.base, usize);
|
||||
bigint_init_unsigned(&result->value->data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
|
||||
result->value->type = usize;
|
||||
return result;
|
||||
} else if (val->data.x_ptr.special == ConstPtrSpecialNull) {
|
||||
IrInstGen *result = ir_const(ira, &instruction->base.base, usize);
|
||||
bigint_init_unsigned(&result->value->data.x_bigint, 0);
|
||||
result->value->type = usize;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
131
src/link.cpp
131
src/link.cpp
@ -1751,9 +1751,9 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
||||
}
|
||||
|
||||
if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) {
|
||||
assert(g->dynamic_linker_path != nullptr);
|
||||
assert(g->zig_target->dynamic_linker != nullptr);
|
||||
lj->args.append("-dynamic-linker");
|
||||
lj->args.append(buf_ptr(g->dynamic_linker_path));
|
||||
lj->args.append(g->zig_target->dynamic_linker);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2376,99 +2376,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
|
||||
// grouped values as integers. Numbers which are not provided are set to 0.
|
||||
// return true if the entire string was parsed (9.2), or all groups were
|
||||
// parsed (10.3.5extrastuff).
|
||||
static bool darwin_get_release_version(const char *str, int *major, int *minor, int *micro, bool *had_extra) {
|
||||
*had_extra = false;
|
||||
|
||||
*major = 0;
|
||||
*minor = 0;
|
||||
*micro = 0;
|
||||
|
||||
if (*str == '\0')
|
||||
return false;
|
||||
|
||||
char *end;
|
||||
*major = (int)strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (*end != '.')
|
||||
return false;
|
||||
|
||||
str = end + 1;
|
||||
*minor = (int)strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (*end != '.')
|
||||
return false;
|
||||
|
||||
str = end + 1;
|
||||
*micro = (int)strtol(str, &end, 10);
|
||||
if (*str != '\0' && *end == '\0')
|
||||
return true;
|
||||
if (str == end)
|
||||
return false;
|
||||
*had_extra = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
enum DarwinPlatformKind {
|
||||
MacOS,
|
||||
IPhoneOS,
|
||||
IPhoneOSSimulator,
|
||||
};
|
||||
|
||||
struct DarwinPlatform {
|
||||
DarwinPlatformKind kind;
|
||||
int major;
|
||||
int minor;
|
||||
int micro;
|
||||
};
|
||||
|
||||
static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
if (g->mmacosx_version_min) {
|
||||
platform->kind = MacOS;
|
||||
} else if (g->mios_version_min) {
|
||||
platform->kind = IPhoneOS;
|
||||
} else if (g->zig_target->os == OsMacOSX) {
|
||||
platform->kind = MacOS;
|
||||
g->mmacosx_version_min = buf_create_from_str("10.14");
|
||||
} else {
|
||||
zig_panic("unable to infer -mmacosx-version-min or -mios-version-min");
|
||||
}
|
||||
|
||||
bool had_extra;
|
||||
if (platform->kind == MacOS) {
|
||||
if (!darwin_get_release_version(buf_ptr(g->mmacosx_version_min),
|
||||
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
|
||||
had_extra || platform->major != 10 || platform->minor >= 100 || platform->micro >= 100)
|
||||
{
|
||||
zig_panic("invalid -mmacosx-version-min");
|
||||
}
|
||||
} else if (platform->kind == IPhoneOS) {
|
||||
if (!darwin_get_release_version(buf_ptr(g->mios_version_min),
|
||||
&platform->major, &platform->minor, &platform->micro, &had_extra) ||
|
||||
had_extra || platform->major >= 10 || platform->minor >= 100 || platform->micro >= 100)
|
||||
{
|
||||
zig_panic("invalid -mios-version-min");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (platform->kind == IPhoneOS &&
|
||||
(g->zig_target->arch == ZigLLVM_x86 ||
|
||||
g->zig_target->arch == ZigLLVM_x86_64))
|
||||
{
|
||||
platform->kind = IPhoneOSSimulator;
|
||||
}
|
||||
}
|
||||
|
||||
static void construct_linker_job_macho(LinkJob *lj) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
@ -2512,25 +2419,25 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
lj->args.append("-arch");
|
||||
lj->args.append(get_darwin_arch_string(g->zig_target));
|
||||
|
||||
DarwinPlatform platform;
|
||||
get_darwin_platform(lj, &platform);
|
||||
switch (platform.kind) {
|
||||
case MacOS:
|
||||
if (g->zig_target->glibc_or_darwin_version != nullptr) {
|
||||
if (g->zig_target->os == OsMacOSX) {
|
||||
lj->args.append("-macosx_version_min");
|
||||
break;
|
||||
case IPhoneOS:
|
||||
lj->args.append("-iphoneos_version_min");
|
||||
break;
|
||||
case IPhoneOSSimulator:
|
||||
lj->args.append("-ios_simulator_version_min");
|
||||
break;
|
||||
} else if (g->zig_target->os == OsIOS) {
|
||||
if (g->zig_target->arch == ZigLLVM_x86 || g->zig_target->arch == ZigLLVM_x86_64) {
|
||||
lj->args.append("-ios_simulator_version_min");
|
||||
} else {
|
||||
lj->args.append("-iphoneos_version_min");
|
||||
}
|
||||
}
|
||||
Buf *version_string = buf_sprintf("%d.%d.%d",
|
||||
g->zig_target->glibc_or_darwin_version->major,
|
||||
g->zig_target->glibc_or_darwin_version->minor,
|
||||
g->zig_target->glibc_or_darwin_version->patch);
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
|
||||
lj->args.append("-sdk_version");
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
}
|
||||
Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
|
||||
lj->args.append("-sdk_version");
|
||||
lj->args.append(buf_ptr(version_string));
|
||||
|
||||
|
||||
if (g->out_type == OutTypeExe) {
|
||||
lj->args.append("-pie");
|
||||
|
66
src/main.cpp
66
src/main.cpp
@ -89,8 +89,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
||||
" --single-threaded source may assume it is only used single-threaded\n"
|
||||
" -dynamic create a shared library (.so; .dll; .dylib)\n"
|
||||
" --strip exclude debug symbols\n"
|
||||
" -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
|
||||
" -target-glibc [version] target a specific glibc version (default: 2.17)\n"
|
||||
" -target [name] <arch>-<os>-<abi> see the targets command\n"
|
||||
" --verbose-tokenize enable compiler debug output for tokenization\n"
|
||||
" --verbose-ast enable compiler debug output for AST parsing\n"
|
||||
" --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) {
|
||||
" --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
|
||||
" -F[dir] (darwin) add search path for frameworks\n"
|
||||
" -framework [name] (darwin) link against framework\n"
|
||||
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
|
||||
" -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
|
||||
" --ver-major [ver] dynamic library semver major version\n"
|
||||
" --ver-minor [ver] dynamic library semver minor version\n"
|
||||
" --ver-patch [ver] dynamic library semver patch version\n"
|
||||
@ -405,7 +402,7 @@ static int main0(int argc, char **argv) {
|
||||
bool link_eh_frame_hdr = false;
|
||||
ErrColor color = ErrColorAuto;
|
||||
CacheOpt enable_cache = CacheOptAuto;
|
||||
Buf *dynamic_linker = nullptr;
|
||||
const char *dynamic_linker = nullptr;
|
||||
const char *libc_txt = nullptr;
|
||||
ZigList<const char *> clang_argv = {0};
|
||||
ZigList<const char *> lib_dirs = {0};
|
||||
@ -416,11 +413,8 @@ static int main0(int argc, char **argv) {
|
||||
bool have_libc = false;
|
||||
const char *target_string = nullptr;
|
||||
bool rdynamic = false;
|
||||
const char *mmacosx_version_min = nullptr;
|
||||
const char *mios_version_min = nullptr;
|
||||
const char *linker_script = nullptr;
|
||||
Buf *version_script = nullptr;
|
||||
const char *target_glibc = nullptr;
|
||||
ZigList<const char *> rpath_list = {0};
|
||||
bool each_lib_rpath = false;
|
||||
ZigList<const char *> objects = {0};
|
||||
@ -503,7 +497,10 @@ static int main0(int argc, char **argv) {
|
||||
os_path_join(get_zig_special_dir(zig_lib_dir), buf_create_from_str("build_runner.zig"), build_runner_path);
|
||||
|
||||
ZigTarget target;
|
||||
get_native_target(&target);
|
||||
if ((err = target_parse_triple(&target, "native", nullptr, nullptr))) {
|
||||
fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Buf *build_file_buf = buf_create_from_str((build_file != nullptr) ? build_file : "build.zig");
|
||||
Buf build_file_abs = os_path_resolve(&build_file_buf, 1);
|
||||
@ -770,7 +767,7 @@ static int main0(int argc, char **argv) {
|
||||
} else if (strcmp(arg, "--name") == 0) {
|
||||
out_name = argv[i];
|
||||
} else if (strcmp(arg, "--dynamic-linker") == 0) {
|
||||
dynamic_linker = buf_create_from_str(argv[i]);
|
||||
dynamic_linker = argv[i];
|
||||
} else if (strcmp(arg, "--libc") == 0) {
|
||||
libc_txt = argv[i];
|
||||
} else if (strcmp(arg, "-D") == 0) {
|
||||
@ -844,18 +841,12 @@ static int main0(int argc, char **argv) {
|
||||
cache_dir = argv[i];
|
||||
} else if (strcmp(arg, "-target") == 0) {
|
||||
target_string = argv[i];
|
||||
} else if (strcmp(arg, "-mmacosx-version-min") == 0) {
|
||||
mmacosx_version_min = argv[i];
|
||||
} else if (strcmp(arg, "-mios-version-min") == 0) {
|
||||
mios_version_min = argv[i];
|
||||
} else if (strcmp(arg, "-framework") == 0) {
|
||||
frameworks.append(argv[i]);
|
||||
} else if (strcmp(arg, "--linker-script") == 0) {
|
||||
linker_script = argv[i];
|
||||
} else if (strcmp(arg, "--version-script") == 0) {
|
||||
version_script = buf_create_from_str(argv[i]);
|
||||
} else if (strcmp(arg, "-target-glibc") == 0) {
|
||||
target_glibc = argv[i];
|
||||
} else if (strcmp(arg, "-rpath") == 0) {
|
||||
rpath_list.append(argv[i]);
|
||||
} else if (strcmp(arg, "--test-filter") == 0) {
|
||||
@ -978,34 +969,11 @@ static int main0(int argc, char **argv) {
|
||||
init_all_targets();
|
||||
|
||||
ZigTarget target;
|
||||
if ((err = target_parse_triple(&target, target_string, mcpu))) {
|
||||
if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) {
|
||||
fprintf(stderr, "invalid target: %s\n"
|
||||
"See `%s targets` to display valid targets.\n", err_str(err), arg0);
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
if (target_is_glibc(&target)) {
|
||||
target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>();
|
||||
|
||||
if (target_glibc != nullptr) {
|
||||
if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) {
|
||||
fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err));
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
} else {
|
||||
target_init_default_glibc_version(&target);
|
||||
#if defined(ZIG_OS_LINUX)
|
||||
if (target.is_native) {
|
||||
// TODO self-host glibc version detection, and then this logic can go away
|
||||
if ((err = glibc_detect_native_version(target.glibc_version))) {
|
||||
// Fall back to the default version.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (target_glibc != nullptr) {
|
||||
fprintf(stderr, "'%s' is not a glibc-compatible target", target_string);
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
|
||||
Buf zig_triple_buf = BUF_INIT;
|
||||
target_triple_zig(&zig_triple_buf, &target);
|
||||
@ -1226,7 +1194,6 @@ static int main0(int argc, char **argv) {
|
||||
|
||||
codegen_set_strip(g, strip);
|
||||
g->is_dynamic = is_dynamic;
|
||||
g->dynamic_linker_path = dynamic_linker;
|
||||
g->verbose_tokenize = verbose_tokenize;
|
||||
g->verbose_ast = verbose_ast;
|
||||
g->verbose_link = verbose_link;
|
||||
@ -1265,18 +1232,6 @@ static int main0(int argc, char **argv) {
|
||||
}
|
||||
|
||||
codegen_set_rdynamic(g, rdynamic);
|
||||
if (mmacosx_version_min && mios_version_min) {
|
||||
fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
|
||||
return main_exit(root_progress_node, EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (mmacosx_version_min) {
|
||||
codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
|
||||
}
|
||||
|
||||
if (mios_version_min) {
|
||||
codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
|
||||
}
|
||||
|
||||
if (test_filter) {
|
||||
codegen_set_test_filter(g, buf_create_from_str(test_filter));
|
||||
@ -1365,7 +1320,10 @@ static int main0(int argc, char **argv) {
|
||||
return main_exit(root_progress_node, EXIT_SUCCESS);
|
||||
} else if (cmd == CmdTest) {
|
||||
ZigTarget native;
|
||||
get_native_target(&native);
|
||||
if ((err = target_parse_triple(&native, "native", nullptr, nullptr))) {
|
||||
fprintf(stderr, "Unable to get native target: %s\n", err_str(err));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
g->enable_cache = get_cache_opt(enable_cache, output_dir == nullptr);
|
||||
codegen_build_and_link(g);
|
||||
|
@ -1073,8 +1073,8 @@ static Error set_file_times(OsFile file, OsTimeStamp ts) {
|
||||
return ErrorNone;
|
||||
#else
|
||||
struct timespec times[2] = {
|
||||
{ ts.sec, ts.nsec },
|
||||
{ ts.sec, ts.nsec },
|
||||
{ (time_t)ts.sec, (time_t)ts.nsec },
|
||||
{ (time_t)ts.sec, (time_t)ts.nsec },
|
||||
};
|
||||
if (futimens(file, times) == -1) {
|
||||
switch (errno) {
|
||||
|
115
src/stage2.cpp
115
src/stage2.cpp
@ -91,7 +91,109 @@ void stage2_progress_complete_one(Stage2ProgressNode *node) {}
|
||||
void stage2_progress_disable_tty(Stage2Progress *progress) {}
|
||||
void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
|
||||
|
||||
Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) {
|
||||
static Os get_zig_os_type(ZigLLVM_OSType os_type) {
|
||||
switch (os_type) {
|
||||
case ZigLLVM_UnknownOS:
|
||||
return OsFreestanding;
|
||||
case ZigLLVM_Ananas:
|
||||
return OsAnanas;
|
||||
case ZigLLVM_CloudABI:
|
||||
return OsCloudABI;
|
||||
case ZigLLVM_DragonFly:
|
||||
return OsDragonFly;
|
||||
case ZigLLVM_FreeBSD:
|
||||
return OsFreeBSD;
|
||||
case ZigLLVM_Fuchsia:
|
||||
return OsFuchsia;
|
||||
case ZigLLVM_IOS:
|
||||
return OsIOS;
|
||||
case ZigLLVM_KFreeBSD:
|
||||
return OsKFreeBSD;
|
||||
case ZigLLVM_Linux:
|
||||
return OsLinux;
|
||||
case ZigLLVM_Lv2:
|
||||
return OsLv2;
|
||||
case ZigLLVM_Darwin:
|
||||
case ZigLLVM_MacOSX:
|
||||
return OsMacOSX;
|
||||
case ZigLLVM_NetBSD:
|
||||
return OsNetBSD;
|
||||
case ZigLLVM_OpenBSD:
|
||||
return OsOpenBSD;
|
||||
case ZigLLVM_Solaris:
|
||||
return OsSolaris;
|
||||
case ZigLLVM_Win32:
|
||||
return OsWindows;
|
||||
case ZigLLVM_Haiku:
|
||||
return OsHaiku;
|
||||
case ZigLLVM_Minix:
|
||||
return OsMinix;
|
||||
case ZigLLVM_RTEMS:
|
||||
return OsRTEMS;
|
||||
case ZigLLVM_NaCl:
|
||||
return OsNaCl;
|
||||
case ZigLLVM_CNK:
|
||||
return OsCNK;
|
||||
case ZigLLVM_AIX:
|
||||
return OsAIX;
|
||||
case ZigLLVM_CUDA:
|
||||
return OsCUDA;
|
||||
case ZigLLVM_NVCL:
|
||||
return OsNVCL;
|
||||
case ZigLLVM_AMDHSA:
|
||||
return OsAMDHSA;
|
||||
case ZigLLVM_PS4:
|
||||
return OsPS4;
|
||||
case ZigLLVM_ELFIAMCU:
|
||||
return OsELFIAMCU;
|
||||
case ZigLLVM_TvOS:
|
||||
return OsTvOS;
|
||||
case ZigLLVM_WatchOS:
|
||||
return OsWatchOS;
|
||||
case ZigLLVM_Mesa3D:
|
||||
return OsMesa3D;
|
||||
case ZigLLVM_Contiki:
|
||||
return OsContiki;
|
||||
case ZigLLVM_AMDPAL:
|
||||
return OsAMDPAL;
|
||||
case ZigLLVM_HermitCore:
|
||||
return OsHermitCore;
|
||||
case ZigLLVM_Hurd:
|
||||
return OsHurd;
|
||||
case ZigLLVM_WASI:
|
||||
return OsWASI;
|
||||
case ZigLLVM_Emscripten:
|
||||
return OsEmscripten;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void get_native_target(ZigTarget *target) {
|
||||
// first zero initialize
|
||||
*target = {};
|
||||
|
||||
ZigLLVM_OSType os_type;
|
||||
ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
|
||||
ZigLLVMGetNativeTarget(
|
||||
&target->arch,
|
||||
&target->vendor,
|
||||
&os_type,
|
||||
&target->abi,
|
||||
&oformat);
|
||||
target->os = get_zig_os_type(os_type);
|
||||
target->is_native = true;
|
||||
if (target->abi == ZigLLVM_UnknownEnvironment) {
|
||||
target->abi = target_default_abi(target->arch, target->os);
|
||||
}
|
||||
if (target_is_glibc(target)) {
|
||||
target->glibc_or_darwin_version = heap::c_allocator.create<Stage2SemVer>();
|
||||
target_init_default_glibc_version(target);
|
||||
}
|
||||
}
|
||||
|
||||
Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
|
||||
const char *dynamic_linker)
|
||||
{
|
||||
Error err;
|
||||
|
||||
if (zig_triple == nullptr) {
|
||||
@ -100,13 +202,11 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
|
||||
if (mcpu == nullptr) {
|
||||
target->llvm_cpu_name = ZigLLVMGetHostCPUName();
|
||||
target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
|
||||
target->builtin_str = "Target.Cpu.baseline(arch);\n";
|
||||
target->cache_hash = "native\n\n";
|
||||
} else if (strcmp(mcpu, "baseline") == 0) {
|
||||
target->is_native = false;
|
||||
target->llvm_cpu_name = "";
|
||||
target->llvm_cpu_features = "";
|
||||
target->builtin_str = "Target.Cpu.baseline(arch);\n";
|
||||
target->cache_hash = "baseline\n\n";
|
||||
} else {
|
||||
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
|
||||
const char *msg = "stage0 can't handle CPU/features in the target";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
target->builtin_str = "Target.Cpu.baseline(arch);\n";
|
||||
target->cache_hash = "\n\n";
|
||||
}
|
||||
|
||||
if (dynamic_linker != nullptr) {
|
||||
target->dynamic_linker = dynamic_linker;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
@ -186,11 +288,6 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
|
||||
const char *msg = "stage0 called stage2_detect_dynamic_linker";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) {
|
||||
native_paths->include_dirs_ptr = nullptr;
|
||||
native_paths->include_dirs_len = 0;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user